From OpenSSL documentation
Creating an ECDSA signature of a given SHA-256 hash value using the named curve prime256v1 (aka P-256).
Second step: compute the ECDSA signature of a SHA-256 hash value using ECDSA_do_sign():
sig = ECDSA_do_sign(digest, 32, eckey);
if (sig == NULL) {
/* error */
}
or using ECDSA_sign():
unsigned char *buffer, *pp;
int buf_len;
buf_len = ECDSA_size(eckey);
buffer = OPENSSL_malloc(buf_len);
pp = buffer;
if (ECDSA_sign(0, dgst, dgstlen, pp, &buf_len, eckey) == 0) {
/* error */
}
Third step: verify the created ECDSA signature using ECDSA_do_verify():
ret = ECDSA_do_verify(digest, 32, sig, eckey);
or using ECDSA_verify():
ret = ECDSA_verify(0, digest, 32, buffer, buf_len, eckey);
and finally evaluate the return value:
if (ret == 1) {
/* signature ok */
} else if (ret == 0) {
/* incorrect signature */
} else {
/* error */
}
EOF
This brings me to an understanding that I need to verify every signature I create with ECDSA_do_sign or ECDSA_sign, do I? Can it happen that a created signature is not valid?
From NIST PUB 186-4 - Digital Signature Standard section 4.7:
Signature verification may be performed by any party (i.e., the signatory, the intended recipient or any other party) using the signatory’s public key. A signatory may wish to verify that the computed signature is correct, perhaps before sending the signed message to the intended recipient. The intended recipient (or any other party) verifies the signature to determine its
authenticity.
(where the signatory is the signature creator)
Related
As stated in OpenSSL 3, DES_crypt macro is deprecated.
We are encouraged to use the sequence EVP_EncryptInit_ex(3), EVP_EncryptUpdate(3) and EVP_EncryptFinal_ex(3) as stated here:
https://www.openssl.org/docs/manmaster/man3/DES_crypt.html
However, it doesn't state where the old parameters are going to be placed.
Where is the "buf" and "salt" going on which EVP API? Which is the *In, Key, IV value on the EVP APIs?
Which cipher should I use?
Sample of our old code:
char* theDESCrypt (const char *myBuf, const char *mySalt)
{
// some code here
// ...
return DES_crypt(myBuf, mySalt);
}
This is what I tried to use. Is the placement of buffer and salt correct on this one?
char* theDESCrypt (const char *myBuf, const char *mySalt)
{
int myRetLen = 0;
int myRetLenFinal = 0;
unsigned char *myRet = malloc(strlen(myBuf) + 1);
/* fetch cipher */
EVP_CIPHER *des_cipher = EVP_CIPHER_fetch(NULL, "DES", NULL);
/* setup context */
EVP_CIPHER_CTX *p_Ctx = EVP_CIPHER_CTX_new();
EVP_CIPHER_CTX_init(p_Ctx);
/* encrypt data */
EVP_EncryptInit_ex2(p_Ctx, des_cipher, NULL, mySalt, NULL);
EVP_EncryptUpdate(p_Ctx, myRet, &myRetLen, (unsigned char*)myBuf, strlen(myBuf)+1);
EVP_EncryptFinal_ex(p_Ctx, &myRet[myRetLen], &myRetLenFinal);
/* cleanup contexts*/
EVP_CIPHER_free(des_cipher);
EVP_CIPHER_CTX_free(p_Ctx);
return myBuf;
}
I tried using the above code and it fails our unit tests so I'm not sure if my changes are correct.
How to use this function.
int mbedtls_pk_verify(mbedtls_pk_context * ctx, mbedtls_md_type_t md_alg, const unsigned char * hash, size_t hash_len, const unsigned char * sig, size_t sig_len)
So by calling the function like this mbedtls_pk_verify(&public_key_context, MBEDTLS_MD_SHA1, md, sizeof(md), signature, signature_lenght) how should I initialize md and how do I know what it is?
md is the message digest (usually a hash value).
To verify a signature, you have to feed the message through the same hash algorithm that was used when creating the signature. If the signature was created using SHA1, then you have to calculate the SHA1 hash value for the message you want to verify first. Then you pass this value together with its length (20 bytes in this case) to the function.
You can use the mbedtls library itself to calculate the message digest:
// Get the message digest info structure for SHA1
mbetdtls_md_info_t *mdinfo = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1);
char *md = malloc(mdinfo->size);
// Calculate the message digest for the data
mbedtls_md(mdinfo, data, datalen, md);
// Now verify the signature for the given hash of the data
int st = mbedtls_pk_verify(&public_key_context,
mdinfo->type, md, mdinfo->size,
signature, signature_length);
if (st != 0) {
// Signature invalid!
} else {
// Signature valid
}
free(md);
This should do what you need.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
I want to use an ECC private key for encryption because of mutual authentication.
But I cannot find a method (or function) in wolfcrypt (wolfSSL) or the micro-ecc library.
Is is okay to use an (ECC) private key for encryption?
And if so, how can I do this?
To address the initial question "Is it possible to use ECC private key for encryption?"
Typically users maintain a private key and share their public key. The public key is mathematically entangled with the private key so messages encrypted with the public key can be decrypted with the private key. In this way the private key remains exactly that, private! It is not recommended to use a private key for encrypting ever. If you can justify your reason for wishing to do this by all means please explain. Happy to hear your reasoning. If however you are learning and just unsure then please avoid doing what you asked.
To address the statement about private key encryption for mutual authentication... I'm not sure how that will help to provide mutual authentication and I am genuinely curious what #comomind was talking about there. Here is a link about how SSL/TLS can solve the problem of mutual authentication:
(https://www.codeproject.com/Articles/326574/An-Introduction-to-Mutual-SSL-Authentication)
For the second part of the question where wolfCrypt is concerned, the method (or function) in wolfSSL's wolfCrypt library is:
wc_ecc_encrypt
Here is the section from the manual describing this API and the arguments:
(https://www.wolfssl.com/wolfSSL/Docs-wolfssl-manual-18-14-wolfcrypt-api-ecc.html)
wc_ecc_encrypt
Synopsis:
include header: wolfssl/wolfcrypt/ecc.h
int wc_ecc_encrypt(ecc_key* privKey, ecc_key* pubKey, const byte* msg,
word32 msgSz, byte* out, word32* outSz, ecEncCtx* ctx);
Description: This function encrypts the given input message from msg
to out. This function takes an optional ctx object as parameter. When
supplied, encryption proceeds based on the ecEncCtx's encAlgo,
kdfAlgo, and macAlgo. If ctx is not supplied, processing completes
with the default algorithms, ecAES_128_CBC, ecHKDF_SHA256 and
ecHMAC_SHA256.
This function requires that the messages are padded according to the
encryption type specified by ctx.
Return Values: 0: Returned upon successfully encrypting the input
message BAD_FUNC_ARG: Returned if privKey, pubKey, msg, msgSz, out, or
outSz are NULL, or the ctx object specifies an unsupported encryption
type BAD_ENC_STATE_E: Returned if the ctx object given is in a state
that is not appropriate for encryption BUFFER_E: Returned if the
supplied output buffer is too small to store the encrypted ciphertext
MEMORY_E: Returned if there is an error allocating memory for the
shared secret key
Parameters: privKey - pointer to the ecc_key object containing the
private key to use for encryption pubKey - pointer to the ecc_key
object containing the public key of the peer with whom one wishes to
communicate msg- pointer to the buffer holding the message to encrypt
msgSz - size of the buffer to encrypt out - pointer to the buffer in
which to store the encrypted ciphertext outSz - pointer to a word32
object containing the available size in the out buffer. Upon
successfully encrypting the message, holds the number of bytes written
to the output buffer ctx - Optional: pointer to an ecEncCtx object
specifying different encryption algorithms to use
Example:
byte msg[] = { /* initialize with msg to encrypt. Ensure
padded to block size */ };
byte out[sizeof(msg)]; word32 outSz = sizeof(out);
int ret;
ecc_key cli, serv; // initialize cli with
private key // initialize serv with received public key
ecEncCtx* cliCtx, servCtx; // initialize cliCtx and servCtx //
exchange salts
ret = wc_ecc_encrypt(&cli, &serv, msg, sizeof(msg), out, &outSz,
cliCtx);
if(ret != 0) { // error encrypting message }
See Also: wc_ecc_decrypt
Notice this API takes in both a public and private key, where the public key came from the peer and the private key is your own private key. This API will then use ECDH to generate a shared secret. The shared secret is what should be used for encrypting and decrypting. The party you are trying to talk to will also take your public key and his private key to generate his own shared-secret key. The shared secret is never sent over the wire by either party. See more on the topic of shared secret here: (https://crypto.stackexchange.com/questions/21169/how-does-ecdh-arrive-on-a-shared-secret)
TEST CASE:
(https://github.com/wolfSSL/wolfssl/blob/master/wolfcrypt/test/test.c#L8701)
#ifdef HAVE_ECC_ENCRYPT
int ecc_encrypt_test(void)
{
WC_RNG rng;
int ret;
ecc_key userA, userB;
byte msg[48];
byte plain[48];
byte out[80];
word32 outSz = sizeof(out);
word32 plainSz = sizeof(plain);
int i;
ret = wc_InitRng(&rng);
if (ret != 0)
return -3001;
wc_ecc_init(&userA);
wc_ecc_init(&userB);
ret = wc_ecc_make_key(&rng, 32, &userA);
ret += wc_ecc_make_key(&rng, 32, &userB);
if (ret != 0)
return -3002;
for (i = 0; i < 48; i++)
msg[i] = i;
/* encrypt msg to send to userB */
ret = wc_ecc_encrypt(&userA, &userB, msg, sizeof(msg), out, &outSz, NULL);
if (ret != 0)
return -3003;
/* userB decrypt the message received from userA */
ret = wc_ecc_decrypt(&userB, &userA, out, outSz, plain, &plainSz, NULL);
if (ret != 0)
return -3004;
if (XMEMCMP(plain, msg, sizeof(msg)) != 0)
return -3005;
{ /* let's verify message exchange works, A is client, B is server */
ecEncCtx* cliCtx = wc_ecc_ctx_new(REQ_RESP_CLIENT, &rng);
ecEncCtx* srvCtx = wc_ecc_ctx_new(REQ_RESP_SERVER, &rng);
byte cliSalt[EXCHANGE_SALT_SZ];
byte srvSalt[EXCHANGE_SALT_SZ];
const byte* tmpSalt;
if (cliCtx == NULL || srvCtx == NULL)
return -3006;
/* get salt to send to peer */
tmpSalt = wc_ecc_ctx_get_own_salt(cliCtx);
if (tmpSalt == NULL)
return -3007;
XMEMCPY(cliSalt, tmpSalt, EXCHANGE_SALT_SZ);
tmpSalt = wc_ecc_ctx_get_own_salt(srvCtx);
if (tmpSalt == NULL)
return -3007;
XMEMCPY(srvSalt, tmpSalt, EXCHANGE_SALT_SZ);
/* in actual use, we'd get the peer's salt over the transport */
ret = wc_ecc_ctx_set_peer_salt(cliCtx, srvSalt);
ret += wc_ecc_ctx_set_peer_salt(srvCtx, cliSalt);
ret += wc_ecc_ctx_set_info(cliCtx, (byte*)"wolfSSL MSGE", 11);
ret += wc_ecc_ctx_set_info(srvCtx, (byte*)"wolfSSL MSGE", 11);
if (ret != 0)
return -3008;
/* get encrypted msg (request) to send to B */
outSz = sizeof(out);
ret = wc_ecc_encrypt(&userA, &userB, msg, sizeof(msg), out, &outSz,cliCtx);
if (ret != 0)
return -3009;
/* B decrypts msg (request) from A */
plainSz = sizeof(plain);
ret = wc_ecc_decrypt(&userB, &userA, out, outSz, plain, &plainSz, srvCtx);
if (ret != 0)
return -3010;
if (XMEMCMP(plain, msg, sizeof(msg)) != 0)
return -3011;
{
/* msg2 (response) from B to A */
byte msg2[48];
byte plain2[48];
byte out2[80];
word32 outSz2 = sizeof(out2);
word32 plainSz2 = sizeof(plain2);
for (i = 0; i < 48; i++)
msg2[i] = i+48;
/* get encrypted msg (response) to send to B */
ret = wc_ecc_encrypt(&userB, &userA, msg2, sizeof(msg2), out2,
&outSz2, srvCtx);
if (ret != 0)
return -3012;
/* A decrypts msg (response) from B */
ret = wc_ecc_decrypt(&userA, &userB, out2, outSz2, plain2, &plainSz2,
cliCtx);
if (ret != 0)
return -3013;
if (XMEMCMP(plain2, msg2, sizeof(msg2)) != 0)
return -3014;
}
/* cleanup */
wc_ecc_ctx_free(srvCtx);
wc_ecc_ctx_free(cliCtx);
}
/* cleanup */
wc_ecc_free(&userB);
wc_ecc_free(&userA);
wc_FreeRng(&rng);
return 0;
}
#endif /* HAVE_ECC_ENCRYPT */
I want to use an ECC private key for encryption because of mutual authentication. But I cannot find a method (or function) in wolfcrypt (wolfSSL) or the micro-ecc library.
There's a subtle difference in the definitions and operations. "Encrypting with the private key" is not a valid cryptographic operation. Usually what you want is a Signature Scheme with Recovery.
When libraries like OpenSSL or wolfSSL sign a message, they often apply a formatting function and then treat the resulting message as an instance of ciphertext. Then, the private key is used to decrypt the ciphertext.
Is is okay to use an (ECC) private key for encryption?
Probably not, but we need to hear more about what you want to do.
If you want help with designing the scheme, then you should probably visit Cryptography Stack Exchange or Information Security Stack Exchange.
[If its OK] And if so, how can I do this?
Again, it depends on what you are doing. At some point, you will need to treat a formatted message as an instance of ciphertext. I can't say anymore because I am not familiar with wolfSSL.
You might also be interested in Should we sign-then-encrypt, or encrypt-then-sign? on the Crypto.SE. It appears to have some intersection with what you are doing.
I was doing some experiments with cryptography. Now I have the public key of receiver and i want to encrypt some data and pass to the receiver.
I want to use RSAES-OAEP algorithm. with SHA-256 as hash function and MGF1 as mask generation function.
I want do this using openssl. I found a function RSA_public_encrypt() with this function we can specify the padding. One of the padding option available was
RSA_PKCS1_OAEP_PADDING
EME-OAEP as defined in PKCS #1 v2.0 with SHA-1 , MGF1 .
they are using sha-1.
I want to reconfigure the function to use SHA256 as hash function ans MGF1 as hash function. How can I do it ?
The following excerpt allows using OAEP with SHA256 for both the MGF and hash function. Tested with OpenSSL 1.0.2L
int flags = CMS_BINARY | CMS_PARTIAL | CMS_KEY_PARAM;
cms = CMS_encrypt(NULL, in, cipher, flags)
ri = CMS_add1_recipient_cert(cms, cert, flags);
pctx = CMS_RecipientInfo_get0_pkey_ctx(ri);
EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_OAEP_PADDING);
EVP_PKEY_CTX_set_rsa_oaep_md(pctx, EVP_sha256());
EVP_PKEY_CTX_set_rsa_mgf1_md(pctx, EVP_sha256());
With a newer OpenSSL 1.0.2+ you can do it using the command:
openssl pkeyutl -in PlaintextKeyMaterial.bin -out EncryptedKeyMaterial.bin -inkey PublicKey.bin -keyform DER -pubin -encrypt -pkeyopt rsa_padding_mode:oaep
-pkeyopt rsa_oaep_md:sha256
This is taken from AWS KMS doc here: https://aws.amazon.com/es/premiumsupport/knowledge-center/invalidciphertext-kms/
OpenSSL uses definitions from PKCS #1 v2.0 and so the default for EME-OAEP is SHA-1 and MGF1. If you need to use SHA-256, you'll need to do the encoding yourself. This isn't terribly difficult however, see PKCS #1 v2.2 PDF Page 18 for details.
In the latest version of Openssl(1.0.2k) the signature of the API is changed which gives us more flexibility. Please find the details below,
int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
const unsigned char *from, int flen,
int num, const unsigned char *param,
int plen, const EVP_MD *md,
const EVP_MD *mgf1md)
You can pass the EVP_MD structure to invoke the SHA-256 hashing using this.
The PKCS#1 doc referred to above is more mathematical and doesn't give coding examples, and the CMS answer is for ASN.1/SMIME data and not really relevant for the question asked, which was how to replace RSA_public_encrypt() which deals with simple binary/text data. I spent a whole day with trial and error and online searching to find the answer to this, and eventually got the answer (which was to use OpenSSL's EVP API) from looking at the source code of "openssl pkeyutl" - once I discovered that it was not difficult.
In my case I was looking to replace RSA_private_decrypt() for decryption using the private key and this is how to do that - it should be pretty easy to put to together an RSA_public_encrypt() replacement based on this:
EVP_PKEY *privKey = NULL;
BIO *bioPrivKey;
int outLen = 0, ret;
if ((bioPrivKey = BIO_new(BIO_s_mem())))
{
// Read the private key from the RSA context into the memory BIO,
// then convert it to an EVP_PKEY:
if ((ret = PEM_write_bio_RSAPrivateKey(bioPrivKey, rsaCtxt, NULL, NULL, 0, NULL, NULL)) &&
(privKey = PEM_read_bio_PrivateKey(bioPrivKey, NULL, NULL, NULL)))
{
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(privKey, NULL);
EVP_PKEY_free(privKey);
if (ctx)
{
if (EVP_PKEY_decrypt_init(ctx) > 0)
{
EVP_PKEY_CTX_ctrl_str(ctx, "rsa_padding_mode", "oaep");
EVP_PKEY_CTX_ctrl_str(ctx, "rsa_oaep_md", "sha256");
EVP_PKEY_CTX_ctrl_str(ctx, "rsa_mgf1_md", "sha256");
outLen = dataOutMax;
ret = EVP_PKEY_decrypt(ctx, dataOut, &outLen, dataIn, inDataLen);
if (ret > 0 && outLen > 0 && outLen <= dataOutMax)
{
// Success :-)
}
}
EVP_PKEY_CTX_free(ctx);
}
}
BIO_free_all(bioPrivKey);
}
You can add error handling for the failure cases using ERR_get_error().
I am trying to read in an AES-128-CBC encrypted PEM key file generated using Ruby with the OpenSSL API. The code that generated the PEM key is the following:
OpenSSL::PKey::RSA.new(2048).to_pem(OpenSSL::Cipher::AES.new('128-CBC'), "password")
Here's the code that reads the PEM file:
RSA *rsa;
BIO *pem = BIO_new(BIO_s_mem());
BIO_puts(pem, "-----BEGIN RSA PRIVATE KEY-----\n"
"Proc-Type: 4,ENCRYPTED\n"
"DEK-Info: AES-128-CBC,BB13D39833DD6ED1FF9843644E7981EE\n\n
"Eugt8JZNKQKErsabWkwfm3wQhU/Tmp9T0QaP5HM8VIWpZwKlDmRlSUDptADU6RPD\n"
"5VtG3DPieXcf+6deyARImid9sBBmQ9mK2omkNRcTMemqTOhAuaKBu78TMt9G4YSf\n"
"RjoXWSqu3jMwrlcGkpn7bIum8wImITRZ3p28oSzk9aDUNBrIU/2Si8DM4RYIZ/fK\n"
"Uvvgdok9dgcd0SjvucivX2HaGeg/IUz23q1jg9inDpimZvFJD1FJfGEUWDgyfJfa\n"
"M8JIxTKbWOPEopONDkT7u4dC5VcSjK29MVbfd7iCKFPMh5UN+c96rPxTng/OWyW5\n"
"0tvzHyyyvAG9p0Hx5Lr4pDbv21GHyu43sA6wbs9jWyqO3AB7CaoEEQhumwfLsdjj\n"
"YGrX6bWThpYv/XNBDmmvltHlKFfe01NCybivOb4KwBnvi45x21PBqaZCKDTFdEkL\n"
"iwDMTiG2iTxSUvPFLy30VFozE+pGyMcGDUyZDVqjsaqI/MRj8khnn5nyubXc27G3\n"
"8Kbsnlix2SW2M0VDxqiy9dyjcxXrkFRSnOFYVs1PFlgjFVTG4Mwh6CZxKw8mFVbi\n"
"EmLvUYwzoDZ1ve4VXSPp/vrKEh33JuHhM0vJOpqI6wqw0QR0I2o6etM1ZRJClPcw\n"
"VIcgcvwenEgLOkoHDqOr0IZQAtYWvAuqq822wKt258hc6z8+ALQf5iMroqk7ADd4\n"
"FlRLz4XTwqlg7pPtTde/emI1DT8dQWzq++QI0lr0CS/N1GXJKqTQDvauXLIiI3Qy\n"
"KfFYFpV9jyYfRfTjNtisI/edPtp98auK0mb9o/wS/hruFI9behgv63iW1IwAOXCW\n"
"ZlkWgobUH13gS864rL+AcrAXreo2j4dDQouTeRaJUEG0HoYTP65Zun/VsCi2aSOH\n"
"JwSnnmHz9OxvcGY80WJDN3kqOCBRIJoDKBv6jcOxGVCsVK+WSdGZ7cfb8lwp7aA8\n"
"8ND1bwL9FYkwkeIsoakj91iinqv4o3+3PUPgCU5oe68WYvAFjuU+criyf+EhmXJV\n"
"JQ1vFFZPrGzgntJz19uXXh1h2iwQPggRouJm2RozYwvv1nz4eQ40Y3eT1F9UOYJU\n"
"CKEhOtI2NpLeVOayqo8g9wO2oC+CQVhZhdYBE5o7pM7akFnYLvRg9s1UsWdcvT0G\n"
"IpFmejLSRJ/F954aQMHTUc6vBOJZH/VNC5Qt+ulFXl634Sr9wQQK2qlqSJyA04TR\n"
"1ixbCNOX71esvpFImsrlsO5oTA22T3h2GyJPUM10XhqGtDXtsTnal6smLna9U9B3\n"
"gTVxFWWukQOF5Lm8ZFQipo2loHWjkozTBc4REPYP44SoXJXstv7k4pt1cK7x6/2H\n"
"ElspXzjveqMhcrveWv1KaA2OGd+hGfUiNsCoIdapJjLz1Bd/+oIQ/ZWQeo0nRowE\n"
"R/HlbbED3V+fRIdJpgydFEAw6gK5E9sYJcgF7uf/n2NabFxxEZL3g6MJQ64Dtusg\n"
"DEH/MpvIYDSX4Navh1gTwCtOeG1CzW3diYaqbZK+UZCBLFU7j27YvVPSd6F2+Wud\n"
"WnAqU3S5BCPqk5OD3wqZv+sEcqJgGPGy1Gv0tl8ARJomdKAru03KsRn2eIWqR5/C\n"
"-----END RSA PRIVATE KEY-----\n");
// Retrieve RSA key from PEM file.
rsa = PEM_read_bio_RSAPrivateKey(pem, NULL, pem_password_callback, "password");
And here's a dummy password callback (not sure about this function's purpose, but I think it may return the length of the password):
int pem_password_callback(char *buf, int max_len, int flag, void *pwd)
{
return 8;
}
Currently, the rsa = ... part does not throw an error, but doesn't return a well-formed result either.
And here's a dummy password callback (not sure about this function's
purpose, but I think it may return the length of the password):
int pem_password_callback(char *buf, int max_len, int flag, void *pwd)
{
return 8;
}
No, its not a dummy. In your example, you just returned a buffer with 8 junk characters (whatever happened to be in buf).
The password callback is where you programmatically plug in your password. You are supplied with a buff of max_len, and you need to copy the password into the buffer and return the number of bytes copied.
int pem_password_callback(char *buf, int max_len, int flag, void *ctx)
{
const char* PASSWD = "password";
int len = strlen(PASSWD);
if(len > max_len)
return 0;
memcpy(buf, PASSWD, len);
return len;
}
The flag is a read/write flag to denote if you are reading a key or writing a key. In practice, I have never used it.
You will use it similar to:
FILE* file = ...;
EVP_PKEY* pkey = PEM_read_PrivateKey(file, NULL, pem_password_callback, NULL);
Unlike the write routine (which needs an EVP_* cipher), the read routine knows what you used to encrypt the key with because its encoded in the private key.
In my systems, I actually use the context for a label to ensure the same passwords arrive at different derived keys:
EVP_PKEY* pkey = PEM_read_PrivateKey(file, NULL, pem_password_callback, "Some Context");
Then, in my password callback:
int pem_password_callback(char *buf, int max_len, int flag, void *ctx)
{
// "Some Context" in the example above
char* label = (char*)ctx;
// Hash password and label
// ...
// Copy hash to buffer, return length
...
}