Crypto changes

--HG--
extra : rebase_source : 0a953a43c01b95e7c467ec4ca7feeb0aaa00f5e1
This commit is contained in:
Anant Narayanan 2009-07-21 11:18:29 -07:00
parent d04ec4df06
commit 1509f1d1cb
6 changed files with 290 additions and 0 deletions

View File

@ -179,5 +179,46 @@ interface IWeaveCrypto : nsISupports
in ACString aPassphrase,
in ACString aSalt,
in ACString aIV);
/**
* Rewrap a private key with a new user passphrase.
*
* @param aWrappedPrivateKey
* The base64 encoded string holding an encrypted private key.
* @param aPassphrase
* The passphrase to decrypt the private key.
* @param aSalt
* The salt for the passphrase.
* @param aIV
* The random IV used when unwrapping the private key.
* @param aNewPassphrase
* The new passphrase to wrap the private key with.
* @returns The (re)wrapped private key, base64 encoded
*
*/
ACString rewrapPrivateKey(in ACString aWrappedPrivateKey,
in ACString aPassphrase,
in ACString aSalt,
in ACString aIV,
in ACString aNewPassphrase);
/**
* Verify a user's passphrase against a private key.
*
* @param aWrappedPrivateKey
* The base64 encoded string holding an encrypted private key.
* @param aPassphrase
* The passphrase to decrypt the private key.
* @param aSalt
* The salt for the passphrase.
* @param aIV
* The random IV used when unwrapping the private key.
* @returns Boolean true if the passphrase decrypted the key correctly.
*
*/
boolean verifyPassphrase(in ACString aWrappedPrivateKey,
in ACString aPassphrase,
in ACString aSalt,
in ACString aIV);
};

View File

@ -1005,3 +1005,194 @@ unwrap_done:
return rv;
}
/*
* RewrapPrivateKey
*/
NS_IMETHODIMP
WeaveCrypto::RewrapPrivateKey(const nsACString& aWrappedPrivateKey,
const nsACString& aPassphrase,
const nsACString& aSalt,
const nsACString& aIV,
const nsACString& aNewPassphrase,
nsACString& aPrivateKey)
{
nsresult rv = NS_OK;
PK11SlotInfo *slot = nsnull;
PK11SymKey *pbeKey = nsnull;
SECKEYPrivateKey *privKey = nsnull;
SECItem *ivParam = nsnull;
SECItem *keyID = nsnull;
CK_ATTRIBUTE_TYPE privKeyUsage[] = { CKA_UNWRAP };
PRUint32 privKeyUsageLength = sizeof(privKeyUsage) / sizeof(CK_ATTRIBUTE_TYPE);
// Step 1. Get rid of the base64 encoding on the inputs.
char privateKeyBuffer[STACK_BUFFER_SIZE];
PRUint32 privateKeyBufferSize = sizeof(privateKeyBuffer);
rv = DecodeBase64(aWrappedPrivateKey, privateKeyBuffer, &privateKeyBufferSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem wrappedPrivKey = {siBuffer, (unsigned char *)privateKeyBuffer, privateKeyBufferSize};
// Step 2. Convert the passphrase to a symmetric key and get the IV in the proper form.
rv = DeriveKeyFromPassphrase(aPassphrase, aSalt, &pbeKey);
NS_ENSURE_SUCCESS(rv, rv);
char ivData[STACK_BUFFER_SIZE];
PRUint32 ivDataSize = sizeof(ivData);
rv = DecodeBase64(aIV, ivData, &ivDataSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem ivItem = {siBuffer, (unsigned char*)ivData, ivDataSize};
// AES_128_CBC --> CKM_AES_CBC --> CKM_AES_CBC_PAD
CK_MECHANISM_TYPE wrapMech = PK11_AlgtagToMechanism(mAlgorithm);
wrapMech = PK11_GetPadMechanism(wrapMech);
if (wrapMech == CKM_INVALID_MECHANISM) {
NS_WARNING("Unknown key mechanism");
rv = NS_ERROR_FAILURE;
goto rewrap_done;
}
ivParam = PK11_ParamFromIV(wrapMech, &ivItem);
if (!ivParam) {
NS_WARNING("Couldn't create IV param");
rv = NS_ERROR_FAILURE;
goto rewrap_done;
}
// Step 3. Unwrap the private key with the key from the passphrase.
slot = PK11_GetInternalSlot();
if (!slot) {
NS_WARNING("Can't get internal PK11 slot");
rv = NS_ERROR_FAILURE;
goto rewrap_done;
}
keyID = &ivItem;
privKey = PK11_UnwrapPrivKey(slot,
pbeKey, wrapMech, ivParam, &wrappedPrivKey,
nsnull,
keyID,
PR_FALSE,
PR_TRUE,
CKK_RSA,
privKeyUsage, privKeyUsageLength,
nsnull);
if (!privKey) {
NS_WARNING("PK11_UnwrapPrivKey failed");
rv = NS_ERROR_FAILURE;
goto rewrap_done;
}
// Step 4. Rewrap the private key with the new passphrase.
rv = WrapPrivateKey(privKey, aNewPassphrase, aSalt, aIV, aPrivateKey);
if (NS_FAILED(rv)) {
NS_WARNING("RewrapPrivateKey failed");
rv = NS_ERROR_FAILURE;
goto rewrap_done;
}
rewrap_done:
if (privKey)
SECKEY_DestroyPrivateKey(privKey);
if (pbeKey)
PK11_FreeSymKey(pbeKey);
if (slot)
PK11_FreeSlot(slot);
if (ivParam)
SECITEM_FreeItem(ivParam, PR_TRUE);
return rv;
}
/*
* VerifyPassphrase
*/
NS_IMETHODIMP
WeaveCrypto::VerifyPassphrase(const nsACString& aWrappedPrivateKey,
const nsACString& aPassphrase,
const nsACString& aSalt,
const nsACString& aIV,
PRBool *result)
{
*result = PR_FALSE;
nsresult rv = NS_OK;
PK11SlotInfo *slot = nsnull;
PK11SymKey *pbeKey = nsnull;
SECKEYPrivateKey *privKey = nsnull;
SECItem *ivParam = nsnull;
SECItem *keyID = nsnull;
CK_ATTRIBUTE_TYPE privKeyUsage[] = { CKA_UNWRAP };
PRUint32 privKeyUsageLength = sizeof(privKeyUsage) / sizeof(CK_ATTRIBUTE_TYPE);
// Step 1. Get rid of the base64 encoding on the input.
char privateKeyBuffer[STACK_BUFFER_SIZE];
PRUint32 privateKeyBufferSize = sizeof(privateKeyBuffer);
rv = DecodeBase64(aWrappedPrivateKey, privateKeyBuffer, &privateKeyBufferSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem wrappedPrivKey = {siBuffer, (unsigned char *)privateKeyBuffer, privateKeyBufferSize};
// Step 2. Convert the passphrase to a symmetric key and get the IV in the proper form.
rv = DeriveKeyFromPassphrase(aPassphrase, aSalt, &pbeKey);
NS_ENSURE_SUCCESS(rv, rv);
char ivData[STACK_BUFFER_SIZE];
PRUint32 ivDataSize = sizeof(ivData);
rv = DecodeBase64(aIV, ivData, &ivDataSize);
NS_ENSURE_SUCCESS(rv, rv);
SECItem ivItem = {siBuffer, (unsigned char*)ivData, ivDataSize};
// AES_128_CBC --> CKM_AES_CBC --> CKM_AES_CBC_PAD
CK_MECHANISM_TYPE wrapMech = PK11_AlgtagToMechanism(mAlgorithm);
wrapMech = PK11_GetPadMechanism(wrapMech);
if (wrapMech == CKM_INVALID_MECHANISM) {
NS_WARNING("Unknown key mechanism");
rv = NS_ERROR_FAILURE;
goto verify_done;
}
ivParam = PK11_ParamFromIV(wrapMech, &ivItem);
if (!ivParam) {
NS_WARNING("Couldn't create IV param");
rv = NS_ERROR_FAILURE;
goto verify_done;
}
// Step 3. Unwrap the private key with the key from the passphrase.
slot = PK11_GetInternalSlot();
if (!slot) {
NS_WARNING("Can't get internal PK11 slot");
rv = NS_ERROR_FAILURE;
goto verify_done;
}
keyID = &ivItem;
privKey = PK11_UnwrapPrivKey(slot,
pbeKey, wrapMech, ivParam, &wrappedPrivKey,
nsnull,
keyID,
PR_FALSE,
PR_TRUE,
CKK_RSA,
privKeyUsage, privKeyUsageLength,
nsnull);
if (!privKey) {
NS_WARNING("PK11_UnwrapPrivKey failed");
} else {
*result = PR_TRUE;
}
verify_done:
if (privKey)
SECKEY_DestroyPrivateKey(privKey);
if (pbeKey)
PK11_FreeSymKey(pbeKey);
if (slot)
PK11_FreeSlot(slot);
if (ivParam)
SECITEM_FreeItem(ivParam, PR_TRUE);
return rv;
}

View File

@ -0,0 +1,35 @@
function run_test() {
var cryptoSvc = Cc["@labs.mozilla.com/Weave/Crypto;1"].
getService(Ci.IWeaveCrypto);
var salt = cryptoSvc.generateRandomBytes(16);
var iv = cryptoSvc.generateRandomIV();
var symKey = cryptoSvc.generateRandomKey();
// Tests with a 2048 bit key (the default)
do_check_eq(cryptoSvc.keypairBits, 2048)
var pubOut = {};
var privOut = {};
cryptoSvc.generateKeypair("old passphrase", salt, iv, pubOut, privOut);
var pubKey = pubOut.value;
var privKey = privOut.value;
// do some key wrapping
var wrappedKey = cryptoSvc.wrapSymmetricKey(symKey, pubKey);
var unwrappedKey = cryptoSvc.unwrapSymmetricKey(wrappedKey, privKey,
"old passphrase", salt, iv);
// Is our unwrapped key the same thing we started with?
do_check_eq(unwrappedKey, symKey);
// Rewrap key with a new passphrase
var newPrivKey = cryptoSvc.rewrapPrivateKey(privKey, "old passphrase",
salt, iv, "new passphrase");
// Unwrap symkey with new symkey
var newUnwrappedKey = cryptoSvc.unwrapSymmetricKey(wrappedKey, newPrivKey,
"new passphrase", salt, iv);
// The acid test... Is this unwrapped symkey the same as before?
do_check_eq(newUnwrappedKey, unwrappedKey);
}

View File

@ -0,0 +1,23 @@
function run_test() {
var cryptoSvc = Cc["@labs.mozilla.com/Weave/Crypto;1"].
getService(Ci.IWeaveCrypto);
var salt = cryptoSvc.generateRandomBytes(16);
var iv = cryptoSvc.generateRandomIV();
// Tests with a 2048 bit key (the default)
do_check_eq(cryptoSvc.keypairBits, 2048)
var privOut = {};
cryptoSvc.generateKeypair("passphrase", salt, iv, {}, privOut);
var privKey = privOut.value;
// Check with correct passphrase
var shouldBeTrue = cryptoSvc.verifyPassphrase(privKey, "passphrase",
salt, iv);
do_check_eq(shouldBeTrue, true);
// Check with incorrect passphrase
var shouldBeFalse = cryptoSvc.verifyPassphrase(privKey, "NotPassphrase",
salt, iv);
do_check_eq(shouldBeFalse, false);
}