/* check mcapi des3 */ static int check_des3(void) { CRYPT_TDES_CTX mcDes3; Des3 defDes3; int ret; byte out1[TDES_TEST_SIZE]; byte out2[TDES_TEST_SIZE]; strncpy((char*)key, "1234567890abcdefghijklmn", 24); strncpy((char*)iv, "12345678", 8); /* cbc encrypt */ ret = CRYPT_TDES_KeySet(&mcDes3, key, iv, CRYPT_TDES_ENCRYPTION); if (ret != 0) { printf("mcapi tdes key set failed\n"); return -1; } Des3_SetKey(&defDes3, key, iv, DES_ENCRYPTION); ret = CRYPT_TDES_CBC_Encrypt(&mcDes3, out1, ourData, TDES_TEST_SIZE); if (ret != 0) { printf("mcapi tdes cbc encrypt failed\n"); return -1; } Des3_CbcEncrypt(&defDes3, out2, ourData, TDES_TEST_SIZE); if (memcmp(out1, out2, TDES_TEST_SIZE) != 0) { printf("mcapi tdes cbc encrypt cmp failed\n"); return -1; } /* cbc decrypt */ ret = CRYPT_TDES_KeySet(&mcDes3, key, iv, CRYPT_TDES_DECRYPTION); if (ret != 0) { printf("mcapi tdes key set failed\n"); return -1; } Des3_SetKey(&defDes3, key, iv, DES_DECRYPTION); ret = CRYPT_TDES_CBC_Decrypt(&mcDes3, out2, out1, TDES_TEST_SIZE); if (ret != 0) { printf("mcapi tdes cbc decrypt failed\n"); return -1; } Des3_CbcDecrypt(&defDes3, out1, out1, TDES_TEST_SIZE); if (memcmp(out1, out2, TDES_TEST_SIZE) != 0) { printf("mcapi tdes cbc decrypt cmp failed\n"); return -1; } if (memcmp(out1, ourData, TDES_TEST_SIZE) != 0) { printf("mcapi tdes cbc decrypt orig cmp failed\n"); return -1; } printf("tdes mcapi test passed\n"); return 0; }
/* Triple DES CBC Decrypt */ int CRYPT_TDES_CBC_Decrypt(CRYPT_TDES_CTX* tdes, unsigned char* out, const unsigned char* in, unsigned int inSz) { if (tdes == NULL || out == NULL || in == NULL) return BAD_FUNC_ARG; return Des3_CbcDecrypt((Des3*)tdes, out, in, inSz); }
int des3_test() { const byte vector[] = { /* "Now is the time for all " w/o trailing 0 */ 0x4e,0x6f,0x77,0x20,0x69,0x73,0x20,0x74, 0x68,0x65,0x20,0x74,0x69,0x6d,0x65,0x20, 0x66,0x6f,0x72,0x20,0x61,0x6c,0x6c,0x20 }; byte plain[24]; byte cipher[24]; Des3 enc; Des3 dec; const byte key3[] = { 0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef, 0xfe,0xde,0xba,0x98,0x76,0x54,0x32,0x10, 0x89,0xab,0xcd,0xef,0x01,0x23,0x45,0x67 }; const byte iv3[] = { 0x12,0x34,0x56,0x78,0x90,0xab,0xcd,0xef, 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01, 0x11,0x21,0x31,0x41,0x51,0x61,0x71,0x81 }; const byte verify3[] = { 0x43,0xa0,0x29,0x7e,0xd1,0x84,0xf8,0x0e, 0x89,0x64,0x84,0x32,0x12,0xd5,0x08,0x98, 0x18,0x94,0x15,0x74,0x87,0x12,0x7d,0xb0 }; Des3_SetKey(&enc, key3, iv3, DES_ENCRYPTION); Des3_CbcEncrypt(&enc, cipher, vector, sizeof(vector)); Des3_SetKey(&dec, key3, iv3, DES_DECRYPTION); Des3_CbcDecrypt(&dec, plain, cipher, sizeof(cipher)); if (memcmp(plain, vector, sizeof(plain))) return -33; if (memcmp(cipher, verify3, sizeof(cipher))) return -34; return 0; }
/* * k5_des3_decrypt: Decrypt data buffer using 3DES. * * @key DES key (with odd parity) * @ivec Initialization Vector * @data Input/Output buffer (in-place decryption, block-by-block) * @num_data Number of blocks * * Returns 0 on success, krb5_error_code on error */ static krb5_error_code k5_des3_decrypt(krb5_key key, const krb5_data *ivec, krb5_crypto_iov *data, size_t num_data) { int ret; Des3 des3; unsigned char iv[DES_BLOCK_SIZE]; unsigned char iblock[DES_BLOCK_SIZE]; unsigned char oblock[DES_BLOCK_SIZE]; struct iov_cursor cursor; krb5_boolean empty; ret = validate(key, ivec, data, num_data, &empty); if (ret != 0 || empty) return ret; memset(iv, 0, sizeof(iv)); /* Check if IV exists and is the correct size */ if (ivec && ivec->data) { if (ivec->length != sizeof(iv)) return KRB5_CRYPTO_INTERNAL; memcpy(iv, ivec->data, ivec->length); } Des3_SetKey(&des3, key->keyblock.contents, iv, DES_DECRYPTION); k5_iov_cursor_init(&cursor, data, num_data, DES_BLOCK_SIZE, FALSE); for (;;) { if (!k5_iov_cursor_get(&cursor, iblock)) break; Des3_CbcDecrypt(&des3, oblock, iblock, DES_BLOCK_SIZE); k5_iov_cursor_put(&cursor, oblock); } if (ivec != NULL) memcpy(ivec->data, iblock, DES_BLOCK_SIZE); zap(iv, sizeof(iv)); zap(iblock, sizeof(iblock)); zap(oblock, sizeof(oblock)); return 0; }
/* unwrap and decrypt PKCS#7 envelopedData object, return decoded size */ CYASSL_API int PKCS7_DecodeEnvelopedData(PKCS7* pkcs7, byte* pkiMsg, word32 pkiMsgSz, byte* output, word32 outputSz) { int recipFound = 0; int ret, version, length; word32 savedIdx = 0, idx = 0; word32 contentType, encOID; byte issuerHash[SHA_DIGEST_SIZE]; mp_int serialNum; int encryptedKeySz, keySz; byte tmpIv[DES_BLOCK_SIZE]; byte encryptedKey[MAX_ENCRYPTED_KEY_SZ]; byte* decryptedKey = NULL; RsaKey privKey; int encryptedContentSz; byte padLen; byte* encryptedContent = NULL; if (pkcs7 == NULL || pkcs7->singleCert == NULL || pkcs7->singleCertSz == 0 || pkcs7->privateKey == NULL || pkcs7->privateKeySz == 0) return BAD_FUNC_ARG; if (pkiMsg == NULL || pkiMsgSz == 0 || output == NULL || outputSz == 0) return BAD_FUNC_ARG; /* load private key */ ret = InitRsaKey(&privKey, 0); if (ret != 0) return ret; ret = RsaPrivateKeyDecode(pkcs7->privateKey, &idx, &privKey, pkcs7->privateKeySz); if (ret != 0) { CYASSL_MSG("Failed to decode RSA private key"); return ret; } idx = 0; /* read past ContentInfo, verify type is envelopedData */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) return ASN_PARSE_E; if (contentType != ENVELOPED_DATA) { CYASSL_MSG("PKCS#7 input not of type EnvelopedData"); return PKCS7_OID_E; } if (pkiMsg[idx++] != (ASN_CONSTRUCTED | ASN_CONTEXT_SPECIFIC | 0)) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; /* remove EnvelopedData and version */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetMyVersion(pkiMsg, &idx, &version) < 0) return ASN_PARSE_E; if (version != 0) { CYASSL_MSG("PKCS#7 envelopedData needs to be of version 0"); return ASN_VERSION_E; } /* walk through RecipientInfo set, find correct recipient */ if (GetSet(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; savedIdx = idx; recipFound = 0; /* when looking for next recipient, use first sequence and version to * indicate there is another, if not, move on */ while(recipFound == 0) { /* remove RecipientInfo, if we don't have a SEQUENCE, back up idx to * last good saved one */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) { idx = savedIdx; break; } if (GetMyVersion(pkiMsg, &idx, &version) < 0) { idx = savedIdx; break; } if (version != 0) return ASN_VERSION_E; /* remove IssuerAndSerialNumber */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetNameHash(pkiMsg, &idx, issuerHash, pkiMsgSz) < 0) return ASN_PARSE_E; /* if we found correct recipient, issuer hashes will match */ if (XMEMCMP(issuerHash, pkcs7->issuerHash, SHA_DIGEST_SIZE) == 0) { recipFound = 1; } if (GetInt(&serialNum, pkiMsg, &idx, pkiMsgSz) < 0) return ASN_PARSE_E; mp_clear(&serialNum); if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) return ASN_PARSE_E; /* key encryption algorithm must be RSA for now */ if (encOID != RSAk) return ALGO_ID_E; /* read encryptedKey */ if (pkiMsg[idx++] != ASN_OCTET_STRING) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &encryptedKeySz, pkiMsgSz) < 0) return ASN_PARSE_E; if (recipFound == 1) XMEMCPY(encryptedKey, &pkiMsg[idx], encryptedKeySz); idx += encryptedKeySz; /* update good idx */ savedIdx = idx; } if (recipFound == 0) { CYASSL_MSG("No recipient found in envelopedData that matches input"); return PKCS7_RECIP_E; } /* remove EncryptedContentInfo */ if (GetSequence(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetContentType(pkiMsg, &idx, &contentType, pkiMsgSz) < 0) return ASN_PARSE_E; if (GetAlgoId(pkiMsg, &idx, &encOID, pkiMsgSz) < 0) return ASN_PARSE_E; /* get block cipher IV, stored in OPTIONAL parameter of AlgoID */ if (pkiMsg[idx++] != ASN_OCTET_STRING) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &length, pkiMsgSz) < 0) return ASN_PARSE_E; if (length != DES_BLOCK_SIZE) { CYASSL_MSG("Incorrect IV length, must be of DES_BLOCK_SIZE"); return ASN_PARSE_E; } XMEMCPY(tmpIv, &pkiMsg[idx], length); idx += length; /* read encryptedContent, cont[0] */ if (pkiMsg[idx++] != (ASN_CONTEXT_SPECIFIC | 0)) return ASN_PARSE_E; if (GetLength(pkiMsg, &idx, &encryptedContentSz, pkiMsgSz) < 0) return ASN_PARSE_E; encryptedContent = XMALLOC(encryptedContentSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); XMEMCPY(encryptedContent, &pkiMsg[idx], encryptedContentSz); /* decrypt encryptedKey */ keySz = RsaPrivateDecryptInline(encryptedKey, encryptedKeySz, &decryptedKey, &privKey); FreeRsaKey(&privKey); if (keySz <= 0) return keySz; /* decrypt encryptedContent */ if (encOID == DESb) { Des des; ret = Des_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION); if (ret == 0) Des_CbcDecrypt(&des, encryptedContent, encryptedContent, encryptedContentSz); if (ret != 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } } else if (encOID == DES3b) { Des3 des; ret = Des3_SetKey(&des, decryptedKey, tmpIv, DES_DECRYPTION); if (ret == 0) ret = Des3_CbcDecrypt(&des, encryptedContent, encryptedContent, encryptedContentSz); if (ret != 0) { XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; } } else { CYASSL_MSG("Unsupported content encryption OID type"); return ALGO_ID_E; } padLen = encryptedContent[encryptedContentSz-1]; /* copy plaintext to output */ XMEMCPY(output, encryptedContent, encryptedContentSz - padLen); /* free memory, zero out keys */ XMEMSET(encryptedKey, 0, MAX_ENCRYPTED_KEY_SZ); XMEMSET(encryptedContent, 0, encryptedContentSz); XFREE(encryptedContent, NULL, DYNAMIC_TYPE_TMP_BUFFER); return encryptedContentSz - padLen; }