diff options
Diffstat (limited to 'base/tps/src/main/Util.cpp')
-rw-r--r-- | base/tps/src/main/Util.cpp | 1168 |
1 files changed, 1168 insertions, 0 deletions
diff --git a/base/tps/src/main/Util.cpp b/base/tps/src/main/Util.cpp new file mode 100644 index 000000000..2849121e4 --- /dev/null +++ b/base/tps/src/main/Util.cpp @@ -0,0 +1,1168 @@ +// --- BEGIN COPYRIGHT BLOCK --- +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, +// Boston, MA 02110-1301 USA +// +// Copyright (C) 2007 Red Hat, Inc. +// All rights reserved. +// --- END COPYRIGHT BLOCK --- + +#include <string.h> +#include "prmem.h" +#include "prio.h" +#include "pk11func.h" +#include "main/Util.h" +#include "main/Buffer.h" +#include "engine/RA.h" +#include "main/Memory.h" + +#ifdef XP_WIN32 +#define TPS_PUBLIC __declspec(dllexport) +#else /* !XP_WIN32 */ +#define TPS_PUBLIC +#endif /* !XP_WIN32 */ + +TPS_PUBLIC Util::Util () +{ +} + +TPS_PUBLIC Util::~Util () +{ +} + +/* + * Reads a line from file + */ +TPS_PUBLIC int Util::ReadLine(PRFileDesc *f, char *buf, int buf_len, int *removed_return) +{ + char *cur = buf; + int sum = 0; + PRInt32 rc; + + *removed_return = 0; + while (1) { + rc = PR_Read(f, cur, 1); + if (rc == -1 || rc == 0) + break; + if (*cur == '\r') { + continue; + } + if (*cur == '\n') { + *cur = '\0'; + *removed_return = 1; + break; + } + sum++; + cur++; + } + return sum; +} + +TPS_PUBLIC int Util::ascii2numeric (char c) +{ + int num; + switch (c) { + case '0': case '1': case '2':case '3':case '4':case '5': + case '6': case '7': case '8': case '9': + num = c - '0'; + break; + default: + num = -1; + break; + } + return num; +} + +static BYTE ZERO[1] = { 0 }; +static BYTE ONE[1] = { 1 }; + +TPS_PUBLIC BYTE* Util::bool2byte(bool b) { + if (b) + return ONE; + else + return ZERO; +} + +static int isAlphaNumeric (char ch) +{ + return (((ch >='a') && (ch <= 'z')) || /* logical AND &&, OR || */ + ((ch >='A') && (ch <= 'Z')) || + ((ch >='0') && (ch <= '9')) ); +} + +static char bin2hex (BYTE ch) +{ + ch = ch & 0x0f; + ch += '0'; + if (ch > '9') + ch += 7; + return (ch); +} + +static BYTE hex2bin (BYTE ch) +{ + if (ch > '9') + ch = ch - 'A' + 10; + else + ch = ch - '0'; + return (ch); +} + + +TPS_PUBLIC char *Util::SpecialURLEncode(Buffer &data) { + int i; + BYTE *buf = (BYTE*)data; + int len = (int)data.size(); + char *ret = NULL; + int sum = 0; + + for (i = 0; i < len; i ++) { + if (buf[i] == ' ') { + sum+=1; + } else if (isAlphaNumeric(buf[i])) { + sum+=1; + } else { + sum+=3; + } + } + ret = (char *)PR_Malloc(sum + 1); // allocate more than we may need + if (ret == NULL) + return NULL; + char *cur = ret; + + for (i = 0; i < len; i ++) { + if (buf[i] == ' ') { + *cur++ = '+'; + } else if (isAlphaNumeric(buf[i])) { + *cur++ = buf[i]; + } else { + *cur++ = '#'; + *cur++ = bin2hex(buf[i] >> 4); + *cur++ = bin2hex(buf[i]); + } + } + *cur = '\0'; // null-terminated + return ret; +} + +TPS_PUBLIC char *Util::URLEncode (Buffer &data) +{ + int i; + BYTE *buf = (BYTE*)data; + int len = (int)data.size(); + int sum = 0; + + for (i = 0; i < len; i ++) { + if (buf[i] == ' ') { + sum+=1; + } else if (isAlphaNumeric(buf[i])) { + sum+=1; + } else { + sum+=3; + } + } + char *ret = (char *)PR_Malloc(sum + 1); // allocate more than we may need + char *cur = ret; + + for (i = 0; i < len; i ++) { + if (buf[i] == ' ') { + *cur++ = '+'; + } else if (isAlphaNumeric(buf[i])) { + *cur++ = buf[i]; + } else { + *cur++ = '%'; + *cur++ = bin2hex(buf[i] >> 4); + *cur++ = bin2hex(buf[i]); + } + } + *cur = '\0'; // null-terminated + return ret; +} + +TPS_PUBLIC char *Util::URLEncodeInHex (Buffer &data) +{ + int i; + BYTE *buf = (BYTE*)data; + int len = (int)data.size(); + int sum = 0; + + for (i = 0; i < len; i ++) { + sum+=3; + } + + char *ret = (char *)PR_Malloc(sum + 1); // allocate more than we may need + char *cur = ret; + + for (i = 0; i < len; i ++) { + *cur++ = '%'; + *cur++ = bin2hex(buf[i] >> 4); + *cur++ = bin2hex(buf[i]); + } + *cur = '\0'; // null-terminated + return ret; +} + +TPS_PUBLIC char * Util::URLEncode1(const char *str) +{ + int sum = 0; + if (str == NULL) + return NULL; + + // URL-encode the base-64 encoded public key. This code copies + // From input buffer str[] to output buffer encoded_str[] + int i = 0; + int j = 0; + char c; + + i = 0; + j = 0; + while (1) { + c = str[j]; + if (c == '/') { + sum+=3; + } else if (c == '=') { + sum+=3; + } else if (c == '\r') { + sum+=3; + } else if (c == '\n') { + sum+=3; + } else if (c == '+') { + sum+=3; + } else if (c == '&') { + sum+=3; + } else if (c == ' ') { + sum+=1; + } else { + sum+=1; + } + if (c == '\0') { + break; + } + i++; + j++; + } + + char *encoded_str = (char *)PR_Malloc(sum); //allocate more than we may need + + if (encoded_str == NULL) + return NULL; + + i = 0; + j = 0; + while (1) { + c = str[j]; + if (c == '/') { + encoded_str[i++] = '%'; + encoded_str[i++] = '2'; + encoded_str[i] = 'F'; + } else if (c == '&') { + encoded_str[i++] = '%'; + encoded_str[i++] = '2'; + encoded_str[i] = '6'; + } else if (c == '=') { + encoded_str[i++] = '%'; + encoded_str[i++] = '3'; + encoded_str[i] = 'D'; + } else if (c == '\r') { + encoded_str[i++] = '%'; + encoded_str[i++] = '0'; + encoded_str[i] = 'D'; + } else if (c == '\n') { + encoded_str[i++] = '%'; + encoded_str[i++] = '0'; + encoded_str[i] = 'A'; + } else if (c == '+') { + encoded_str[i++] = '%'; + encoded_str[i++] = '2'; + encoded_str[i] = 'B'; + } else if (c == ' ') { + encoded_str[i] = '+'; + } else { + encoded_str[i] = str[j]; + } + if (encoded_str[i] == '\0') { + break; + } + i++; + j++; + } + encoded_str[i] = '\0'; + + // DONT print, some of the sensitive information get printed. + /* + RA::Debug(LL_PER_PDU, "CertEnroll::urlEncode", + "URL-encoded encoded_str =%s",encoded_str); + */ + + return encoded_str; +} +/** + * this urlEncode function takes a char string + */ +TPS_PUBLIC char * Util::URLEncode(const char *str) +{ + int sum = 0; + if (str == NULL) + return NULL; + + // URL-encode the base-64 encoded public key. This code copies + // From input buffer str[] to output buffer encoded_str[] + int i = 0; + int j = 0; + char c; + + i = 0; + j = 0; + while (1) { + c = str[j]; + if (c == '/') { + sum+=3; + } else if (c == '=') { + sum+=3; + } else if (c == '\r') { + sum+=3; + } else if (c == '\n') { + sum+=3; + } else if (c == '+') { + sum+=3; + } else if (c == ' ') { + sum+=1; + } else { + sum+=1; + } + if (c == '\0') { + break; + } + i++; + j++; + } + + char *encoded_str = (char *)PR_Malloc(sum); //allocate more than we may need + + if (encoded_str == NULL) + return NULL; + + i = 0; + j = 0; + while (1) { + c = str[j]; + if (c == '/') { + encoded_str[i++] = '%'; + encoded_str[i++] = '2'; + encoded_str[i] = 'F'; + } else if (c == '=') { + encoded_str[i++] = '%'; + encoded_str[i++] = '3'; + encoded_str[i] = 'D'; + } else if (c == '\r') { + encoded_str[i++] = '%'; + encoded_str[i++] = '0'; + encoded_str[i] = 'D'; + } else if (c == '\n') { + encoded_str[i++] = '%'; + encoded_str[i++] = '0'; + encoded_str[i] = 'A'; + } else if (c == '+') { + encoded_str[i++] = '%'; + encoded_str[i++] = '2'; + encoded_str[i] = 'B'; + } else if (c == ' ') { + encoded_str[i] = '+'; + } else { + encoded_str[i] = str[j]; + } + if (encoded_str[i] == '\0') { + break; + } + i++; + j++; + } + encoded_str[i] = '\0'; + + // DONT print, some of the sensitive information get printed. + /* + RA::Debug(LL_PER_PDU, "CertEnroll::urlEncode", + "URL-encoded encoded_str =%s",encoded_str); + */ + + return encoded_str; +} + +/* s Format: 01AFEE */ +TPS_PUBLIC Buffer *Util::Str2Buf (const char *s) +{ + int len = strlen(s) / 2; + BYTE *ret = (BYTE *)PR_Malloc(len); + if (ret == NULL) + return NULL; + + for (int i = 0; i < len; i ++) { + ret[i] = hex2bin(s[i*2]) * 16 + hex2bin(s[i*2+1]); + } + + Buffer *newbuf = new Buffer(ret, len); + if( ret != NULL ) { + PR_Free( ret ); + ret = NULL; + } + return newbuf; +} + +TPS_PUBLIC char *Util::Buffer2String (Buffer &data) +{ + int i; + BYTE *buf = (BYTE*)data; + int len = (int)data.size(); + int sum = 0; + + for (i = 0; i < len; i ++) { + sum+=2; + } + char *ret = (char *)PR_Malloc(sum + 1); // allocate more than we may need + if (ret == NULL) + return NULL; + char *cur = ret; + + for (i = 0; i < len; i ++) { + *cur++ = bin2hex(buf[i] >> 4); + *cur++ = bin2hex(buf[i]); + } + *cur = '\0'; // null-terminated + return ret; +} + +TPS_PUBLIC Buffer *Util::SpecialURLDecode(const char *data) +{ + int i; + Buffer buf; + Buffer *ret = NULL; + int len = strlen(data); + BYTE *tmp = NULL; + int sum = 0; + + if (len == 0) + return NULL; + tmp = (BYTE *)malloc(len); + if (tmp == NULL) + return NULL; + for (i = 0; i < len; i++) { + if (data[i] == '+') { + tmp[sum++] = ' '; + } else if (data[i] == '#') { + tmp[sum++] = (hex2bin(data[i+1]) << 4) + hex2bin(data[i+2]); + i+=2; + } else { + tmp[sum++] = (BYTE)data[i]; + } + } + + ret = new Buffer(tmp, sum); + if( tmp != NULL ) { + free( tmp ); + tmp = NULL; + } + return ret; +} + +TPS_PUBLIC Buffer *Util::URLDecode(const char *data) +{ + int i; + Buffer buf; + Buffer *ret = NULL; + int len = strlen(data); + BYTE *tmp = NULL; + int sum = 0; + + if (len == 0) + return NULL; + tmp = (BYTE *)PR_Malloc(len); + for (i = 0; i < len; i++) { + if (data[i] == '+') { + tmp[sum++] = ' '; + } else if (data[i] == '%') { + tmp[sum++] = (hex2bin(data[i+1]) << 4) + hex2bin(data[i+2]); + i+=2; + } else { + tmp[sum++] = (BYTE)data[i]; + } + } + + ret = new Buffer(tmp, sum); + if( tmp != NULL ) { + PR_Free( tmp ); + tmp = NULL; + } + return ret; +} + + +TPS_PUBLIC PRStatus Util::GetRandomChallenge(Buffer &random) +{ + PRStatus rv = PR_FAILURE; + SECStatus status; + + status = PK11_GenerateRandom(random, random.size()); + if (status != SECSuccess) { + goto loser; + } + rv = PR_SUCCESS; +loser: + return rv; +} /* GetRandomChallenge */ + +#define DES2_WORKAROUND + +TPS_PUBLIC PK11SymKey *Util::DiversifyKey(PK11SymKey *masterKey, Buffer &data, PK11SlotInfo *slot) +{ + PK11SymKey *key = NULL; + PRStatus status = PR_FAILURE ; + PK11Context *context = NULL; +#ifdef DES2_WORKAROUND + unsigned char keyData[24]; +#else + unsigned char keyData[16]; +#endif + SECItem keyItem = { siBuffer, keyData, sizeof keyData }; + SECStatus s; + int i; + int len; + static SECItem noParams = { siBuffer, 0, 0 }; + + /* XXX + - masterKey could be just a double-length + DES Key (16 bytes). + - we may need to add the first 8 bytes to + the end to make the key 24 bytes long (DES3 Key) + */ + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, + masterKey, + &noParams); + if (!context) goto done; + + /* Part 1 */ + s = PK11_CipherOp(context, &keyData[0], &len, 8, &((BYTE*)data)[0], 8); + if (s != SECSuccess) goto done; + + /* Part 2 */ + s = PK11_CipherOp(context, &keyData[8], &len, 8, &((BYTE*)data)[8], 8); + if (s != SECSuccess) goto done; + +#ifdef DES2_WORKAROUND + /* Part 3 */ + for(i = 0;i < 8;i++) + { + keyData[i+16] = keyData[i]; + } +#endif + + key = PK11_ImportSymKeyWithFlags( + slot, + CKM_DES3_ECB, + PK11_OriginGenerated, + CKA_ENCRYPT, + &keyItem, CKF_SIGN | CKF_ENCRYPT, PR_FALSE, 0); + + status = PR_SUCCESS; + +done: + + return key; +} + +TPS_PUBLIC PRStatus Util::ComputeKeyCheck(const Buffer& newKey, Buffer& output) +{ + PK11SymKey *key = NULL; + PRStatus status = PR_FAILURE ; + PK11SlotInfo *slot = PK11_GetInternalKeySlot(); + PK11Context *context = NULL; + SECStatus s = SECFailure; + int len; + static SECItem noParams = { siBuffer, 0, 0 }; +#ifdef DES2_WORKAROUND + unsigned char keyData[24]; +#else + unsigned char keyData[16]; +#endif + SECItem keyItem = {siBuffer, keyData, sizeof(keyData) }; + unsigned char value[8]; + // convert 16-byte to 24-byte triple-DES key + memcpy(keyData, newKey, 16); +#ifdef DES2_WORKAROUND + memcpy(keyData+16, newKey, 8); +#endif + + memset(value, 0, sizeof value); + + key = PK11_ImportSymKeyWithFlags(slot, CKM_DES3_ECB, + PK11_OriginGenerated, CKA_ENCRYPT, &keyItem, + CKF_ENCRYPT, PR_FALSE, 0); + if( ! key ) { + goto done; + } + + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, key, + &noParams); + if (!context) { + goto done; + } + s = PK11_CipherOp(context, &value[0], &len, 8, &value[0], 8); + if (s != SECSuccess) { + goto done; + } + + output.resize(3); + output.replace(0, value, 3); + + status = PR_SUCCESS; +done: + memset(keyData, 0, sizeof keyData); + if( context != NULL ) { + PK11_DestroyContext( context, PR_TRUE ); + context = NULL; + } + if( slot != NULL ) { + PK11_FreeSlot( slot ); + slot = NULL; + } + if( key != NULL ) { + PK11_FreeSymKey( key ); + key = NULL; + } + + return status; +} + +TPS_PUBLIC PRStatus Util::ComputeCryptogram(PK11SymKey *key, + const Buffer &card_challenge, const Buffer &host_challenge, + Buffer &output) +{ + Buffer icv(8, (BYTE)0); + Buffer input = card_challenge + host_challenge; + + return ComputeMAC(key, input, icv, output); +} /* ComputeCryptogram */ + + +TPS_PUBLIC PRStatus Util::ComputeMAC(PK11SymKey *key, Buffer &x_input, + const Buffer &icv, Buffer &output) +{ + PRStatus rv = PR_SUCCESS; + PK11Context *context = NULL; +// NetkeyICV temp; + unsigned char result[8]; + int i; + SECStatus s; + int len; +#ifdef USE_DESMAC + CK_ULONG macLen = sizeof result; + SECItem params = { siBuffer, (unsigned char *)&macLen, sizeof macLen }; +#endif + static SECItem noParams = { siBuffer, 0, 0 }; + static unsigned char macPad[] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; + BYTE *input = (BYTE *) x_input; + int inputLen = x_input.size(); + +#ifdef USE_DESMAC + context = PK11_CreateContextBySymKey(CKM_DES3_MAC_GENERAL, CKA_SIGN, + key, ¶ms); + if (!context) { rv = PR_FAILURE; goto done; } + + s = PK11_DigestBegin(context); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + + s = PK11_DigestOp(context, icv, 8); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + + while(inputLen >= 8) + { + s = PK11_DigestOp(context, input, 8); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + + input += 8; + inputLen -= 8; + } + + for (i = 0;i < inputLen;i++) + { + result[i] = input[i]; + } + + input = macPad; + for(;i < 8;i++) + { + result[i] = *input++; + } + + s = PK11_DigestOp(context, result, sizeof result); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + + s = PK11_DigestFinal(context, output, (unsigned int *)&len, sizeof output); + if (1 != SECSuccess) { rv = PR_FAILURE; goto done; } + +#else + + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, key, &noParams); + if (!context) { rv = PR_FAILURE; goto done; } + + memcpy(result, icv, sizeof result); + + /* Process whole blocks */ + while(inputLen >= 8) + { + for(i = 0;i < 8;i++) + { + result[i] ^= input[i]; + } + + s = PK11_CipherOp(context, result, &len, sizeof result, result, sizeof result); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + if (len != sizeof result) /* assert? */ + { + //PR_SetError(PR_UNKNOWN_ERROR, 0); + rv = PR_FAILURE; + goto done; + } + + input += 8; + inputLen -= 8; + } + + /* + * Fold in remaining data (if any) + * Set i to number of bytes processed + */ + for(i = 0;i < inputLen;i++) + { + result[i] ^= input[i]; + } + + /* + * Fill remainder of last block. There + * will be at least one byte handled here. + */ + input = macPad; + while(i < 8) + { + result[i] ^= *input++; + i++; + } + + s = PK11_CipherOp(context, result, &len, sizeof result, result, sizeof result); + if (s != SECSuccess) { rv = PR_FAILURE; goto done; } + if (len != sizeof result) + { + //PR_SetError(PR_UNKNOWN_ERROR, 0); + rv = PR_FAILURE; + goto done; + } + + output.replace(0, result, sizeof result); +#endif + +done: + if( context != NULL ) + { + PK11_Finalize( context ); + PK11_DestroyContext( context, PR_TRUE ); + context = NULL; + } + memset(result, 0, sizeof result); + + return rv; +} /* ComputeMAC */ + +TPS_PUBLIC PK11SymKey *Util::DeriveKey(const Buffer& permKey, + const Buffer& hostChallenge, + const Buffer& cardChallenge) +{ + PK11SymKey *key = NULL, *master = NULL; + PK11SlotInfo *slot = PK11_GetInternalKeySlot(); + PK11Context *context = NULL; + unsigned char derivationData[16]; +#ifdef DES2_WORKAROUND + unsigned char keyData[24]; +#else + unsigned char keyData[16]; +#endif + int i; + SECStatus s; + int len; + SECItem keyItem = { siBuffer, keyData, sizeof keyData }; + static SECItem noParams = { siBuffer, 0, 0 }; + BYTE masterKeyData[24]; + SECItem masterKeyItem = {siBuffer, masterKeyData, sizeof(masterKeyData) }; + + // convert 16-byte to 24-byte triple-DES key + memcpy(masterKeyData, permKey, 16); + memcpy(masterKeyData+16, permKey, 8); + + master = PK11_ImportSymKeyWithFlags(slot, CKM_DES3_ECB, + PK11_OriginGenerated, CKA_ENCRYPT, &masterKeyItem, + CKF_ENCRYPT, PR_FALSE, 0); + if( ! master ) goto done; + + for(i = 0;i < 4;i++) + { + derivationData[i] = cardChallenge[i+4]; + derivationData[i+4] = hostChallenge[i]; + derivationData[i+8] = cardChallenge[i]; + derivationData[i+12] = hostChallenge[i+4]; + } + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, master, + &noParams); + if (!context) goto done; + + /* Part 1 */ + s = PK11_CipherOp(context, &keyData[0], &len, 8, &derivationData[0], 8); + if (s != SECSuccess) goto done; + + /* Part 2 */ + s = PK11_CipherOp(context, &keyData[8], &len, 8, &derivationData[8], 8); + if (s != SECSuccess) goto done; + +#ifdef DES2_WORKAROUND + /* Part 3 */ + for(i = 0;i < 8;i++) + { + keyData[i+16] = keyData[i]; + } +#endif + + key = PK11_ImportSymKeyWithFlags(slot, CKM_DES3_ECB, PK11_OriginGenerated, + CKA_ENCRYPT, &keyItem, CKF_SIGN | CKF_ENCRYPT, PR_FALSE, 0); + +done: + memset(keyData, 0, sizeof keyData); + if( context != NULL ) { + PK11_DestroyContext( context, PR_TRUE ); + context = NULL; + } + if( slot != NULL ) { + PK11_FreeSlot( slot ); + slot = NULL; + } + if( master != NULL ) { + PK11_FreeSymKey( master ); + master = NULL; + } + + return key; +} + +/** + * + * 01 + * 81 10 B4 BA A8 9A 8C D0 29 2B 45 21 0E (AUTH KEY) + * 1B C8 4B 1C 31 + * 03 8B AF 47 + * 81 10 B4 BA A8 9A 8C D0 29 2B 45 21 0E (MAC KEY) + * 1B C8 4B 1C 31 + * 03 8B AF 47 + * 81 10 B4 BA A8 9A 8C D0 29 2B 45 21 0E (KEK KEY) + * 1B C8 4B 1C 31 + * 03 8B AF 47 + * + */ +TPS_PUBLIC PRStatus Util::CreateKeySetData(Buffer &newMasterVer, Buffer &old_kek_key, Buffer &new_auth_key, Buffer &new_mac_key, Buffer &new_kek_key, Buffer &output) +{ + PRStatus rv = PR_FAILURE; + + Buffer result; + + Buffer encrypted_auth_key(16); + Util::EncryptData(old_kek_key, new_auth_key, encrypted_auth_key); + Buffer kc_auth_key(3); + Util::ComputeKeyCheck(new_auth_key, kc_auth_key); + Buffer encrypted_mac_key(16); + Util::EncryptData(old_kek_key, new_mac_key, encrypted_mac_key); + Buffer kc_mac_key(3); + Util::ComputeKeyCheck(new_mac_key, kc_mac_key); + Buffer encrypted_kek_key(16); + Util::EncryptData(old_kek_key, new_auth_key, encrypted_kek_key); + Buffer kc_kek_key(3); + Util::ComputeKeyCheck(new_kek_key, kc_kek_key); + + result = newMasterVer + + Buffer(1, (BYTE)0x81) + + Buffer(1, (BYTE)0x10) + + encrypted_auth_key + + Buffer(1, (BYTE)0x03) + + kc_auth_key + + Buffer(1, (BYTE)0x81) + + Buffer(1, (BYTE)0x10) + + encrypted_mac_key + + Buffer(1, (BYTE)0x03) + + kc_mac_key + + Buffer(1, (BYTE)0x81) + + Buffer(1, (BYTE)0x10) + + encrypted_kek_key + + Buffer(1, (BYTE)0x03) + + kc_kek_key; + + output = result; + + rv = PR_SUCCESS; + return rv; +} + + +/* + * for Secure Messaging in Secure Channel + */ +TPS_PUBLIC PRStatus Util::EncryptData(PK11SymKey *encSessionKey, + Buffer &input, Buffer &output) +{ + PRStatus rv = PR_FAILURE; + SECStatus s = SECFailure; + //static SECItem noParams = { siBuffer, 0, 0 }; + static unsigned char d[8] = { 0,0,0,0,0,0,0,0 }; + static SECItem ivParams = { siBuffer, d, 8 }; + PK11Context *context = NULL; + unsigned char result[8]; + int len; + int i; + + /* this is ECB mode + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, encSessionKey, + &noParams); + */ + // use CBC mode + context = PK11_CreateContextBySymKey(CKM_DES3_CBC, CKA_ENCRYPT, encSessionKey, + &ivParams); + if (!context) { + goto done; + } + + for(i = 0;i < (int)input.size();i += 8) { + s = PK11_CipherOp(context, result, &len, 8, + (unsigned char *)(((BYTE*)input)+i), 8); + + if (s != SECSuccess) { + goto done; + } + output.replace(i, result, 8); + } + + rv = PR_SUCCESS; +// RA::Debug("Util::EncryptData", "success"); +done: + + //#define VRFY_ENC_SESSION_KEY + // fix this to use CBC mode later +#ifdef VRFY_ENC_SESSION_KEY + Buffer enc_key_buffer = Buffer((BYTE *) PK11_GetKeyData(encSessionKey)->data, PK11_GetKeyData(encSessionKey)->len); + RA::DebugBuffer("Util::EncryptData", "Verifying Encrypted Data", + &output); + Buffer out1 = Buffer(16, (BYTE)0); + PRStatus status = Util::DecryptData(enc_key_buffer, output, out1); + RA::DebugBuffer("Util::EncryptData", "Decrypted Data", + &out1); +#endif + + + if( context != NULL ) { + PK11_DestroyContext( context, PR_TRUE ); + context = NULL; + } + + return rv; +} + + +TPS_PUBLIC PRStatus Util::EncryptData(Buffer &kek_key, Buffer &input, Buffer &output) +{ + PRStatus rv = PR_FAILURE; + + PK11SymKey *master = NULL; + PK11SlotInfo *slot = PK11_GetInternalKeySlot(); + PK11Context *context = NULL; + int i; + SECStatus s = SECFailure; + int len; + static SECItem noParams = { siBuffer, 0, 0 }; +#ifdef DES2_WORKAROUND + unsigned char masterKeyData[24]; +#else + unsigned char masterKeyData[16]; +#endif + SECItem masterKeyItem = {siBuffer, masterKeyData, sizeof(masterKeyData) }; + unsigned char result[8]; + + // convert 16-byte to 24-byte triple-DES key + memcpy(masterKeyData, (BYTE*)kek_key, 16); +#ifdef DES2_WORKAROUND + memcpy(masterKeyData+16, (BYTE*)kek_key, 8); +#endif + + master = PK11_ImportSymKeyWithFlags(slot, CKM_DES3_ECB, + PK11_OriginGenerated, CKA_ENCRYPT, &masterKeyItem, + CKF_ENCRYPT, PR_FALSE, 0); + if( ! master ) { + goto done; + } + + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_ENCRYPT, master, + &noParams); + if (!context) { + goto done; + } + + for(i = 0;i < (int)input.size();i += 8) { + s = PK11_CipherOp(context, result, &len, 8, + (unsigned char *)(((BYTE*)input)+i), 8); + + if (s != SECSuccess) { + goto done; + } + output.replace(i, result, 8); + } + + rv = PR_SUCCESS; + +done: + + memset(masterKeyData, 0, sizeof masterKeyData); + if( context != NULL ) { + PK11_DestroyContext( context, PR_TRUE ); + context = NULL; + } + if( slot != NULL ) { + PK11_FreeSlot( slot ); + slot = NULL; + } + if( master != NULL ) { + PK11_FreeSymKey( master ); + master = NULL; + } + + return rv; +} + +TPS_PUBLIC PRStatus Util::DecryptData(Buffer &kek_key, Buffer &input, Buffer &output) +{ + PRStatus rv = PR_FAILURE; + + PK11SymKey *master = NULL; + PK11SlotInfo *slot = PK11_GetInternalKeySlot(); + PK11Context *context = NULL; + int i; + SECStatus s = SECFailure; + int len; + static SECItem noParams = { siBuffer, 0, 0 }; +#ifdef DES2_WORKAROUND + unsigned char masterKeyData[24]; +#else + unsigned char masterKeyData[16]; +#endif + SECItem masterKeyItem = {siBuffer, masterKeyData, sizeof(masterKeyData) }; + unsigned char result[8]; + + // convert 16-byte to 24-byte triple-DES key + memcpy(masterKeyData, (BYTE*)kek_key, 16); +#ifdef DES2_WORKAROUND + memcpy(masterKeyData+16, (BYTE*)kek_key, 8); +#endif + + master = PK11_ImportSymKeyWithFlags(slot, CKM_DES3_ECB, + PK11_OriginGenerated, CKA_DECRYPT, &masterKeyItem, + CKF_DECRYPT, PR_FALSE, 0); + if( ! master ) { + goto done; + } + + context = PK11_CreateContextBySymKey(CKM_DES3_ECB, CKA_DECRYPT, master, + &noParams); + if (!context) { + goto done; + } + + for(i = 0;i < (int)input.size();i += 8) { + s = PK11_CipherOp(context, result, &len, 8, + (unsigned char *)(((BYTE *)input)+i), 8); + + if (s != SECSuccess) { + goto done; + } + output.replace(i, result, 8); + } + + rv = PR_SUCCESS; + +done: + + memset(masterKeyData, 0, sizeof masterKeyData); + if( context != NULL ) { + PK11_DestroyContext( context, PR_TRUE ); + context = NULL; + } + if( slot != NULL ) { + PK11_FreeSlot( slot ); + slot = NULL; + } + if( master != NULL ) { + PK11_FreeSymKey( master ); + master = NULL; + } + + return rv; +} + +// this one takes PK11SymKey instead +TPS_PUBLIC PRStatus Util::DecryptData(PK11SymKey* enc_key, Buffer &input, Buffer &output) +{ + PRStatus rv = PR_FAILURE; + + PK11Context *context = NULL; + int i; + SECStatus s = SECFailure; + int len; + // static SECItem noParams = { siBuffer, 0, 0 }; + static unsigned char d[8] = { 0,0,0,0,0,0,0,0 }; + static SECItem ivParams = { siBuffer, d, 8 }; + unsigned char result[8]; + + if( ! enc_key ) { + goto done; + } + + context = PK11_CreateContextBySymKey(CKM_DES3_CBC, CKA_DECRYPT, enc_key, + &ivParams); + if (!context) { + goto done; + } + + for(i = 0;i < (int)input.size();i += 8) { + s = PK11_CipherOp(context, result, &len, 8, + (unsigned char *)(((BYTE *)input)+i), 8); + + if (s != SECSuccess) { + goto done; + } + output.replace(i, result, 8); + } + + rv = PR_SUCCESS; + +done: + + if( context != NULL ) { + PK11_DestroyContext( context, PR_TRUE ); + context = NULL; + } + + return rv; +} + |