So, I got this problem and I have no clue how to solve it.
I have an RSA private key with a part of it censored.
$ cat key.pem
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDGlcensoredcensoredcensoredcensored1TUxhnjkCbowxZc
7PIpI1E2Po6aIgCBd9+6i0NUIfYm8vR6kqiqLz8k8o4LYoBkq/9Jx7pgV2Jqhr4u
wvlaQQUzi9c4qPKXp+QGoUu9f1zp8ORIMpeJmF7uA20DC93uba07qdC6twIDAQAB
AoGBAIovDuYnGiiQS6K27L4EY8e/5sbqAwdlTOVlWsfz+ai3DLNiFPSbbT1Wx9G4
4b06X6O258SD1suZ/g/ICnmnxxe5ua3a5+iiDIwGYmBDcNfq5gMq/d+1/UJF/Bb4
A1nuH2iUg6gRTPEpbg2+RYwquyWenFbqfHMgXqbHVGmOXj7hAkEA8rChKjs5zVmd
j9Gk53psry4CtuxRc39NrHuLqat9Iu0MA51Sgv4c+8dgo75DVAnT5PoLBhHJJAVa
e+rUMC4kfwJBANF7jcKzJ2UuPmL6JpbWcyirybjMIm2eCxR5U1bYlNYT+A49oOFS
Eg5woswgCyH9gDPk2Zwpq3qud9HD7Rn0bckCQQDHgwdrRXc2ZybN1eZAWffBaAzZ
PpuTXKOJWaOuX4mnTcLjsdDkWW2QWw8Kbd7B1rZ49kpbugFmeHQzjRDVbwmXAkBm
T3nFBcrP1+4QWSxPrx0/V+eFoe2OrAmtTjQtzkmi5M3Z5q+UXIkFFG3uVBgb2bur
nLHLW26s1Fkg0hgS/RZBAkAFnE+7QvRCW4+v3OsIkN63f+GIjHfCuv8L15RpBLlf
XXQyOmmu8YekTu5vbFHtSAiLyuW1yCeSsNmKYkX6Ew99
-----END RSA PRIVATE KEY-----
As you can see, the first part line is partially censored. The task is yo decrypt this message:
Qe7+h9OPQ7PN9CmF0ZOmD32fwpJotrUL67zxdRvhBn2U3fDtoz4iUGRXNOxwUXdJ2Cmz7zjS0DE8
ST5dozBysByz/u1H//iAN+QeGlFVaS1Ee5a/TZilrTCbGPWxfNY4vRXHP6CB82QxhMjQ7/x90/+J
LrhdAO99lvmdNetGZjY=
My first guess would be to bruteforce the part missing, but that doesn't seem realistic to do.
Anyone know if this is even possible? And if so how would you go about to do it?
The key is 824 characters long and the censored part is 32 character, however I do not know if each character of the censoring corresponds to one in the private key...
You can solve this using an online ASN.1 parser (or openssl asn1parse), where you will find out that the base 64 string - the text in the middle, between the lines starting with --- - is an ASN.1 encoding of the private key. The second element within the SEQUENCE - which has been altered - contains the modulus, not the private exponent. The structure is defined in PKCS#1, which is a rather readable standard, also copied in RFC 3447
The modulus is normally public, but if you haven't got the public key, you can still recreate it:
How to factor RSA modulus given the public and private exponent?
Related
I try to encrypt files in Laravel5.7
$encryptedContent = encrypt($fileContent);
worked for encrypt the files.
$decryptedContent = base64_encode(decrypt($encryptedContent));
worked for decrypt.
My problem is I need to use different keys for different user for encrypt the files and decrypt.
I tried the following way.
$crypt = new \Illuminate\Encryption\Encrypter($newkey);
$encryptedContent = $crypt->encrypt($fileContent);
But it gives following error.
The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths
Can anyone please help me?
Thanks.
The problem was with key length.
If we use AES-128-CBC key should be 16 character length and AES-256-CBC 32 character length.
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 am encrypting the plain text using RSA and converting that value to base64 string.But while decrypting the I altered the base64 string and try to decrypt it...it given me same original text return.
Is there any thing wrong ?
Original Plain Text :007189562312
Output Base64 string : VfZN7WXwVz7Rrxb+W08u9F0N9Yt52DUnfCOrF6eltK3tzUUYw7KgvY3C8c+XER5nk6yfQFI9qChAes/czWOjKzIRMUTgGPjPPBfAwUjCv4Acodg7F0+EwPkdnV7Pu7jmQtp4IMgGaNpZpt33DgV5AJYj3Uze0A3w7wSQ6/tIgL4=
Altered Base64 String : VfZN7WXwVz7Rrxb+W08u9F0N9Yt52DUnfCOrF6eltK3tzUUYw7KgvY3C8c+XER5nk6yfQFI9qChAes/czWOjKzIRMUTgGPjPPBfAwUjCv4Acodg7F0+EwPkdnV7Pu7jmQtp4IMgGaNpZpt33DgV5AJYj3Uze0A3w7wSQ6/tIgL4=55
Please explain. Thank you.
I'm assuming you're asking whether the altered ciphertext should have thrown an error when decrypting. It looks like the altered string only adds two characters to the end and is otherwise the same string.
Your Base 64 library probably makes some reasonable assumptions when parsing Base 64 data. Base 64 works by encoding 3 bytes into 4 characters. If at the end the data length is not a multiple of 3 it must be padded. That is signalized by the = at the end of the encoded string.
This also means that during parsing, the library knows that padding characters are at the end and stops parsing there. If the alteration appeared at the end of the string then the encoded ciphertext didn't effectively change.
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.]