Convert code using openssl to use mbedtls - c

I am trying to convert some C code written to run on a Mac to an embedded device that does not have any encryption libraries. The code for the Mac is using libcrypto. I tried building libcrypto from openssl sources for the embedded device but I get hundreds of errors due to function pointer prototypes not matching. openssl is riddled with huge macros. As an alternative I am now trying to use mbedtls but I have not been able to get a decrypt function to work.
The code I am trying to port is a bit odd. It has what it calls a public key and is actually calling RSA_public_encrypt() with no padding to decrypt data. As a test, I changed the Mac code to call RSA_public_decrypt() and it worked so I assume the key is symmetric. The key it is using looks like this:
"-----BEGIN PUBLIC KEY-----\n"
5 lines of Base64 strings
"-----END PUBLIC KEY-----\n"
For mbedtls I am using mbedtls_pk_parse_public_key() to parse the key. If I inspect the low level RSA key structure after parsing the key there is a 128 byte N component and a 16 byte E component. I get the same key data with both openssl and mbedtls so it appears that the key is parsed properly. When decrypting on the Mac with RSA_public_decrypt(), the input and output are both 128 bytes. For mbedtls, I am calling mbedtls_pk_decrypt() to decrypt but when I trace through the code it calls mbedtls_rsa_rsaes_pkcs1_v15_decrypt() which forces the padding to be 11 bytes.
So my questions are: 1) exactly what kind of "public" key contains only N and E components and uses no padding; 2) Am I calling the correct mbedtls decryption function?
EDIT: Tried another approach and my output buffer just gets filled with zeros.
mbedtls_rsa_context rsa;
mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
mbedtls_rsa_import_raw(&rsa, modulus, sizeof(modulus), NULL, 0, NULL, 0, NULL, 0, exp, sizeof(exp));
mbedtls_rsa_complete(&rsa);
mbedtls_rsa_public(&rsa, inBfr, outBfr);
mbedtls_rsa_free(&rsa);
EDIT 2: My ultimate target is an embedded device with an ARM processor but I was testing on Windows to see if mbedtls would work. I started with VS 2010 because that is what was being used for the project I am working on. I switched to VS 2015 and the 2nd approach of importing the raw key data and calling mbedtls_rsa_public() worked perfectly. I guess the VS 2010 compiler just isn't good enough. I then ported the code to the devlepment system for my embedded device and it also worked.

The equivalent of OpenSSL's RSA_public_encrypt(…, RSA_NO_PADDING) would be mbedtls_rsa_public. The function mbedtls_pk_encrypt only lets you access encryption mechanisms based on RSA (RSAES-PKCS1-v1_5 and RSAES-OAEP), not the raw RSA primitive (“textbook RSA” a.k.a. “RSA with no padding”).
You need to call mbedtls_pk_parse_public_key to parse the key, then get a pointer to the RSA key object with mbedtls_pk_rsa, and call mbedtls_rsa_public using this RSA key object.
mbedtls_pk_context pk;
mbedtls_pk_init(&pk);
mbedtls_rsa_context *rsa = mbedtls_pk_rsa(&pk);
mbedtls_rsa_public(&rsa, inBfr, outBfr);
mbedtls_pk_free(&pk);
I think this should work from your description, but obviously I can't test this without sample data.

Related

Password callback for reading public key with OpenSSL API

When using public key cryptography, it is often customary to store private keys in an encrypted format, since they are of course supposed to be a secret. This is reflected in the OpenSSL C API, which provides functions like PEM_write_PrivateKey, which takes as function arguments an optional cipher to use to encrypt the key (like AES). Then, when reading the encrypted key back in from disk, the OpenSSL API provides functions like PEM_read_PrivateKey, which allows the user to provide a function pointer used as a callback so the application can provide OpenSSL with the password for the encrypted key.
But what confuses me is that the OpenSSL API also seems to let the user provide a password callback when reading in a Public key. For example, one API function signature for reading in a public key is:
EVP_PKEY *PEM_read_PUBKEY(FILE *fp, EVP_PKEY **x,
pem_password_cb *cb, void *u);
So what is the purpose of providing a password callback when reading in a public key? AFAIK it makes no sense to encrypt a public key, since a public key is by definition supposed to be available to the general public. So why does the OpenSSL API have a function parameter here that takes a password callback?
As mentioned in this comment, any PEM-encoded data can be encrypted. Message encryption for privacy-enhanced mail (PEM) is defined in RFC 1421 and in the context of your question, it is interesting to look at the example message in
section 4.6 Summary of Encapsulated Header Fields
-----BEGIN PRIVACY-ENHANCED MESSAGE-----
Proc-Type: 4,ENCRYPTED
Content-Domain: RFC822
DEK-Info: DES-CBC,F8143EDE5960C597
Originator-ID-Symmetric: linn#zendia.enet.dec.com,,
Recipient-ID-Symmetric: linn#zendia.enet.dec.com,ptf-kmc,3
Key-Info: DES-ECB,RSA-MD2,9FD3AAD2F2691B9A,
B70665BB9BF7CBCDA60195DB94F727D3
Recipient-ID-Symmetric: pem-dev#tis.com,ptf-kmc,4
Key-Info: DES-ECB,RSA-MD2,161A3F75DC82EF26,
E2EF532C65CBCFF79F83A2658132DB47
LLrHB0eJzyhP+/fSStdW8okeEnv47jxe7SJ/iN72ohNcUk2jHEUSoH1nvNSIWL9M
8tEjmF/zxB+bATMtPjCUWbz8Lr9wloXIkjHUlBLpvXR0UrUzYbkNpk0agV2IzUpk
J6UiRRGcDSvzrsoK+oNvqu6z7Xs5Xfz5rDqUcMlK1Z6720dcBWGGsDLpTpSCnpot
dXd/H5LMDWnonNvPCwQUHt==
-----END PRIVACY-ENHANCED MESSAGE-----
Looking at the 1.1 branch of OpenSSL it has a function PEM_read_bio() that supports reading such a message and splitting it into its name (as given in the top line), header (the name-value pairs below that) and data (the base64-encoded stuff):
int PEM_read_bio(BIO *in, char **name, char **header,
unsigned char **data, long *len);
All OpenSSL PEM_read_XYZ() functions at some point invoke it, from PEM_bytes_read_bio(), because they are all implemented in the same way by means of macro expansions. That function contains the following calls:
PEM_read_bio(bp, &nm, &header, &data, &len)
to split the message, then
PEM_get_EVP_CIPHER_INFO(header, &cipher);
to figure out which type of encryption information is found in the header of that message and fill an EVP_CIPHER_INFO object with it, and then
PEM_do_header(&cipher, data, &len, cb, u);
to do the decryption of the data based on the cipher information found -- again if needed. Note the cb parameter which stands for callback, a mechanism to get input for any passphrase if needed.
Now what might be confusing, is that certain private key formats, like for example PKCS#8, also have their own mechanism of storing encryption information independent of the PEM encoding. Technically speaking, it should be possible to apply encryption to such keys twice: once at the PEM level and once at the PKCS#8 level. The OpenSSL tools for generating or converting to PKCS#8 formatted keys do not seem to offer that option though. Also, none of the tools seem to expose the option of encrypting any generated public key PEM files, unless a private key is included as well.
You can check some of the outputs to see if they match my story. First, generating an RSA key pair to a PKCS#1 format, nothing encrypted:
$ openssl genrsa
Generating RSA private key, 2048 bit long modulus (2 primes)
.................+++++
............+++++
e is 65537 (0x010001)
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAlcnR/w7zPoLrhuqFvcfz5fn8DFb0fEcCKOKSj+x+JJxGth9P
rJbxkt4pRXxbMIL0fX59HN5bRvQh2g59l/kfr30kCOnclap9nRrohWyg2i7720Cw
<truncated>
Then the same command, but using encryption, which happens at the PEM level, as you can see in the headers:
$ openssl genrsa -des3
Generating RSA private key, 2048 bit long modulus (2 primes)
.....................+++++
....................+++++
e is 65537 (0x010001)
Enter pass phrase:
Verifying - Enter pass phrase:
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,D90861647707F687
DIupLghCjcvpLenqAAULaJj1EDvUUfc2Xc58YVh7rMTSVgLwZ+9CtnUQJcup4aUQ
a1EdGXTadwBQB2jTtiFJbH67/5D26PHXPnM+YN2rnoReOExVS7hKu3DTq7c4j6a3
<truncated>
Finally generating a similar key but now to PKCS#8, which has its own encryption and therefore does not get encrypted at the PEM level. You can see that the PEM headers are not there.
$ openssl genpkey -algorithm RSA -des3
.........................................+++++
...........................................................................+++++
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----BEGIN ENCRYPTED PRIVATE KEY-----
MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIV0Ih4bsI6egCAggA
MAwGCCqGSIb3DQIJBQAwFAYIKoZIhvcNAwcECNOim8HAN8j5BIIEyEe05hHtc8HL
<truncated>
If all my reasoning is correct, then the prompt "Enter PEM pass phrase" is inaccurate since this is not a PEM-level encryption but a PKCS#8-level encryption.

OpenSSL Extract encryptedKeyPackage from x509 certificate

I'm very new to OpenSSL (been using it for literally two days). I'm using OpenSSL version 1.0.1, and I'm trying to implement OpenSSL functions to extract a particular x509 OID from an ASN.1 (DER-encoded) signedData Package (in particular, the OID is 2.16.840.1.101.2.1.2.78.2, id-ct-KP-encryptedKeyPkg). Just for now, I'm only trying to have a program that can extract this data from the package given any ASN.1 encoded package. I'm able to encode the certificate into a buffer using the following code:
#include <openssl/x509.h>
int main()
{
/* for brevity, please assume "encrypted" points to a DER-encoded buffer */
char* encrypted = malloc( 3000 );
int sizeOfEncrypted = 3000; // assume this number is correct
BIO* bp = BIO_new( BIO_s_mem() );
ASN1_parse( bp, (unsigned char*) encrypted, (long) encryptedSize, 4 );
BUF_MEM *bptr;
BIO_get_mem_ptr( bp, &bptr );
BIO_set_close( bp, BIO_NOCLOSE );
BIO_free( bp );
return 0;
}
If I write the bytes of the buffer pointed to by "bptr" to a file, I get all the fields of the encoded data, similar to the output of:
$ openssl asn1parse -inform DER -in my_pkg.dat -i
I've confirmed the data is correct, but now as I mentioned, I'm looking for the correct OpenSSL instructions to extract a particular OID (so instead of X509_get_version(), it would be something like X509_get_encryptedKeyPkg(), per se, for a particular OID). How can I do this? I can write code that just searches for the OID in the cert and can potentially parse the data I need, but I'm almost certain/hoping OpenSSL has the tools to do that already, and more reliably. Once again, I'm an OpenSSL noobie, so I'm looking as best as I can for the solution on the internet, but perhaps I'm not using the right wording. Please let me know if you can help me out. Thanks!

Encryption Program That Works With NodeJs and mbedtls

First, let me start by stating that I am not a cryptographer by any means, and I am not very good at writing c code either, so please excuse me if the answer to this question is obvious or answered. I am developing a messaging program and cannot use TLS on the target platform. As a result, I need to find a way to encrypt each message using a symmetric pre shared key cipher, like AES.
I am seeking a method to encrypt and decrypt data between an mbedtls program (such as aescrypt2) on one end, and a nodejs program on the other. Mbedtls, formerly polarssl, is a library which provides encryption for embedded devices. Included with the source code are some sample programs, like aescrypt2, rsaencrypt, ecdsa and crypt_and_hash.
Aescrypt2 works fine when the resulting encrypted data is also decrypted using aescrypt2, but I cannot seem to get data encrypted with aescrypt to decrypt using nodejs crypto or any other program for that matter, including openssl. For example:
echo 'this is a test message' >test.txt
aescrypt 0 test.txt test.out hex:E76B2413958B00E193
aescrypt 1 test.out test.denc hex:E76B2413958B00E193
cat test.denc
this is a test message
With openssl:
openssl enc -in out.test -out outfile.txt -d -aes256 -k E76B2413958B00E193
bad magic number
Some sample node code that doesn't currently work
var crypto = require('crypto');
var AESCrypt = {};
AESCrypt.decrypt = function(cryptkey, iv, encryptdata) {
encryptdata = new Buffer(encryptdata, 'base64').toString('binary');
var decipher = crypto.createDecipheriv('aes-256-cbc', cryptkey, iv),
decoded = decipher.update(encryptdata, 'binary', 'utf8');
decoded += decipher.final('utf8');
return decoded;
}
AESCrypt.encrypt = function(cryptkey, iv, cleardata) {
var encipher = crypto.createCipheriv('aes-256-cbc', cryptkey, iv),
encryptdata = encipher.update(cleardata, 'utf8', 'binary');
encryptdata += encipher.final('binary');
encode_encryptdata = new Buffer(encryptdata, 'binary').toString('base64');
return encode_encryptdata;
}
var cryptkey = crypto.createHash('sha256').update('Nixnogen').digest(),
iv = 'a2xhcgAAAAAAAAAA',
buf = "Here is some data for the encrypt", // 32 chars
enc = AESCrypt.encrypt(cryptkey, iv, buf);
var dec = AESCrypt.decrypt(cryptkey, iv, enc);
console.warn("encrypt length: ", enc.length);
console.warn("encrypt in Base64:", enc);
console.warn("decrypt all: " + dec);
This results in either errors or garbage text every time. I have tried tweaking a variety of things as well.
I've tried this a hundred different ways, including using the -pass pass:password arg to no avail. Using nodejs, I have either gotten bad decrypt errors, or garbled nonsense back upon decryption. I have tried following many tutorials on the net, such as this one, and suggestions from this thread, and everything else I can find. I have read that different encryption programs use different standards, so compatibility across platforms/programs/languages is not always guaranteed, but I imagine somebody has been in this predicement before and knows a solution?
How would I, using nodejs, decrypt data encrypted by aescrypt2 (or a program like it)? I have only been able to make it work using a system exec call and having node execute aescrypt2 to decrypt/encrypt the data, which is not ideal, as it slows things down considerably. I am open to using a different program than aescrypt2. The only requirements are that it must run on Linux, cannot use openssl libs (because they are not supported on the target system), the program should be small and simple, due to space limitations, and foremost, the encryption/decryption needs to be compatible with nodejs. Any help would be much appreciated.
How would I, using nodejs, decrypt data encrypted by aescrypt2 (or a program like it)?
Sorry to say, but there's no better answer than: by doing the exact same thing that aescrypt2 does when decrypting a file. You've linked to the source by yourself, so just perform the same steps in node.js as they do in C in the decrypt branch.
First of all, get familiar with the layout of the file containing the encrypted data:
/*
* The encrypted file must be structured as follows:
*
* 00 .. 15 Initialization Vector
* 16 .. 31 AES Encrypted Block #1
* ..
* N*16 .. (N+1)*16 - 1 AES Encrypted Block #N
* (N+1)*16 .. (N+1)*16 + 32 HMAC-SHA-256(ciphertext)
*/
So you need to extract the IV, the encrypted blocks and the HMAC from the file, not try to decrypt the whole thing as you try with openssl (your openssl example also does not use the right IV but rather tries to derive it from the key provided - read the man page).
Next, get the key right. The actual key used to encrypt/decrypt is not the one provided on the command line, but rather 8192 iterations of hashing the IV with the key passed on the command line, using SHA256.
Finally, they decrypt, using AES-256-ECB (your openssl and node.js examples use CBC!), every 16 bytes and XOR the result with the pervious 16 bytes (the IV is used for the first 16 bytes).
There's maybe more to it, I just listed the most obvious things I saw when reading through the aescrypt2.c code.
So my advise is: try to write the same logic in node.js and try to find node.js crypto calls for the respective mbedtls counterparts.
I'm not a crypto expert, but I bet that the aescrypt implementation has so many steps that feel complicated (like generating the actual key used), because they know how to do crypto and are just doing it the right way.

Issue with crypt C API on AIX 7.1

I am writing a password reset utility on AIX (7.1.0.0) and I need to support SMD5, SSHA256, SSHA512 and BLOWFISH password hash algorithms. I have successfully implemented the code for SMD5, SSHA256 and SSHA512. However, for BLOWFISH algorithm the 'crypt' API still returns normal DES hash and not the BLOWFISH hash. I tried different prefixes in salt value - {sblowfish} {sblowfish}08$ {SBLOWFISH} {SBLOWFISH}08$. However, I still don't get blowfish hash. For, AIX 5.3 {sblowfish} prefix in salt value works and I get required hash. However, for AIX 7.1 it doesn't work.
The format for the salt value I am using is as follows -
MD5 - {smd5}<randomly generated 8 characters>$
SHA256 - {ssha256}06$<randomly generated 8 characters>$
SHA512 - {ssha512}06$<randomly generated 8 characters>$
BLOWFISH - {sblowfish}08$<randomly generated 22 characters>$
I then pass the user password and salt value to the 'crypt' API in 'C'.
crypt(password, salt);
For MD5, SHA256 and SHA512 I get the password hash which is compliant to the corresponding algorithm.
However, for BLOWFISH salt, the 'crypt' API rejects the salt and instead returns normal DES hash though i have the blowfish in the system.
Can anybody please help out here? Thanks in advance.

Different encrypted outputs in AES implementations? [duplicate]

I've compiled some AES implementation code from this site, it's supposed to perfrom a 128 bits key encryption. I tested the encryption/decryption programs which work OK together.
However if I encrypt anything with the mentioned code and then try to decrypt it by openssl tool built-in in linux, I just can't get decrypt it, it even logs me the bad magic number error. Same, if I encrypt anything with openssl and try to decrypt with the code won't work. I tried with both cbc ecb.
If they're both implementing AES, shouldn't it work same way?
it looks like the C code is using ECB and does no padding. so try encrypting a message (a multiple) of 16 bytes followed by 16 bytes of value 16 (pkcs#7 padding). or use a message (a multiple) of 16 bytes and --nopad in openssl (more likely to work). also, use aes-128-ecb or whatever it's called.
a block cipher works on "chunks" of text - in this case, it's 16 characters long. so if you don't want to worry about padding you need to give an exact number of chunks.
also, ecb mode (doing each chunk in turn with no extra processing) isn't secure for many uses. see the wikipedia article (look at the penguin photos).
[edit:] [edit 2:]
> echo -n "abcdabcdabcdabcd" > msg
> wc msg
0 1 16 msg
> openssl enc -aes-128-ecb -nopad -in msg -K 0 -S "" -iv ""
[noise]
> openssl enc -aes-128-ecb -nopad -in msg -K 0 -S "" -iv "" | wc
0 1 16
try the above yourself and see if the other code decrypts it (edit 2 sets the key explicitly, and removes IV and salt - not sure what the latter two are for in this case).
[edit 3:]
as far as i can tell, the problem is related to the way that the password is converted to a key. openssl seems to be doing something extra that i can't get rid of unless i specify a key as hex (-K 0). and if i do that, the other program doesn't work (needs a password).
sorry, i'm out of ideas.

Resources