Bug 419794 - "work out key API for nsICryptoHMAC" (API use nsIKeyObject + fix nsKeyModule + nsICryptoHMAC usage fix) [p=honzab@allpeers.com (Honza Bambas [mayhemer]) r=rrelyea sr=dveditz a=blocking1.9+]

This commit is contained in:
reed@reedloden.com 2008-03-18 12:45:40 -07:00
Родитель edd8a37696
Коммит ac89e9bc4e
8 изменённых файлов: 138 добавлений и 50 удалений

Просмотреть файл

@ -38,13 +38,14 @@
#include "nsISupports.idl"
interface nsIInputStream;
interface nsIKeyObject;
/**
* nsICryptoHMAC
* This interface provides HMAC signature algorithms.
*/
[scriptable, uuid(B8E1AC84-E10D-47fe-9D03-F0AF2E943E71)]
[scriptable, uuid(8FEB4C7C-1641-4a7b-BC6D-1964E2099497)]
interface nsICryptoHMAC : nsISupports
{
/**
@ -69,10 +70,13 @@ interface nsICryptoHMAC : nsISupports
* This value must be one of the above valid
* algorithm types.
*
* @param aKeyData the raw key data used for the HMAC
* computation
* @param aKeyObject
* Object holding a key. To create the key object use for instance:
* var keyObject = Components.classes["@mozilla.org/security/keyobjectfactory;1"]
* .getService(Components.interfaces.nsIKeyObjectFactory)
* .keyFromString(Components.interfaces.nsIKeyObject.HMAC, rawKeyData);
*
* @param aKeyLength length of the key in bytes
* WARNING: This approach is not FIPS compliant.
*
* @throws NS_ERROR_INVALID_ARG if an unsupported algorithm
* type is passed.
@ -80,8 +84,7 @@ interface nsICryptoHMAC : nsISupports
* NOTE: This method must be called before any other method
* on this interface is called.
*/
void init(in unsigned long aAlgorithm, [const, array, size_is(aKeyLen)] in octet aKeyData,
in unsigned long aKeyLen);
void init(in unsigned long aAlgorithm, in nsIKeyObject aKeyObject);
/**
* @param aData a buffer to calculate the hash over

Просмотреть файл

@ -48,6 +48,7 @@ interface nsIKeyObject : nsISupports
// Algorithm types
const short RC4 = 1;
const short AES_CBC = 2;
const short HMAC = 257;
// aAlgorithm is an algorithm type
// aKey is either a PK11SymKey, SECKEYPublicKey, or a SECKEYPrivateKey.

Просмотреть файл

@ -87,6 +87,7 @@ nsKeyObject::InitKey(PRInt16 aAlgorithm, void * aKey)
switch (aAlgorithm) {
case nsIKeyObject::RC4:
case nsIKeyObject::HMAC:
mSymKey = reinterpret_cast<PK11SymKey*>(aKey);
if (!mSymKey) {
@ -151,7 +152,7 @@ nsKeyObject::GetType(PRInt16 *_retval)
//////////////////////////////////////////////////////////////////////////////
// nsIKeyObjectFactory
NS_IMPL_ISUPPORTS1(nsKeyObjectFactory, nsIKeyObjectFactory)
NS_IMPL_THREADSAFE_ISUPPORTS1(nsKeyObjectFactory, nsIKeyObjectFactory)
nsKeyObjectFactory::nsKeyObjectFactory()
{
@ -176,9 +177,24 @@ NS_IMETHODIMP
nsKeyObjectFactory::KeyFromString(PRInt16 aAlgorithm, const nsACString & aKey,
nsIKeyObject **_retval)
{
if (aAlgorithm != nsIKeyObject::RC4)
CK_MECHANISM_TYPE cipherMech;
CK_ATTRIBUTE_TYPE cipherOperation;
switch (aAlgorithm)
{
case nsIKeyObject::HMAC:
cipherMech = CKM_GENERIC_SECRET_KEY_GEN;
cipherOperation = CKA_SIGN;
break;
case nsIKeyObject::RC4:
cipherMech = CKM_RC4;
cipherOperation = CKA_ENCRYPT;
break;
default:
return NS_ERROR_INVALID_ARG;
}
nsresult rv;
nsCOMPtr<nsIKeyObject> key =
do_CreateInstance(NS_KEYMODULEOBJECT_CONTRACTID, &rv);
@ -191,8 +207,6 @@ nsKeyObjectFactory::KeyFromString(PRInt16 aAlgorithm, const nsACString & aKey,
keyItem.len = flatKey.Length();
PK11SlotInfo *slot = nsnull;
CK_MECHANISM_TYPE cipherMech;
cipherMech = CKM_RC4;
slot = PK11_GetBestSlot(cipherMech, nsnull);
if (!slot) {
NS_ERROR("no slot");
@ -200,7 +214,7 @@ nsKeyObjectFactory::KeyFromString(PRInt16 aAlgorithm, const nsACString & aKey,
}
PK11SymKey* symKey = PK11_ImportSymKey(slot, cipherMech, PK11_OriginUnwrap,
CKA_ENCRYPT, &keyItem, nsnull);
cipherOperation, &keyItem, nsnull);
// cleanup code
if (slot)
PK11_FreeSlot(slot);

Просмотреть файл

@ -103,7 +103,7 @@
#include "nsICRLManager.h"
#include "nsNSSShutDown.h"
#include "nsSmartCardEvent.h"
#include "nsICryptoHash.h"
#include "nsIKeyModule.h"
#include "nss.h"
#include "pk11func.h"
@ -2556,8 +2556,8 @@ nsCryptoHMAC::~nsCryptoHMAC()
PK11_DestroyContext(mHMACContext, PR_TRUE);
}
/* void init (in unsigned long aAlgorithm, in octet aKeyData, in long aKeyLength); */
NS_IMETHODIMP nsCryptoHMAC::Init(PRUint32 aAlgorithm, const PRUint8 *aKeyData, PRUint32 aKeyLen)
/* void init (in unsigned long aAlgorithm, in nsIKeyObject aKeyObject); */
NS_IMETHODIMP nsCryptoHMAC::Init(PRUint32 aAlgorithm, nsIKeyObject *aKeyObject)
{
if (mHMACContext)
{
@ -2584,25 +2584,26 @@ NS_IMETHODIMP nsCryptoHMAC::Init(PRUint32 aAlgorithm, const PRUint8 *aKeyData, P
return NS_ERROR_INVALID_ARG;
}
PK11SlotInfo *slot = PK11_GetBestSlot(HMACMechType, nsnull);
NS_ENSURE_TRUE(slot, NS_ERROR_FAILURE);
NS_ENSURE_ARG_POINTER(aKeyObject);
nsresult rv;
PRInt16 keyType;
rv = aKeyObject->GetType(&keyType);
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(keyType == nsIKeyObject::SYM_KEY, NS_ERROR_INVALID_ARG);
PK11SymKey* key;
// GetKeyObj doesn't addref the key
rv = aKeyObject->GetKeyObj((void**)&key);
NS_ENSURE_SUCCESS(rv, rv);
SECItem rawData;
rawData.data = const_cast<unsigned char*>(aKeyData);
rawData.len = aKeyLen;
PK11SymKey* key = PK11_ImportSymKey(
slot, HMACMechType, PK11_OriginUnwrap, CKA_SIGN, &rawData, nsnull);
PK11_FreeSlot(slot);
NS_ENSURE_TRUE(key, NS_ERROR_FAILURE);
rawData.data = 0;
rawData.len = 0;
mHMACContext = PK11_CreateContextBySymKey(
HMACMechType, CKA_SIGN, key, &rawData);
PK11_FreeSymKey(key);
NS_ENSURE_TRUE(mHMACContext, NS_ERROR_FAILURE);
SECStatus ss = PK11_DigestBegin(mHMACContext);

Просмотреть файл

@ -2,45 +2,89 @@ var ScriptableUnicodeConverter =
Components.Constructor("@mozilla.org/intl/scriptableunicodeconverter",
"nsIScriptableUnicodeConverter");
function getHMAC(data, key)
function getHMAC(data, key, alg)
{
var converter = new ScriptableUnicodeConverter();
converter.charset = 'utf8';
var keyarray = converter.convertToByteArray(key, {});
var dataarray = converter.convertToByteArray(data, {});
var keyObject = Components.classes["@mozilla.org/security/keyobjectfactory;1"]
.getService(Components.interfaces.nsIKeyObjectFactory)
.keyFromString(Components.interfaces.nsIKeyObject.HMAC, key);
var cryptoHMAC = Components.classes["@mozilla.org/security/hmac;1"]
.createInstance(Components.interfaces.nsICryptoHMAC);
cryptoHMAC.init(Components.interfaces.nsICryptoHMAC.SHA1, keyarray, keyarray.length);
cryptoHMAC.init(alg, keyObject);
cryptoHMAC.update(dataarray, dataarray.length);
var digest1 = cryptoHMAC.finish(true);
var digest1 = cryptoHMAC.finish(false);
cryptoHMAC.reset();
cryptoHMAC.update(dataarray, dataarray.length);
var digest2 = cryptoHMAC.finish(true);
var digest2 = cryptoHMAC.finish(false);
do_check_eq(digest1, digest2);
return digest1;
}
function run_test() {
function testHMAC(alg) {
const key1 = 'MyKey_ABCDEFGHIJKLMN';
const key2 = 'MyKey_01234567890123';
const dataA = "Secret message";
const dataB = "Secres message";
var diegest1a = getHMAC(key1, dataA);
var diegest2 = getHMAC(key2, dataA);
var diegest1b = getHMAC(key1, dataA);
var diegest1a = getHMAC(key1, dataA, alg);
var diegest2 = getHMAC(key2, dataA, alg);
var diegest1b = getHMAC(key1, dataA, alg);
do_check_eq(diegest1a, diegest1b);
do_check_neq(diegest1a, diegest2);
var diegest1 = getHMAC(key1, dataA);
diegest2 = getHMAC(key1, dataB);
var diegest1 = getHMAC(key1, dataA, alg);
diegest2 = getHMAC(key1, dataB, alg);
do_check_neq(diegest1, diegest2);
return diegest1;
}
function hexdigest(data) {
return [("0" + data.charCodeAt(i).toString(16)).slice(-2) for (i in data)].join("");
}
function testVectors() {
// These are test vectors taken from RFC 4231, section 4.3. (Test Case 2)
const keyTestVector = "Jefe";
const dataTestVector = "what do ya want for nothing?";
var diegest;
/*
Bug 356713
diegest = hexdigest(getHMAC(dataTestVector, keyTestVector,
Components.interfaces.nsICryptoHMAC.SHA224));
do_check_eq(diegest, "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44");
*/
diegest = hexdigest(getHMAC(dataTestVector, keyTestVector,
Components.interfaces.nsICryptoHMAC.SHA256));
do_check_eq(diegest, "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843");
diegest = hexdigest(getHMAC(dataTestVector, keyTestVector,
Components.interfaces.nsICryptoHMAC.SHA384));
do_check_eq(diegest, "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649");
diegest = hexdigest(getHMAC(dataTestVector, keyTestVector,
Components.interfaces.nsICryptoHMAC.SHA512));
do_check_eq(diegest, "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737");
}
function run_test() {
testVectors();
testHMAC(Components.interfaces.nsICryptoHMAC.SHA1);
testHMAC(Components.interfaces.nsICryptoHMAC.SHA512);
testHMAC(Components.interfaces.nsICryptoHMAC.MD5);
}

Просмотреть файл

@ -51,6 +51,7 @@
#include "nsICryptoHash.h"
#include "nsICryptoHMAC.h"
#include "nsIDirectoryService.h"
#include "nsIKeyModule.h"
#include "nsIObserverService.h"
#include "nsIPrefBranch.h"
#include "nsIPrefBranch2.h"
@ -2690,17 +2691,31 @@ nsUrlClassifierDBServiceWorker::BeginStream(const nsACString &table,
// If we're expecting a MAC, create the nsICryptoHMAC component now.
if (!mUpdateClientKey.IsEmpty()) {
nsCOMPtr<nsIKeyObjectFactory> keyObjectFactory(do_GetService(
"@mozilla.org/security/keyobjectfactory;1", &rv));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to get nsIKeyObjectFactory service");
mUpdateStatus = rv;
return mUpdateStatus;
}
nsCOMPtr<nsIKeyObject> keyObject;
rv = keyObjectFactory->KeyFromString(nsIKeyObject::HMAC, mUpdateClientKey,
getter_AddRefs(keyObject));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create key object, maybe not FIPS compliant?");
mUpdateStatus = rv;
return mUpdateStatus;
}
mHMAC = do_CreateInstance(NS_CRYPTO_HMAC_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to create nsICryptoHMAC instance");
mUpdateStatus = rv;
return mUpdateStatus;
}
NS_ENSURE_SUCCESS(rv, rv);
rv = mHMAC->Init(nsICryptoHMAC::SHA1,
reinterpret_cast<const PRUint8*>(mUpdateClientKey.BeginReading()),
mUpdateClientKey.Length());
rv = mHMAC->Init(nsICryptoHMAC::SHA1, keyObject);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to initialize nsICryptoHMAC instance");
mUpdateStatus = rv;

Просмотреть файл

@ -40,6 +40,7 @@
#include "nsIChannel.h"
#include "nsICryptoHMAC.h"
#include "nsIHttpChannel.h"
#include "nsIKeyModule.h"
#include "nsIObserverService.h"
#include "nsIUploadChannel.h"
#include "nsNetUtil.h"
@ -224,13 +225,21 @@ nsUrlClassifierHashCompleterRequest::HandleMAC(nsACString::const_iterator& begin
nsUrlClassifierUtils::UnUrlsafeBase64(serverMAC);
nsresult rv;
nsCOMPtr<nsIKeyObjectFactory> keyObjectFactory(
do_GetService("@mozilla.org/security/keyobjectfactory;1", &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIKeyObject> keyObject;
rv = keyObjectFactory->KeyFromString(nsIKeyObject::HMAC, mClientKey,
getter_AddRefs(keyObject));
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsICryptoHMAC> hmac =
do_CreateInstance(NS_CRYPTO_HMAC_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = hmac->Init(nsICryptoHMAC::SHA1,
reinterpret_cast<const PRUint8*>(mClientKey.BeginReading()),
mClientKey.Length());
rv = hmac->Init(nsICryptoHMAC::SHA1, keyObject);
NS_ENSURE_SUCCESS(rv, rv);
const nsCSubstring &remaining = Substring(begin, end);

Просмотреть файл

@ -8,11 +8,12 @@ function MAC(content, clientKey)
var converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
var result = {};
var data = converter.convertToByteArray(clientKey, result);
hmac.init(Ci.nsICryptoHMAC.SHA1, data, data.length);
result = {};
var keyObject = Cc["@mozilla.org/security/keyobjectfactory;1"]
.getService(Ci.nsIKeyObjectFactory).keyFromString(Ci.nsIKeyObject.HMAC, clientKey);
hmac.init(Ci.nsICryptoHMAC.SHA1, keyObject);
var result = {};
data = converter.convertToByteArray(content, result);
hmac.update(data, data.length);
return hmac.finish(true);