Suppose I'm encrypting a data string:
DATA: "This is my data!" (hex 54686973206973206d79206461746121)
with a key:
KEY: "This is my key!!" (hex 54686973206973206d79206b65792121)
Using AES-128 I will get this result (in hex):
RESULT: 425acf4117829a37be386995408ba1a9
Now, suppose that some one gets the DATA and RESULT strings. Is it possible to calculate the KEY with this information?
Thank you very much!!!
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).
i'm trying to find out the key of a xor encryption but something seems be wrong.
the ecrypted file begins with this hex string:
78DF2B983C9428942894892CD8D6CFF4F8942895289428952894319428949BFD8F0289089D068DC556C458C25D94289428942894289428942894289428942894289428942894289C289428942894289428942894289428942894289428942894289428942894289428942894289428942894289428942894289428942894289428942894289428942894289428942894..
i know this is a zip comressed file. the zip header structure is something like:
504B0304140000000800CC898C459C47ECC9DA8350002DC06400120000003937373048442D56312E30302E352E676E78 (https://users.cs.jmu.edu/buchhofp/forensics/formats/pkzip.html)
the first 4 bytes of a zip header is always the signature:
504B0304, after xor this with the ecrypted hex, i get: 2894289c
but 2894289c seems to be wrong, why? look at the encrypted hex string..
there's lot of '2894' hex values in the content..these must be decrypted '0000', so is '2894' the right key?
now, i xor the encrypted zip header signature with the key '2894'
78DF2B98 xor 28942894 => 504b030c
pretty strange, because the last hex value is '0c' but it must be '04'!
what is my fault?
(sorry for my english)
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 know I can use GUID to generate a unique string, but it's too long.
Now I only need generate un-duplicate string within an website, how can I do? Thanks!
For example: In the website http://mathurl.com/, you can generate a permanent URL, such as http://mathurl.com/75ujy7b and 75ujy7b is very short and un-duplicate.
First of all you can start with a counter that you make sure using Mutex/lock that return unique incremental numbers, and you save the last number somewhere on your site, maybe in web.config, maybe in database, or in a file.
Then you convert this unique number to a different base number, eg to a base-64. Here is some code, and mode details on how you can do that
https://stackoverflow.com/a/5901201/159270
And you can get results like
value: 0 encoded: A
value: 1 encoded: B
value: 9999999999 encoded: SrYsNt
value: 4294965286 encoded: ZNGEvT
value: 2292964213 encoded: rHd24J
value: 1000000000 encoded: TrNVzD
Now, if you scramble the map on the characters you can also make a not so easy to find number.
you can use a random number of sufficient length.. between lets say 10,000 and 99,999..
if that aint good enough for you, you could look into some hashing algorithms.. i think..
I was looking at a video game's xml prefrences document and it had this as one of its nodes
< shop_vehicle >
KEYxLjAKUydtZWRpdW1UYW5rJwpwMApTJ2luSGFuZ2FyJwpwMQp0cDIKLg==
< /shop_vehicle >
I am assuming that is some sort of hashed value, but I was curious if the "KEY" at the beginning or the == at the end ment anything, seeing as there are other nodes that start with the same value. If it does have some meaning would there be a way to decrypt this value?
here is another value
< inventory_shell > KEY0LjAKUydBUk1PUl9QSUVSQ0lORycKcDAKUydBUk1PUl9QSUVSQ0lOR19DUicKcDEKUydIT0xMT1dfQ0hBUkdFJwpwMgpTJ0hJR0hfRVhQTE9TSVZFJwpwMwpTJ215VmVoaWNsZUd1bicKcDQKUyIobHAwXG5jZ3VpLlNjYWxlZm9ybS51dGlscy5ndWlfaXRlbXNcbkludmVudG9yeVZlaGljbGVcbnAxXG5hKFMnIVxceDAyXFx4MDNcXHgwMFxceDA0XFx4MDBcXHhjOVxceDAwXFx4MDRcXHgwMFxceDA0XFx4MDBcXHgwNlxceDAwXFx4MDAnXG5wMlxuSTNcbihscDNcbkk2XG5hSTdcbmF0cDRcbmEuIgpwNQp0cDYKLg==
< /inventory_shell >
You cannot "decrypt" hashes - the defining property of a hash is that the only way to find a content whose hash that matches the given hash value is to brute-force-test all possible contents.
Fortunately, this isn't a hash, it's merely base64 (an encoding). In Python (or online):
>>> import base64
>>> s = b'KEYxLjAKUydtZWRpdW1UYW5rJwpwMApTJ2luSGFuZ2FyJwpwMQp0cDIKLg=='
>>> base64.b64decode(s)
"(F1.0\nS'mediumTank'\np0\nS'inHangar'\np1\ntp2\n."
On second thought, both values start with KEY, so it's likely the author of this format added some home-brewed encoding. Also, the content is not a plain string, but a binary data format.
It is just a Base64 encoded string. Use a tool like this one to decode it: http://www.opinionatedgeek.com/dotnet/tools/base64decode/