1731 строка
52 KiB
C++
1731 строка
52 KiB
C++
//
|
|
// SslPlay.cpp : This file contains the 'main' function. Program execution begins and ends there.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
|
|
//
|
|
|
|
#include <iostream>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <openssl/ecdsa.h>
|
|
#include <openssl/obj_mac.h>
|
|
#include <openssl/kdf.h>
|
|
#include "scossl.h"
|
|
|
|
BIO *bio_err = NULL;
|
|
|
|
// By default exit Sslplay application if an error is encountered
|
|
#define SSLPLAY_EXIT_ON_ERROR (1)
|
|
|
|
void handleError(const char* description)
|
|
{
|
|
printf("Failure:%s:\n", description);
|
|
#if SSLPLAY_EXIT_ON_ERROR
|
|
exit(1);
|
|
#endif
|
|
}
|
|
|
|
void handleOpenSSLError(const char* description)
|
|
{
|
|
printf("Failure:%s:\n", description);
|
|
BIO_printf(bio_err, "OpenSSL Error:\n");
|
|
ERR_print_errors(bio_err);
|
|
#if SSLPLAY_EXIT_ON_ERROR
|
|
exit(1);
|
|
#endif
|
|
}
|
|
|
|
const char SeparatorLine[] = "-----------------------------------------------------------------------------------------\n";
|
|
|
|
void printBytes(char* data, int len, const char* header)
|
|
{
|
|
printf("\n%s (%d bytes): ", header, len);
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
printf("%X",data[i]);
|
|
}
|
|
printf("\n\n");
|
|
}
|
|
|
|
// Largest supported curve is P521 => 66 * 2 + 4 (int headers) + 3 (seq header)
|
|
#define SCOSSL_ECDSA_MAX_DER_SIGNATURE_LEN (139)
|
|
|
|
void TestEcdsa(EC_KEY* key)
|
|
{
|
|
unsigned char testHash[] = {
|
|
0x1, 0x54, 0xF, 0x2, 0xC9, 0xC, 0xFF, 0x31,
|
|
0x1, 0x54, 0xF, 0x2, 0xC9, 0xC, 0xFF, 0x31,
|
|
0x1, 0x54, 0xF, 0x2, 0xC9, 0xC, 0xFF, 0x31,
|
|
0x1, 0x54, 0xF, 0x2, 0xC9, 0xC, 0xFF, 0x31
|
|
};
|
|
unsigned char resultBytes[SCOSSL_ECDSA_MAX_DER_SIGNATURE_LEN] = { 0 };
|
|
bool result = true;
|
|
int currentIteration = 0;
|
|
unsigned int signatureBytesCount = sizeof(resultBytes);
|
|
ECDSA_SIG* ecdsaSig = NULL;
|
|
printf("Command ECDSA_sign\n");
|
|
if( !ECDSA_sign(0, testHash, sizeof(testHash), resultBytes, &signatureBytesCount, key) )
|
|
{
|
|
handleOpenSSLError("ECDSA_sign failed\n");
|
|
goto end;
|
|
}
|
|
printf("Command ECDSA_verify\n");
|
|
if( ECDSA_verify(0, testHash, sizeof(testHash), resultBytes, signatureBytesCount, key) != 1 )
|
|
{
|
|
handleOpenSSLError("ECDSA_verify failed\n");
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
printf("ECDSA_verify Succeeded\n");
|
|
}
|
|
printf("Command ECDSA_do_sign\n");
|
|
ecdsaSig = ECDSA_do_sign(testHash, sizeof(testHash), key);
|
|
if( ecdsaSig == NULL )
|
|
{
|
|
handleOpenSSLError("ECDSA_do_sign failed\n");
|
|
goto end;
|
|
}
|
|
printf("Command ECDSA_do_verify\n");
|
|
if( ECDSA_do_verify(testHash, sizeof(testHash), ecdsaSig, key) != 1 ){
|
|
handleOpenSSLError("ECDSA_do_verify failed\n");
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
printf("ECDSA_do_verify Succeeded\n");
|
|
}
|
|
end:
|
|
if( ecdsaSig )
|
|
ECDSA_SIG_free(ecdsaSig);
|
|
return;
|
|
}
|
|
|
|
// Smallest supported curve is P256 => 32 * 2 byte shared secret is largest secret that can be generated by all curves
|
|
#define SCOSSL_ECDH_SHARED_SECRET_LEN (64)
|
|
|
|
void TestEcdh(EC_KEY* key1, EC_KEY* key2)
|
|
{
|
|
unsigned char sharedSecretBytes1[SCOSSL_ECDH_SHARED_SECRET_LEN] = { 0 };
|
|
unsigned char sharedSecretBytes2[SCOSSL_ECDH_SHARED_SECRET_LEN] = { 0 };
|
|
const EC_POINT* publicKey1 = EC_KEY_get0_public_key(key1);
|
|
const EC_POINT* publicKey2 = EC_KEY_get0_public_key(key2);
|
|
|
|
printf("Command ECDH_compute_key #1\n");
|
|
if( ECDH_compute_key(sharedSecretBytes1, SCOSSL_ECDH_SHARED_SECRET_LEN, publicKey2, key1, NULL) <= 0 )
|
|
{
|
|
handleOpenSSLError("ECDH_compute_key failed\n");
|
|
goto end;
|
|
}
|
|
|
|
printf("Command ECDH_compute_key #2\n");
|
|
if( ECDH_compute_key(sharedSecretBytes2, SCOSSL_ECDH_SHARED_SECRET_LEN, publicKey1, key2, NULL) <= 0 )
|
|
{
|
|
handleOpenSSLError("ECDH_compute_key failed\n");
|
|
goto end;
|
|
}
|
|
|
|
if (memcmp(sharedSecretBytes1, sharedSecretBytes2, SCOSSL_ECDH_SHARED_SECRET_LEN) != 0)
|
|
{
|
|
handleError("Shared secrets don't match\n");
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
printf("ECDH_compute_key Succeeded\n");
|
|
}
|
|
end:
|
|
return;
|
|
}
|
|
|
|
void TestEccCurve(int nid)
|
|
{
|
|
EC_KEY* key1 = NULL;
|
|
EC_KEY* key2 = NULL;
|
|
printf("Command EC_KEY_new_by_curve_name\n");
|
|
key1 = EC_KEY_new_by_curve_name(nid);
|
|
key2 = EC_KEY_new_by_curve_name(nid);
|
|
printf("Command EC_KEY_generate_key\n");
|
|
EC_KEY_generate_key(key1);
|
|
EC_KEY_generate_key(key2);
|
|
TestEcdsa(key1);
|
|
TestEcdh(key1, key2);
|
|
EC_KEY_free(key1);
|
|
EC_KEY_free(key2);
|
|
return;
|
|
}
|
|
|
|
void TestEcc()
|
|
{
|
|
TestEccCurve(NID_X9_62_prime256v1);
|
|
TestEccCurve(NID_secp384r1);
|
|
TestEccCurve(NID_secp521r1);
|
|
printf("%s", SeparatorLine);
|
|
}
|
|
|
|
// Largest supported dlgroup is ffdhe4096/MODP4096 => 512 byte shared secret is largest secret that can be generated
|
|
#define SCOSSL_DH_SHARED_SECRET_MAX_LEN (512)
|
|
|
|
void TestDhDlgroup(const BIGNUM* p)
|
|
{
|
|
DH* key1 = NULL;
|
|
DH* key2 = NULL;
|
|
unsigned char sharedSecretBytes1[SCOSSL_DH_SHARED_SECRET_MAX_LEN] = { 0 };
|
|
unsigned char sharedSecretBytes2[SCOSSL_DH_SHARED_SECRET_MAX_LEN] = { 0 };
|
|
BIGNUM* p1 = NULL;
|
|
BIGNUM* g1 = NULL;
|
|
BIGNUM* p2 = NULL;
|
|
BIGNUM* g2 = NULL;
|
|
const BIGNUM* pubkey1 = NULL;
|
|
const BIGNUM* pubkey2 = NULL;
|
|
|
|
printf("Command DH_new\n");
|
|
key1 = DH_new();
|
|
key2 = DH_new();
|
|
if( key1 == NULL || key2 == NULL )
|
|
{
|
|
handleOpenSSLError("DH_new failed\n");
|
|
goto end;
|
|
}
|
|
|
|
p1 = BN_dup(p);
|
|
p2 = BN_dup(p);
|
|
g1 = BN_new();
|
|
g2 = BN_new();
|
|
if( p1==NULL || p2==NULL || g1==NULL || g2==NULL || !BN_set_word(g1, 2) || !BN_set_word(g2, 2) )
|
|
{
|
|
handleOpenSSLError("BN_dup, BN_new, or BN_set_word failed\n");
|
|
goto end;
|
|
}
|
|
|
|
printf("Command DH_set0_pqg\n");
|
|
if( DH_set0_pqg(key1, p1, NULL, g1) != 1 )
|
|
{
|
|
handleOpenSSLError("DH_set0_pqg failed\n");
|
|
goto end;
|
|
}
|
|
p1 = NULL; // key1 manages p1 and g1 BIGNUMs now
|
|
g1 = NULL;
|
|
if( DH_set0_pqg(key2, p2, NULL, g2) != 1 )
|
|
{
|
|
handleOpenSSLError("DH_set0_pqg failed\n");
|
|
goto end;
|
|
}
|
|
p2 = NULL; // key2 manages p2 and g2 BIGNUMs now
|
|
g2 = NULL;
|
|
|
|
printf("Command DH_generate_key\n");
|
|
if( DH_generate_key(key1) != 1 || DH_generate_key(key2) != 1 )
|
|
{
|
|
handleOpenSSLError("DH_generate_key failed\n");
|
|
goto end;
|
|
}
|
|
|
|
printf("Command DH_get0_key\n");
|
|
DH_get0_key(key1, &pubkey1, NULL);
|
|
DH_get0_key(key2, &pubkey2, NULL);
|
|
if( pubkey1 == NULL || pubkey2 == NULL )
|
|
{
|
|
handleOpenSSLError("DH_get0_key failed\n");
|
|
goto end;
|
|
}
|
|
|
|
printf("Command DH_compute_key_padded\n");
|
|
if( DH_compute_key_padded(sharedSecretBytes1, pubkey2, key1) != DH_size(key1) ||
|
|
DH_compute_key_padded(sharedSecretBytes2, pubkey1, key2) != DH_size(key2) )
|
|
{
|
|
handleOpenSSLError("DH_compute_key_padded failed\n");
|
|
goto end;
|
|
}
|
|
|
|
if (memcmp(sharedSecretBytes1, sharedSecretBytes2, SCOSSL_DH_SHARED_SECRET_MAX_LEN) != 0)
|
|
{
|
|
handleError("Shared secrets don't match\n");
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
printf("ECDH_compute_key Succeeded\n");
|
|
}
|
|
|
|
end:
|
|
BN_free(p1);
|
|
BN_free(p2);
|
|
BN_free(g1);
|
|
BN_free(g2);
|
|
DH_free(key1);
|
|
DH_free(key2);
|
|
return;
|
|
}
|
|
|
|
void TestDh()
|
|
{
|
|
BIGNUM* p_modp = NULL;
|
|
DH* dh_ffdhe = NULL;
|
|
const BIGNUM* p_ffdhe = NULL;
|
|
|
|
// Test MODP safe-prime groups
|
|
p_modp = BN_get_rfc3526_prime_2048(NULL);
|
|
TestDhDlgroup(p_modp);
|
|
BN_free(p_modp);
|
|
p_modp = BN_get_rfc3526_prime_3072(NULL);
|
|
TestDhDlgroup(p_modp);
|
|
BN_free(p_modp);
|
|
p_modp = BN_get_rfc3526_prime_4096(NULL);
|
|
TestDhDlgroup(p_modp);
|
|
BN_free(p_modp);
|
|
|
|
// Test ffdhe safe-prime groups
|
|
dh_ffdhe = DH_new_by_nid(NID_ffdhe2048);
|
|
DH_get0_pqg(dh_ffdhe, &p_ffdhe, NULL, NULL);
|
|
TestDhDlgroup(p_ffdhe);
|
|
DH_free(dh_ffdhe);
|
|
dh_ffdhe = DH_new_by_nid(NID_ffdhe3072);
|
|
DH_get0_pqg(dh_ffdhe, &p_ffdhe, NULL, NULL);
|
|
TestDhDlgroup(p_ffdhe);
|
|
DH_free(dh_ffdhe);
|
|
dh_ffdhe = DH_new_by_nid(NID_ffdhe4096);
|
|
DH_get0_pqg(dh_ffdhe, &p_ffdhe, NULL, NULL);
|
|
TestDhDlgroup(p_ffdhe);
|
|
DH_free(dh_ffdhe);
|
|
|
|
printf("%s", SeparatorLine);
|
|
}
|
|
|
|
/*
|
|
* Read whole contents of a BIO into an allocated memory buffer and return
|
|
* it.
|
|
*/
|
|
int bio_to_mem(unsigned char **out, int maxlen, BIO *in)
|
|
{
|
|
BIO *mem;
|
|
int len, ret;
|
|
unsigned char tbuf[1024];
|
|
|
|
mem = BIO_new(BIO_s_mem());
|
|
if (mem == NULL)
|
|
return -1;
|
|
for (;;) {
|
|
if ((maxlen != -1) && maxlen < 1024)
|
|
len = maxlen;
|
|
else
|
|
len = 1024;
|
|
len = BIO_read(in, tbuf, len);
|
|
if (len < 0) {
|
|
BIO_free(mem);
|
|
return -1;
|
|
}
|
|
if (len == 0)
|
|
break;
|
|
if (BIO_write(mem, tbuf, len) != len) {
|
|
BIO_free(mem);
|
|
return -1;
|
|
}
|
|
maxlen -= len;
|
|
|
|
if (maxlen == 0)
|
|
break;
|
|
}
|
|
ret = BIO_get_mem_data(mem, (char **)out);
|
|
BIO_set_flags(mem, BIO_FLAGS_MEM_RDONLY);
|
|
BIO_free(mem);
|
|
return ret;
|
|
}
|
|
|
|
void TestRsaEncryptDecrypt(
|
|
EVP_PKEY *encryptionKey,
|
|
EVP_PKEY *decryptionKey,
|
|
const char* paddingStr,
|
|
int padding)
|
|
{
|
|
printf("\nTesting EVP_PKEY Encrypt/Decrypt Functions: Padding: %s(%d)\n", paddingStr, padding);
|
|
unsigned char plaintext[512];
|
|
size_t plaintext_len = 0;
|
|
|
|
EVP_PKEY_CTX *pEncryptContext = NULL;
|
|
unsigned char *encryptedtext = NULL;
|
|
size_t encryptedtext_len = 0;
|
|
|
|
EVP_PKEY_CTX *pDecryptContext = NULL;
|
|
unsigned char *decryptedtext = NULL;
|
|
size_t decryptedtext_len = 0;
|
|
|
|
if (padding == RSA_NO_PADDING) {
|
|
// PlainText has to be size of modulus of the key
|
|
plaintext_len = EVP_PKEY_size(encryptionKey);
|
|
} else {
|
|
plaintext_len = 42; // Choosen at whim
|
|
}
|
|
|
|
while(!RAND_bytes(plaintext, plaintext_len));
|
|
|
|
if (padding == RSA_NO_PADDING) {
|
|
// PlainText value has to be less than RSA public modulus
|
|
// We can just mask out the most significant bit
|
|
plaintext[0] &= 0x7f;
|
|
}
|
|
|
|
//
|
|
// Encrypt
|
|
//
|
|
printf("\nTesting EVP_PKEY_encrypt* Functions\n\n");
|
|
printf("Command EVP_PKEY_CTX_new\n");
|
|
pEncryptContext = EVP_PKEY_CTX_new(encryptionKey, NULL);
|
|
if (pEncryptContext == NULL)
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_encrypt_init\n");
|
|
if (EVP_PKEY_encrypt_init(pEncryptContext) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_set_rsa_padding\n");
|
|
if (EVP_PKEY_CTX_set_rsa_padding(pEncryptContext, padding) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
/* Determine buffer length */
|
|
printf("Command EVP_PKEY_encrypt\n");
|
|
if (EVP_PKEY_encrypt(
|
|
pEncryptContext,
|
|
NULL,
|
|
&encryptedtext_len,
|
|
plaintext,
|
|
plaintext_len) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
encryptedtext = (unsigned char *)OPENSSL_zalloc(encryptedtext_len);
|
|
printf("Command EVP_PKEY_encrypt (%zu)\n", encryptedtext_len);
|
|
if (EVP_PKEY_encrypt(
|
|
pEncryptContext,
|
|
encryptedtext,
|
|
&encryptedtext_len,
|
|
plaintext,
|
|
plaintext_len) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
|
|
printf("PlainText:\n");
|
|
BIO_dump_fp (stdout, (const char *)plaintext, plaintext_len);
|
|
printf("EncryptedText:\n");
|
|
BIO_dump_fp (stdout, (const char *)encryptedtext, encryptedtext_len);
|
|
|
|
//
|
|
// Decrypt with Private Key
|
|
//
|
|
|
|
printf("\nTesting EVP_PKEY_decrypt* Functions\n\n");
|
|
|
|
printf("Command EVP_PKEY_encrypt\n");
|
|
pDecryptContext = EVP_PKEY_CTX_new(decryptionKey, NULL);
|
|
if (pDecryptContext == NULL) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_decrypt_init\n");
|
|
if (EVP_PKEY_decrypt_init(pDecryptContext) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_set_rsa_padding\n");
|
|
if (EVP_PKEY_CTX_set_rsa_padding(pDecryptContext, padding) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
/* Determine buffer length */
|
|
printf("Command EVP_PKEY_decrypt\n");
|
|
if (EVP_PKEY_decrypt(pDecryptContext, NULL, &decryptedtext_len, (const unsigned char*)encryptedtext, encryptedtext_len) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
decryptedtext = (unsigned char *)OPENSSL_zalloc(decryptedtext_len);
|
|
printf("Command EVP_PKEY_decrypt\n");
|
|
if (EVP_PKEY_decrypt(pDecryptContext, decryptedtext, &decryptedtext_len, (const unsigned char*)encryptedtext, encryptedtext_len) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("DecryptedText:\n");
|
|
BIO_dump_fp (stdout, (const char *)decryptedtext, decryptedtext_len);
|
|
|
|
if (decryptedtext_len != plaintext_len ||
|
|
memcmp(plaintext, decryptedtext, decryptedtext_len) != 0)
|
|
{
|
|
handleError("PlainText and DecryptedText don't match\n");
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
printf("PlainText and DecryptedText match\n");
|
|
}
|
|
|
|
end:
|
|
if (encryptedtext)
|
|
OPENSSL_free(encryptedtext);
|
|
if (decryptedtext)
|
|
OPENSSL_free(decryptedtext);
|
|
if (pEncryptContext)
|
|
EVP_PKEY_CTX_free(pEncryptContext);
|
|
if (pDecryptContext)
|
|
EVP_PKEY_CTX_free(pDecryptContext);
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
void TestRsaSignVerify(
|
|
EVP_PKEY *signingKey,
|
|
EVP_PKEY *verificationKey,
|
|
const char* paddingStr,
|
|
int padding,
|
|
const char* digestStr,
|
|
const EVP_MD *digest,
|
|
size_t digest_length
|
|
)
|
|
{
|
|
printf("\nTesting EVP_PKEY Sign/Verify Functions: Padding: %s(%d), digest: %s\n", paddingStr, padding, digestStr);
|
|
EVP_PKEY_CTX *pSignContext = NULL;
|
|
unsigned char *signature = NULL;
|
|
size_t signature_len = 0;
|
|
EVP_PKEY_CTX *pVerifyContext = NULL;
|
|
unsigned char message_digest[64];
|
|
size_t message_digest_len = digest_length;
|
|
int ret = 0;
|
|
|
|
while(!RAND_bytes(message_digest, digest_length));
|
|
|
|
printf("\nTesting EVP_PKEY_sign* Functions - PKCS1 PADDING\n\n");
|
|
printf("Command EVP_PKEY_CTX_new\n");
|
|
pSignContext = EVP_PKEY_CTX_new(signingKey, NULL);
|
|
if (pSignContext == NULL) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_sign_init\n");
|
|
if (EVP_PKEY_sign_init(pSignContext) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_set_rsa_padding\n");
|
|
if (EVP_PKEY_CTX_set_rsa_padding(pSignContext, padding) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_set_signature_md\n");
|
|
if (EVP_PKEY_CTX_set_signature_md(pSignContext, digest) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
if (padding == RSA_PKCS1_PSS_PADDING)
|
|
{
|
|
printf("Command EVP_PKEY_CTX_set_rsa_pss_saltlen RSA_PSS_SALTLEN_DIGEST\n");
|
|
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pSignContext, RSA_PSS_SALTLEN_DIGEST) <= 0)
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
}
|
|
/* Determine buffer length */
|
|
printf("Command EVP_PKEY_sign\n");
|
|
if (EVP_PKEY_sign(pSignContext, NULL, &signature_len, message_digest, message_digest_len) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
signature = (unsigned char *)OPENSSL_zalloc(signature_len);
|
|
if (!signature) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_sign\n");
|
|
if (EVP_PKEY_sign(pSignContext, signature, &signature_len, message_digest, message_digest_len) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
|
|
printf("Message Digest:\n");
|
|
BIO_dump_fp (stdout, (const char *)message_digest, message_digest_len);
|
|
|
|
printf("Signature:\n");
|
|
BIO_dump_fp (stdout, (const char *)signature, signature_len);
|
|
|
|
//
|
|
// Verify with Public Key
|
|
//
|
|
|
|
printf("\nTesting EVP_PKEY_verify* Functions\n\n");
|
|
|
|
printf("Command EVP_PKEY_sign\n");
|
|
pVerifyContext = EVP_PKEY_CTX_new(verificationKey, NULL);
|
|
if (pVerifyContext == NULL) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_verify_init\n");
|
|
if (EVP_PKEY_verify_init(pVerifyContext) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_set_rsa_padding\n");
|
|
if (EVP_PKEY_CTX_set_rsa_padding(pVerifyContext, padding) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_set_signature_md\n");
|
|
if (EVP_PKEY_CTX_set_signature_md(pVerifyContext, digest) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
if (padding == RSA_PKCS1_PSS_PADDING)
|
|
{
|
|
printf("Command EVP_PKEY_CTX_set_rsa_pss_saltlen RSA_PSS_SALTLEN_DIGEST\n");
|
|
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pVerifyContext, RSA_PSS_SALTLEN_DIGEST) <= 0)
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
}
|
|
printf("Command EVP_PKEY_verify\n");
|
|
ret = EVP_PKEY_verify(pVerifyContext, signature, signature_len, message_digest, message_digest_len);
|
|
if (ret != 1)
|
|
{
|
|
handleError("EVP_PKEY_verify failed\n");
|
|
goto end;
|
|
} else {
|
|
printf("EVP_PKEY_verify succeeded\n");
|
|
}
|
|
|
|
end:
|
|
if (pSignContext)
|
|
EVP_PKEY_CTX_free(pSignContext);
|
|
if (pVerifyContext)
|
|
EVP_PKEY_CTX_free(pVerifyContext);
|
|
if (signature)
|
|
OPENSSL_free(signature);
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
void TestRsaDigestSignVerify(
|
|
EVP_PKEY *signingKey,
|
|
EVP_PKEY *verificationKey,
|
|
const char* paddingStr,
|
|
int padding,
|
|
const char* digestStr,
|
|
const EVP_MD *digest
|
|
)
|
|
{
|
|
printf("\nTesting EVP_PKEY DigestSign/DigestVerify Functions: digest: %s\n", digestStr);
|
|
EVP_MD_CTX* RSASignCtx = NULL;
|
|
EVP_MD_CTX* RSAVerifyCtx = NULL;
|
|
unsigned char *signature = NULL;
|
|
size_t signature_len = 0;
|
|
const unsigned char plaintext[] =
|
|
"Message for testing EVP_PKEY_Encrypt* APIs for encryption/decryption";
|
|
size_t plaintext_len = sizeof(plaintext);
|
|
const char message[] = "My EVP_DigestSign Message";
|
|
size_t message_len = sizeof(message);
|
|
bool authentic = false;
|
|
int AuthStatus = 0;
|
|
EVP_PKEY_CTX *pSigningKeyContext = NULL;
|
|
EVP_PKEY_CTX *pVerificationKeyContext = NULL;
|
|
|
|
printf("\nTesting DigestSign* Functions\n\n");
|
|
|
|
printf("Command EVP_MD_CTX_new\n");
|
|
RSASignCtx = EVP_MD_CTX_new();
|
|
printf("Command EVP_DigestSignInit\n");
|
|
if (EVP_DigestSignInit(RSASignCtx,&pSigningKeyContext, digest, NULL, signingKey)<=0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
|
|
if (paddingStr) {
|
|
printf("Setting Padding: %s(%d)\n", paddingStr, padding);
|
|
printf("Command EVP_PKEY_CTX_set_rsa_padding\n");
|
|
if (EVP_PKEY_CTX_set_rsa_padding(pSigningKeyContext, padding)<=0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
// if (EVP_PKEY_CTX_set_rsa_mgf1_md(pSigningKeyContext, EVP_sha512())<=0) {
|
|
// printOpenSSLError("");
|
|
// goto end;
|
|
// }
|
|
}
|
|
if (padding == RSA_PKCS1_PSS_PADDING)
|
|
{
|
|
printf("Command EVP_PKEY_CTX_set_rsa_pss_saltlen RSA_PSS_SALTLEN_DIGEST\n");
|
|
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pSigningKeyContext, RSA_PSS_SALTLEN_DIGEST) <= 0)
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
}
|
|
|
|
printf("Command EVP_DigestSignUpdate\n");
|
|
if (EVP_DigestSignUpdate(RSASignCtx, message, message_len) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_DigestSignFinal\n");
|
|
if (EVP_DigestSignFinal(RSASignCtx, NULL, &signature_len) <=0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("signature_length= %ld\n", signature_len);
|
|
signature = (unsigned char*)OPENSSL_zalloc(signature_len);
|
|
printf("Command EVP_DigestSignFinal\n");
|
|
if (EVP_DigestSignFinal(RSASignCtx, signature, &signature_len) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
|
|
printf("Message:\n");
|
|
BIO_dump_fp (stdout, (const char *)message, message_len);
|
|
|
|
printf("Signature:\n");
|
|
BIO_dump_fp (stdout, (const char *)signature, signature_len);
|
|
|
|
//
|
|
// DigestVerify
|
|
//
|
|
printf("\nTesting EVP_DigestVerify* Functions\n\n");
|
|
printf("Command EVP_MD_CTX_new\n");
|
|
RSAVerifyCtx = EVP_MD_CTX_new();
|
|
printf("Verify Signature\n");
|
|
printf("Command EVP_DigestVerifyInit\n");
|
|
if (EVP_DigestVerifyInit(RSAVerifyCtx,&pVerificationKeyContext, digest,NULL,verificationKey)<=0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
if (paddingStr) {
|
|
printf("Setting Padding: %s(%d)\n", paddingStr, padding);
|
|
printf("Command EVP_PKEY_CTX_set_rsa_padding\n");
|
|
if (EVP_PKEY_CTX_set_rsa_padding(pVerificationKeyContext, padding)<=0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
// if (EVP_PKEY_CTX_set_rsa_mgf1_md(pVerificationKeyContext, EVP_sha512())<=0) {
|
|
// printOpenSSLError("");
|
|
// goto end;
|
|
// }
|
|
}
|
|
if (padding == RSA_PKCS1_PSS_PADDING)
|
|
{
|
|
printf("Command EVP_PKEY_CTX_set_rsa_pss_saltlen RSA_PSS_SALTLEN_DIGEST\n");
|
|
if (EVP_PKEY_CTX_set_rsa_pss_saltlen(pVerificationKeyContext, RSA_PSS_SALTLEN_DIGEST) <= 0)
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
}
|
|
printf("Command EVP_DigestVerifyUpdate\n");
|
|
if (EVP_DigestVerifyUpdate(RSAVerifyCtx, message, message_len) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_DigestVerifyFinal\n");
|
|
AuthStatus = EVP_DigestVerifyFinal(RSAVerifyCtx, signature, signature_len);
|
|
if (AuthStatus==1) {
|
|
authentic = true;
|
|
} else if(AuthStatus==0) {
|
|
authentic = false;
|
|
} else {
|
|
authentic = false;
|
|
}
|
|
if (!authentic) {
|
|
handleError("Signature Not Verified\n");
|
|
} else {
|
|
printf("Signature Verified\n");
|
|
}
|
|
|
|
end:
|
|
if (RSASignCtx)
|
|
EVP_MD_CTX_free(RSASignCtx);
|
|
if (RSAVerifyCtx)
|
|
EVP_MD_CTX_free(RSAVerifyCtx);
|
|
if (signature)
|
|
OPENSSL_free(signature);
|
|
return;
|
|
}
|
|
|
|
void TestRsaSealOpen(
|
|
EVP_PKEY *sealKey,
|
|
EVP_PKEY *openKey,
|
|
const char* cipherStr,
|
|
const EVP_CIPHER *cipher
|
|
)
|
|
{
|
|
printf("\nTesting EVP_PKEY Seal/Open Functions: Cipher: %s\n", cipherStr);
|
|
EVP_CIPHER_CTX *rsaSealCtx = NULL;
|
|
EVP_CIPHER_CTX *rsaOpenCtx = NULL;
|
|
static const unsigned char message[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
|
|
size_t message_len = sizeof(message);
|
|
unsigned char *encKey = NULL;
|
|
int encKey_len = 0;
|
|
unsigned char iv[EVP_MAX_IV_LENGTH];
|
|
unsigned char ciphertext[32], plaintext[16];
|
|
int ciphertext_len = 0;
|
|
int encryptedBlockLen = 0;
|
|
|
|
int decryptedMessageLen = 0;
|
|
int decryptedBlockLen = 0;
|
|
unsigned char *decryptedMessage = NULL;
|
|
|
|
memset(iv, 0, EVP_MAX_IV_LENGTH);
|
|
memset(ciphertext, 0, 32);
|
|
memset(plaintext, 0, 16);
|
|
|
|
printf("\nTesting EVP_Seal* Functions\n\n");
|
|
|
|
printf("Command EVP_CIPHER_CTX_new\n");
|
|
rsaSealCtx = EVP_CIPHER_CTX_new();
|
|
|
|
printf("Command EVP_CIPHER_CTX_init\n");
|
|
if (EVP_CIPHER_CTX_init(rsaSealCtx) != 1) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
encKey = (unsigned char *) OPENSSL_zalloc(EVP_PKEY_size(sealKey));
|
|
printf("Command EVP_SealInit\n");
|
|
if (EVP_SealInit(rsaSealCtx, cipher, &encKey, &encKey_len, iv, &sealKey, 1) != 1) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_SealUpdate\n");
|
|
if (EVP_SealUpdate(rsaSealCtx, ciphertext, &ciphertext_len, message, message_len) != 1) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_SealFinal\n");
|
|
if (EVP_SealFinal(rsaSealCtx, ciphertext + ciphertext_len, &encryptedBlockLen) != 1) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
ciphertext_len += encryptedBlockLen;
|
|
|
|
printf("Message:\n");
|
|
BIO_dump_fp (stdout, (const char *)message, message_len);
|
|
|
|
printf("Sealed output:\n");
|
|
BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len);
|
|
|
|
//
|
|
// Open
|
|
//
|
|
|
|
printf("\nTesting EVP_Open* Functions\n\n");
|
|
printf("Command EVP_CIPHER_CTX_new\n");
|
|
rsaOpenCtx = EVP_CIPHER_CTX_new();
|
|
|
|
printf("Command EVP_CIPHER_CTX_init\n");
|
|
if (EVP_CIPHER_CTX_init(rsaOpenCtx) != 1) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_OpenInit\n");
|
|
if (EVP_OpenInit(rsaOpenCtx, cipher, encKey, encKey_len, iv, openKey) != 1) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
decryptedMessage = (unsigned char *) OPENSSL_zalloc(ciphertext_len + EVP_MAX_IV_LENGTH);
|
|
// the length of the encrypted message
|
|
decryptedMessageLen = 0;
|
|
decryptedBlockLen = 0;
|
|
// decrypt message with AES secret
|
|
printf("Command EVP_OpenUpdate\n");
|
|
if (EVP_OpenUpdate(rsaOpenCtx, decryptedMessage, &decryptedMessageLen, ciphertext, ciphertext_len) != 1) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
// finalize by decrypting padding
|
|
printf("Command EVP_OpenFinal\n");
|
|
EVP_OpenFinal(rsaOpenCtx, decryptedMessage + decryptedMessageLen, &decryptedBlockLen);
|
|
decryptedMessageLen += decryptedBlockLen;
|
|
|
|
printf("Opened Bytes:\n");
|
|
BIO_dump_fp (stdout, (const char *)decryptedMessage, decryptedMessageLen);
|
|
|
|
if (message_len != decryptedMessageLen ||
|
|
memcmp(message,decryptedMessage, decryptedMessageLen) != 0)
|
|
{
|
|
handleError("Decrypted/Opened text don't match original message\n");
|
|
}
|
|
else
|
|
{
|
|
printf("Decrypted/Opened text match original message\n");
|
|
}
|
|
|
|
end:
|
|
if (encKey)
|
|
OPENSSL_free(encKey);
|
|
if (rsaSealCtx)
|
|
EVP_CIPHER_CTX_free(rsaSealCtx);
|
|
if (rsaOpenCtx)
|
|
EVP_CIPHER_CTX_free(rsaOpenCtx);
|
|
if (decryptedMessage)
|
|
OPENSSL_free(decryptedMessage);
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
int CreateKeys(int id, int modulus, uint32_t exponent, char* publicFileName, char* privateFileName, EVP_PKEY** publicKey, EVP_PKEY** privateKey)
|
|
{
|
|
BIGNUM* exponent_bn = NULL;
|
|
EVP_PKEY* pKey = NULL;
|
|
EVP_PKEY_CTX* pKeyContext = NULL;
|
|
BIO *privateBIO = NULL;
|
|
BIO *publicBIO = NULL;
|
|
FILE *fp = NULL;
|
|
int ret = -1;
|
|
|
|
//
|
|
// Generate RSA Key
|
|
//
|
|
printf("Command EVP_PKEY_CTX_new_id\n");
|
|
pKeyContext = EVP_PKEY_CTX_new_id(id, NULL);
|
|
if (pKeyContext == NULL) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_keygen_init\n");
|
|
if (EVP_PKEY_keygen_init(pKeyContext) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_set_rsa_keygen_bits\n");
|
|
if (EVP_PKEY_CTX_set_rsa_keygen_bits(pKeyContext, modulus) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
exponent_bn = BN_new();
|
|
BN_set_word(exponent_bn, exponent);
|
|
if (EVP_PKEY_CTX_set_rsa_keygen_pubexp(pKeyContext, exponent_bn) <= 0) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_keygen\n");
|
|
if (EVP_PKEY_keygen(pKeyContext, &pKey) != 1) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
|
|
printf("%s", SeparatorLine);
|
|
|
|
//
|
|
// Export Public Key
|
|
//
|
|
printf("\nTesting Exporting Public Key\n\n");
|
|
publicBIO = BIO_new(BIO_s_mem());
|
|
PEM_write_bio_PUBKEY(publicBIO, pKey);
|
|
fp = fopen(publicFileName, "w");
|
|
PEM_write_PUBKEY(fp, pKey);
|
|
PEM_write_PUBKEY(stdout, pKey);
|
|
fflush(fp);
|
|
fclose(fp);
|
|
BIO_free(publicBIO);
|
|
printf("%s", SeparatorLine);
|
|
|
|
//
|
|
// Export Private Key
|
|
//
|
|
printf("\nTesting Exporting Private Key\n\n");
|
|
privateBIO = BIO_new(BIO_s_mem());
|
|
PEM_write_bio_PrivateKey(privateBIO, pKey, NULL, NULL, 0, 0, NULL);
|
|
fp = fopen(privateFileName, "w");
|
|
PEM_write_PrivateKey(fp, pKey, NULL, NULL, 0, NULL, NULL);
|
|
PEM_write_PrivateKey(stdout, pKey, NULL, NULL, 0, NULL, NULL);
|
|
fflush(fp);
|
|
fclose(fp);
|
|
BIO_free(privateBIO);
|
|
printf("%s", SeparatorLine);
|
|
|
|
//
|
|
// Import Public Key
|
|
//
|
|
printf("\nTesting Importing Public Key\n\n");
|
|
fp = fopen(publicFileName, "r");
|
|
*publicKey = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
|
|
fflush(fp);
|
|
fclose(fp);
|
|
printf("%s", SeparatorLine);
|
|
|
|
//
|
|
// Import Private Key
|
|
//
|
|
printf("\nTesting Importing Private Key\n\n");
|
|
fp = fopen(privateFileName, "r");
|
|
*privateKey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
|
|
fflush(fp);
|
|
fclose(fp);
|
|
printf("%s", SeparatorLine);
|
|
|
|
ret = 0;
|
|
|
|
end:
|
|
if (pKeyContext)
|
|
EVP_PKEY_CTX_free(pKeyContext);
|
|
if (pKey)
|
|
EVP_PKEY_free(pKey);
|
|
return ret;
|
|
}
|
|
|
|
void TestRsaEvp(int modulus, uint32_t exponent)
|
|
{
|
|
printf("\nTest RSA: Modulus: %d, Exponent: %d\n\n", modulus, exponent);
|
|
EVP_PKEY *privateKey = NULL;
|
|
EVP_PKEY *privateKeyPss = NULL;
|
|
EVP_PKEY *publicKey = NULL;
|
|
EVP_PKEY *publicKeyPss = NULL;
|
|
char publicFileName[1024];
|
|
char publicPssFileName[1024];
|
|
char privateFileName[1024];
|
|
char privatePssFileName[1024];
|
|
|
|
// Initialize Data
|
|
sprintf(publicFileName, "%s_%d.pem", "public", modulus);
|
|
sprintf(privateFileName, "%s_%d.pem", "private", modulus);
|
|
sprintf(publicPssFileName, "%s_pss_%d.pem", "public", modulus);
|
|
sprintf(privatePssFileName, "%s_pss_%d.pem", "private", modulus);
|
|
|
|
printf("\nTesting EVP_PKEY_keygen* Functions\n\n");
|
|
if( CreateKeys(EVP_PKEY_RSA, modulus, exponent, publicFileName, privateFileName, &publicKey, &privateKey) == -1 )
|
|
{
|
|
handleError("CreateKeys EVP_PKEY_RSA failed");
|
|
goto end;
|
|
}
|
|
if( CreateKeys(EVP_PKEY_RSA_PSS, modulus, exponent, publicPssFileName, privatePssFileName, &publicKeyPss, &privateKeyPss) == -1 )
|
|
{
|
|
handleError("CreateKeys EVP_PKEY_RSA_PSS failed");
|
|
goto end;
|
|
}
|
|
|
|
//
|
|
// Encrypt/Decrypt
|
|
//
|
|
TestRsaEncryptDecrypt(publicKey, privateKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING);
|
|
TestRsaEncryptDecrypt(publicKey, privateKey, "RSA_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING);
|
|
TestRsaEncryptDecrypt(publicKey, privateKey, "RSA_SSLV23_PADDING", RSA_SSLV23_PADDING);
|
|
TestRsaEncryptDecrypt(publicKey, privateKey, "RSA_NO_PADDING", RSA_NO_PADDING);
|
|
printf("%s", SeparatorLine);
|
|
|
|
//
|
|
// Sign/Verify
|
|
//
|
|
TestRsaSignVerify(privateKey, publicKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING, "EVP_MD5", EVP_md5(), 16);
|
|
TestRsaSignVerify(privateKey, publicKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING, "EVP_sha1", EVP_sha1(), 20);
|
|
TestRsaSignVerify(privateKey, publicKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING, "EVP_sha256", EVP_sha256(), 32);
|
|
TestRsaSignVerify(privateKey, publicKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING, "EVP_sha384", EVP_sha384(), 48);
|
|
TestRsaSignVerify(privateKey, publicKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING, "EVP_sha512", EVP_sha512(), 64);
|
|
printf("%s", SeparatorLine);
|
|
|
|
TestRsaSignVerify(privateKey, publicKey, "RSA_PKCS1_PSS_PADDING", RSA_PKCS1_PSS_PADDING, "EVP_sha256", EVP_sha256(), 32);
|
|
TestRsaSignVerify(privateKeyPss, publicKeyPss, "RSA_PKCS1_PSS_PADDING", RSA_PKCS1_PSS_PADDING, "EVP_sha256", EVP_sha256(), 32);
|
|
printf("%s", SeparatorLine);
|
|
|
|
//
|
|
// DigestSign/DigestVerify
|
|
//
|
|
TestRsaDigestSignVerify(privateKey, publicKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING, "EVP_MD5", EVP_md5());
|
|
TestRsaDigestSignVerify(privateKey, publicKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING, "EVP_sha1", EVP_sha1());
|
|
TestRsaDigestSignVerify(privateKey, publicKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING, "EVP_sha256", EVP_sha256());
|
|
TestRsaDigestSignVerify(privateKey, publicKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING, "EVP_sha384", EVP_sha384());
|
|
TestRsaDigestSignVerify(privateKey, publicKey, "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING, "EVP_sha512", EVP_sha512());
|
|
printf("%s", SeparatorLine);
|
|
|
|
TestRsaDigestSignVerify(privateKey, publicKey, "RSA_PKCS1_PSS_PADDING", RSA_PKCS1_PSS_PADDING, "EVP_sha256", EVP_sha256());
|
|
TestRsaDigestSignVerify(privateKeyPss, publicKeyPss, "RSA_PKCS1_PSS_PADDING", RSA_PKCS1_PSS_PADDING, "EVP_sha256", EVP_sha256());
|
|
printf("%s", SeparatorLine);
|
|
|
|
//
|
|
// Seal/Open
|
|
//
|
|
TestRsaSealOpen(publicKey, privateKey, "EVP_aes_128_cbc", EVP_aes_128_cbc());
|
|
TestRsaSealOpen(publicKey, privateKey, "EVP_aes_192_cbc", EVP_aes_192_cbc());
|
|
TestRsaSealOpen(publicKey, privateKey, "EVP_aes_256_cbc", EVP_aes_256_cbc());
|
|
TestRsaSealOpen(publicKey, privateKey, "EVP_aes_128_ecb", EVP_aes_128_ecb());
|
|
TestRsaSealOpen(publicKey, privateKey, "EVP_aes_192_ecb", EVP_aes_192_ecb());
|
|
TestRsaSealOpen(publicKey, privateKey, "EVP_aes_256_ecb", EVP_aes_256_ecb());
|
|
printf("%s", SeparatorLine);
|
|
|
|
printf("\nCompleted Test RSA: Modulus: %d, Exponent: %d\n\n", modulus, exponent);
|
|
printf("%s", SeparatorLine);
|
|
|
|
end:
|
|
|
|
if (publicKey)
|
|
EVP_PKEY_free(publicKey);
|
|
if (privateKey)
|
|
EVP_PKEY_free(privateKey);
|
|
if (publicKeyPss)
|
|
EVP_PKEY_free(publicKeyPss);
|
|
if (privateKeyPss)
|
|
EVP_PKEY_free(privateKeyPss);
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
void TestRsaEvpAll()
|
|
{
|
|
TestRsaEvp(1024, 65537);
|
|
TestRsaEvp(2048, 65537);
|
|
TestRsaEvp(3072, 65537);
|
|
TestRsaEvp(4096, 65537);
|
|
printf("%s", SeparatorLine);
|
|
|
|
}
|
|
|
|
bool TestDigest(const char* digestname)
|
|
{
|
|
bool result = false;
|
|
EVP_MD_CTX *mdctx;
|
|
char mess1[] = "Test Message1234567";
|
|
char mess2[] = "Hello World";
|
|
unsigned char md_value[EVP_MAX_MD_SIZE];
|
|
unsigned int md_len, i;
|
|
|
|
printf("\nTestDigest: %s\n\n", digestname);
|
|
|
|
const EVP_MD *md = EVP_get_digestbyname(digestname);
|
|
if (md == NULL)
|
|
{
|
|
printf("No Digest found for %s\n", digestname);
|
|
goto end;
|
|
}
|
|
|
|
printf("Command EVP_MD_CTX_new\n");
|
|
mdctx = EVP_MD_CTX_new();
|
|
printf("Command EVP_DigestInit_ex\n");
|
|
EVP_DigestInit_ex(mdctx, md, NULL);
|
|
printf("Command EVP_DigestUpdate\n");
|
|
EVP_DigestUpdate(mdctx, mess1, strlen(mess1));
|
|
printf("Command EVP_DigestUpdate\n");
|
|
EVP_DigestUpdate(mdctx, mess2, strlen(mess2));
|
|
printf("Command EVP_DigestFinal_ex\n");
|
|
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
|
|
printf("Command EVP_MD_CTX_free\n");
|
|
EVP_MD_CTX_free(mdctx);
|
|
|
|
printf("Digest (%s) : \t", digestname);
|
|
for (i = 0; i < md_len; i++)
|
|
printf("%02x", md_value[i]);
|
|
printf("\n");
|
|
result = true;
|
|
end:
|
|
printf("%s", SeparatorLine);
|
|
return result;
|
|
}
|
|
|
|
void TestDigests()
|
|
{
|
|
EVP_MD *md = NULL;
|
|
char mess1[] = "Test Message1234567";
|
|
char mess2[] = "Hello World";
|
|
unsigned int md_len=32, i;
|
|
|
|
TestDigest("MD5");
|
|
TestDigest("SHA1");
|
|
TestDigest("SHA224");
|
|
TestDigest("SHA256");
|
|
TestDigest("SHA384");
|
|
TestDigest("SHA512");
|
|
|
|
unsigned char md1[SHA256_DIGEST_LENGTH]; // 32 bytes
|
|
SHA256_CTX context;
|
|
SHA256_Init(&context);
|
|
SHA256_Update(&context, mess1, strlen(mess1));
|
|
SHA256_Update(&context, mess2, strlen(mess2));
|
|
SHA256_Final(md1, &context);
|
|
printf("\nSHA256 Digest using Lower level API's is: ");
|
|
for (i = 0; i < md_len; i++)
|
|
printf("%02x", md1[i]);
|
|
printf("\n");
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
int encrypt(const EVP_CIPHER *cipher, unsigned char *plaintext, int plaintext_len, unsigned char *key,
|
|
unsigned char *iv, unsigned char *ciphertext)
|
|
{
|
|
EVP_CIPHER_CTX *ctx = NULL;
|
|
int len = 0;
|
|
int ciphertext_len = 0;
|
|
printf("Command EVP_CIPHER_CTX_new\n");
|
|
if(!(ctx = EVP_CIPHER_CTX_new()))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_EncryptInit_ex\n");
|
|
if(!EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_EncryptUpdate\n");
|
|
if(!EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
ciphertext_len = len;
|
|
printf("Command EVP_EncryptFinal_ex\n");
|
|
if(!EVP_EncryptFinal_ex(ctx, ciphertext + len, &len))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("len %d\n", len);
|
|
ciphertext_len += len;
|
|
end:
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
printf("%s", SeparatorLine);
|
|
return ciphertext_len;
|
|
}
|
|
|
|
int decrypt(const EVP_CIPHER *cipher, unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
|
|
unsigned char *iv, unsigned char *plaintext)
|
|
{
|
|
EVP_CIPHER_CTX *ctx;
|
|
int len;
|
|
int plaintext_len;
|
|
printf("Command EVP_CIPHER_CTX_new\n");
|
|
if(!(ctx = EVP_CIPHER_CTX_new()))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_DecryptInit_ex\n");
|
|
if(!EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_DecryptUpdate\n");
|
|
if(!EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
plaintext_len = len;
|
|
printf("Command EVP_DecryptFinal_ex\n");
|
|
if(!EVP_DecryptFinal_ex(ctx, plaintext + len, &len))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
plaintext_len += len;
|
|
|
|
end:
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
printf("%s", SeparatorLine);
|
|
return plaintext_len;
|
|
}
|
|
|
|
bool TestAesCipher(
|
|
const char* ciphername,
|
|
const EVP_CIPHER *cipher,
|
|
unsigned char *key,
|
|
int key_length,
|
|
unsigned char *iv,
|
|
int iv_length,
|
|
unsigned char* plaintext,
|
|
int plaintext_len)
|
|
{
|
|
bool result = false;
|
|
unsigned char ciphertext[8192];
|
|
int ciphertext_len = 0;
|
|
unsigned char decryptedtext[8300];
|
|
int decryptedtext_len = 0;
|
|
|
|
printf("\nTestAesCipher: %s\n\n", ciphername);
|
|
|
|
printf("Key Bytes:\n");
|
|
BIO_dump_fp (stdout, (const char *)key, key_length);
|
|
|
|
printf("IV:\n");
|
|
BIO_dump_fp (stdout, (const char *)iv, iv_length);
|
|
|
|
printf("PlainText:\n");
|
|
BIO_dump_fp (stdout, (const char *)plaintext, plaintext_len);
|
|
|
|
/* Encrypt the plaintext */
|
|
ciphertext_len = encrypt(cipher, plaintext, plaintext_len, key, iv, ciphertext);
|
|
|
|
/* Do something useful with the ciphertext here */
|
|
printf("Ciphertext:\n");
|
|
BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len);
|
|
|
|
/* Decrypt the ciphertext */
|
|
decryptedtext_len = decrypt(cipher, ciphertext, ciphertext_len, key, iv,
|
|
decryptedtext);
|
|
|
|
/* Show the decrypted text */
|
|
printf("DecryptedText:\n");
|
|
BIO_dump_fp (stdout, (const char *)decryptedtext, decryptedtext_len);
|
|
|
|
if (decryptedtext_len != plaintext_len ||
|
|
memcmp(plaintext, decryptedtext, decryptedtext_len) != 0)
|
|
{
|
|
handleError("PlainText and DecryptedText don't match\n");
|
|
goto end;
|
|
}
|
|
else
|
|
{
|
|
printf("PlainText and DecryptedText match\n");
|
|
}
|
|
|
|
result = true;
|
|
end:
|
|
/* Clean up */
|
|
EVP_cleanup();
|
|
printf("%s", SeparatorLine);
|
|
return result;
|
|
}
|
|
|
|
void TestAesCbc()
|
|
{
|
|
unsigned char plaintext[8192];
|
|
int plaintext_len = 70;
|
|
unsigned char iv[16];
|
|
unsigned char key[32];
|
|
|
|
while(!RAND_bytes(key, 32));
|
|
while(!RAND_bytes(iv, 16));
|
|
while(!RAND_bytes(plaintext, plaintext_len));
|
|
|
|
TestAesCipher("EVP_aes_128_cbc", EVP_aes_128_cbc(), key, 16, iv, 16, plaintext, plaintext_len);
|
|
TestAesCipher("EVP_aes_192_cbc", EVP_aes_192_cbc(), key, 24, iv, 16, plaintext, plaintext_len);
|
|
TestAesCipher("EVP_aes_256_cbc", EVP_aes_256_cbc(), key, 32, iv, 16, plaintext, plaintext_len);
|
|
|
|
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
void TestAesEcb()
|
|
{
|
|
unsigned char plaintext[8192];
|
|
int plaintext_len = 70;
|
|
unsigned char iv[16];
|
|
unsigned char key[32];
|
|
|
|
while(!RAND_bytes(key, 32));
|
|
while(!RAND_bytes(iv, 16));
|
|
while(!RAND_bytes(plaintext, plaintext_len));
|
|
|
|
TestAesCipher("EVP_aes_128_ecb", EVP_aes_128_ecb(), key, 16, iv, 16, plaintext, plaintext_len);
|
|
TestAesCipher("EVP_aes_192_ecb", EVP_aes_192_ecb(), key, 24, iv, 16, plaintext, plaintext_len);
|
|
TestAesCipher("EVP_aes_256_ecb", EVP_aes_256_ecb(), key, 32, iv, 16, plaintext, plaintext_len);
|
|
|
|
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
void TestAesXts()
|
|
{
|
|
unsigned char plaintext[8192];
|
|
int plaintext_len = 64;
|
|
unsigned char iv[8];
|
|
unsigned char key[64];
|
|
|
|
while(!RAND_bytes(key, 64));
|
|
while(!RAND_bytes(iv, 8));
|
|
while(!RAND_bytes(plaintext, plaintext_len));
|
|
|
|
TestAesCipher("EVP_aes_128_xts", EVP_aes_128_xts(), key, 32, iv, 8, plaintext, plaintext_len);
|
|
TestAesCipher("EVP_aes_256_xts", EVP_aes_256_xts(), key, 64, iv, 8, plaintext, plaintext_len);
|
|
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
|
|
/* AES-GCM test data from NIST public test vectors */
|
|
|
|
static unsigned char gcm_key[] = {
|
|
0xee, 0xbc, 0x1f, 0x57, 0x48, 0x7f, 0x51, 0x92, 0x1c, 0x04, 0x65, 0x66, 0x5f, 0x8a, 0xe6, 0xd1,
|
|
0x65, 0x8b, 0xb2, 0x6d, 0xe6, 0xf8, 0xa0, 0x69, 0xa3, 0x52, 0x02, 0x93, 0xa5, 0x72, 0x07, 0x8f
|
|
};
|
|
static unsigned char gcm_iv[] = {
|
|
0x99, 0xaa, 0x3e, 0x68, 0xed, 0x81, 0x73, 0xa0, 0xee, 0xd0, 0x66, 0x84
|
|
};
|
|
static unsigned char gcm_pt[] = {
|
|
0xf5, 0x6e, 0x87, 0x05, 0x5b, 0xc3, 0x2d, 0x0e, 0xeb, 0x31, 0xb2, 0xea, 0xcc, 0x2b, 0xf2, 0xa5
|
|
};
|
|
static unsigned char gcm_aad[] = {
|
|
0x4d, 0x23, 0xc3, 0xce, 0xc3, 0x34, 0xb4, 0x9b, 0xdb, 0x37, 0x0c, 0x43, 0x7f, 0xec, 0x78, 0xde
|
|
};
|
|
static unsigned char gcm_ct[] = {
|
|
0xf7, 0x26, 0x44, 0x13, 0xa8, 0x4c, 0x0e, 0x7c, 0xd5, 0x36, 0x86, 0x7e, 0xb9, 0xf2, 0x17, 0x36
|
|
};
|
|
static unsigned char gcm_tag[] = {
|
|
0x67, 0xba, 0x05, 0x10, 0x26, 0x2a, 0xe4, 0x87, 0xd7, 0x37, 0xee, 0x62, 0x98, 0xf7, 0x7e, 0x0c
|
|
};
|
|
|
|
int encrypt_gcm(
|
|
const EVP_CIPHER *cipher, unsigned char *plaintext, int plaintext_len, unsigned char *aad, int aad_len,
|
|
unsigned char *key, unsigned char *iv, unsigned char *ciphertext, unsigned char *tag)
|
|
{
|
|
EVP_CIPHER_CTX *ctx;
|
|
int len=0, ciphertext_len=0;
|
|
/* Create and initialise the context */
|
|
if(!(ctx = EVP_CIPHER_CTX_new())) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
/* Initialise the encryption operation. */
|
|
if(1 != EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv)) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
/* Provide any AAD data. This can be called zero or more times as required */
|
|
if(1 != EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
/* Provide the message to be encrypted, and obtain the encrypted output.
|
|
* EVP_EncryptUpdate can be called multiple times if necessary */
|
|
/* encrypt in block lengths of 16 bytes */
|
|
while(ciphertext_len <= plaintext_len-16) {
|
|
if(1 != EVP_EncryptUpdate(ctx, ciphertext+ciphertext_len, &len, plaintext+ciphertext_len, 16))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
ciphertext_len+=len;
|
|
}
|
|
if(1 != EVP_EncryptUpdate(ctx, ciphertext+ciphertext_len, &len, plaintext+ciphertext_len, plaintext_len-ciphertext_len)) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
ciphertext_len+=len;
|
|
/* Finalise the encryption. Normally ciphertext bytes may be written at
|
|
* this stage, but this does not occur in GCM mode
|
|
*/
|
|
if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + ciphertext_len, &len)) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
ciphertext_len += len;
|
|
/* Get the tag */
|
|
if(1 != EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, tag)) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
/* Clean up */
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
end:
|
|
printf("%s", SeparatorLine);
|
|
return ciphertext_len;
|
|
}
|
|
|
|
int decrypt_gcm(
|
|
const EVP_CIPHER *cipher, unsigned char *ciphertext, int ciphertext_len, unsigned char *aad, int aad_len,
|
|
unsigned char *key, unsigned char *iv, unsigned char *decryptedtext, unsigned char *tag)
|
|
{
|
|
EVP_CIPHER_CTX *ctx;
|
|
int len=0, decryptedtext_len=0, ret;
|
|
/* Create and initialise the context */
|
|
if(!(ctx = EVP_CIPHER_CTX_new())) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
/* Initialise the decryption operation. */
|
|
if(!EVP_DecryptInit_ex(ctx, cipher, NULL, key, iv)) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
/* Provide any AAD data. This can be called zero or more times as
|
|
* required */
|
|
if(!EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
/* Provide the message to be decrypted, and obtain the decryptedtext output.
|
|
* EVP_DecryptUpdate can be called multiple times if necessary
|
|
*/
|
|
while(decryptedtext_len <= ciphertext_len-16)
|
|
{
|
|
if(1!=EVP_DecryptUpdate(ctx, decryptedtext+decryptedtext_len, &len, ciphertext+decryptedtext_len, 16))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
decryptedtext_len+=len;
|
|
}
|
|
if(1!=EVP_DecryptUpdate(ctx, decryptedtext+decryptedtext_len, &len, ciphertext+decryptedtext_len, ciphertext_len-decryptedtext_len))
|
|
{
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
decryptedtext_len+=len;
|
|
/* Set expected tag value. Works in OpenSSL 1.0.1d and later */
|
|
if(!EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, tag)) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
/* Finalise the decryption. A positive return value indicates success,
|
|
* anything else is a failure - the plaintext is not trustworthy.
|
|
*/
|
|
ret = EVP_DecryptFinal_ex(ctx, decryptedtext + decryptedtext_len, &len);
|
|
/* Clean up */
|
|
EVP_CIPHER_CTX_free(ctx);
|
|
if(ret > 0)
|
|
{
|
|
/* Success */
|
|
//decryptedtext_len += len;
|
|
return decryptedtext_len;
|
|
} else {
|
|
/* Verify failed */
|
|
handleError("AES-GCM decryption failed");
|
|
return -1;
|
|
}
|
|
end:
|
|
|
|
printf("%s", SeparatorLine);
|
|
return 0;
|
|
}
|
|
|
|
void TestAesGcmCipher(
|
|
const char* ciphername, const EVP_CIPHER *cipher, unsigned char *key, int key_length,
|
|
unsigned char *iv, int iv_length, unsigned char *aad, int aad_length, unsigned char* plaintext,
|
|
int plaintext_len)
|
|
{
|
|
unsigned char ciphertext[8192];
|
|
int ciphertext_len = 0;
|
|
unsigned char decryptedtext[8300];
|
|
int decryptedtext_len = 0;
|
|
unsigned char tag[100];
|
|
printf("\nTestAesGcmCipher: %s\n\n", ciphername);
|
|
printf("Key Bytes:\n");
|
|
BIO_dump_fp (stdout, (const char *)key, key_length);
|
|
printf("IV:\n");
|
|
BIO_dump_fp (stdout, (const char *)iv, iv_length);
|
|
printf("AAD:\n");
|
|
BIO_dump_fp (stdout, (const char *)aad, aad_length);
|
|
printf("PlainText:\n");
|
|
BIO_dump_fp (stdout, (const char *)plaintext, plaintext_len);
|
|
/* Encrypt the plaintext */
|
|
ciphertext_len = encrypt_gcm(cipher, plaintext, plaintext_len, aad, aad_length, key, iv, ciphertext, tag);
|
|
/* Do something useful with the ciphertext here */
|
|
printf("Ciphertext:\n");
|
|
BIO_dump_fp (stdout, (const char *)ciphertext, ciphertext_len);
|
|
printf("Tag:\n");
|
|
BIO_dump_fp (stdout, (const char *)tag, 16);
|
|
/* Decrypt the ciphertext */
|
|
decryptedtext_len = decrypt_gcm(cipher, ciphertext, ciphertext_len, aad, aad_length, key, iv, decryptedtext, tag);
|
|
/* Show the decrypted text */
|
|
printf("DecryptedText:\n");
|
|
BIO_dump_fp (stdout, (const char *)decryptedtext, decryptedtext_len);
|
|
if (decryptedtext_len != plaintext_len ||
|
|
memcmp(plaintext, decryptedtext, decryptedtext_len) != 0)
|
|
{
|
|
handleError("PlainText and DecryptedText don't match\n");
|
|
}
|
|
else
|
|
{
|
|
printf("PlainText and DecryptedText match\n");
|
|
}
|
|
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
void
|
|
TestAesGcmGeneric()
|
|
{
|
|
unsigned char plaintext[8192];
|
|
int plaintext_len = 70;
|
|
unsigned char iv[12]; // Symcrypt only support 12 byte Nonce for GCM
|
|
unsigned char key[32];
|
|
unsigned char aad[32];
|
|
|
|
while(!RAND_bytes(key, 32));
|
|
while(!RAND_bytes(iv, 12));
|
|
while(!RAND_bytes(aad, 32));
|
|
while(!RAND_bytes(plaintext, plaintext_len));
|
|
|
|
TestAesGcmCipher("EVP_aes_128_gcm", EVP_aes_128_gcm(), key, 16, iv, 12, aad, 16, plaintext, plaintext_len);
|
|
TestAesGcmCipher("EVP_aes_192_gcm", EVP_aes_192_gcm(), key, 24, iv, 12, aad, 16, plaintext, plaintext_len);
|
|
TestAesGcmCipher("EVP_aes_256_gcm", EVP_aes_256_gcm(), key, 32, iv, 12, aad, 16, plaintext, plaintext_len);
|
|
|
|
TestAesGcmCipher("EVP_aes_256_gcm", EVP_aes_256_gcm(), gcm_key, 32, gcm_iv, 12, gcm_aad, 16, gcm_pt, 16);
|
|
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
void TestCiphers()
|
|
{
|
|
TestAesCbc();
|
|
TestAesEcb();
|
|
TestAesGcmGeneric();
|
|
TestAesXts();
|
|
printf("%s", SeparatorLine);
|
|
|
|
}
|
|
|
|
void TestHKDF(void)
|
|
{
|
|
EVP_PKEY_CTX *pctx;
|
|
unsigned char out[20];
|
|
size_t outlen;
|
|
int i;
|
|
unsigned char salt[] = "0123456789";
|
|
unsigned char key[] = "012345678901234567890123456789";
|
|
unsigned char info[] = "infostring";
|
|
const unsigned char expected[] = {
|
|
0xe5, 0x07, 0x70, 0x7f, 0xc6, 0x78, 0xd6, 0x54, 0x32, 0x5f, 0x7e, 0xc5,
|
|
0x7b, 0x59, 0x3e, 0xd8, 0x03, 0x6b, 0xed, 0xca
|
|
};
|
|
size_t expectedlen = sizeof(expected);
|
|
|
|
printf("\n Testing HKDF \n\n");
|
|
|
|
printf("Command EVP_PKEY_CTX_new_id\n");
|
|
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
|
|
if (pctx == NULL) {
|
|
handleOpenSSLError("");
|
|
goto end;
|
|
}
|
|
|
|
/* We do this twice to test reuse of the EVP_PKEY_CTX */
|
|
for (i = 0; i < 2; i++) {
|
|
outlen = sizeof(out);
|
|
memset(out, 0, outlen);
|
|
|
|
printf("Command EVP_PKEY_derive_init\n");
|
|
if (EVP_PKEY_derive_init(pctx) <= 0)
|
|
{
|
|
handleOpenSSLError("EVP_PKEY_derive_init");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_set_hkdf_md\n");
|
|
if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0) {
|
|
handleOpenSSLError("EVP_PKEY_CTX_set_hkdf_md");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_set1_hkdf_salt\n");
|
|
if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, sizeof(salt) - 1) <= 0) {
|
|
handleOpenSSLError("EVP_PKEY_CTX_set1_hkdf_salt");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_set1_hkdf_key\n");
|
|
if (EVP_PKEY_CTX_set1_hkdf_key(pctx, key, sizeof(key) - 1) <= 0) {
|
|
handleOpenSSLError("EVP_PKEY_CTX_set1_hkdf_key");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_CTX_add1_hkdf_info\n");
|
|
if (EVP_PKEY_CTX_add1_hkdf_info(pctx, info, sizeof(info) - 1) <= 0) {
|
|
handleOpenSSLError("EVP_PKEY_CTX_add1_hkdf_info");
|
|
goto end;
|
|
}
|
|
printf("Command EVP_PKEY_derive\n");
|
|
if (EVP_PKEY_derive(pctx, out, &outlen) <= 0) {
|
|
handleOpenSSLError("EVP_PKEY_derive");
|
|
goto end;
|
|
}
|
|
|
|
printBytes((char *)out, outlen, "Output KDF");
|
|
printBytes((char *)expected, expectedlen, "Expected KDF");
|
|
|
|
if ((outlen != expectedlen) ||
|
|
(memcmp(out, expected, expectedlen) != 0))
|
|
{
|
|
handleError("KDF didn't derive the expected values\n");
|
|
}
|
|
else {
|
|
printf("KDF produced the right value\n");
|
|
}
|
|
}
|
|
|
|
end:
|
|
EVP_PKEY_CTX_free(pctx);
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
void TestTls1Prf(void)
|
|
{
|
|
EVP_PKEY_CTX *pctx;
|
|
unsigned char out[16];
|
|
size_t outlen = sizeof(out);
|
|
int i;
|
|
const unsigned char expected[sizeof(out)] = {
|
|
0x8e, 0x4d, 0x93, 0x25, 0x30, 0xd7, 0x65, 0xa0,
|
|
0xaa, 0xe9, 0x74, 0xc3, 0x04, 0x73, 0x5e, 0xcc
|
|
};
|
|
size_t expectedlen = sizeof(expected);
|
|
|
|
printf("\n Testing TLS1PRF \n\n");
|
|
|
|
pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL);
|
|
|
|
/* We do this twice to test reuse of the EVP_PKEY_CTX */
|
|
for (i = 0; i < 2; i++) {
|
|
outlen = sizeof(out);
|
|
memset(out, 0, outlen);
|
|
|
|
if (EVP_PKEY_derive_init(pctx) <= 0) {
|
|
handleOpenSSLError("EVP_PKEY_derive_init");
|
|
goto end;
|
|
}
|
|
if (EVP_PKEY_CTX_set_tls1_prf_md(pctx, EVP_sha256()) <= 0) {
|
|
handleOpenSSLError("EVP_PKEY_CTX_set_tls1_prf_md");
|
|
goto end;
|
|
}
|
|
if (EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, "secret", 6) <= 0) {
|
|
handleOpenSSLError("EVP_PKEY_CTX_set1_tls1_prf_secret");
|
|
goto end;
|
|
}
|
|
if (EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, "seed", 4) <= 0) {
|
|
handleOpenSSLError("EVP_PKEY_CTX_add1_tls1_prf_seed");
|
|
goto end;
|
|
}
|
|
if (EVP_PKEY_derive(pctx, out, &outlen) <= 0) {
|
|
handleOpenSSLError("EVP_PKEY_derive");
|
|
goto end;
|
|
}
|
|
|
|
if ((outlen != expectedlen) ||
|
|
(memcmp(out, expected, expectedlen) != 0))
|
|
{
|
|
handleError("TLS1Prf didn't derive the expected values\n");
|
|
}
|
|
else {
|
|
printf("TLS1Prf derived the expected value\n");
|
|
}
|
|
}
|
|
|
|
end:
|
|
EVP_PKEY_CTX_free(pctx);
|
|
printf("%s", SeparatorLine);
|
|
return;
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
int scossl_log_level_debug = SCOSSL_LOG_LEVEL_ERROR;
|
|
if (argc >= 2) {
|
|
scossl_log_level_debug = atoi(argv[1]);
|
|
SCOSSL_ENGINE_set_trace_level(scossl_log_level_debug);
|
|
}
|
|
SCOSSL_ENGINE_Initialize();
|
|
bio_err = BIO_new_fp(stdout, BIO_NOCLOSE);
|
|
|
|
TestDigests();
|
|
TestCiphers();
|
|
TestHKDF();
|
|
TestTls1Prf();
|
|
TestRsaEvpAll();
|
|
TestEcc();
|
|
TestDh();
|
|
|
|
BIO_free(bio_err);
|
|
return 0;
|
|
}
|