pkcs#5 v.20 and pkcs#12 private encryption for pkcs#8 keys

This commit is contained in:
Todd A Ouska
2011-04-14 10:04:24 -07:00
parent 2da2e15484
commit d788030343
13 changed files with 431 additions and 31 deletions

View File

@@ -519,12 +519,35 @@ int ToTraditional(byte* input, word32 sz)
/* Check To see if PKCS version algo is supported, set id if it is return 0
< 0 on error */
static int CheckAlgo(int version, int algo, int* id)
static int CheckAlgo(int first, int second, int* id, int* version)
{
if (version != PKCS5)
*id = -1;
*version = PKCS5; /* default */
if (first == 1) {
switch (second) {
case 1:
*id = PBE_SHA1_RC4_128;
*version = PKCS12;
return 0;
case 3:
*id = PBE_SHA1_DES3;
*version = PKCS12;
return 0;
default:
return -1;
}
}
if (first != PKCS5)
return ASN_INPUT_E; /* VERSION ERROR */
switch (algo) {
if (second == PBES2) {
*version = PKCS5v2;
return 0;
}
switch (second) {
case 3: /* see RFC 2898 for ids */
*id = PBE_MD5_DES;
return 0;
@@ -538,44 +561,129 @@ static int CheckAlgo(int version, int algo, int* id)
}
/* Check To see if PKCS v2 algo is supported, set id if it is return 0
< 0 on error */
static int CheckAlgoV2(int oid, int* id)
{
switch (oid) {
case 69:
*id = PBE_SHA1_DES;
return 0;
case 652:
*id = PBE_SHA1_DES3;
return 0;
default:
return -1;
}
}
/* Decrypt intput in place from parameters based on id */
static int DecryptKey(const char* password, int passwordSz, byte* salt,
int saltSz, int iterations, int id, byte* input, int length)
int saltSz, int iterations, int id, byte* input,
int length, int version, byte* cbcIv)
{
byte key[MAX_KEY_SIZE];
int hashType;
int derivedLen;
int decryptionType;
int ret = 0;
switch (id) {
case PBE_MD5_DES:
hashType = MD5;
derivedLen = 16;
derivedLen = 16; /* may need iv for v1.5 */
decryptionType = DES_TYPE;
break;
case PBE_SHA1_DES:
hashType = SHA;
derivedLen = 16;
derivedLen = 16; /* may need iv for v1.5 */
decryptionType = DES_TYPE;
break;
case PBE_SHA1_DES3:
hashType = SHA;
derivedLen = 32; /* may need iv for v1.5 */
decryptionType = DES3_TYPE;
break;
case PBE_SHA1_RC4_128:
hashType = SHA;
derivedLen = 16;
decryptionType = RC4_TYPE;
break;
default:
return -1; /* unknown algo id */
}
PBKDF1(key, (byte*)password, passwordSz, salt, saltSz, iterations,
derivedLen, hashType);
if (version == PKCS5v2)
ret = PBKDF2(key, (byte*)password, passwordSz, salt, saltSz, iterations,
derivedLen, hashType);
else if (version == PKCS5)
ret = PBKDF1(key, (byte*)password, passwordSz, salt, saltSz, iterations,
derivedLen, hashType);
else if (version == PKCS12) {
int i, idx = 0;
byte unicodePasswd[MAX_UNICODE_SZ];
if ( (passwordSz * 2 + 2) > sizeof(unicodePasswd))
return -1; /* unicode passwd too big */
for (i = 0; i < passwordSz; i++) {
unicodePasswd[idx++] = 0x00;
unicodePasswd[idx++] = (byte)password[i];
}
/* add trailing NULL */
unicodePasswd[idx++] = 0x00;
unicodePasswd[idx++] = 0x00;
ret = PKCS12_PBKDF(key, unicodePasswd, idx, salt, saltSz,
iterations, derivedLen, hashType, 1);
if (decryptionType != RC4_TYPE)
ret += PKCS12_PBKDF(cbcIv, unicodePasswd, idx, salt, saltSz,
iterations, 8, hashType, 2);
}
if (ret != 0)
return ret;
switch (decryptionType) {
case DES_TYPE:
{
Des dec;
Des_SetKey(&dec, key, key + 8, DES_DECRYPTION);
byte* desIv = key + 8;
if (version == PKCS5v2 || version == PKCS12)
desIv = cbcIv;
Des_SetKey(&dec, key, desIv, DES_DECRYPTION);
Des_CbcDecrypt(&dec, input, input, length);
break;
}
case DES3_TYPE:
{
Des3 dec;
byte* desIv = key + 24;
if (version == PKCS5v2 || version == PKCS12)
desIv = cbcIv;
Des3_SetKey(&dec, key, desIv, DES_DECRYPTION);
Des3_CbcDecrypt(&dec, input, input, length);
break;
}
case RC4_TYPE:
{
Arc4 dec;
Arc4SetKey(&dec, key, derivedLen);
Arc4Process(&dec, input, input, length);
break;
}
default:
return -1; /* unknown algo id */
}
@@ -589,8 +697,10 @@ static int DecryptKey(const char* password, int passwordSz, byte* salt,
int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
{
word32 inOutIdx = 0, oid;
int type, algo, version, length, iterations, saltSz, id;
int type, first, second, length, iterations, saltSz, id;
int version;
byte salt[MAX_SALT_SIZE];
byte cbcIv[MAX_IV_SIZE];
if (GetSequence(input, &inOutIdx, &length) < 0)
return ASN_PARSE_E;
@@ -601,12 +711,27 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
if (GetAlgoId(input, &inOutIdx, &oid) < 0)
return ASN_PARSE_E;
version = input[inOutIdx - 2]; /* PKCS version alwyas 2nd to last byte */
algo = input[inOutIdx - 1]; /* version.algo, algo id last byte */
first = input[inOutIdx - 2]; /* PKCS version alwyas 2nd to last byte */
second = input[inOutIdx - 1]; /* version.algo, algo id last byte */
if (CheckAlgo(version, algo, &id) < 0)
if (CheckAlgo(first, second, &id, &version) < 0)
return ASN_INPUT_E; /* Algo ID error */
if (version == PKCS5v2) {
if (GetSequence(input, &inOutIdx, &length) < 0)
return ASN_PARSE_E;
if ((word32)length > (sz - inOutIdx))
return ASN_INPUT_E;
if (GetAlgoId(input, &inOutIdx, &oid) < 0)
return ASN_PARSE_E;
if (oid != PBKDF2_OID)
return ASN_PARSE_E;
}
if (GetSequence(input, &inOutIdx, &length) < 0)
return ASN_PARSE_E;
@@ -631,6 +756,27 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
if (GetShortInt(input, &inOutIdx, &iterations) < 0)
return ASN_PARSE_E;
if (version == PKCS5v2) {
/* get encryption algo */
if (GetAlgoId(input, &inOutIdx, &oid) < 0)
return ASN_PARSE_E;
if (CheckAlgoV2(oid, &id) < 0)
return ASN_PARSE_E; /* PKCS v2 algo id error */
if (input[inOutIdx++] != ASN_OCTET_STRING)
return ASN_PARSE_E;
if (GetLength(input, &inOutIdx, &length) < 0)
return ASN_PARSE_E;
if ((word32)length > (sz - inOutIdx))
return ASN_INPUT_E;
XMEMCPY(cbcIv, &input[inOutIdx], length);
inOutIdx += length;
}
if (input[inOutIdx++] != ASN_OCTET_STRING)
return ASN_PARSE_E;
@@ -641,7 +787,7 @@ int ToTraditionalEnc(byte* input, word32 sz,const char* password,int passwordSz)
return ASN_INPUT_E;
if (DecryptKey(password, passwordSz, salt, saltSz, iterations, id,
input + inOutIdx, length) < 0)
input + inOutIdx, length, version, cbcIv) < 0)
return ASN_INPUT_E; /* decrypt failure */
XMEMMOVE(input, input + inOutIdx, length);

View File

@@ -3591,7 +3591,7 @@ int fast_s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
}
#if defined(CYASSL_KEY_GEN) || defined(HAVE_ECC)
#if defined(CYASSL_KEY_GEN) || defined(HAVE_ECC) || !defined(NO_PWDBASED)
/* c = a * a (mod b) */
int mp_sqrmod (mp_int * a, mp_int * b, mp_int * c)

View File

@@ -24,6 +24,7 @@
#include "pwdbased.h"
#include "ctc_hmac.h"
#include "integer.h"
#ifdef CYASSL_SHA512
#include "sha512.h"
#endif
@@ -148,5 +149,159 @@ int PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt,
return 0;
}
int PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,const byte* salt,
int saltLen, int iterations, int kLen, int hashType, int id)
{
/* all in bytes instead of bits */
word32 u, v, dLen, pLen, iLen, sLen, totalLen;
int dynamic = 0;
int ret = 0;
int i;
byte *D, *S, *P, *I;
byte staticBuffer[1024];
byte* buffer = staticBuffer;
#ifdef CYASSL_SHA512
byte Ai[SHA512_DIGEST_SIZE];
byte B[SHA512_BLOCK_SIZE];
#else
byte Ai[SHA256_DIGEST_SIZE];
byte B[SHA256_BLOCK_SIZE];
#endif
if (!iterations)
iterations = 1;
if (hashType == MD5) {
v = MD5_BLOCK_SIZE;
u = MD5_DIGEST_SIZE;
}
else if (hashType == SHA) {
v = SHA_BLOCK_SIZE;
u = SHA_DIGEST_SIZE;
}
else if (hashType == SHA256) {
v = SHA256_BLOCK_SIZE;
u = SHA256_DIGEST_SIZE;
}
#ifdef CYASSL_SHA512
else if (hashType == SHA512) {
v = SHA512_BLOCK_SIZE;
u = SHA512_DIGEST_SIZE;
}
#endif
else
return -1; /* bad hashType */
dLen = v;
sLen = v * ((saltLen + v - 1) / v);
if (passLen)
pLen = v * ((passLen + v - 1) / v);
else
pLen = 0;
iLen = sLen + pLen;
totalLen = dLen + sLen + pLen;
if (totalLen > sizeof(staticBuffer)) {
buffer = (byte*)XMALLOC(totalLen, 0, DYNAMIC_TYPE_KEY);
if (buffer == NULL) return -1;
dynamic = 1;
}
D = buffer;
S = D + dLen;
P = S + sLen;
I = S;
XMEMSET(D, id, dLen);
for (i = 0; i < sLen; i++)
S[i] = salt[i % saltLen];
for (i = 0; i < pLen; i++)
P[i] = passwd[i % passLen];
while (kLen > 0) {
word32 currentLen;
mp_int B1;
if (hashType == MD5) {
}
else if (hashType == SHA) {
Sha sha;
InitSha(&sha);
ShaUpdate(&sha, buffer, totalLen);
ShaFinal(&sha, Ai);
for (i = 1; i < iterations; i++) {
ShaUpdate(&sha, Ai, u);
ShaFinal(&sha, Ai);
}
}
else if (hashType == SHA256) {
}
#ifdef CYASSL_SHA512
else if (hashType == SHA512) {
}
#endif
for (i = 0; i < v; i++)
B[i] = Ai[i % u];
mp_init(&B1);
if (mp_read_unsigned_bin(&B1, B, v) != MP_OKAY)
ret = -1;
else if (mp_add_d(&B1, (mp_digit)1, &B1) != MP_OKAY) {
ret = -1;
mp_clear(&B1);
break;
}
for (i = 0; i < iLen; i += v) {
int outSz;
mp_int i1;
mp_int res;
mp_init(&i1);
mp_init(&res);
if (mp_read_unsigned_bin(&i1, I + i, v) != MP_OKAY)
ret = -1;
else if (mp_add(&i1, &B1, &res) != MP_OKAY)
ret = -1;
else if ( (outSz = mp_unsigned_bin_size(&res)) < 0)
ret = -1;
else {
if (outSz > v) {
/* take off MSB */
byte tmp[129];
mp_to_unsigned_bin(&res, tmp);
XMEMCPY(I + i, tmp + 1, v);
}
else if (outSz < v) {
XMEMSET(I + i, 0, v - outSz);
mp_to_unsigned_bin(&res, I + i + v - outSz);
}
else
mp_to_unsigned_bin(&res, I + i);
}
mp_clear(&i1);
mp_clear(&res);
if (ret < 0) break;
}
currentLen = min(kLen, u);
XMEMCPY(output, Ai, currentLen);
output += currentLen;
kLen -= currentLen;
mp_clear(&B1);
}
if (dynamic) XFREE(buffer, 0, DYNAMIC_TYPE_KEY);
return ret;
}
#endif /* NO_PWDBASED */

View File

@@ -2302,11 +2302,7 @@ void fp_gcd(fp_int *a, fp_int *b, fp_int *c)
#endif /* CYASSL_KEY_GEN */
#ifdef HAVE_ECC
/* chars used in radix conversions */
const char *fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
#if defined(HAVE_ECC) || !defined(NO_PWDBASED)
/* c = a + b */
void fp_add_d(fp_int *a, fp_digit b, fp_int *c)
{
@@ -2315,6 +2311,20 @@ void fp_add_d(fp_int *a, fp_digit b, fp_int *c)
fp_add(a,&tmp,c);
}
/* external compatibility */
int mp_add_d(fp_int *a, fp_digit b, fp_int *c)
{
fp_add_d(a, b, c);
return MP_OKAY;
}
#endif /* HAVE_ECC || !NO_PWDBASED */
#ifdef HAVE_ECC
/* chars used in radix conversions */
const char *fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
int fp_read_radix(fp_int *a, const char *str, int radix)
{