I'm trying porting some code to do RSA verification. I googled ,and found some code in xlnx u-boot .
I put this rsa-mod-exp.c in my code and of course with some other .h files. My SOC is little endian ,so I use the little endian definitions.
After all above are done , I try to create a signature to verify my code.
Before that , I noticed that the u-boot rsa structure is different from openssl RSA structure. So to get the u-boot rsa structure , I need to install a tool called dumppublickey . I found one from here and installed.
OpenSSL RSA public key structure:
struct {
BIGNUM *n; // public modulus
BIGNUM *e; // public exponent
BIGNUM *d; // private exponent
BIGNUM *p; // secret prime factor
BIGNUM *q; // secret prime factor
BIGNUM *dmp1; // d mod (p-1)
BIGNUM *dmq1; // d mod (q-1)
BIGNUM *iqmp; // q^-1 mod p
// ...
};RSA
U-boot RSA public key structure:
struct rsa_public_key {
uint len; /* len of modulus[] in number of uint32_t */
uint32_t n0inv; /* -1 / modulus[0] mod 2^32 */
uint32_t modulus; / modulus as little endian array */
uint32_t rr; / R^2 as little endian array */
uint64_t exponent; /* public exponent */
};
Now, every thing is ready beside a signature. Here is the step I create my signature.
1. Create private key.It's a 2048 bit and the public exponent is three.
openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048 -pkeyopt rsa_keygen_pubexp:3
2. Create cert file.
openssl req -new -x509 -key key.pem -out newcert.pem -days 3650
3. Get the U-boot structure public key.
dumppublickey newcert.pem
I got :
{
64, //lenth
0x63b40d47, //n0inv
{2799858569,......,1105502226,1577608370,1150603850,3030884821}, // modules (N)
{909785043,.......,3050452165,3418434484,2529136815,837355943}, // r^2
3 //exponent
}
4. Sign my file using the private key.
echo "hello world" > a.txt
openssl dgst -sign key.pem -sha256 -hex a.txt
I got :
RSA-SHA256(a.txt)= 157eb60ad0c77427cd....6b02b5d331d610b27f32aaa0
I put key length, n0inv, modulus, rr, exponent and the signature in my code. Notice that modulus and rr I useu_int32 array like I showed above while signature I use a u_int8 array like below.
{0x15,0x7e.0xb6,0x0a,.......0xaa,0xa0}
Here is what I think the rsa-mod-exp.c (function rsa_mod_exp_sw) will give me . I thought I will get the result of the sha256 hash value of file a.txt. Same as the result I did using openssl.
openssl dgst -sha256 a.txt
However, I did't get this sha256 hash value . I got something strange.
Could anyone point which part is wrong and how to correct it ?
It seems struct key_prop argument of rsa_mod_exp_sw assumes that modulus and rr are big-endian.
So modulus and rr generated by dumppublickey should be converted to big-endian.
I could decrypt sign and confirmed that decrypted data contains pkcs v1.5 padding format.
Related
Unpadded RSA is basically modular exponentiation. So it seems like openssl_public_encrypt($plaintext, $result, "$rsa", OPENSSL_NO_PADDING) ought to be a good way to do fast modular exponentiation (where $rsa contained the modulus and the exponent and $plaintext was the number you wanted to do the modular exponentiation on). Only problem: it doesn't work consistently. In particular, when the modulo is even, I get the following error:
failure: error:0906D06C:PEM routines:PEM_read_bio:no start line
So I thought I'd look into the code to figure out why.
Here's what PHP does for openssl_public_encrypt (openssl.c):
successful = (RSA_public_encrypt((int)data_len,
(unsigned char *)data,
(unsigned char *)ZSTR_VAL(cryptedbuf),
EVP_PKEY_get0_RSA(pkey),
(int)padding) == cryptedlen);
Here's what OpenSSL does for RSA_public_encrypt (rsa_crpt.c):
int RSA_public_encrypt(int flen, const unsigned char *from, unsigned char *to,
RSA *rsa, int padding)
{
return (rsa->meth->rsa_pub_enc(flen, from, to, rsa, padding));
}
From here it's not clear to me what's happening. Where is rsa->meth_rsa_pub_enc defined? Maybe it corresponds to something in the engines subdirectory of the OpenSSL repo?:
https://github.com/openssl/openssl/tree/master/engines
edit: an RSA key with an even (invalid) modulo:
-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAQEAylq1ZRSREX7DWHUKg4HX
KGN5C8GQgasXaobkF0J5ok/TfDQnG4WntB/brjQaQRN9phFovHEClj2XywYfL/s9
syHHioaVOIMZ86cLP7xzJc6dF/bydPLD1p14DkpJLgCSx6CyTlFzOhmm4/YMEh4t
XR8FHY1f3pgWwEDXkkMKo/2U5FIIH0HBfnXgZeYSw7DalriaiZ+PyxpnqfYA5TT2
AXCiguSHlo14ZEf/dwNlDmEfjBLrJPltOp69ZlqZYeykuEjg54KbvR2EMjQWj3V6
9sh1jPZvEeK8Tw/3E+aC4AoQzOB0VLF56yn1yfMZFvBRYd6RAhtcoU7Lli3/J7c3
egKCAQEAyHrqMMUZnP28SE1dJ0Fii69R4+XYZ7+8qVwPa0P/AmKYIvwAqvHWX00Y
9xTD1imbWQbyf5Bvga5wT0M3bvA6Btm2unXwLVcmRRIAwRrR8mkrluyg9mD2yhCl
O3M54YvL4GBDh/iGcs+rWzsQZnrjctki1k6U5xJDqCIV8eDeD+2O3E1hN3gJ2lTX
+5qHi9dpY+hWKdEsBEG7XZSwkTf0rbPusyK0BsBjv/suxivC2OiKhmbX/eXqBsuf
jkpw0qXXQuVF1BvvaCHK0+Td1daPrdb2BjJfdyzvnRmFLoBdzt2EBpcRnCTOewqb
Oe3+em4bbWRehVbbCuwySF/731TBwQ==
-----END PUBLIC KEY-----
I also tried the key in an alt format:
-----BEGIN RSA PUBLIC KEY-----
MIICCgKCAQEAylq1ZRSREX7DWHUKg4HXKGN5C8GQgasXaobkF0J5ok/TfDQnG4Wn
tB/brjQaQRN9phFovHEClj2XywYfL/s9syHHioaVOIMZ86cLP7xzJc6dF/bydPLD
1p14DkpJLgCSx6CyTlFzOhmm4/YMEh4tXR8FHY1f3pgWwEDXkkMKo/2U5FIIH0HB
fnXgZeYSw7DalriaiZ+PyxpnqfYA5TT2AXCiguSHlo14ZEf/dwNlDmEfjBLrJPlt
Op69ZlqZYeykuEjg54KbvR2EMjQWj3V69sh1jPZvEeK8Tw/3E+aC4AoQzOB0VLF5
6yn1yfMZFvBRYd6RAhtcoU7Lli3/J7c3egKCAQEAyHrqMMUZnP28SE1dJ0Fii69R
4+XYZ7+8qVwPa0P/AmKYIvwAqvHWX00Y9xTD1imbWQbyf5Bvga5wT0M3bvA6Btm2
unXwLVcmRRIAwRrR8mkrluyg9mD2yhClO3M54YvL4GBDh/iGcs+rWzsQZnrjctki
1k6U5xJDqCIV8eDeD+2O3E1hN3gJ2lTX+5qHi9dpY+hWKdEsBEG7XZSwkTf0rbPu
syK0BsBjv/suxivC2OiKhmbX/eXqBsufjkpw0qXXQuVF1BvvaCHK0+Td1daPrdb2
BjJfdyzvnRmFLoBdzt2EBpcRnCTOewqbOe3+em4bbWRehVbbCuwySF/731TBwQ==
-----END RSA PUBLIC KEY-----
Neither work.
I am trying to write code to verify some RSA signatures. The signatures were made using the OpenSSL command-line tool, using the equivalent of this command line:
openssl dgst -sha1 -sign private_key_file.pem < binary_data_file > sig
I am trying to use libtomcrypt to do the verify:
https://www.libtom.net/
Here is the calling signature of the RSA verification function in libtomcrypt:
int rsa_verify_hash_ex(
const unsigned char *sig, unsigned long siglen, // signature to verify
const unsigned char *hash, unsigned long hashlen, // hash value to check against sig
int padding, // defined constant value, see below
int hash_idx, // identifies which hash algorithm, see below
unsigned long saltlen, // specify salt length, see below
int *stat, // output parameter, returns whether verify succeeded or not
rsa_key *key); // RSA public key to use for verify
This function returns a 0 if it operates without error, otherwise returns an error code. If it operates without error, the stat output parameter indicates whether the signature verified.
Most of the arguments seem straightforward: pass in the signature to check, the hash value to use to compare it, and the RSA key to use for the check. hash_idx is clear from the example code included with libtomcrypt; it is an index into a table of supported hash algorithms, and I can find the correct value to use with this code snippet: hash_idx = find_hash("sha1")
But I'm wondering about the padding and saltlen values. padding doesn't worry me too much, as there are only two possible values, and I can just try them both. But what should I pass for saltlen?
The OpenSSL documentation for the OpenSSL functions for RSA verify don't show a saltlen parameter. The man page for openssl dgst (i.e. the result of man dgst) does not discuss salt.
So my questions:
How can I determine the correct salt length to use?
Does OpenSSL's dgst command insert any extra stuff in the input, such as: (stdin)=
(I found that (stdin)= thing by searching StackOverflow: Why are the RSA-SHA256 signatures I generate with OpenSSL and Java different?)
libtomcrypt also has a function called pkcs_1_pss_decode() which is documented to "decode a PSS encoded signature block". Is there any chance that this is the function I need to call?
Thanks for any help you can give me.
EDIT: thanks to the help below, from #Jonathan Ben-Avraham, I was able to get this working today. The answers to my questions are, respectively:
Use length 0 for the salt, no salt at all.
No, OpenSSL did not insert anything extra such as (stdin)=
I needed to call rsa_verify_hash_ex(), and I needed to specify the padding argument as LTC_LTC_PKCS_1_V1_5.
No salt:
First, generate a binary SHA1 hash of your data:
openssl dgst -sha1 -binary -out hash1 some_data_file
This is an SHA1 hash or digest. There is no salt prependended to the file some_data_file. The openssl dgst -sha1 itself does not add salt. Note that the output file is just a 20 byte SHA1 hash with no salt. If there were salt, the hash would have to include it, probably prepended before the last 20 bytes that hold the SHA1 hash.
Next, sign the SHA1 hash file hash1 with your private key:
openssl pkeyutl -sign -in hash1 -inkey privkey.pem -pkeyopt digest:sha1 -out sig1
Now sign the some_data_file with openssl dgst:
openssl dgst -sha1 -sign privkey.pem < some_data_file > sig2
Finally, compare the two signatures:
diff sig1 sig2
and you should see that they are the same. This tells us that signing the raw SHA1 hash of a file with no salt is the same as using the openssl dgst -sha1 -sign command to sign the file, so it must be that the openssl dgst -sha1 -sign command also did not use any salt when generating its SHA1 hash for sig2.
Note also that you cannot achieve the same result using the deprecated rsautl:
openssl rsautl -sign -in hash1 -inkey privkey.pem -out sig1
instead of openssl pkeyutl, because openssl rsautl -sign does not do the ASN.1 encoding of DigestInfo as required by RSASSA-PKCS1-v1_5 defined in e.g. RFC3447 section 9.2 step 2. (This is why you need -pkeyopt digest: even though pkeyutl -sign itself doesn't do any hashing.) See this SE post for details.
One thing to emphasize: Be sure to pass the hash instead of the actual data. That threw me off for some time. Here's a snippet that works (but use sha256):
void
verify_tomcrypt(unsigned char *keyblob, size_t klen,
unsigned char *payload, size_t dlen,
unsigned char *signature, size_t slen)
{
rsa_key key;
int stat;
unsigned long len;
unsigned char digest2[SHA256_DIGEST_LENGTH];
ltc_mp = ltm_desc;
register_hash(&sha256_desc);
/* try reading the key */
if (rsa_import(keyblob, klen, &key) != CRYPT_OK) {
printf("Error reading key\n");
exit(-1);
}
int hash_idx = find_hash("sha256");
if (hash_idx == -1) {
printf("LTC_SHA256 not found...?\n");
exit(-1);
}
len = sizeof(digest2);
if (hash_memory(hash_idx, payload, dlen, digest2, &len) != CRYPT_OK) {
printf("sha256 fails...?\n");
exit(-1);
}
if (rsa_verify_hash_ex(signature, slen, digest2, sizeof(digest2), LTC_LTC_PKCS_1_V1_5, hash_idx, 0, &stat, &key) == CRYPT_OK) {
if (stat == 1)
printf("Tomcrypt: Signature OK!\n");
else
printf("Tomcrypt: Signature NOK?\n");
} else {
printf("Tomcrypt: Signature error\n");
}
}
I have been given a sample encryption module which simply xor a key with the packet data and place the result in data field of constructed packet itself....
The code for xoricv module is here.
void
xorcrypto(uint8_t *key, uint32_t keylen,
uint8_t *data, uint32_t datalen)
{
int d, k;
for (d=0, k=0; d < datalen; ++d, k = (k+1)%keylen) {
data[d] ^= key[k];
}
}
Now i need to change the module so that it performed the AES Encryption rather than simple xor operation.
Would you suggest possible transformation i need to do ????
It is a small part of my project and i am stuck in between..
The AES Command I have used on command line for encryption
openssl enc -aes-256-cbc -salt -in file.txt -out file.enc
Daily i am going through plenty of errors when i tried to implement it by my own and i have very limited time so please help me.......
Here is my implementation ...... although i am adding it here in answer column because may be there is small bug in my implementation which i could be able to solve through some valuable suggestions but still If any other way is possible please suggest and provide me some implementation code...
/* u_int8_t ... etc all are typedefs for uint8_t....etc
so don't bother about them */
void xorcrypto(u_int8_t *key, u_int32_t keylen,u_int8_t *data,
u_int32_t datalen)
{
int ch,i,j;
uint8_t modata[100];
FILE *fp,*fr,*fq,*ft;
fp=fopen("key","w");
fputs((char *)key,fp);
fq=fopen("file.txt","w");
fputs((char *)data,fq);
fclose(fp);
fclose(fq);
system("sudo openssl enc -aes-256-cbc -salt -in file.txt -out file.enc -pass file:key");
fr=fopen("file.enc","r");
memset(data,0,sizeof(data));
i=0;
while( (ch=fgetc(fr))==EOF) {
data[i]=ch;
i++;
}
fclose(fr);
system("sudo openssl enc -d -aes-256-cbc -salt -in file.enc
-out file1.txt -pass file:key");
ft=fopen("file1.txt","r");
memset(modata,0,sizeof(modata));
j=0;
while( (ch=fgetc(ft)) != EOF) {
modata[j]=ch;
j++;
}
fclose(ft);
}
Call to function in module is described as -
bool
espcrypto(esp_private *epriv, sendip_data *data, sendip_data *pack)
{
u_int32_t keylen;
u_int8_t *key;
static u_int8_t fakekey;
struct ip_esp_hdr *esp = (struct ip_esp_hdr *)pack->data;
if (!epriv->keylen) { /* This isn't going to be very productive... */
key = &fakekey;
keylen = 1;
} else {
key = (u_int8_t *)epriv->key;
keylen = epriv->keylen;
}
/* Encrypt everything past the ESP header */
xorcrypto(key, keylen,
(u_int8_t *)esp->enc_data,
pack->alloc_len + data->alloc_len -
sizeof(struct ip_esp_hdr));
return TRUE;
}
This is code in the xorcrypto.c file in packet generator tool i am using which is linked during packet construction through command line as -am xorcrypto.so .That is the reason why I was being so lazy.I am first looking for an implementation which can act as proof of concept .Rest all optimizations can be done later.
The output I am getting is - encryption not performed at all the data is still in plain text in packet.
udit#udit-Dabba ~/Downloads/sendip-2.5-mec-2/mec $ cat file.txt
udit#udit-Dabba ~/Downloads/sendip-2.5-mec-2/mec $ cat file.enc
Salted__����
}�#��G�����0����iudit#udit-Dabba ~/Downloads/sendip-2.5-mec-2/mec $ cat file1.txt
udit#udit-Dabba ~/Downloads/sendip-2.5-mec-2/mec $
Why file.txt is null even key file is not updated ???
If any other information needed i will add it here......but please help me getting out of the mesh .
This may not even be possible without making some additional changes to your software. It doesn't look like your function allows for the resulting encrypted data to be larger than the unencrypted data, for one, which will be required for RSA.
The key you pass to your function will also be quite different; one side of an RSA key will consist of the modulus and an exponent. The modulus will be a large number (not representable with the normal integer types), and the exponent is typically a large number for one side and a (relatively) small one for the other.
Aside from that, there are a number of issues and difficulties with RSA. You could try to deal with these yourself, but you'd probably be better off using an existing library like OpenSSL. Some of these issues include:
Implementing RSA (with usefully long keys) requires modular arithmetic on very large numbers, far larger than any of the normal integer types. You'd either have to write functions for this, or find a library.
The data has to be broken into pieces that are shorter than the modulus (part of the key), including whatever padding and such is encrypted along with the data. The length of each piece after encryption will be the length of the modulus. That's why the resulting encrypted data will be longer than the original data (and also padding).
Avoiding certain vulnerabilities requires additional steps, such as adding random padding into each piece of data and ensuring that the padded data, raised to the exponent from the key, would exceed the modulus (if it weren't done as modular exponentiation).
So first, you'll need to make it possible for your encryption function to return more data than you gave it. Then you should probably look at using an encryption library to do the actual encryption, to save a lot of work and reduce the chances of letting vulnerabilities slip through.
Well,
I feel the line :
while( (ch=fgetc(fr))==EOF)
// Also, Similar statements that you have used many times.
You are reading 1 character from the file and comparing that to EOF. That works fine untill you are working with normal text files.
But here you are working with an encrypted file, file.enc which can contain anything at all.
It can even posses EOF character itself as data content.
That means if file has 100 characters and 2nd character is EOF then it will terminate at 2nd character itself.
I feel this as a possible problem.
Remains.. the other problems - I suggest using fprintf() instead of fputs(), these are easy to use and hence avoids unseen bugs. Since you are working on strings instead of characters logically.
Moreover, using these you also get an advantage of string formatting when needed.
Try out and then get back.. :)
As a reference and as continuation to the post:
how to use OpenSSL to decrypt Java AES-encrypted data?
I have the following questions.
I am using OpenSSL libs and programming in C for encrypting data in aes-cbc-128.
I am given any input binary data and I have to encrypt this.
I learn that Java has a CipherParameters interface to set IV and KeyParameters too.
Is there a way to generate IV and a key using openSSL? In short how could one use in a C program to call the random generator of openSSL for these purposes. Can any of you provide some docs/examples/links on this?
Thanks
An AES key, and an IV for symmetric encryption, are just bunchs of random bytes. So any cryptographically strong random number generator will do the trick. OpenSSL provides such a random number generator (which itself feeds on whatever the operating system provides, e.g. CryptGenRandom() on Windows or /dev/random and /dev/urandom on Linux). The function is RAND_bytes(). So the code would look like this:
#include <openssl/rand.h>
/* ... */
unsigned char key[16], iv[16];
if (!RAND_bytes(key, sizeof key)) {
/* OpenSSL reports a failure, act accordingly */
}
if (!RAND_bytes(iv, sizeof iv)) {
/* OpenSSL reports a failure, act accordingly */
}
Assuming AES-128:
unsigned char key[16];
RAND_bytes(key, sizeof(key));
unsigned char iv[16];
RAND_bytes(iv, sizeof(iv));
The random generator needs to be seeded before using one of those.
I'm trying to implement an X.509 certificate generator from scratch (I know about the existing ones, but I need yet another one). What I cannot understand is how to calculate the SHA-1 (or any other) fingerprint of the certificate.
The RFC5280 says that the input to the signature function is the DER-encoded tbsCertificate field. Unfortunately, the hash that I calculate differs from the one produced by OpenSSL. Here's a step-by-step example.
Generate a certificate using OpenSSL's x509 tool (in a binary DER form, not the ASCII PEM)
Calculate its SHA-1 hash using openssl x509 -fingerprint
Extract the TBS field using dd (or anything else) and store it in a separate file; calculate its hash using the sha1sum utility
Now, the hashes I get at steps 2 and 3 are different. Can someone please give me a hint what I may be doing wrong?
Ok, so it turned out that the fingerprint calculated by OpenSSL is simply a hash over the whole certificate (in its DER binary encoding, not the ASCII PEM one!), not only the TBS part, as I thought.
For anyone who cares about calculating certificate's digest, it is done in a different way: the hash is calculated over the DER-encoded (again, not the PEM string) TBS part only, including its ASN.1 header (the ID 0x30 == ASN1_SEQUENCE | ASN1_CONSTRUCTED and the length field). Please note that the certificate's ASN.1 header is not taken into account.
The finger print is similar to term "Thumbprint" in .net. Below code snippet should help you to compute finger print :
public String generateFingerPrint(X509Certificate cert) throws CertificateEncodingException,NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
byte[] hash = digest.digest(cert.getEncoded[]);
final char delimiter = ':';
// Calculate the number of characters in our fingerprint
// ('# of bytes' * 2) chars + ('# of bytes' - 1) chars for delimiters
final int len = hash.length * 2 + hash.length - 1;
// Typically SHA-1 algorithm produces 20 bytes, i.e. len should be 59
StringBuilder fingerprint = new StringBuilder(len);
for (int i = 0; i < hash.length; i++) {
// Step 1: unsigned byte
hash[i] &= 0xff;
// Steps 2 & 3: byte to hex in two chars
// Lower cased 'x' at '%02x' enforces lower cased char for hex value!
fingerprint.append(String.format("%02x", hash[i]));
// Step 4: put delimiter
if (i < hash.length - 1) {
fingerprint.append(delimiter);
}
}
return fingerprint.toString();
}