Here is the function, with variable names in place
encrypt(arguments.input, key, algorithm, encoding, arguments.salt, iterations)
I'm using a 256 bit AES key which is 44 characters long.
I am choosing AES and base64 for Algorithm and Encoding.
I've tried various ways of generating a salt,
createUUID(), generatesecretkey('AES',128) and generatesecretkey('AES',256)
The encrypted result is always the same with the same input, when the salt changes each time. Like it's ignoring it, there is no error to suggest why.
I also note, iterations has no effect on the encryption either.
The algorithm "AES" is actually shorthand for "AES/ECB/PKCS5Padding" (ie algorithm/mode/padding). When using the default ECB mode, the iv will be ignored. Use the longhand algorithm form to specify CBC mode, ie "AES/CBC/PKCS5Padding"
Runnable Example on Trycf.com:
<cfscript>
for (i = 1; i <= 5; i++) {
key = "ji3fd0ZKB87COPz5ZwqsQEQKcuRggtvvO98t3mZFxns=";
// generate different iv's for DEMO only
uuid = CreateUUID();
iv = BinaryDecode( replace(uuid, "-", "", "all"), "hex");
input = "This is plain text to be encrypted";
encoding = "base64";
algorithm = "AES/CBC/PKCS5Padding";
encrypted = encrypt(input, key, algorithm, encoding, iv);
decrypted = decrypt(encrypted, key, algorithm, encoding, iv);
writeOutput("<hr>["& i &"] encrypted="& encrypted );
writeOutput("<br>["& i &"] decrypted="& decrypted );
writeOutput("<br>["& i &"] iv="& uuid );
}
</cfscript>
Note: To use larger keys, like 256bit, you must first have installed the (JCE) Unlimited Strength Jurisdiction Policy Files
AES only supports three key lengths, 16, 24 and 32 bytes. Note that 44 characters is 352-bits which is none of these. But it appears that the encrypt method expects a Base64 encoded string as the key so a 44 character Base64 key would seems to be correct. The documentation does not detail the key form.
Also note that the iv (arguments.salt) must be exactly one block in size, for AES that is 16-bytes.
See Encrypt for more information.
For more help please supply the encrypt arguments and the result.
Related
I implemented AES 128 bit encryption using initialization vector and padding, as seen in the code below. I happen to be using ColdFusion, but I don’t think that matters. The encrypted result shows some repeating patterns, which I would not have expected, but then again I don't know the characteristics of correct output for this. Am I doing initialization vector and padding correctly?
<!---
To encrypt this, for example:
"String1"
Prefix the string with an Initialization Vector of 16 random characters,
plus enough padding ("000000001") to make the entire string a multiple of 16 characters (32 characters, here)
"HoMoz4yT0+WAU7CX000000001String1"
Now encrypt the string to this (64 characters):
"Bn0k3q9aGJt91nWNA0xun6va8t8+OiJVmCqv0RzUzPWFyT4jUMzZ56pG5uFt6bGG"
--->
<cfoutput>
<cfset EncryptKey="LpEecqQe3OderPakcZeMcw==">
<cfloop index="StringToEncrypt" list="String1,String2,String3,String3">
<!--- Make random Initialization Vector (IV) of length 16
(create it from GenerateSecretKey(), but GenerateSecretKey is NOT the key that we encrypt/decrypt with) --->
<cfset IV=left(GenerateSecretKey("AES",128),16)>
<!--- Pad the string so its length is a multiple of 16 --->
<cfset padlength=16 - (len(StringToEncrypt) mod 16)>
<cfset padding=repeatstring("0",padlength-1) & "1">
<cfset NewStringToEncrypt=IV & padding & StringToEncrypt>
<cfset EncryptedString=encrypt(NewStringToEncrypt,EncryptKey,"AES","Base64")>
<pre>Original string: #StringToEncrypt#
StringToEncrypt: #NewStringToEncrypt#
EncryptedString: #EncryptedString#</pre>
</cfloop>
</cfoutput>
Below is sample output:
Original string: String1
StringToEncrypt: QLkApY6XKka7mQge000000001String1
EncryptedString: BOAVeSKidQyyHrEa15x9Uava8t8+OiJVmCqv0RzUzPWFyT4jUMzZ56pG5uFt6bGG
Original string: String2
StringToEncrypt: DboCmHHuVrU05oTV000000001String2
EncryptedString: 4Yk14F0ffz9+djbvSiwA1/X3FHhS5Vhta7Q8iocBPhmFyT4jUMzZ56pG5uFt6bGG
Original string: String3
StringToEncrypt: 8om5VbbWQgvRWK7Q000000001String3
EncryptedString: 01AF+pmF9sDsUHcIXSVfom8Egv8Oiyb2yy12hiVcJjqFyT4jUMzZ56pG5uFt6bGG
Original string: String3
StringToEncrypt: T4qJodVe6aEv0p1E000000001String3
EncryptedString: aAjCbSBRZ+cd7ZwpFPZUxW8Egv8Oiyb2yy12hiVcJjqFyT4jUMzZ56pG5uFt6bGG
Each EncryptedString ends with the same 21 characters:
FyT4jUMzZ56pG5uFt6bGG
When the original string is the same ("String3" in the 3rd and 4th example), the EncryptedString ends with the same 42 characters:
8Egv8Oiyb2yy12hiVcJjqFyT4jUMzZ56pG5uFt6bGG
Update: Per the accepted answer, I should not do my own padding or initialization vector. Coldfusion's encrypt/decrypt functions can handle that automatically, and the encrypted values will have no repeating patterns. For example:
EncryptedString=encrypt(StringToEncrypt, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64')
DecryptedString=decrypt(EncryptedString, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64')
Do not do your own padding, but let the encrypt function do it. It's appended to the plaintext, not prepended. The usual padding is called PKCS5 padding and adds $t$ times the byte $t \in {1,2,3,\ldots,16}$ to make up full blocks.
Also, the iv is an argument to the encrypt function and not prepended before the plaintext. It's actually (when you use a chain-mode like CBC, OFB, CFB) prepended to the ciphertext.
So you could generate the IV as you do (though there are probably better functions to do it) and then use the plaintext as is and encrypt:
EncryptedString=encrypt(StringToEncrypt, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64', binaryDecode(IV, "base64"))
(based on this documentation)
added 2
The iv should be binary according to these docs, so the base64 from generateKey has to be converted. Thx to comments by #Agax and his "cftry" examples...
added 1 It turns out that omitting the IV will cause the function
to generate its own IV, and in a seemingly non-repeating way.
In any case we can use
EncryptedString=encrypt(StringToEncrypt, EncryptKey, 'AES/CBC/PKCS5Padding', 'Base64')
instead. It's essential to use a chaining mode like CBC to get the propagation effect from a random IV that masks identical plaintexts and which the default 'AES' leaves visible (this does ECB mode, presumably).
The IV is actually not prepended to the ciphertext, when we give it as an argument, so you have to remember it somehow to be able to decrypt the first block of plain text. Quite non-standard. When you let encrypt generate it itself, it does prepend it. So you have to use the same signature version of decrypt.
A possible reason for this is that the mode of AES you are using doesnt use the previous block with the current block before encrypting the current block.
For example, CBC mode performs an XOR with the previous block cipher text and the current block plaintext before encrypting the current block. This means that even with the same string ("string3") and same key, a different IV will yield a completely different result, and there will never be string repetition.
Other modes of AES that use XORs include: CBC, PCBC, OFB, CFB. This link describes the different modes of AES in more detail (under the "common modes" section).
Thank you for your help.
I have a problem with sjcl library or cryptojs aes library.
Everytime i encrypt my file with aes the file size is * 2.
For example: When i upload a 4mb file then there is a 8mb file on my server.
I split the file on block which bytesize can be divided by 16.
Please help me
This is the way i encrypt the file:
var l_EncryptetData = CryptoJS.AES.encrypt(p_ChunkData, p_FileKey).toString();
And this is a example array with block sizes from the 4mb file:
0: 1572864
1: 1572864
2: 867005
length: 3
And the FileKey is a SHA-256 Hash
You are converting the cipher output (a CipherParams object) to a character string. By default, CryptoJS does this by representing the result in hexadecimal, where each byte is encoded as two hex digits. You can override this behavior by providing a custom format strategy. Or better yet, don't convert the cipher text to a character string; keep it as binary data.
Please warn users of your application that it is not secure.
My company is working on a project that will put card readers in the field. The readers use DUKPT TripleDES encryption, so we will need to develop software that will decrypt the card data on our servers.
I have just started to scratch the surface on this one, but I find myself stuck on a seemingly simple problem... In trying to generate the IPEK (the first step to recreating the symmetric key).
The IPEK's a 16 byte hex value created by concatenating two triple DES encrypted 8 byte hex strings.
I have tried ECB and CBC (zeros for IV) modes with and without padding, but the result of each individual encoding is always 16 bytes or more (2 or more blocks) when I need a result that's the same size as the input. In fact, throughout this process, the cyphertexts should be the same size as the plaintexts being encoded.
<cfset x = encrypt("FFFF9876543210E0",binaryEncode(binaryDecode("0123456789ABCDEFFEDCBA98765432100123456789ABCDEF", "hex"), "base64") ,"DESEDE/CBC/PKCS5Padding","hex",BinaryDecode("0000000000000000","hex"))>
Result: 3C65DEC44CC216A686B2481BECE788D197F730A72D4A8CDD
If you use the NoPadding flag, the result is:
3C65DEC44CC216A686B2481BECE788D1
I have also tried encoding the plaintext hex message as base64 (as the key is). In the example above that returns a result of:
DE5BCC68EB1B2E14CEC35EB22AF04EFC.
If you do the same, except using the NoPadding flag, it errors with "Input length not multiple of 8 bytes."
I am new to cryptography, so hopefully I'm making some kind of very basic error here. Why are the ciphertexts generated by these block cipher algorithms not the same lengths as the plaintext messages?
For a little more background, as a "work through it" exercise, I have been trying to replicate the work laid out here:
https://www.parthenonsoftware.com/blog/how-to-decrypt-magnetic-stripe-scanner-data-with-dukpt/
I'm not sure if it is related and it may not be the answer you are looking for, but I spent some time testing bug ID 3842326. When using different attributes CF is handling seed and salt differently under the hood. For example if you pass in a variable as the string to encrypt rather than a constant (hard coded string in the function call) the resultant string changes every time. That probably indicates different method signatures - in your example with one flag vs another flag you are seeing something similar.
Adobe's response is, given that the resulting string can be unecrypted in either case this is not really a bug - more of a behavior to note. Can your resultant string be unencrypted?
The problem is encrypt() expects the input to be a UTF-8 string. So you are actually encrypting the literal characters F-F-F-F-9.... rather than the value of that string when decoded as hexadecimal.
Instead, you need to decode the hex string into binary, then use the encryptBinary() function. (Note, I did not see an iv mentioned in the link, so my guess is they are using ECB mode, not CBC.) Since the function also returns binary, use binaryEncode to convert the result to a more friendly hex string.
Edit: Switching to ECB + "NoPadding" yields the desired result:
ksnInHex = "FFFF9876543210E0";
bdkInHex = "0123456789ABCDEFFEDCBA98765432100123456789ABCDEF";
ksnBytes = binaryDecode(ksnInHex, "hex");
bdkBase64 = binaryEncode(binaryDecode(bdkInHex, "hex"), "base64");
bytes = encryptBinary(ksnBytes, bdkBase64, "DESEDE/ECB/NoPadding");
leftRegister = binaryEncode(bytes, "hex");
... which produces:
6AC292FAA1315B4D
In order to do this we want to start with our original 16 byte BDK
... and XOR it with the following mask ....
Unfortunately, most of the CF math functions are limited to 32 bit integers. So you probably cannot do that next step using native CF functions alone. One option is to use java's BigInteger class. Create a large integer from the hex strings and use the xor() method to apply the mask. Finally, use the toString(radix) method to return the result as a hex string:
bdkText ="0123456789ABCDEFFEDCBA9876543210";
maskText = "C0C0C0C000000000C0C0C0C000000000";
// use radix=16 to create integers from the hex strings
bdk = createObject("java", "java.math.BigInteger").init(bdkText, 16);
mask = createObject("java", "java.math.BigInteger").init(maskText, 16);
// apply the mask and convert the result to hex (upper case)
newKeyHex = ucase( bdk.xor(mask).toString(16) );
WriteOutput("<br>newKey="& newKeyHex);
writeOutput("<br>expected=C1E385A789ABCDEF3E1C7A5876543210");
That should be enough to get you back on track. Given some of CF's limitations here, java would be a better fit IMO. If you are comfortable with it, you could write a small java class and invoke that from CF instead.
I am encoding strings using C#'s Rijndael AES encryption. I generate a key and an IV, and use them to encode strings and values that I can then save to disk (I am using Unity3D's playerprefs).
The problem I am facing is that the PlayerPrefs keys and values need to be valid character sequences, and the encoded bytes are not necessarily valid.
So, after encoding my string with my key and IV, I get a byte array that I can enode in Unicode, but (sometimes) when I try to save it, I get an error message:
byte[] encryptedBytes = Encode("someText", encryptionKey, initVector);
string encodedString = Encoding.Unicode.GetString(encryptedBytes);
PlayerPrefs.SetString("SecretData",encodedString);
PlayerPrefs.Save();
Error:
invalid utf-16 sequence at -1073752512 (missing surrogate tail)
Any way to make sure the string is in a valid format?
The bytes returned by the encrypt function are indistinguishable from random and may not contain valid character encoding. To convert the result into a string (if required) you may use base 64.
I want to use PKCS#7 as a container format for some encrypted, signed content and we need to use AES in CBC mode with ISO 10126 based padding. I can't seem to find a concrete reference to an algorithm identifier to use for this combination. I can invent my own but would then lose interoperability with other tools.
The padding mode does not need to be specified. This is true because PKCS#7 (like many other cryptographic containers) uses ASN.1/BER encoding. As the BER encoding contains the exact length of the message inside the padded plain text, the actual value of the padding doesn't matter.
It turns out that the padding mode does not need to be specified, only the crypto algorithm matters.
I believe if you are using PKCS#7 as your format, the padding is dictated to be, well, "PKCS7" padding (n octets of value 'n', see RFC 2315, section 10.3.2).
The algorithm identifier(s) for AES/CBC are given in e.g. RFC 3565:
-- AES information object identifiers --
aes OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840)
organization(1) gov(101) csor(3)_ nistAlgorithms(4) 1 }
-- AES using CBC-chaining mode for key sizes of 128, 192, 256
id-aes128-CBC OBJECT IDENTIFIER ::= { aes 2 }
id-aes192-CBC OBJECT IDENTIFIER ::= { aes 22 }
id-aes256-CBC OBJECT IDENTIFIER ::= { aes 42 }
So, e.g. the OID for 128-bit AES in CBC mode is 2.16.840.1.101.3.4.1.2
Technically, these are for CMS, which is essentially the updated PKCS#7.