/** PKCS #5 self-test @return CRYPT_OK if successful, CRYPT_NOP if tests have been disabled. */ int pkcs_5_test (void) { #ifndef LTC_TEST return CRYPT_NOP; #else typedef struct { const char* P; unsigned long P_len; const char* S; unsigned long S_len; int c; unsigned long dkLen; unsigned char DK[40]; } case_item; static const case_item cases_5_2[] = { { "password", 8, "salt", 4, 1, 20, { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, 0x2f, 0xe0, 0x37, 0xa6 } }, { "password", 8, "salt", 4, 2, 20, { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, 0xd8, 0xde, 0x89, 0x57 } }, #ifdef LTC_TEST_EXT { "password", 8, "salt", 4, 4096, 20, { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, 0x65, 0xa4, 0x29, 0xc1 } }, { "password", 8, "salt", 4, 16777216, 20, { 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4, 0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c, 0x26, 0x34, 0xe9, 0x84 } }, { "passwordPASSWORDpassword", 25, "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, 4096, 25, { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, 0x38 } }, { "pass\0word", 9, "sa\0lt", 5, 4096, 16, { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 } }, #endif /* LTC_TEST_EXT */ }; static const case_item cases_5_1[] = { { "password", 8, "saltsalt", /* must be 8 octects */ 8, /* ignored by alg1 */ 1, 20, { 0xca, 0xb8, 0x6d, 0xd6, 0x26, 0x17, 0x10, 0x89, 0x1e, 0x8c, 0xb5, 0x6e, 0xe3, 0x62, 0x56, 0x91, 0xa7, 0x5d, 0xf3, 0x44 } }, }; static const case_item cases_5_1o[] = { { "password", 8, "saltsalt", /* must be 8 octects */ 8, /* ignored by alg1_openssl */ 1, 20, { 0xca, 0xb8, 0x6d, 0xd6, 0x26, 0x17, 0x10, 0x89, 0x1e, 0x8c, 0xb5, 0x6e, 0xe3, 0x62, 0x56, 0x91, 0xa7, 0x5d, 0xf3, 0x44 } }, { "password", 8, "saltsalt", /* must be 8 octects */ 8, /* ignored by alg1_openssl */ 1, 30, { 0xca, 0xb8, 0x6d, 0xd6, 0x26, 0x17, 0x10, 0x89, 0x1e, 0x8c, 0xb5, 0x6e, 0xe3, 0x62, 0x56, 0x91, 0xa7, 0x5d, 0xf3, 0x44, 0xf0, 0xbf, 0xf4, 0xc1, 0x2c, 0xf3, 0x59, 0x6f, 0xc0, 0x0b } } }; unsigned char DK[40]; unsigned long dkLen; int i, err; int tested=0, failed=0; int hash = find_hash("sha1"); if (hash == -1) { #ifdef LTC_TEST_DBG printf("PKCS#5 test failed: 'sha1' hash not found\n"); #endif return CRYPT_ERROR; } /* testing alg 2 */ for(i=0; i < (int)(sizeof(cases_5_2) / sizeof(cases_5_2[0])); i++) { ++tested; dkLen = cases_5_2[i].dkLen; if((err = pkcs_5_alg2((unsigned char*)cases_5_2[i].P, cases_5_2[i].P_len, (unsigned char*)cases_5_2[i].S, cases_5_2[i].S_len, cases_5_2[i].c, hash, DK, &dkLen)) != CRYPT_OK) { #ifdef LTC_TEST_DBG printf("\npkcs_5_alg2() #%d: Failed/1 (%s)\n", i, error_to_string(err)); #endif ++failed; } else if (compare_testvector(DK, dkLen, cases_5_2[i].DK, cases_5_2[i].dkLen, "PKCS#5_2", i)) { ++failed; } } /* testing alg 1 */ for(i=0; i < (int)(sizeof(cases_5_1) / sizeof(case_item)); i++, tested++) { dkLen = cases_5_1[i].dkLen; if((err = pkcs_5_alg1((unsigned char*)cases_5_1[i].P, cases_5_1[i].P_len, (unsigned char*)cases_5_1[i].S, cases_5_1[i].c, hash, DK, &dkLen)) != CRYPT_OK) { #ifdef LTC_TEST_DBG printf("\npkcs_5_alg1() #%d: Failed/1 (%s)\n", i, error_to_string(err)); #endif ++failed; } else if (compare_testvector(DK, dkLen, cases_5_1[i].DK, cases_5_1[i].dkLen, "PKCS#5_1", i)) { ++failed; } } /* testing alg 1_openssl */ for(i = 0; i < (int)(sizeof(cases_5_1o) / sizeof(cases_5_1o[0])); i++, tested++) { dkLen = cases_5_1o[i].dkLen; if ((err = pkcs_5_alg1_openssl((unsigned char*)cases_5_1o[i].P, cases_5_1o[i].P_len, (unsigned char*)cases_5_1o[i].S, cases_5_1o[i].c, hash, DK, &dkLen)) != CRYPT_OK) { #ifdef LTC_TEST_DBG printf("\npkcs_5_alg1_openssl() #%d: Failed/1 (%s)\n", i, error_to_string(err)); #endif ++failed; } else if (compare_testvector(DK, dkLen, cases_5_1o[i].DK, cases_5_1o[i].dkLen, "PKCS#5_1o", i)) { ++failed; } } return (failed != 0) ? CRYPT_FAIL_TESTVECTOR : CRYPT_OK; #endif }
/* * The main routine. Mostly validate cmdline params, open files, run the KDF, * and do the crypt. */ int main(int argc, char *argv[]) { unsigned char salt[SALT_LENGTH]; FILE *infd = NULL, *outfd = NULL; int encrypt = -1; int hash = -1; int ret; unsigned char keyiv[KEY_LENGTH + IV_LENGTH]; unsigned long keyivlen = (KEY_LENGTH + IV_LENGTH); unsigned char *key, *iv; /* Check proper number of cmdline args */ if(argc < 5 || argc > 6) BARF("Invalid number of arguments"); /* Check proper mode of operation */ if (!strncmp(argv[1], "enc", 3)) encrypt = 1; else if(!strncmp(argv[1], "dec", 3)) encrypt = 0; else BARF("Bad command name"); /* Check we can open infile/outfile */ infd = fopen(argv[2], "rb"); if(infd == NULL) BARF("Could not open infile"); outfd = fopen(argv[3], "wb"); if(outfd == NULL) BARF("Could not open outfile"); /* Get the salt from wherever */ if(argc == 6) { /* User-provided */ if(parse_hex_salt((unsigned char*) argv[5], salt) != CRYPT_OK) BARF("Bad user-specified salt"); } else if(!strncmp(argv[1], "enc", 3)) { /* Encrypting; get from RNG */ if(rng_get_bytes(salt, sizeof(salt), NULL) != sizeof(salt)) BARF("Not enough random data"); } else { /* Parse from infile (decrypt only) */ if(parse_openssl_header(infd, salt) != CRYPT_OK) BARF("Invalid OpenSSL header in infile"); } /* Fetch the MD5 hasher for PKCS#5 */ hash = register_hash(&md5_desc); if(hash == -1) BARF("Could not register MD5 hash"); /* Set things to a sane initial state */ zeromem(keyiv, sizeof(keyiv)); key = keyiv + 0; /* key comes first */ iv = keyiv + KEY_LENGTH; /* iv comes next */ /* Run the key derivation from the provided passphrase. This gets us the key and iv. */ ret = pkcs_5_alg1_openssl((unsigned char*)argv[4], strlen(argv[4]), salt, OPENSSL_ITERATIONS, hash, keyiv, &keyivlen ); if(ret != CRYPT_OK) BARF("Could not derive key/iv from passphrase"); /* Display the salt/key/iv like OpenSSL cmdline does when -p */ printf("salt="); dump_bytes(salt, sizeof(salt)); printf("\n"); printf("key="); dump_bytes(key, KEY_LENGTH); printf("\n"); printf("iv ="); dump_bytes(iv, IV_LENGTH ); printf("\n"); /* If we're encrypting, write the salt header as OpenSSL does */ if(!strncmp(argv[1], "enc", 3)) { if(fwrite(salt_header, 1, sizeof(salt_header), outfd) != sizeof(salt_header) ) BARF("Error writing salt header to outfile"); if(fwrite(salt, 1, sizeof(salt), outfd) != sizeof(salt)) BARF("Error writing salt to outfile"); } /* At this point, the files are open, the salt has been figured out, and we're ready to pump data through crypt. */ /* Do the crypt operation */ if(do_crypt(infd, outfd, key, iv, encrypt) != CRYPT_OK) BARF("Error during crypt operation"); /* Clean up */ fclose(infd); fclose(outfd); return 0; }