mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 998802 - Add support for symmetric-key encryption and MAC to WebCrypto API. r=bz,dkeeler
This commit is contained in:
parent
cc95c8261d
commit
439225237c
@ -20,24 +20,6 @@ class OwningArrayBufferViewOrArrayBuffer;
|
||||
class CryptoBuffer : public FallibleTArray<uint8_t>
|
||||
{
|
||||
public:
|
||||
CryptoBuffer()
|
||||
: FallibleTArray<uint8_t>()
|
||||
{}
|
||||
|
||||
template<class T>
|
||||
explicit CryptoBuffer(const T& aData)
|
||||
: FallibleTArray<uint8_t>()
|
||||
{
|
||||
Assign(aData);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
CryptoBuffer& operator=(const T& aData)
|
||||
{
|
||||
Assign(aData);
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t* Assign(const uint8_t* aData, uint32_t aLength);
|
||||
uint8_t* Assign(const SECItem* aItem);
|
||||
uint8_t* Assign(const ArrayBuffer& aData);
|
||||
|
@ -24,6 +24,20 @@ namespace dom {
|
||||
|
||||
// Convenience functions for extracting / converting information
|
||||
|
||||
// OOM-safe CryptoBuffer initialization, suitable for constructors
|
||||
#define ATTEMPT_BUFFER_INIT(dst, src) \
|
||||
if (!dst.Assign(src)) { \
|
||||
mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR; \
|
||||
return; \
|
||||
}
|
||||
|
||||
// OOM-safe CryptoBuffer-to-SECItem copy, suitable for DoCrypto
|
||||
#define ATTEMPT_BUFFER_TO_SECITEM(dst, src) \
|
||||
dst = src.ToSECItem(); \
|
||||
if (!dst) { \
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR; \
|
||||
}
|
||||
|
||||
class ClearException
|
||||
{
|
||||
public:
|
||||
@ -107,6 +121,264 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class AesTask : public ReturnArrayBufferViewTask
|
||||
{
|
||||
public:
|
||||
AesTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
mozilla::dom::Key& aKey, const CryptoOperationData& aData,
|
||||
bool aEncrypt)
|
||||
: mSymKey(aKey.GetSymKey())
|
||||
, mEncrypt(aEncrypt)
|
||||
{
|
||||
ATTEMPT_BUFFER_INIT(mData, aData);
|
||||
|
||||
nsString algName;
|
||||
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that we got a reasonable key
|
||||
if ((mSymKey.Length() != 16) &&
|
||||
(mSymKey.Length() != 24) &&
|
||||
(mSymKey.Length() != 32))
|
||||
{
|
||||
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache parameters depending on the specific algorithm
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC)) {
|
||||
mMechanism = CKM_AES_CBC_PAD;
|
||||
AesCbcParams params;
|
||||
nsresult rv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(rv) || !params.mIv.WasPassed()) {
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
ATTEMPT_BUFFER_INIT(mIv, params.mIv.Value())
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR)) {
|
||||
mMechanism = CKM_AES_CTR;
|
||||
AesCtrParams params;
|
||||
nsresult rv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(rv) || !params.mCounter.WasPassed() ||
|
||||
!params.mLength.WasPassed()) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
ATTEMPT_BUFFER_INIT(mIv, params.mCounter.Value())
|
||||
if (mIv.Length() != 16) {
|
||||
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
mCounterLength = params.mLength.Value();
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
|
||||
mMechanism = CKM_AES_GCM;
|
||||
AesGcmParams params;
|
||||
nsresult rv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(rv) || !params.mIv.WasPassed()) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
ATTEMPT_BUFFER_INIT(mIv, params.mIv.Value())
|
||||
|
||||
if (params.mAdditionalData.WasPassed()) {
|
||||
ATTEMPT_BUFFER_INIT(mAad, params.mAdditionalData.Value())
|
||||
}
|
||||
|
||||
// 32, 64, 96, 104, 112, 120 or 128
|
||||
mTagLength = 128;
|
||||
if (params.mTagLength.WasPassed()) {
|
||||
mTagLength = params.mTagLength.Value();
|
||||
if ((mTagLength > 128) ||
|
||||
!(mTagLength == 32 || mTagLength == 64 ||
|
||||
(mTagLength >= 96 && mTagLength % 8 == 0))) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CK_MECHANISM_TYPE mMechanism;
|
||||
CryptoBuffer mSymKey;
|
||||
CryptoBuffer mIv; // Initialization vector
|
||||
CryptoBuffer mData;
|
||||
CryptoBuffer mAad; // Additional Authenticated Data
|
||||
uint8_t mTagLength;
|
||||
uint8_t mCounterLength;
|
||||
bool mEncrypt;
|
||||
|
||||
virtual nsresult DoCrypto() MOZ_OVERRIDE
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Construct the parameters object depending on algorithm
|
||||
SECItem param;
|
||||
ScopedSECItem cbcParam;
|
||||
CK_AES_CTR_PARAMS ctrParams;
|
||||
CK_GCM_PARAMS gcmParams;
|
||||
switch (mMechanism) {
|
||||
case CKM_AES_CBC_PAD:
|
||||
ATTEMPT_BUFFER_TO_SECITEM(cbcParam, mIv);
|
||||
param = *cbcParam;
|
||||
break;
|
||||
case CKM_AES_CTR:
|
||||
ctrParams.ulCounterBits = mCounterLength;
|
||||
MOZ_ASSERT(mIv.Length() == 16);
|
||||
memcpy(&ctrParams.cb, mIv.Elements(), 16);
|
||||
param.type = siBuffer;
|
||||
param.data = (unsigned char*) &ctrParams;
|
||||
param.len = sizeof(ctrParams);
|
||||
break;
|
||||
case CKM_AES_GCM:
|
||||
gcmParams.pIv = mIv.Elements();
|
||||
gcmParams.ulIvLen = mIv.Length();
|
||||
gcmParams.pAAD = mAad.Elements();
|
||||
gcmParams.ulAADLen = mAad.Length();
|
||||
gcmParams.ulTagBits = mTagLength;
|
||||
param.type = siBuffer;
|
||||
param.data = (unsigned char*) &gcmParams;
|
||||
param.len = sizeof(gcmParams);
|
||||
break;
|
||||
default:
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
|
||||
// Import the key
|
||||
ScopedSECItem keyItem;
|
||||
ATTEMPT_BUFFER_TO_SECITEM(keyItem, mSymKey);
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
MOZ_ASSERT(slot.get());
|
||||
ScopedPK11SymKey symKey(PK11_ImportSymKey(slot, mMechanism, PK11_OriginUnwrap,
|
||||
CKA_ENCRYPT, keyItem.get(), nullptr));
|
||||
if (!symKey) {
|
||||
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
}
|
||||
|
||||
// Initialize the output buffer (enough space for padding / a full tag)
|
||||
uint32_t dataLen = mData.Length();
|
||||
uint32_t maxLen = dataLen + 16;
|
||||
if (!mResult.SetLength(maxLen)) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
uint32_t outLen = 0;
|
||||
|
||||
// Perform the encryption/decryption
|
||||
if (mEncrypt) {
|
||||
rv = MapSECStatus(PK11_Encrypt(symKey.get(), mMechanism, ¶m,
|
||||
mResult.Elements(), &outLen, maxLen,
|
||||
mData.Elements(), mData.Length()));
|
||||
} else {
|
||||
rv = MapSECStatus(PK11_Decrypt(symKey.get(), mMechanism, ¶m,
|
||||
mResult.Elements(), &outLen, maxLen,
|
||||
mData.Elements(), mData.Length()));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
||||
mResult.SetLength(outLen);
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
class HmacTask : public WebCryptoTask
|
||||
{
|
||||
public:
|
||||
HmacTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
mozilla::dom::Key& aKey,
|
||||
const CryptoOperationData& aSignature,
|
||||
const CryptoOperationData& aData,
|
||||
bool aSign)
|
||||
: mMechanism(aKey.Algorithm()->Mechanism())
|
||||
, mSymKey(aKey.GetSymKey())
|
||||
, mSign(aSign)
|
||||
{
|
||||
ATTEMPT_BUFFER_INIT(mData, aData);
|
||||
if (!aSign) {
|
||||
ATTEMPT_BUFFER_INIT(mSignature, aSignature);
|
||||
}
|
||||
|
||||
// Check that we got a symmetric key
|
||||
if (mSymKey.Length() == 0) {
|
||||
mEarlyRv = NS_ERROR_DOM_DATA_ERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CK_MECHANISM_TYPE mMechanism;
|
||||
CryptoBuffer mSymKey;
|
||||
CryptoBuffer mData;
|
||||
CryptoBuffer mSignature;
|
||||
CryptoBuffer mResult;
|
||||
bool mSign;
|
||||
|
||||
virtual nsresult DoCrypto() MOZ_OVERRIDE
|
||||
{
|
||||
// Initialize the output buffer
|
||||
if (!mResult.SetLength(HASH_LENGTH_MAX)) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
uint32_t outLen;
|
||||
|
||||
// Import the key
|
||||
ScopedSECItem keyItem;
|
||||
ATTEMPT_BUFFER_TO_SECITEM(keyItem, mSymKey);
|
||||
ScopedPK11SlotInfo slot(PK11_GetInternalSlot());
|
||||
MOZ_ASSERT(slot.get());
|
||||
ScopedPK11SymKey symKey(PK11_ImportSymKey(slot, mMechanism, PK11_OriginUnwrap,
|
||||
CKA_SIGN, keyItem.get(), nullptr));
|
||||
if (!symKey) {
|
||||
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
}
|
||||
|
||||
// Compute the MAC
|
||||
SECItem param = { siBuffer, nullptr, 0 };
|
||||
ScopedPK11Context ctx(PK11_CreateContextBySymKey(mMechanism, CKA_SIGN,
|
||||
symKey.get(), ¶m));
|
||||
if (!ctx.get()) {
|
||||
return NS_ERROR_DOM_OPERATION_ERR;
|
||||
}
|
||||
nsresult rv = MapSECStatus(PK11_DigestBegin(ctx.get()));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
rv = MapSECStatus(PK11_DigestOp(ctx.get(), mData.Elements(), mData.Length()));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
rv = MapSECStatus(PK11_DigestFinal(ctx.get(), mResult.Elements(),
|
||||
&outLen, HASH_LENGTH_MAX));
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
|
||||
mResult.SetLength(outLen);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Returns mResult as an ArrayBufferView, or an error
|
||||
virtual void Resolve() MOZ_OVERRIDE
|
||||
{
|
||||
if (mSign) {
|
||||
// Return the computed MAC
|
||||
TypedArrayCreator<Uint8Array> ret(mResult);
|
||||
mResultPromise->MaybeResolve(ret);
|
||||
} else {
|
||||
// Compare the MAC to the provided signature
|
||||
// No truncation allowed
|
||||
bool equal = (mResult.Length() == mSignature.Length());
|
||||
int cmp = NSS_SecureMemcmp(mSignature.Elements(),
|
||||
mResult.Elements(),
|
||||
mSignature.Length());
|
||||
equal = equal && (cmp == 0);
|
||||
mResultPromise->MaybeResolve(equal);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class SimpleDigestTask : public ReturnArrayBufferViewTask
|
||||
{
|
||||
public:
|
||||
@ -114,10 +386,7 @@ public:
|
||||
const ObjectOrString& aAlgorithm,
|
||||
const CryptoOperationData& aData)
|
||||
{
|
||||
if (!mData.Assign(aData)) {
|
||||
mEarlyRv = NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
return;
|
||||
}
|
||||
ATTEMPT_BUFFER_INIT(mData, aData);
|
||||
|
||||
nsString algName;
|
||||
mEarlyRv = GetAlgorithmName(aCx, aAlgorithm, algName);
|
||||
@ -513,6 +782,24 @@ WebCryptoTask::EncryptDecryptTask(JSContext* aCx,
|
||||
const CryptoOperationData& aData,
|
||||
bool aEncrypt)
|
||||
{
|
||||
nsString algName;
|
||||
nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
|
||||
if (NS_FAILED(rv)) {
|
||||
return new FailureTask(rv);
|
||||
}
|
||||
|
||||
// Ensure key is usable for this operation
|
||||
if ((aEncrypt && !aKey.HasUsage(Key::ENCRYPT)) ||
|
||||
(!aEncrypt && !aKey.HasUsage(Key::DECRYPT))) {
|
||||
return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
}
|
||||
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CBC) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_AES_CTR) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_AES_GCM)) {
|
||||
return new AesTask(aCx, aAlgorithm, aKey, aData, aEncrypt);
|
||||
}
|
||||
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
}
|
||||
|
||||
@ -524,6 +811,22 @@ WebCryptoTask::SignVerifyTask(JSContext* aCx,
|
||||
const CryptoOperationData& aData,
|
||||
bool aSign)
|
||||
{
|
||||
nsString algName;
|
||||
nsresult rv = GetAlgorithmName(aCx, aAlgorithm, algName);
|
||||
if (NS_FAILED(rv)) {
|
||||
return new FailureTask(rv);
|
||||
}
|
||||
|
||||
// Ensure key is usable for this operation
|
||||
if ((aSign && !aKey.HasUsage(Key::SIGN)) ||
|
||||
(!aSign && !aKey.HasUsage(Key::VERIFY))) {
|
||||
return new FailureTask(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
}
|
||||
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_HMAC)) {
|
||||
return new HmacTask(aCx, aAlgorithm, aKey, aSignature, aData, aSign);
|
||||
}
|
||||
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,7 @@ public:
|
||||
const CryptoOperationData& aData)
|
||||
{
|
||||
CryptoOperationData dummy;
|
||||
dummy.SetAsArrayBuffer(aCx);
|
||||
return SignVerifyTask(aCx, aAlgorithm, aKey, dummy, aData, true);
|
||||
}
|
||||
|
||||
|
@ -50,4 +50,156 @@ tv = {
|
||||
result: util.hex2abv("248D6A61D20638B8E5C026930C3E6039A33CE45964F" +
|
||||
"F2167F6ECEDD419DB06C1"),
|
||||
},
|
||||
|
||||
// Test vector 2 from:
|
||||
// <https://github.com/geertj/bluepass/blob/master/tests/vectors/aes-cbc-pkcs7.txt>
|
||||
aes_cbc_enc: {
|
||||
/*
|
||||
key: util.hex2abv("893123f2d57b6e2c39e2f10d3ff818d1"),
|
||||
iv: util.hex2abv("64be1b06ea7453ed2df9a79319d5edc5"),
|
||||
data: util.hex2abv("44afb9a64ac896c2"),
|
||||
result: util.hex2abv("7067c4cb6dfc69df949c2f39903c9310"),
|
||||
*/
|
||||
key: util.hex2abv("893123f2d57b6e2c39e2f10d3ff818d1"),
|
||||
iv: util.hex2abv("64be1b06ea7453ed2df9a79319d5edc5"),
|
||||
data: util.hex2abv("44afb9a64ac896c2"),
|
||||
result: util.hex2abv("7067c4cb6dfc69df949c2f39903c9310"),
|
||||
},
|
||||
|
||||
// Test vector 11 from:
|
||||
// <https://github.com/geertj/bluepass/blob/master/tests/vectors/aes-cbc-pkcs7.txt>
|
||||
aes_cbc_dec: {
|
||||
key: util.hex2abv("04952c3fcf497a4d449c41e8730c5d9a"),
|
||||
iv: util.hex2abv("53549bf7d5553b727458c1abaf0ba167"),
|
||||
data: util.hex2abv("7fa290322ca7a1a04b61a1147ff20fe6" +
|
||||
"6fde58510a1d0289d11c0ddf6f4decfd"),
|
||||
result: util.hex2abv("c9a44f6f75e98ddbca7332167f5c45e3"),
|
||||
},
|
||||
|
||||
// Test vector 2 from:
|
||||
// <http://tools.ietf.org/html/rfc3686#section-6>
|
||||
aes_ctr_enc: {
|
||||
key: util.hex2abv("7E24067817FAE0D743D6CE1F32539163"),
|
||||
iv: util.hex2abv("006CB6DBC0543B59DA48D90B00000001"),
|
||||
data: util.hex2abv("000102030405060708090A0B0C0D0E0F" +
|
||||
"101112131415161718191A1B1C1D1E1F"),
|
||||
result: util.hex2abv("5104A106168A72D9790D41EE8EDAD3" +
|
||||
"88EB2E1EFC46DA57C8FCE630DF9141BE28"),
|
||||
},
|
||||
|
||||
// Test vector 3 from:
|
||||
// <http://tools.ietf.org/html/rfc3686#section-6>
|
||||
aes_ctr_dec: {
|
||||
key: util.hex2abv("7691BE035E5020A8AC6E618529F9A0DC"),
|
||||
iv: util.hex2abv("00E0017B27777F3F4A1786F000000001"),
|
||||
data: util.hex2abv("000102030405060708090A0B0C0D0E0F" +
|
||||
"101112131415161718191A1B1C1D1E1F20212223"),
|
||||
result: util.hex2abv("C1CF48A89F2FFDD9CF4652E9EFDB72D7" +
|
||||
"4540A42BDE6D7836D59A5CEAAEF3105325B2072F"),
|
||||
},
|
||||
|
||||
// Test case #18 from McGrew and Viega
|
||||
// <http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf>
|
||||
aes_gcm_enc: {
|
||||
key: util.hex2abv("feffe9928665731c6d6a8f9467308308" +
|
||||
"feffe9928665731c6d6a8f9467308308"),
|
||||
iv: util.hex2abv("9313225df88406e555909c5aff5269aa" +
|
||||
"6a7a9538534f7da1e4c303d2a318a728" +
|
||||
"c3c0c95156809539fcf0e2429a6b5254" +
|
||||
"16aedbf5a0de6a57a637b39b"),
|
||||
adata: util.hex2abv("feedfacedeadbeeffeedfacedeadbeefabaddad2"),
|
||||
data: util.hex2abv("d9313225f88406e5a55909c5aff5269a" +
|
||||
"86a7a9531534f7da2e4c303d8a318a72" +
|
||||
"1c3c0c95956809532fcf0e2449a6b525" +
|
||||
"b16aedf5aa0de657ba637b39"),
|
||||
result: util.hex2abv("5a8def2f0c9e53f1f75d7853659e2a20" +
|
||||
"eeb2b22aafde6419a058ab4f6f746bf4" +
|
||||
"0fc0c3b780f244452da3ebf1c5d82cde" +
|
||||
"a2418997200ef82e44ae7e3f" +
|
||||
"a44a8266ee1c8eb0c8b5d4cf5ae9f19a"),
|
||||
},
|
||||
|
||||
|
||||
// Test case #17 from McGrew and Viega
|
||||
// <http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf>
|
||||
aes_gcm_dec: {
|
||||
key: util.hex2abv("feffe9928665731c6d6a8f9467308308" +
|
||||
"feffe9928665731c6d6a8f9467308308"),
|
||||
iv: util.hex2abv("cafebabefacedbad"),
|
||||
adata: util.hex2abv("feedfacedeadbeeffeedfacedeadbeefabaddad2"),
|
||||
data: util.hex2abv("c3762df1ca787d32ae47c13bf19844cb" +
|
||||
"af1ae14d0b976afac52ff7d79bba9de0" +
|
||||
"feb582d33934a4f0954cc2363bc73f78" +
|
||||
"62ac430e64abe499f47c9b1f" +
|
||||
"3a337dbf46a792c45e454913fe2ea8f2"),
|
||||
result: util.hex2abv("d9313225f88406e5a55909c5aff5269a" +
|
||||
"86a7a9531534f7da2e4c303d8a318a72" +
|
||||
"1c3c0c95956809532fcf0e2449a6b525" +
|
||||
"b16aedf5aa0de657ba637b39"),
|
||||
},
|
||||
|
||||
// Test case #17 from McGrew and Viega
|
||||
// ... but with part of the authentication tag zeroed
|
||||
// <http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf>
|
||||
aes_gcm_dec_fail: {
|
||||
key: util.hex2abv("feffe9928665731c6d6a8f9467308308" +
|
||||
"feffe9928665731c6d6a8f9467308308"),
|
||||
iv: util.hex2abv("cafebabefacedbad"),
|
||||
adata: util.hex2abv("feedfacedeadbeeffeedfacedeadbeefabaddad2"),
|
||||
data: util.hex2abv("c3762df1ca787d32ae47c13bf19844cb" +
|
||||
"af1ae14d0b976afac52ff7d79bba9de0" +
|
||||
"feb582d33934a4f0954cc2363bc73f78" +
|
||||
"62ac430e64abe499f47c9b1f" +
|
||||
"00000000000000005e454913fe2ea8f2"),
|
||||
result: util.hex2abv("d9313225f88406e5a55909c5aff5269a" +
|
||||
"86a7a9531534f7da2e4c303d8a318a72" +
|
||||
"1c3c0c95956809532fcf0e2449a6b525" +
|
||||
"b16aedf5aa0de657ba637b39"),
|
||||
},
|
||||
|
||||
// RFC 4231 <http://tools.ietf.org/html/rfc4231>, Test Case 7
|
||||
hmac_sign: {
|
||||
key: util.hex2abv("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaa"),
|
||||
data: util.hex2abv("54686973206973206120746573742075" +
|
||||
"73696e672061206c6172676572207468" +
|
||||
"616e20626c6f636b2d73697a65206b65" +
|
||||
"7920616e642061206c61726765722074" +
|
||||
"68616e20626c6f636b2d73697a652064" +
|
||||
"6174612e20546865206b6579206e6565" +
|
||||
"647320746f2062652068617368656420" +
|
||||
"6265666f7265206265696e6720757365" +
|
||||
"642062792074686520484d414320616c" +
|
||||
"676f726974686d2e"),
|
||||
result: util.hex2abv("9b09ffa71b942fcb27635fbcd5b0e944" +
|
||||
"bfdc63644f0713938a7f51535c3a35e2"),
|
||||
},
|
||||
|
||||
// RFC 4231 <http://tools.ietf.org/html/rfc4231>, Test Case 6
|
||||
hmac_verify: {
|
||||
key: util.hex2abv("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" +
|
||||
"aaaaaa"),
|
||||
data: util.hex2abv("54657374205573696e67204c61726765" +
|
||||
"72205468616e20426c6f636b2d53697a" +
|
||||
"65204b6579202d2048617368204b6579" +
|
||||
"204669727374"),
|
||||
sig: util.hex2abv("60e431591ee0b67f0d8a26aacbf5b77f" +
|
||||
"8e0bc6213728c5140546040f0ee37f54"),
|
||||
sig_fail: util.hex2abv("000000001ee0b67f0d8a26aacbf5b77f" +
|
||||
"8e0bc6213728c5140546040f0ee37f54"),
|
||||
},
|
||||
}
|
||||
|
@ -332,3 +332,261 @@ TestArray.addTest(
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"AES-CBC encrypt",
|
||||
function () {
|
||||
var that = this;
|
||||
|
||||
function doEncrypt(x) {
|
||||
console.log(x);
|
||||
return crypto.subtle.encrypt(
|
||||
{ name: "AES-CBC", iv: tv.aes_cbc_enc.iv },
|
||||
x, tv.aes_cbc_enc.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.aes_cbc_enc.key, "AES-CBC", false, ['encrypt'])
|
||||
.then(doEncrypt)
|
||||
.then(
|
||||
memcmp_complete(that, tv.aes_cbc_enc.result),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"AES-CBC decrypt",
|
||||
function () {
|
||||
var that = this;
|
||||
|
||||
function doDecrypt(x) {
|
||||
return crypto.subtle.decrypt(
|
||||
{ name: "AES-CBC", iv: tv.aes_cbc_dec.iv },
|
||||
x, tv.aes_cbc_dec.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.aes_cbc_dec.key, "AES-CBC", false, ['decrypt'])
|
||||
.then(doDecrypt)
|
||||
.then(
|
||||
memcmp_complete(that, tv.aes_cbc_dec.result),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"AES-CTR encryption",
|
||||
function () {
|
||||
var that = this;
|
||||
|
||||
function doEncrypt(x) {
|
||||
return crypto.subtle.encrypt(
|
||||
{ name: "AES-CTR", counter: tv.aes_ctr_enc.iv, length: 32 },
|
||||
x, tv.aes_ctr_enc.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.aes_ctr_enc.key, "AES-CTR", false, ['encrypt'])
|
||||
.then(doEncrypt)
|
||||
.then(
|
||||
memcmp_complete(that, tv.aes_ctr_enc.result),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"AES-CTR decryption",
|
||||
function () {
|
||||
var that = this;
|
||||
|
||||
function doDecrypt(x) {
|
||||
return crypto.subtle.decrypt(
|
||||
{ name: "AES-CTR", counter: tv.aes_ctr_dec.iv, length: 32 },
|
||||
x, tv.aes_ctr_dec.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.aes_ctr_dec.key, "AES-CTR", false, ['decrypt'])
|
||||
.then(doDecrypt)
|
||||
.then(
|
||||
memcmp_complete(that, tv.aes_ctr_dec.result),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"AES-GCM encryption",
|
||||
function () {
|
||||
var that = this;
|
||||
|
||||
function doEncrypt(x) {
|
||||
return crypto.subtle.encrypt(
|
||||
{
|
||||
name: "AES-GCM",
|
||||
iv: tv.aes_gcm_enc.iv,
|
||||
additionalData: tv.aes_gcm_enc.adata,
|
||||
tagLength: 128
|
||||
},
|
||||
x, tv.aes_gcm_enc.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.aes_gcm_enc.key, "AES-GCM", false, ['encrypt'])
|
||||
.then(doEncrypt)
|
||||
.then(
|
||||
memcmp_complete(that, tv.aes_gcm_enc.result),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"AES-GCM decryption",
|
||||
function () {
|
||||
var that = this;
|
||||
|
||||
function doDecrypt(x) {
|
||||
return crypto.subtle.decrypt(
|
||||
{
|
||||
name: "AES-GCM",
|
||||
iv: tv.aes_gcm_dec.iv,
|
||||
additionalData: tv.aes_gcm_dec.adata,
|
||||
tagLength: 128
|
||||
},
|
||||
x, tv.aes_gcm_dec.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.aes_gcm_dec.key, "AES-GCM", false, ['decrypt'])
|
||||
.then(doDecrypt)
|
||||
.then(
|
||||
memcmp_complete(that, tv.aes_gcm_dec.result),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"AES-GCM decryption, failing authentication check",
|
||||
function () {
|
||||
var that = this;
|
||||
|
||||
function doDecrypt(x) {
|
||||
return crypto.subtle.decrypt(
|
||||
{
|
||||
name: "AES-GCM",
|
||||
iv: tv.aes_gcm_dec_fail.iv,
|
||||
additionalData: tv.aes_gcm_dec_fail.adata,
|
||||
tagLength: 128
|
||||
},
|
||||
x, tv.aes_gcm_dec_fail.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.aes_gcm_dec_fail.key, "AES-GCM", false, ['decrypt'])
|
||||
.then(doDecrypt)
|
||||
.then(
|
||||
error(that),
|
||||
complete(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"HMAC SHA-256 sign",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = {
|
||||
name: "HMAC",
|
||||
hash: "SHA-256"
|
||||
}
|
||||
|
||||
function doSign(x) {
|
||||
return crypto.subtle.sign("HMAC", x, tv.hmac_sign.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.hmac_sign.key, alg, false, ['sign'])
|
||||
.then(doSign)
|
||||
.then(
|
||||
memcmp_complete(that, tv.hmac_sign.result),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"HMAC SHA-256 verify",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = {
|
||||
name: "HMAC",
|
||||
hash: "SHA-256"
|
||||
}
|
||||
|
||||
function doVerify(x) {
|
||||
return crypto.subtle.verify("HMAC", x, tv.hmac_verify.sig, tv.hmac_verify.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.hmac_verify.key, alg, false, ['verify'])
|
||||
.then(doVerify)
|
||||
.then(
|
||||
complete(that, function(x) { return !!x; }),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"HMAC SHA-256, failing verification due to bad signature",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = {
|
||||
name: "HMAC",
|
||||
hash: "SHA-256"
|
||||
}
|
||||
|
||||
function doVerify(x) {
|
||||
return crypto.subtle.verify("HMAC", x, tv.hmac_verify.sig_fail,
|
||||
tv.hmac_verify.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.hmac_verify.key, alg, false, ['verify'])
|
||||
.then(doVerify)
|
||||
.then(
|
||||
complete(that, function(x) { return !x; }),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"HMAC SHA-256, failing verification due to key usage restriction",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = {
|
||||
name: "HMAC",
|
||||
hash: "SHA-256"
|
||||
}
|
||||
|
||||
function doVerify(x) {
|
||||
return crypto.subtle.verify("HMAC", x, tv.hmac_verify.sig,
|
||||
tv.hmac_verify.data);
|
||||
}
|
||||
|
||||
crypto.subtle.importKey("raw", tv.hmac_verify.key, alg, false, ['encrypt'])
|
||||
.then(doVerify)
|
||||
.then(
|
||||
error(that),
|
||||
complete(that, function(x) { return true; })
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user