I have used following code to encrypt string in C++ with OpenSSL and it works fine only if text is up to 256 bytes, it doesn't work for larger size:
void encrypt(char* message, int sourceSzie, char* encryptedMessage, int &destSize)
{
char err[130];
RSA *rsa_pubkey = NULL;
FILE *rsa_pub_file = fopen("pubkey_file.bin", "rb");
if(PEM_read_RSAPublicKey(rsa_pub_file, &rsa_pubkey, NULL, NULL) == NULL)
{
printf("Error reading public key \n");
}
if((destSize = RSA_public_encrypt(sourceSzie, (unsigned char*)message, (unsigned char*)encryptedMessage, rsa_pubkey, RSA_PKCS1_OAEP_PADDING)) == -1)
{
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr, "Error encrypting message: %s\n", err);
}
fclose(rsa_pub_file);
}
char msg[1024];
stcpy(msg, "A test message");
int size;
char encrypted[1024];
encrypt(msg, strlen(msg), encrypted, size);
But if size of string crosses 256, it doesn't work and generates Data too large error.
What should I do to make it work for string of any size?
But if size of string crosses 256, it doesn't work and generates Data too large error.
Correct. RSA encryption is defined as c = m ^ e mod n. The message cannot be larger than the modulus size n. You can get the modulus size with RSA_size().
More correctly, the limit is modulus size - padding size because messages are padded. OAEP padding size is approximately 41 bytes, so the limit is somewhere around RSA_size(rsa) - 41.
I omitted PKCS padding because its insecure. In the sources, it is #define RSA_PKCS1_PADDING_SIZE 11. See A bad couple of years for the cryptographic token industry for an approachable discussion.
What should I do to make it work for string of any size?
You would need an arbitrarily large key ;) But OpenSSL limits your key size to 16K-bits. So you can't make the keys arbitrarily large.
Plus, its hard to generate those large keys. Generation time grows with key size, and you could spend a couple of days generating large keys.
In your particular case:
char msg[1024];
...
encrypt(rsa, msg, sizeof(msg), ...);
Try generating a key that is (1024 + 64) * 8 or 8704-bits. That should handle the 1024-byte buffer with padding.
To use public key encryption in this case, you should encrypt the string with a symmetric cipher like AES. Then, encrypt the AES key with the public RSA key. That's basically how SSL/TLS and others operate.
If you use the hybrid encryption, you should choose a mode like EAX or GCM; and not CBC mode. EAX and GCM are authenticated encryption modes, and they provide both confidentiality and authenticity. With authenticated encryption, you will provide privacy and be able to detect tampering.
If you chose to use OpenSSL with AES/GCM, then see the examples of how to use it on the OpenSSL wiki at EVP Authenticated Encryption and Decryption.
There are a couple of cryptosystems that provide the service as a package. See Shoupe's Elliptic Curve Integrated Encryption Scheme (ECIES); or Abdalla, Bellare, and Rogaway's Diffie-Hellman Authenticates Encryption Schemes (DHAES). Unfortunately, OpenSSL does not provide either.
But if you are interested in ECIES or DHAES, then take a look at Crpyto++. The library offers both of them. For an example of its usage in Crypto++, see Elliptic Curve Integrated Encryption Scheme.
I have found the solution at link https://shanetully.com/2012/06/openssl-rsa-aes-and-c/.
The functions Crypto::aesEncrypt() and Crypto::aesDecrypt() are able to encrypt/decrypt strings of any size.
Related
I'm working with the Microsoft Authentication Library for iOS. It is being flagged by a Microfocus Fortify scan for the following vulnerability. I need to understand two things:
What encryption mode is this using with AES 128 (CBC, ECB, GCM, etc) ?
How and where is the Initialized Vector (key) being generated? If it's null in this case, I saw another post discussing the NULL key scenario for CCCrypt
The function msidAES128DecryptedDataWithKey:keySize:() in NSData+AES.m
uses a cryptographic encryption algorithm with an insecure mode of
operation on line 48.
The mode of operation of a block cipher is an algorithm that describes
how to repeatedly apply a cipher's single-block operation to securely
transform amounts of data larger than a block. Some modes of operation
include Electronic Codebook (ECB), Cipher Block Chaining (CBC), Cipher
Feedback (CFB), and Counter (CTR).
ECB mode is inherently weak, as it produces the same ciphertext for
identical blocks of plain text. CBC mode is vulnerable to padding
oracle attacks. CTR mode is the superior choice because it does not
have these weaknesses.
Avoid using ECB and CBC modes of operation when encrypting data larger
than a block. CBC mode is somewhat inefficient and poses a serious
risk if used with SSL 1. Instead, use CCM (Counter with CBC-MAC)
mode or, if performance is a concern, GCM (Galois/Counter Mode) mode
where they are available.
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
key, keySize,
NULL /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesDecrypted);
Example Solution - The following code uses the AES cipher with CTR mode:
ccStatus = CCCryptorCreateWithMode( kCCEncrypt,
kCCModeCTR, // Uses CTR mode
kCCOptionPKCS7Padding,
ccPKCS7Padding,
iv,
key,
kCCKeySizeAES128,
tweak,
kCCKeySizeAES128,
0,
0,
&cryptor);
CVE 2014-3566,
http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-3566
I am using eccrypto library in javascript for encryption using the ECIES algorithm (curve- secp256k1). The cipher generated by encryption in JS code could not be decrypted in Kotlin.
Here is the Javascript code.
var eccrypto = require("eccrypto");
eccrypto.encrypt(publicKeyA, Buffer.from("Sic Mundus Creatus Est")).then(function(encrypted) {
val ciphertext = encrypted.ciphertext
//the hex encoded ciphertext is then sent to the server
}
Here is the decryption code for kotlin
val cipherBytes = DatatypeConverter.parseHexBinary(ciphertext)
val cipher: Cipher = Cipher.getInstance("ECIES", "BC")
cipher.init(Cipher.DECRYPT_MODE, privateKeyA)
print( cipher.doFinal(cipherBytes) )
With this code for decryption, I get an Bad Block Exception.
However, if I just do encryption and decryption using Java, there is no problem. Also, encryption and decryption both in Javascript also work fine.
Is there anything I am missing?
I found the solution (or say figured out the actual issue). Hope it helps future devs:
The mismatch in encryption/decryption between javascript and java implementation is because those implementations are using different parameters of the hash algorithm and AES encryption.
ECIES implementation in Java using BouncyCastle has a crappy implementation. It uses AES with 128 bits, does not use a secure hash algorithm, no robust check for MAC, and has very little test cases.
As a workaround, I now use a custom written ECIES implementation for Java which uses SHA-512 for the hash, AES encryption (using 256 bits key and AES/CBC/PKCS7Padding mode). This new implementation is what eccrypto javascript library engine uses under the hood. Now, they work fine!
Your comment 'Encrypting the same message using the same public key in both environment gives different cipher messages' does not prove a difference between values. I encrypted 10 times the same message '123' with my public key and got 10 times a different encrypted value.
This is due to a random element in the (internal) encryption function:
ciphertext: 0444a9e31cf1f8f7cabcf2a6562622ce2ee1c38bcdf9938fa48401b34fbeae7ea70c9ad1bd16343a3632ef9011ba6081a7df47ed2ca9904bf0f97febdd18f1b5da9315f744a68c87deee353b481cfbe90a49462403550e3a
ciphertext: 04e1970f415cccb62dc61de534bd61ce9627e9b0e857f6270c20b202f3e62a789979d7c9ca893d85f65f00f5462a29cb986764e34fefb8f5c5ce8f0e9700ddf777b616539ec4e860bad4cac04f8cd3b29c61513cb68a1c9b
ciphertext: 04b07bfbfa53e17446ac8ebaf6af53056274ff4e104bfe26da6176aab390d521429971c151f31a1af4b0240703d4b75a81136b22695798b1ad1cf272e842f5e60ba931972e6868ca54301ec6585ff503cfab76f69ad3beb0
ciphertext: 041d90bcfa34af06559c5f482d06a684492001bb3bd52dc2e9f2eb31cd2de27e595fad3178c0f65d3cd160e0444ae6d9cbfbd2a1e12e21525057d79b8ea24fed572426e3fdeba4a298c17fc481acb66db7b0c8f1d0d0701d
ciphertext: 04a440a994dc0a5f712b1190e1dc0bfff15c053e4a03dc3c74c0cfc965a2da5ed6d668a52b4ae1e320b5ed068fc338e2076f2bc68f156fb79d67daf74ab21c4036a23bebcca007417d5c8ed486750dd37b3f495de92312aa
ciphertext: 04033bfaa2fb90c667ca25e77abba6cdc8e6c601ebb5bf836456c810abe54a4d426b3e52477a8b97f1115905d0babbdda572d9294532d7eda032f6fc98a588c77b00b7bebfe1fe1f4319f3aa0b1776c6da02d9f24baa98c2
ciphertext: 047a1aa7e82084af63cdf76ad0bdd21865d38fdee7fa8902dbf5c0e4840c7209c9cb249698802313c83d22fc8e18b376012888ee0878d4e8c186c241b648180613b1ee460bf9eef5c9a6fab15541ae4bc16dd9f98a10c940
ciphertext: 04dbababe30bd8013bd74f846ed2f1bd818e5b826b59b9b6c6336a62e2e373e82e7f80d2a2fbc3094435e61a53325aba6585047af6bfa593260afc6e5ee737783a8dbbc60d3f99277eea95ed2671d2a81d369602388b7cb0
ciphertext: 04eb52c8d946bfd1d84b27858f78d174bf77509058d10d6bfe11ee5f6553b1c571b3c9c7389b08e596735342584c2be43f5ef4e6952d3db7b5239d00b2c7d22f1ca9e588a8f6dc5c8274d97d18999c4a88702d12b9d56ea6
ciphertext: 04808530ee927d5445a1e8f7a06b6bd8c1457cbf89ea6a75e2a28fd8899e06e8ccc5fab8b45536610a79a50ebf3ca1ed5fafb782fe483165fdc483c7e2e3c3724409d539cdbf586f090b783647d791f33ddfa8e2ba29e328
I have searched and found examples of AES with the default 256 key size and find it worked already. But when I want to use 128 key size, there is little information.
I have extracted code from the aes test from CryptoJS:
var C = CryptoJS;
var plainText = '00112233445566778899aabbccddeeff';
var key = '000102030405060708090a0b0c0d0e0f';
var encryptedText = C.AES.encrypt(C.enc.Hex.parse(plainText), C.enc.Hex.parse(key), { mode: C.mode.ECB, padding: C.pad.NoPadding }).ciphertext.toString();
console.log(encryptedText);
var decryptedText = C.AES.decrypt(C.lib.CipherParams.create({ ciphertext: C.enc.Hex.parse(encryptedText) }), C.enc.Hex.parse(key), { mode: C.mode.ECB, padding: C.pad.NoPadding }).toString();
console.log(decryptedText);
This worked, but if I want to use a different plain text like 'Hello World' then it failed. Also what if I want to use a password like 'my-key-001'? As I have read that CryptoJS expect to use 256 key size if I pass a password.
Your help is much appreciated.
This worked, but if I want to use a different plain text like 'Hello World' then it failed.
You have used the noPadding and that is the issue. The example is multiple of 16-byte that causes no problem, however your next plaintext is not. You can use noPadding if
your message is an exact multiple of the block size, though still not recommended.
you want to pad the message yourself, probably that is you want to test a new padding scheme that we don't see in your code.
You should you padding like
padding: CryptoJS.pad.Pkcs7
As I have read that CryptoJS expect to use 256 key size if I pass a password.
CryptoJS supports AES-128, AES-192, and AES-256. According to your key size it will select the key variants. If you use a password it will generate a 256-bit size. That is %40 times slower than AES-128 since it requires 14 rounds. However use a good password, see below.
Also what if I want to use a password like 'my-key-001'?
A password with high entropy is important otherwise the attackers can be successful by testing passwords. The key generation cannot increase entropy. Therefore you need a good way to generate high entropy passwords like using diceware.
How to encrypt in AES using CryptoJS with key size of 128?
Just provide a 128-bit key.
Does AES-128 has 128-bit security
Any block cipher, not only AES, has vulnerable to multi-target attacks. In that case it is not providing 128-bit security. Therefore you should use 192 or 256-bit keys.
For a more detailed see this question Has AES-128 been fully broken?
mode: C.mode.ECB
The ECB mode of operations is not advised, it is insecure and it leaks pattern. You should use modern encryption modes like AES-GCM which provides you not confidentiality but also, integrity and authentication.
While using GCM mode, make sure that you never use the same IV/nonce again under the same key. AES-GCM uses CTR mode for encryption and under the same key if the IV/nonce repeated then crig-dragging is possible. Also, it can leak the authentication key.
We are developing an application that has to work with data that is enycrpted by LoraWan (https://www.lora-alliance.org)
We have already found the documentation of how they encrypt their data, and have been reading through it for the past few days (https://www.lora-alliance.org/sites/default/files/2018-04/lorawantm_specification_-v1.1.pdf) but currently still can't solve our problem.
We have to use AES 128-bit ECB decryption with zero-padding to decrypt the messages, but the problem is it's not working because the encrypted messages we are receiving are not long enough for AES 128 so the algorithm returns a "Data is not a complete block" exception on the last line.
An example key we receive is like this: D6740C0B8417FF1295D878B130784BC5 (not a real key). It is 32 characters long, so 32 bytes, but if treat it as hexadecimal, then it becomes 16 bytes long, which is what is needed for AES 128-bit. This is the code we use to convert the Hex from String:
public static string HextoString(string InputText)
{byte[] hex= Enumerable.Range(0, InputText.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(InputText.Substring(x, 2), 16))
.ToArray();
return System.Text.Encoding.ASCII.GetString(hex);}
(A small thing to note for the above code is that we are not sure what Encoding to use, as we could not find it in the Lora documentation and they have not told us, but depending on this small setting we could be messing up our decryption (though we have tried all possible combinations, ascii, utf8, utf7, etc))
An example message we receive is: d3 73 4c which we are assuming is also in hexadecimal. This is only 6 bytes, and 3 bytes if we convert it from hexa to normal, compared to the 16 bytes we'd need minimum to match the key length.
This is the code for Aes 128 decrypt we are using:
private static string Aes128Decrypt(string cipherText, string key){
string decrypted = null;
var cipherPlainTextBytes = HexStringToByteArray(cipherText);
//var cipherPlainTextBytes = ForcedZeroPadding(HexStringToByteArray(cipherText));
var keyBytes = HexStringToByteArray(key);
using (var aes = new AesCryptoServiceProvider())
{
aes.KeySize = 128;
aes.Key = keyBytes;
aes.Mode = CipherMode.ECB;
aes.Padding = PaddingMode.Zeros;
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
using (MemoryStream ms = new MemoryStream(cipherPlainTextBytes, 0, cipherPlainTextBytes.Length))
{
using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
{
using (StreamReader sr = new StreamReader(cs))
{
decrypted = sr.ReadToEnd();
}
}
}
}
return decrypted;}
So obviously this is going to return "Data is an incomplete block" at sr.ReadToEnd().
As you can see from the example, in that one commented out line, we have also tried to "Pad" the text to the correct size with a full zero byte array of correct length (16 - cipherText), in which case the algorithm runs fine, but it returns complete gibberish and not the original text.
We already have tried all of the modes of operation and messed around with padding modes as well. They are not providing us with anything but a cipherText, and a key for that text. No Initialization vector either, so we are assuming we are supposed to be generating that every time (but for ECB it isn't even needed iirc)
What's more is, they are able to encrypt-decrypt their messages just fine. What is most puzzling about this is that I have been googling this for days now and I cannot find a SINGLE example on google where the CIPHERTEXT is shorter than the key during decryption.
Obviously I have found examples where the message they are Encrypting is shorter than what is needed, but that is what padding is for on the ENCRYPTION side (right?). So that when you then receive the padded message, you can tell the algorithm what padding mode was used to make it correct length, so then it can seperate the padding from the message. But in all of those cases the recieved message during decryption is of correct length.
So the question is - what are we doing wrong? is there some way to decrypt with ciphertexts that are shorter than the key? Or are they messing up somewhere by producing ciphers that are too short?
Thanks for any help.
In AES-ECB, the only valid ciphertext shorter than 16-byte is empty. That 16-byte limit is the block (not key) size of AES, which happens to match the key size for AES-128.
Therefore, the question's
An example message we receive is: d3 73 4c
does not show an ECB encrypted message (since a comment tells that's from a JSON, that can't be bytes that happen to show as hex). And that's way too short to be a FRMPayload (per this comment) for a Join-Accept, since the spec says of the later:
1625 The message is either 16 or 32 bytes long.
Could it be that whatever that JSON message contains is not a full FRMPayload, but a fragment of a packet, encoded as hexadecimal pair with space separator? As long as it is not figured out how to build a FRMPayload, there's not point in deciphering it.
Update: If that mystery message is always 3 bytes, and if it is always the same for a given key (or available a single time per key), then per Maarten Bodewes's comment it might be a Key Check Value. The KCV is often the first 3 bytes of the encryption of the all-zero value with the key per the raw block cipher (equivalently: per ECB). Herbert Hanewinkel's javascript AES can work fully offline (which is necessary to not expose the key), and be used to manually validate an hypothesis. It tells that for the 16-byte key given in the question, a KCV would be cd15e1 (or c076fc per the variant in the next section).
Also: it is used CreateDecryptor to craft a gizmo in charge of the ECB decryption. That's likely incorrect in the context of decryption of a LoraWan payload, which requires ECB encryption for decryption of some fields:
1626 Note: AES decrypt operation in ECB mode is used to encrypt the join-accept message so that the end-device can use an AES encrypt operation to decrypt the message. This way an end device only has to implement AES encrypt but not AES decrypt.
In the context of decryption of a LoraWan packets, you want to communicate with the AES engine using byte arrays, not strings. Strings have an encoding, when LoraWan ciphertext and corresponding plaintext does not. Others seems to have managed to coerce the nice .NET do-it-all crypto API to get a low-level job done.
In the HextoString code, I vaguely get that the intention and perhaps outcome is that hex becomes the originally hex input as a byte array (fully rid of hexadecimal and other encoding sin; in which case the variable hex should be renamed to something on the tune of pure_bytes). But then I'm at loss about System.Text.Encoding.ASCII.GetString(hex). I'd be surprised if it just created a byte string from a byte array, or turned the key back to hexadecimal for later feeding to HexStringToByteArray in Aes128Decrypt. Plus this makes me fear that any byte in [0x80..0xFF] might turn to 0x3F, which is not nice for key, ciphertext, and corresponding LoraWan payload. These have no character encoding when de-hexified.
My conclusion is that if HexStringToByteArray does what its name suggests, and given the current interface of Aes128Decrypt, HextoString should simply remove whitespace (or is unneeded if HexStringToByteArray removes whitespace on the fly). But my recommendation is to change the interface to use byte arrays, not strings (see previous section).
As an aside: creating an ICryptoTransform object from its key is supposed to be performed once for multiple uses of the object.
As the title says, I am trying to decrypt DUKPT encrypted track data coming from a DUKPT enabled scanner.
I have the ANSI Standard (X9.24) for DUKPT and have successfully implemented the ability to generate the IPEK from the KSN and BDK. Furthermore, I have successfully implemented the ability to generate the Left and Right MAC Request and Response Keys by XORing the PIN Encryption Keys. Lastly, I am able to generate the EPB.
From here, I don't understand how to generate the MAC Request and Response from the L/R Keys that I have generated.
Lastly, once I get to that step, what comes next? When do I actually have the key that decrypts the track data sent by a DUKPT enabled device?
I am aware of the Thales Simulator and jPOS. My code is currently referencing the Thales Simulator to do all of its work. But, the file decryption process just isn't returning the expected data.
If anybody can offer some insight into decrypting track data, it would be much appreciated.
http://thalessim.codeplex.com/
http://jpos.org/
I spent too much time studying the horrible X9.24 spec and finally got both the encryption and decryption working with my vendor’s examples and marketing promptly decided to switch vendors. Since it is a standard, you would think that anybody’s implementation would be the same. I wish. Anyway, there are variations on how things are implemented. You have to study the fine print to make sure you are working things the same as your other side.
But that is not your question.
First if you need to decrypt a data track from a credit card, you are probably interested in producing a key that will decrypt the data based upon the original super secret Base Derivation Key. That has nothing to do with the MAC generation and is only mentioned in passing in that dreadful spec. You need to generate the IPEK for that key serial number and device ID and repeatedly apply the “Non-reversible Key Generation Process” from the spec if bits are set in the counter part of the full key serial number from the HSM.
That part of my code looks like this: (Sorry for the long listing in a posting.)
/*
* Bit "zero" set (this is a 21 bit register)(ANSI counts from the left)
* This will be used to test each bit of the encryption counter
* to decide when to find another key.
*/
testBit=0x00100000;
/*
* We have to "encrypt" the IPEK repeatedly to find the current key
* (See Section A.3). Each time we encrypt (generate a new key),
* we need to use the all prior bits to the left of the current bit.
* The Spec says we will have a maximum of ten bits set at any time
* so we should not have to generate more than ten keys to find the
* current encryption key.
*/
cumBits=0;
/*
* For each of the 21 possible key bits,
* if it is set, we need to OR that bit into the cumulative bit
* variable and set that as the KSN count and "encrypt" again.
* The encryption we are using the goofy ANSI Key Generation
* subroutine from page 50.
*/
for(int ii=0; ii<21; ii++)
{
if( (keyNumber&testBit) != 0)
{
char ksr[10];
char eightByte[8]={0};
cumBits |= testBit;
ksn.count=cumBits; /* all bits processed to date */
memcpy(ksr, &ksn,10); /* copy bit structure to char array*/
memcpy(crypt,&ksr[2],8); /* copy bytes 2 through 9 */
/*
* Generate the new Key overwriting the old.
* This will apply the "Non-reversible Key Generation Process"
* to the lower 64 bits of the KSN.
*/
keyGen(&key, &crypt, &key);
}
testBit>>=1;
}
Where
keyNumber is the current counter from the ksn
ksn is an 80 bit structure that contains the 80 bit Key Serial Number from the HSM
crypt is a 64 bit block of data I have it of type DES_cblock since I am using openSSL.
key is a 128 bit double DES_cblock structure.
The keyGen routine is almost verbatim from the “Non-reversible Key Generation Process” local subroutine on page 50 of the spec.
At the end of this, the key variable will contain the key that can be used for the decryption, almost. The dudes that wrote the spec added some “variant” behavior to the key to keep us on our toes. If the key is to be used for decrypting a data stream such as a credit card track, you will need to XOR bytes 5 and 13 with 0xFF and Triple DES encrypt the key with itself (ECB mode). My code looks like:
DOUBLE_KEY keyCopy;
char *p;
p=(char*)&key;
p[ 5]^=0xff;
p[13]^=0xff;
keyCopy=key;
des3(&keyCopy, (DES_cblock *)&key.left, &key.left);
des3(&keyCopy, (DES_cblock *)&key.right, &key.right);
If you are using this to decrypt a PIN block, you will need to XOR bytes 7 and 15 with 0xFF. (I am not 100% sure this should not be applied for the stream mode as well but my vendor is leaving it out.)
If it is a PIN block, it will be encrypted with 3-DES in ECB mode. If it is a data stream, it will be encrypted in CBC mode with a zero initialization vector.
(Did I mention I don’t much care for the spec?) It is interesting to note that the encryption side could be used in a non-hardware, tamper resistant security module if the server side (above) remembers and rejects keys that have been used previously. The technology is pretty neat. The ANSI spec leaves something to be desired but the technology is all right.
Good luck.
/Bob Bryan
For data encryption, the variant is 0000000000FF0000.0000000000FF0000 so you need to XOR bytes 5 and 13 instead of 7 and 15. In addition, you need an additional 3DES self-encryption step of each key parts (left and right).
Here is the relevant code in jPOS
https://github.com/jpos/jPOS/blob/master/jpos/src/main/java/org/jpos/security/jceadapter/JCESecurityModule.java#L1843-1856