I have the following (very simplified) code, which uses OpenSSL to generate an encrypted private key, using a string containing a null as a passphrase:
#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
int main(int argc, char *argv[]) {
char password[32] = "pass\000word";
extern FILE *stdout;
EVP_PKEY *key = NULL;
RSA *rsa;
SSL_library_init();
OpenSSL_add_all_algorithms();
rsa = RSA_generate_key(2048, RSA_F4, NULL, NULL);
key = EVP_PKEY_new();
EVP_PKEY_assign(key, EVP_PKEY_RSA, rsa);
/* Write the private key to the file */
PEM_write_PrivateKey(stdout, key, EVP_des_ede3_cbc(), (unsigned char*)password, 32, NULL, NULL);
return 0;
}
The encrypted private key is created as expected, but I am unable to decrypt it, neither programmatically, using PEM_read_PrivateKey(3ssl), nor from the command line, using openssl pkcs8 -in key.pam -passin file:key.pass.
$ od -ta key.pass
0000000 p a s s nul w o r d nul nul nul nul nul nul nul
0000020 nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul
0000040
From what I can see, PEM_read_PrivateKey only accepts a null-terminated passphrase, unlike PEM_write_PrivateKey.
How is it possible to decrypt the generated key?
Use the caller-provided callback to perform your password-provision. The following is utter brute force, hideous, has no error checking, and in no way is exemplary of my coding habits, but demonstrates what i'm referring to:
#include <stdio.h>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
int password_cb (char *buf, int size, int rwflag, void *userdata)
{
memcpy(buf, userdata, 32);
return 32;
}
int main(int argc, char *argv[])
{
char password[32] = "pass\0word";
EVP_PKEY *key = NULL;
RSA *rsa;
OpenSSL_add_all_algorithms();
rsa = RSA_generate_key(2048, RSA_F4, NULL, NULL);
key = EVP_PKEY_new();
EVP_PKEY_assign(key, EVP_PKEY_RSA, rsa);
/* Write the private key to the file */
FILE *fp = fopen("somekey.pem", "w");
PEM_write_PrivateKey(fp, key, EVP_aes_128_cbc(), (unsigned char*)password, sizeof(password), NULL, NULL);
fclose(fp);
EVP_PKEY* rdkey = NULL;
fp = fopen("somekey.pem", "r");
PEM_read_PrivateKey(fp, &rdkey, password_cb, password);
fclose(fp);
PEM_write_PrivateKey(stdout, key, NULL, NULL, 0, NULL, NULL);
PEM_write_PrivateKey(stdout, rdkey, NULL, NULL, 0, NULL, NULL);
return 0;
}
it should dump the encrypted key to somekey.pem, read the encrypted key from somekey.pem using the same passphrase, and finally dump both keys to stdout. The two cleartext stdout keys had better be the same... And they are:
Sample Output
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAoHDPXfbdKEZDmLsxPNlWY3gBGzG69p0vTrhRZEzO09p5kZ35
T1y9cZAig+lEgY7U/trDWh0d1ABSfsLwT/dv2AAeBE2+avYE+v1jyr6N3FzFXS2O
jKOTkUy+Xw54aAlYHh4S8/K41rrxjcL7cjORWojl+4ZTfGLqCZE8Ga6c41MxBM9v
8ky9Kh2Tnf1zMnGk3Xd69jKnfsZyz7pzeNAZ8g0lezDt8r8b472fXTW2rnwezhTR
YsAbBjoP+P2JhNIQEHXXoTLqflQMfX34TTQLzg5OYOpNNezSqEFh9lFRvnE5B6h+
ov7qF+KyWT17dZMrywd2M6ixVFi3u6JbR/E/9QIDAQABAoIBAGhsZBtVVGYlLVPX
6lkfX+HHtnibqoNelO7YemkcsLUkimFjf2PPCaJDXKOcjLECZNEnU2RwdPyJ5SeJ
+10gwBPHJ8JHU3tMertddrj7w1s8qlxWDWSuBprYZ0N5KJcWFdssWcubHADulc9d
q8iNlbpmRcGqkOXxf0AQ3hwdERHHCLgJzB9Djlurwine1Xs33ZQkr0DecHRS5Unr
IbH9YLKQvGzdohrQfDTSntf/79wxdKRjdiAvPv5AQMz4lrEKYKLp+4B0j3kRq3LN
mokNdCcuhVJKuuN8s4C8EaBYByfWJbzVG2ZqHyoF0Zy1eFkTrXKoaExdv1q37Q3r
hVtD8CECgYEA0YD7sLkrt9WhTIMc0oUdeLLcpI6vvbmJtdkM1bUm/hpacG4VvpJs
Y/Txw4qHydCcbFIh4EyhuEcvnHrbFReyqWB25hLDnsOT/js76xbdJFVN+g7B+pCb
DfDv7LMKf8iJjVO+W5gnxxCrTrW9YbLs11vZUYcMnzySnsHYHtD7/C0CgYEAxAxK
EwkkTMvT0AvyBK6d+EzZPwcSpokWMqs8K2iGdQiGWuvCvrwaSPFOWS54RXx0Cm7j
iE5Nx5U1OXrA2iTwxTMXjcbHHL0mZ5KJIIP+qSu7839hK1b4bx45k0rjiDH5O+we
8y6gAh7Ni+T+7U2LqVBBMVbNzUycTztDshwxh+kCgYEAmCKpIykkhSe+LRidCocd
4rNIJLt1BTpBtWs7tckJ2sZ6XGCkq7Iawe9yzQPBHZ2+qa5u6TncyjvvaBuTElsW
I4docCS6J4Vw59JN7aa5yhOkP20OEg2Ge3Y2VFWjzy1qLdXdSxhP8m+5Zrv1HYhY
Ev+g7WI7mTrcYirz7VTnV7UCgYEAqXRR5qhFNxgLSk248HEaXA/Yy9DKPyZJCJzX
0lFzvt8Seq5D02d1dM0WwqEXFkCfcJEunJfKRRPkQH2pCiVZ86nY1xQU8PNRqb6Q
Romw6frCZ5MXo0V2UV2XuIfHqeZAHppWmi4X4h1L33qdGvKnID8dSo9ULfrlNNru
BZq2+VkCgYBV9wCdkG9CeqpJ2ZrEE4S7ZKUzbQY2nRpLTVp4fS07iE19XGoe+mZH
xFdR7t6mCqddY1SJ5qbKta0I4ibUw5LpaG0odVduqbJmIJskSyocVfQPd7qfoIch
Fku3d1WZiU4DNudSglSf2PIzw6S7Lp1Lp6n5wDzdxF3uJFYv1twlVQ==
-----END RSA PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAoHDPXfbdKEZDmLsxPNlWY3gBGzG69p0vTrhRZEzO09p5kZ35
T1y9cZAig+lEgY7U/trDWh0d1ABSfsLwT/dv2AAeBE2+avYE+v1jyr6N3FzFXS2O
jKOTkUy+Xw54aAlYHh4S8/K41rrxjcL7cjORWojl+4ZTfGLqCZE8Ga6c41MxBM9v
8ky9Kh2Tnf1zMnGk3Xd69jKnfsZyz7pzeNAZ8g0lezDt8r8b472fXTW2rnwezhTR
YsAbBjoP+P2JhNIQEHXXoTLqflQMfX34TTQLzg5OYOpNNezSqEFh9lFRvnE5B6h+
ov7qF+KyWT17dZMrywd2M6ixVFi3u6JbR/E/9QIDAQABAoIBAGhsZBtVVGYlLVPX
6lkfX+HHtnibqoNelO7YemkcsLUkimFjf2PPCaJDXKOcjLECZNEnU2RwdPyJ5SeJ
+10gwBPHJ8JHU3tMertddrj7w1s8qlxWDWSuBprYZ0N5KJcWFdssWcubHADulc9d
q8iNlbpmRcGqkOXxf0AQ3hwdERHHCLgJzB9Djlurwine1Xs33ZQkr0DecHRS5Unr
IbH9YLKQvGzdohrQfDTSntf/79wxdKRjdiAvPv5AQMz4lrEKYKLp+4B0j3kRq3LN
mokNdCcuhVJKuuN8s4C8EaBYByfWJbzVG2ZqHyoF0Zy1eFkTrXKoaExdv1q37Q3r
hVtD8CECgYEA0YD7sLkrt9WhTIMc0oUdeLLcpI6vvbmJtdkM1bUm/hpacG4VvpJs
Y/Txw4qHydCcbFIh4EyhuEcvnHrbFReyqWB25hLDnsOT/js76xbdJFVN+g7B+pCb
DfDv7LMKf8iJjVO+W5gnxxCrTrW9YbLs11vZUYcMnzySnsHYHtD7/C0CgYEAxAxK
EwkkTMvT0AvyBK6d+EzZPwcSpokWMqs8K2iGdQiGWuvCvrwaSPFOWS54RXx0Cm7j
iE5Nx5U1OXrA2iTwxTMXjcbHHL0mZ5KJIIP+qSu7839hK1b4bx45k0rjiDH5O+we
8y6gAh7Ni+T+7U2LqVBBMVbNzUycTztDshwxh+kCgYEAmCKpIykkhSe+LRidCocd
4rNIJLt1BTpBtWs7tckJ2sZ6XGCkq7Iawe9yzQPBHZ2+qa5u6TncyjvvaBuTElsW
I4docCS6J4Vw59JN7aa5yhOkP20OEg2Ge3Y2VFWjzy1qLdXdSxhP8m+5Zrv1HYhY
Ev+g7WI7mTrcYirz7VTnV7UCgYEAqXRR5qhFNxgLSk248HEaXA/Yy9DKPyZJCJzX
0lFzvt8Seq5D02d1dM0WwqEXFkCfcJEunJfKRRPkQH2pCiVZ86nY1xQU8PNRqb6Q
Romw6frCZ5MXo0V2UV2XuIfHqeZAHppWmi4X4h1L33qdGvKnID8dSo9ULfrlNNru
BZq2+VkCgYBV9wCdkG9CeqpJ2ZrEE4S7ZKUzbQY2nRpLTVp4fS07iE19XGoe+mZH
xFdR7t6mCqddY1SJ5qbKta0I4ibUw5LpaG0odVduqbJmIJskSyocVfQPd7qfoIch
Fku3d1WZiU4DNudSglSf2PIzw6S7Lp1Lp6n5wDzdxF3uJFYv1twlVQ==
-----END RSA PRIVATE KEY-----
Hope that's what you were looking for.
Related
I am trying to load a rsa object from a generated public key. I used PEM_write_bio_RSAPublicKey to generate the public key string. Then I used PEM_read_bio_RSA_PUBKEY to load the rsa object from the public key string. The problem is the rsa object is null. The generated string looks okay as far as I can tell. Any ideas?
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAxIReUspesPy6a4CPBjt/4Jt+H13q9MekMiutzNKdNO1uuwqcdqDX
pKPeTKXyUH6oCyRdUxkk6IVXGlBlxtW7OsxaYWhpfl9z3CCERCEpFmzN++dvlK2v
mckFL66e9q6Y+HwgyP1LJqrszeqlg2d29TCVKfD/UURVNmc/nPPjs9nO+IDhh7+P
NTQ2OqGBq8ghwVL5ZZyW3yVO5OAbRB6pjKBe9+j4B2TGnD5JO9Nu0jlFANZOKFJu
HDVE3XuTvOkuzL2i8Lwp4Myk42tbIgcCe4G58vKFddL651rWhg4hN3fRSx5YtDnQ
r5cgfNBOAww58S8lwXgU8lvzvEoNV+WMgwIDAQAB
-----END RSA PUBLIC KEY-----
gcc test_public_private_key.c -lcrypto -o test
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
char* get_public_key() {
RSA* rsa = RSA_new();
int kbits = 2048;
BIGNUM* bne = BN_new();
BN_set_word(bne, RSA_F4);
int status = RSA_generate_key_ex(rsa, kbits, bne, NULL);
if(status == 0) {
fprintf(stderr, "rsa key generation failed\n");
}
BIO *bio = BIO_new(BIO_s_mem());
PEM_write_bio_RSAPublicKey(bio, rsa);
int length = BIO_pending(bio);
char* pem_key = malloc(length+1);
memset(pem_key, '\0', length+1);
BIO_read(bio, pem_key, length);
return pem_key;
}
int main(int argc, char* argv[]) {
char* public_key = get_public_key();
printf("%s", public_key);
BIO* keybio = BIO_new_mem_buf(public_key, -1);
if (keybio == NULL) {
fprintf(stderr, "failed to create key BIO");
}
printf("keybio: %p\n", keybio);
RSA* rsa = PEM_read_bio_RSA_PUBKEY(keybio, NULL, NULL, NULL);
printf("rsa result %p\n", rsa);
BIO_free(keybio);
free(public_key);
return 0;
}
I thought it would be good to add that the reason this didn't work is because PEM_read_RSA_PUBKEY expects a SubjectPublicKeyInfo structure, which starts with BEGIN PUBLIC KEY, while PEM_read_RSAPublicKey expects a RSAPublicKey structure, which starts with BEGIN RSA PUBLIC KEY.
PEM_write_bio_RSAPublicKey generated the latter which corresponds to the second function, PEM_read_RSAPublicKey.
Given the following openssl example prog
#include <openssl/evp.h>
int do_crypt(FILE* in, FILE* out, int do_encrypt)
{
/* Allow enough space in output buffer for additional block */
unsigned char inbuf[1024], outbuf[1024 + EVP_MAX_BLOCK_LENGTH];
int inlen, outlen;
EVP_CIPHER_CTX* ctx;
/* Bogus key and IV: we'd normally set these from
* another source.
*/
unsigned char key[] = "0123456789abcdeF";
unsigned char iv[] = "1234567887654321";
/* Don't set key or IV right away; we want to check lengths */
ctx = EVP_CIPHER_CTX_new();
EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, NULL, NULL, do_encrypt);
OPENSSL_assert(EVP_CIPHER_CTX_key_length(ctx) == 16);
OPENSSL_assert(EVP_CIPHER_CTX_iv_length(ctx) == 16);
/* Now we can set key and IV */
EVP_CipherInit_ex(ctx, NULL, NULL, key, iv, do_encrypt);
for (;;) {
inlen = fread(inbuf, 1, 1024, in);
if (inlen <= 0)
break;
if (!EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen)) {
/* Error */
EVP_CIPHER_CTX_free(ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
}
if (!EVP_CipherFinal_ex(ctx, outbuf, &outlen)) {
/* Error */
EVP_CIPHER_CTX_free(ctx);
return 0;
}
fwrite(outbuf, 1, outlen, out);
EVP_CIPHER_CTX_free(ctx);
return 1;
}
int main(int argc, char* argv[])
{
FILE *fpIn;
FILE *fpOut;
fpIn = fopen("text-in.txt", "rb");
fpOut = fopen("text-out.txt", "wb");
int test = do_crypt(fpIn, fpOut, 1);
fclose(fpIn);
fclose(fpOut);
return 0;
}
I would expect that
openssl aes-128-cbc -in text-in.txt -K 0123456789abcdeF -iv 1234567887654321
would create the same output. But it doesn't. The C prog can decrypt the files it encrypted. But it can't decrypt the files encrypted with openssl.
The encryption key and IV are not actually text but binary data.
When you do the encryption on the command line, the -K and -iv arguments expect their input in hex.
So the key you're passing in is actually:
\x01\x23\x45\x67\x89\xab\xcd\xef\x00\x00\x00\x00\x00\x00\x00\x00
And the IV is:
\x12\x34\x56\x78\x87\x65\x43\x21\x00\x00\x00\x00\x00\x00\x00\x00
Both have tail padding of 0's because the key that was specified was too short.
In order to match the program's output, you need to pass in the hex codes of the characters you specified. For example, 1 is 30, 2 is 31, a is 61, F is 46, and so forth:
openssl aes-128-cbc -in text-in.txt -K 30313233343536373839616263646546 -iv 31323334353637383837363534333231
When I run the following code, which generates a key, writes it to a string, prints it, reads it into the key, and prints it again, against OpenSSL_1_0_2e:
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/aes.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#define RSA_KEYLEN 2048
int main()
{
// Key generation
EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
EVP_PKEY* key = NULL;
EVP_PKEY_keygen_init(ctx);
EVP_PKEY_CTX_set_rsa_keygen_bits(ctx, RSA_KEYLEN);
EVP_PKEY_keygen(ctx, &key);
EVP_PKEY_CTX_free(ctx);
// Serialize to string
unsigned char* keyStr;
BIO *bio = BIO_new(BIO_s_mem());
PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, 0, NULL);
int priKeyLen = BIO_pending(bio);
keyStr = (unsigned char*)malloc(priKeyLen + 1);
BIO_read(bio, keyStr, priKeyLen);
keyStr[priKeyLen] = '\0';
BIO_free_all(bio);
// Print the string
printf("%s", keyStr);
// Reset the key
EVP_PKEY_free(key);
key = NULL;
// Read from string
bio = BIO_new(BIO_s_mem());
BIO_write(bio, keyStr, priKeyLen);
PEM_read_bio_PrivateKey(bio, &key, NULL, NULL);
BIO_free_all(bio);
// Free the string
free(keyStr);
// Serialize to string (again)
bio = BIO_new(BIO_s_mem());
PEM_write_bio_PrivateKey(bio, key, NULL, NULL, 0, 0, NULL);
priKeyLen = BIO_pending(bio);
keyStr = (unsigned char*)malloc(priKeyLen + 1);
BIO_read(bio, keyStr, priKeyLen);
keyStr[priKeyLen] = '\0';
BIO_free_all(bio);
// Print string
printf("%s", keyStr);
}
The private key is obviously way too short in the second output. What am I doing wrong?
The solution to my particular problem was I was trying to set the Public and Private key on the EVP_PKEY thinking that I needed to load both to use it as a keypair. Actually, you only load one of the two. With the private key, the public key is derived.
I received an RSA-2048 bit public key (256 bytes) as a file which contains just those 256 bytes. Which function in SSL enables me to load this key as an RSA structure so I can convert it to another format? This is in C code using openssl source.
I think it's the DER format, but I'm not 100% certain.
I just put this together and it seems to work correctly:
https://github.com/JonathonReinhart/rawrsa
#include <stdio.h>
#include <stdlib.h>
#include <libgen.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
static const char* appname;
static void print_bn(const char *what, const BIGNUM *bn)
{
#ifdef DEBUG
char *str = BN_bn2hex(bn);
printf("%s (hex): %s\n", what, str);
OPENSSL_free(str);
#endif
}
static void usage(void)
{
fprintf(stderr, "Usage: %s modulus-file exponent\n", appname);
}
#define err(fmt, ...) \
fprintf(stderr, "%s: " fmt, appname, ##__VA_ARGS__)
int main(int argc, char *argv[])
{
appname = basename(argv[0]);
if (argc < 3) {
usage();
exit(1);
}
const char *modfile = argv[1];
const char *expstr = argv[2];
/* Read modulus */
FILE *mf = fopen(modfile, "rb");
if (!mf) {
err("Failed to open \"%s\": %m\n", modfile);
return 1;
}
unsigned char buf[256];
if (fread(buf, sizeof(buf), 1, mf) != 1) {
err("Failed to read %zu bytes of modulus\n", sizeof(buf));
return 1;
}
fclose(mf);
BIGNUM *mod = BN_bin2bn(buf, sizeof(buf), NULL);
if (!mod) {
err("BN_bin2bn() failed\n");
return 1;
}
print_bn("Modulus", mod);
/* Parse exponent */
BIGNUM *exp = NULL;
if (BN_dec2bn(&exp, expstr) == 0) {
err("BN_dec2bn() failed\n");
return 1;
}
print_bn("Exponent", exp);
/* Create RSA key */
RSA *rsa = RSA_new();
if (!rsa) {
err("RSA_new() failed\n");
return 1;
}
rsa->e = exp;
rsa->n = mod;
/* Write PEM-encoded RSA public key to stdout */
if (!PEM_write_RSAPublicKey(stdout, rsa)) {
err("PEM_write_RSAPublicKey() failed\n");
return 1;
}
return 0;
}
I use BN_bin2bn to create an OpenSSL bignum from raw binary data from a file. This is where we load your 256-byte modulus.
Then, I use BN_dec2bn to create a bignum from the exponent provided on the command line.
Next, I create an RSA object with RSA_new, and set the public exponent (rsa->e) and modulus (rsa->n).
Finally, I write the RSA public key to a PEM file with PEM_write_RSAPublicKey.
Example:
$ scons -Q
gcc -o main.o -c -Wall -Werror -g main.c
gcc -o rawrsa main.o -lcrypto
$ ./rawrsa key.bin 65537
-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA9cFHSTQ6h1Ls/vx7B+V/84XVlLxUU1dU1mEr9ROAqWrZtfasvx2E
21lbva+AdJ/B4u6fGVhCEMgekXsRB65CqZfwL3DFL6tqam6GvrOyvZgAlQKrA54w
DaKMT8Kfg2I2K9W/HCkCOHczhuHhjFmeiV9BuQgpmcPcNz6UXBwU05d3g6oM/X4m
lEhEsaH4bqo1qsMX6jp6WnsR13GEfsYoYVmHgEbnKJyGpsoRVW6HQXLHvef9XLEJ
v9n7nLdHToya75svxJ3v9JugD3n6PiC48085/FWb9980o4hmG9iW5rehm4Dlui8c
TDnHkQSrvi9WLlZ+S8hdtwDRN/pVVTjgPAIDAQAB
-----END RSA PUBLIC KEY-----
I wrote a code to sign a message that apparently works fine, it can sign a message with a DSA private key (512 bits), and verify it later with the respective public key (no problems here). I´m using Windows 7.
But,
If I want to verify the sign in the console, openssl command always returns: Verification Failure.
#include <stdio.h>
#include <string.h>
#include <openssl\dsa.h>
#include <openssl\engine.h>
#include <openssl\pem.h>
int main(){
char privkey[] = {
"-----BEGIN DSA PRIVATE KEY-----\n"
"MIH4AgEAAkEA3F41fxvcwGZeFxXg2v0/5SR+cxTizT25QugwZgrC7u2zQYTO1Qu0\n"
"PPDKUrLxkaLzKsUEJbQ1DImnG/FxtRjH7QIVAOp+o1qPhOI4DtnvYS86ynTxhDcF\n"
"AkAyKbiUxJigARuuVVlGn4emXOtrT+Al+gmKbbVFfkS62RhSZexQ9+mBLv0/1R8T\n"
"k37AwuybnflijiPjLxB1ZL00AkA2DXjw+0PJOyrQfn2Q44uHyZMG2WfXqT7CIz26\n"
"ZiIAHDOkZQhOvPLqCKAXfwHgGrgl2JLovhVY8nPMdNk2vJijAhUAzK9TuVobhOE8\n"
"kU0xl8lqaI/PMyg=\n"
"-----END DSA PRIVATE KEY-----"
};
char pubkey[] = {
"-----BEGIN PUBLIC KEY-----\n"
"MIHwMIGoBgcqhkjOOAQBMIGcAkEA3F41fxvcwGZeFxXg2v0/5SR+cxTizT25Qugw\n"
"ZgrC7u2zQYTO1Qu0PPDKUrLxkaLzKsUEJbQ1DImnG/FxtRjH7QIVAOp+o1qPhOI4\n"
"DtnvYS86ynTxhDcFAkAyKbiUxJigARuuVVlGn4emXOtrT+Al+gmKbbVFfkS62RhS\n"
"ZexQ9+mBLv0/1R8Tk37AwuybnflijiPjLxB1ZL00A0MAAkA2DXjw+0PJOyrQfn2Q\n"
"44uHyZMG2WfXqT7CIz26ZiIAHDOkZQhOvPLqCKAXfwHgGrgl2JLovhVY8nPMdNk2\n"
"vJij\n"
"-----END PUBLIC KEY-----"
};
char message[] = {"Hello World!"};
//save message for console test
FILE *message_file = fopen ("message.txt","w");
fwrite(message, strlen(message), 1, message_file);
fclose(message_file);
//save private key for console test
FILE *privkey_file = fopen ("privkey.pem","w");
fwrite(privkey, strlen(privkey), 1, privkey_file);
fclose(privkey_file);
//save public key for console test
FILE *pubkey_file = fopen ("pubkey.pem","w");
fwrite(pubkey, strlen(pubkey), 1, pubkey_file);
fclose(pubkey_file);
//Prepare sign -----------------------------------------------------
BIO *priv_bio;
priv_bio = BIO_new_mem_buf(privkey, -1);
if(priv_bio == NULL){ERR_print_errors_fp(stdout);return 1;}
DSA *private_key;
private_key = PEM_read_bio_DSAPrivateKey(priv_bio, NULL, NULL, NULL);
if(private_key == NULL){ERR_print_errors_fp(stdout);return 2;}
unsigned int result, sign_length;
unsigned char signature[1000] = {0};
//generate sign
result = DSA_sign(NULL, (const unsigned char*)message, strlen(message),
(unsigned char*)signature, &sign_length, private_key);
if(result!=1){ERR_print_errors_fp(stdout);return 3;}
//save signature for console test
FILE *sign_file = fopen ("signature","wb");
fwrite((void*)signature, sign_length, 1, sign_file);
fclose(sign_file);
//verify sign -----------------------------------------------------
BIO *pub_bio;
pub_bio = BIO_new_mem_buf(pubkey, -1);
if(pub_bio == NULL){ERR_print_errors_fp(stdout);return 4;}
DSA *public_key;
public_key = PEM_read_bio_DSA_PUBKEY(pub_bio, NULL, NULL, NULL);
if(public_key == NULL){ERR_print_errors_fp(stdout);return 5;}
result = DSA_verify(NULL, (const unsigned char*)message, strlen(message),
signature, sign_length, public_key);
if(result>0){
printf("Verification OK\n");
}else{
printf("Verification Failure. Error = %i\n",result);
}
BIO_free_all(priv_bio);
DSA_free(private_key);
DSA_free(public_key);
//Console verification
system("openssl dgst -verify pubkey.pem -signature signature message.txt");
return 0;
}
Output:
Verification OK
Verification Failure
Solved:
Apply SHA1 to the digest (message) before DSA_sign, and
apply SHA1 to the digest (message) before DSA_verify.
This makes compatible the signature to work in console with OpenSSL.
To use DSA with openssl you must pass in the -dss1 to the dgst, otherwise it will use SHA1. Try this:
system("openssl dgst -dss1 -verify pubkey.pem -signature signature message.txt");