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.
Related
I am struggling for an entire week now, failing at meeting the encryption requirements of HERE traffic api, precisely TPEG API.
Steps to do:
<?xml version="1.0" encoding="UTF-8" ?>
<get-messages>
<locations>
<loc lat="52.55121" lon="13.16565"/>
</locations>
</get-messages>
This xml body must be enrypted, HERE API documents it as follows:
Encrypt and compress all traffic information requests:
Compress the XML body using gzip.
Calculate the length in bytes of the gzip file.
Prepend the length of the gzipped data to the compressed body as a little endian 32 bit integer.
Pad the combination of gziped content and length with zeros to make it evenly divisible by 16 bytes.
Using AES 128, encrypt the resultant padded combination of content and length as follows:
a) Create a random integer 16 bytes long.
b) AES encrypt the result of step 4, in mode CBC using the integer generated in step 5.a as the initialization vector and the key from the InitSession response. Do not apply additional padding.
Send the resulting block of AES encrypted data as an HTTP POST request, prepended by the integer generated in step 5.a as content type application/octet-stream to the URL in the initsession response
So many things are just unclear here, what is the desired result of the gziped xml? Base64? binary?
What is the type of the 32 little endian int, binary?
The key has a length of 32 characters. Since AES128 only fits 16 bytes long keys, I assume the key must be interpreted as hex values. Do all values need to be defined as hex values?
What is the type of the IV? Hex? Text? Binary?
What is the type of the encrypted result? Hex? Binary? Text? Base64?
The http header must contain content_type appilcation/octet-stream.
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).
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.
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.
How do I reversibly (symmetrically) encrypt a filename (with or
without directory path, I'm OK w/ either) so that the result is also a
valid filename (less than 64 characters [or whatever the limit is], no
funny characters, ideally no spaces [but not a requirement], etc)?
Googling finds only filename encryption algorithms where the result is
a long string of binary characters (using MIME64, converting to
non-binary is easy, but this just makes the filename longer) and/or
non-symmetric one-way encrption schemes (eg, salted MD5, SHA1, DES,
etc). I don't want to store a table of hashes: I want to decrypt the
filename with a simple key I've memorized.
My own attempts with things like "mcrypt -b" failed too: the resulting
output (even before converting to ASCII) grows in size very rapidly as
the filename and key length increase.
Reasoning: I plan to use an "infinite backup" service (like mozy,
blazebackup, etc), but none encrypt filenames (just file
content). I'll create a directory that consists of encrypted filenames
with symlinks (or even hard links) to the real file. I'll back up only
that directory (and choose my own private key), and have
filename-encrypted and filecontent-encrypted backups.
EDIT: Petey's method worked like a charm!
# "-b 512" yields "Bits has bad value 512 (too small)"
ssh-keygen -t rsa -b 768 -f /tmp/test.rsa
echo "thisisareallylongfilenameknightswhosayniioratleastusedto" |\
openssl rsautl -inkey /tmp/test.rsa -encrypt | base64 |\
perl -0777 -pnle 's/\//-/isg;s/\n//isg'
yields a 130 character result that should always be a filename!
You could use an RSA key pair to do this. Generate an rsa key pair plus certificate, then import that into your cert store. Use the public key to encrypt your file name, then base64 encode the result. The maximum file name length for ntfs is 255 characters, so a 1024 bit RSA key should be fine, if you need shorter file names, use a 512 bit key. When you want to decrypt the file name: base64 decode the encrypted file name, then use the private key to decrypt back to the actual file name.
Not sure if there is any freeware available to do this. If you don't want to write the program yourself, I'll do it in .Net for you (for a small fee ;).
How strong do you need your encryption to be? You could use one of the classical alphabet based cyphers, such as Vigenère which will produce strictly alphabetical output, though it won't handle non-alphanumeric characters well if you want a valid filename as output. The result will still have "/" and "." where they were before.
If you are very concerned about security, it's worth noting that high entropy filenames may get more attention than just "file000001", ... "fileNNNNNNN". A separate file that maps from fileNNNN to the correct name can be encrypted separately and stored in duplicate in multiple locations. Both methods leak zero information about the original filenames. Alternatively, you could add a short header to every unencrypted file that encrypts the filename, thereby dispensing with a separate index.
What's more, the ability to do error detection of corrupted filenames is easier when the list of names is both known and in a pre-determined order.
[Posting as CW, because this is really more of a comment than an answer.]