I am working on a ChromeApp. In this App, we need to render some HTML, JPEG, PDF files. But all these files are encrypted using AES-128-CBC encryption method. We need to decrypt html, jpeg, png and pdf files using AES-128-CBC method through JavaScript. I have tried below code to decrypt but it does not give expected output:
var ciphertext = '®0Ž.v£=p?°–æ£ËkRdKÓ”‹1Š"°?¥yAÈ_fëo e=Î} ú¿¯¢GE$iV×î’ÚÐøUJ²4Fœ‰=ÄQËÐ*R<Ã(ÕÎFÔ©—+Ùøä[„”Æ29ÿªSÆsi¬ôÓÆ#qÒÞãýñ?!ÉnÑZp²/öÇ~P‘/¿¡ç%í~Ô43]ÃÎG¾‹,+tPÜAàÛLkæ«œ‘ɳf ç·ržúž´J›Ãá¥u®ÞFNœüÊöeL´Jîn<jí<ô¡ îÚY¥N6B•#¬˜krXyëÑtL<ú^ñ!±®¤–ÆœŸÌÉ£R¹ŒPþ*´¬/ú4´š7®´SóOgªr‹©;ï^îìL5̩㎣¡ØÏÞµð’Òyí`d~Lq<I€©|Ñ%ÚSâå½n.»5|zFÔR_ÀèbeẎÇ&Ù3ìñjk¦®7';
function decryptPage()
{
var originalKey = 'SuGpNMqP;md,(%F{';
//var originalKey = '537547704e4d71503b6d642c2825467b';
key = CryptoJS.enc.Hex.parse(originalKey);
console.log(key);
var iv = CryptoJS.enc.Hex.parse(ciphertext.slice(0, 32));
var message = CryptoJS.AES.decrypt({
ciphertext: ciphertext
}, key, {
iv: iv
});
//console.log(hex2a(message.words));
console.log('message');
console.log(message.words);
}
decryptPage();
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/aes.js"></script>
Can anyone help me?
As has already been pointed out in the comments, it's usually a bad idea to encrypt/decrypt in JavaScript.
With that said, decrypting these kinds of files is, in principal, exactly the same as decrypting other kinds of files.
In terms of cryptography itself, the basic idea of symmetric-key algorithms like AES is that items are encrypted and decrypted using the same key (there are separate methods available for making sure that both parties can securely exchange the key, generally relying on public-key cryptography; see, for example, the Diffie-Hellman Key Exchange algorithm). Generally, decryption is more or less a reversal of the procedure used to encrypt in the first place.
The security of these algorithms rest in the secrecy of the key and the strength of the algorithm itself, not in the secrecy of the algorithm. So, for example, knowing the fact that you're encrypting and decrypting messages using AES is definitely not enough information for me to be able to recover the message content (unless I can also recover your key somehow, which is why it's important to store it in a secure manner, do all key exchanges securely, and rotate your keys periodically).
There are plenty of tutorials available on cryptography and encryption in general. For example, here's one below:
http://www.tutorialspoint.com/cryptography/
The Wikipedia articles on the topic are also pretty good.
Related
I am using node and the crypto module to encrypt and decrypt a large binary file. I encrypt the file using crypto.createCipheriv and decrypt it using crypto.createDecipheriv.
For the encryption I use a random IV as follows:
const iv = crypto.randomBytes(16);
const encrypt = crypto.createCipheriv('aes-128-cbc', key, iv)
What I don't understand, do I need to pass a random IV for createDecipheriv as well? The SO here says:
The IV needs to be identical for encryption and decryption.
Can the IV be static? And if it can't, is it considered to be a secret? Where would I store the IV? In the payload?
If I use different random IVs for the encryption and decryption, my payload gets decrypted but the first 16 bytes are corrupt. This means, it looks like the IV needs to be the same but from a security perspective there is also not much value as the payload is decrypted except 16 bytes.
Can anyone elaborate what the go-to approach is? Thanks for your help!
The Key+IV pair must never be duplicated on two encryptions using CBC. Doing so leaks information about the first block (in all cases), and is creates duplicate cipher texts (which is a problem if you ever encrypt the same message prefix twice).
So, if your key changes for every encryption, then your IV could be static. But no one does that. They have a key they reuse. So the IV must change.
There is no requirement that it be random. It just shouldn't repeat and it must not be predictable (in cases where the attacker can control the messages). Random is the easiest way to do that. Anything other than random requires a lot of specialized knowledge to get right, so use random.
Reusing a Key+IV pair in CBC weakens the security of the cipher, but does not destroy it, as in CTR. IV reused with CTR can lead to trivial decryptions. In CBC, it generally just leaks information. It's a serious problem, but it is not catastrophic. (Not all insecure configurations are created equal.)
The IV is not a secret. Everyone can know it. So it is typically prepended to the ciphertext.
For security reasons, the IV needs to be chosen to meet cryptographic randomness security requirements (i.e. use crypto.randomBytes( ) in node). This was shown in Phil Rogaway's research paper. The summary is in Figure 1.2 of the paper, which I transcribe here:
CBC (SP 800-38A): An IV-based encryption scheme, the mode is secure as a probabilistic encryption scheme, achieving indistinguishability from random bits, assuming a random IV. Confidentiality is not achieved if the IV is merely a nonce, nor if it is a nonce enciphered under the same key used by the scheme, as the standard incorrectly suggests to do.
The normal way to implement this is to include the IV prepended to the ciphertext. The receiving party extracts the IV and then decrypts the ciphertext. The IV is not a secret, instead it is just used to bring necessary security properties into the mode of operation.
However, be aware that encryption with CBC does not prevent people from tampering with the data. If an attacker fiddles with ciphertext bits within a block, it affects exactly two plaintext blocks, one of which is in a very controlled way.
To make a very long story short, GCM is a better mode to use to prevent such abuses. In that case, you do not need a random IV, but instead you must never let the IV repeat (in cryptography, we call this property a "nonce"). Luke Park gives an example of how to implement it, here. He uses randomness for the nonce, which achieves the nonce property for all practical purposes (unless you are encrypting 2^48 texts, which is crazy large).
But whatever mode you do, you must never repeat an IV for a given key, which is a very common mistake.
I have an AES-encrypted string ( out of a user backup of a discontinued App) that I want to decrypt.
What I have:
json file with:
Info that key was created with PBKDF2
salt
encrypted string
I do know the password, with which the backup was created, probably the password also for PBKDF2
Is there a way to find out with what parameters the string was encrypted? i.e, how the key was created
Is there an easy way to decrypt the string?
Fortunately, reverse engineering the encryption method and the way that the ciphertext (and possibly other information necessary for decryption) is stored in the file, is a lot easier than trying to crack the password that was used to derive the encryption key. Being that you know the password that the key was derived from, there may be hope.
Is the encrypted string from the json file encoded using an encoding method that you recognize, such as hexadecimal or base64? If so, then when you decode the encrypted string, is it exactly 128 bits?
If so, then the problem gets significantly simpler, because this means that it's only one block of AES encryption. This means that you don't have to worry about the encryption mode (e.g. CBC, GCM, ECB, CTR, etc), or the IV if it's a block cipher mode such as CBC.
In addition, if there is information in the json file about the inputs to the PBKDF2 function (e.g. number of iterations, and/or hash algorithm), this can be helpful.
In the end, it comes down to trial and error, where different values for the parameters that you don't know are tried, until the correct parameters to the PBKDF2 function are found, which produces the correct key, to decrypt the cipher text. This also requires that you know something about the plaintext, in order to know when the decryption was successful.
Of course, the more parameters that unknown, the more rounds of trial-and-error are necessary. If the number of rounds of trial and error are reasonable given an allotted amount of time and resources, then the process can be automated in a fashion similar to https://security.stackexchange.com/questions/226935/write-a-python-or-c-program-to-guess-the-key/226950#226950.
I have an existing set of Python code that uses the primitive (textbook) RSA encryption mechanism to encrypt small pieces of data. Specifically, the python code loads a public key into variable publickey and then encrypts this data using the following code:
ciphertext = publickey.encrypt(plaintext,None)
Yes I have read the disclaimer that "this function performs the plain, primitive RSA encryption (textbook). In real applications, you always need to use proper cryptographic padding,..." Unfortunately, I cannot change this code at the present time, so I am stuck with using this "textbook" encrypt command.
Note that even though this command does not use any padding scheme, it still seems to be able to encrypt any (appropriately small) amount of plaintext. In other words, the plaintext can be any length up to whatever limit is imposed by RSA.
Now however, I want to use the OPENSSL C library in an IOS app to do an identical RSA encryption. I cannot figure out how to do the exact same thing that the python function is doing. OPENSSL has a method RSA_public_encrypt where you pass in the size of the plaintext, the plaintext itself, an RSA object pointer which contains public key information, and the RSA padding mechanism. To replicate what python is doing in the crypto library, I thought I could use RSA_NO_PADDING as the padding mechanism. The problem is that OPENSSL states in their documentation that if you use RSA_NO_PADDING, then the length of the plaintext to encrypt must be EXACTLY equal to a certain value: RSA_Size(rsa) where rsa is a pointer to the RSA object passed in (the object that contains the public key).
In other words, the python crypto library seems to be able to encrypt variable length plaintext with no padding, but OPENSSL requires plaintext to be fixed length. So what exactly is the python crypto library doing to handle the variable size of the plaintext, and is there any way I can replicate this in OPENSSL?
If you look at the documentation for RSA_NO_PADDING, they explain:
This mode should only be used to implement cryptographically sound
padding modes in the application code. Encrypting user data directly
with RSA is insecure.
In other words, RSA_NO_PADDING is for cases where you're going to handle padding on your own, so OpenSSL expects an input of the proper size. It doesn't mean "textbook RSA".
Is there a compelling reason you can't change the python code? Textbook RSA is insecure and you're taking a great risk by using it.
For
`BDK = "0123456789ABCDEFFEDCBA9876543210"` `KSN = "FFFF9876543210E00008"`
The ciphertext generated was below
"C25C1D1197D31CAA87285D59A892047426D9182EC11353C051ADD6D0F072A6CB3436560B3071FC1FD11D9F7E74886742D9BEE0CFD1EA1064C213BB55278B2F12"`
which I found here. I know this cipher-text is based on BDK and KSN but how this 128 length cipher text was generated? What are steps involved in it or algorithm used for this? Could someone explain in simple steps. I found it hard to understand the documents I got while googled.
Regarding DUKPT , there are some explanations given on Wiki. If that doesn't suffice you, here goes some brief explanation.
Quoting http://www.maravis.com/library/derived-unique-key-per-transaction-dukpt/
What is DUKPT?
Derived Unique Key Per Transaction (DUKPT) is a key management scheme. It uses one time encryption keys that are derived from a secret master key that is shared by the entity (or device) that encrypts and the entity (or device) that decrypts the data.
Why DUKPT?
Any encryption algorithm is only as secure as its keys. The strongest algorithm is useless if the keys used to encrypt the data with the algorithm are not secure. This is like locking your door with the biggest and strongest lock, but if you hid the key under the doormat, the lock itself is useless. When we talk about encryption, we also need to keep in mind that the data has to be decrypted at the other end.
Typically, the weakest link in any encryption scheme is the sharing of the keys between the encrypting and decrypting parties. DUKPT is an attempt to ensure that both the parties can encrypt and decrypt data without having to pass the encryption/decryption keys around.
The Cryptographic Best Practices document that VISA has published also recommends the use of DUKPT for PCI DSS compliance.
How DUKPT Works
DUKPT uses one time keys that are generated for every transaction and then discarded. The advantage is that if one of these keys is compromised, only one transaction will be compromised. With DUKPT, the originating (say, a Pin Entry Device or PED) and the receiving (processor, gateway, etc) parties share a key. This key is not actually used for encryption. Instead, another one time key that is derived from this master key is used for encrypting and decrypting the data. It is important to note that the master key should not be recoverable from the derived one time key.
To decrypt data, the receiving end has to know which master key was used to generate the one time key. This means that the receiving end has to store and keep track of a master key for each device. This can be a lot of work for someone that supports a lot of devices. A better way is required to deal with this.
This is how it works in real-life: The receiver has a master key called the Base Derivation Key (BDK). The BDK is supposed to be secret and will never be shared with anyone. This key is used to generate keys called the Initial Pin Encryption Key (IPEK). From this a set of keys called Future Keys is generated and the IPEK discarded. Each of the Future keys is embedded into a PED by the device manufacturer, with whom these are shared. This additional derivation step means that the receiver does not have to keep track of each and every key that goes into the PEDs. They can be re-generated when required.
The receiver shares the Future keys with the PED manufacturer, who embeds one key into each PED. If one of these keys is compromised, the PED can be rekeyed with a new Future key that is derived from the BDK, since the BDK is still safe.
Encryption and Decryption
When data needs to be sent from the PED to the receiver, the Future key within that device is used to generate a one time key and then this key is used with an encryption algorithm to encrypt the data. This data is then sent to the receiver along with the Key Serial Number (KSN) which consists of the Device ID and the device transaction counter.
Based on the KSN, the receiver then generates the IPEK and from that generates the Future Key that was used by the device and then the actual key that was used to encrypt the data. With this key, the receiver will be able to decrypt the data.
Source
First, let me quote the complete sourcecode you linked and of which you provided only 3 lines...
require 'bundler/setup'
require 'test/unit'
require 'dukpt'
class DUKPT::DecrypterTest < Test::Unit::TestCase
def test_decrypt_track_data
bdk = "0123456789ABCDEFFEDCBA9876543210"
ksn = "FFFF9876543210E00008"
ciphertext = "C25C1D1197D31CAA87285D59A892047426D9182EC11353C051ADD6D0F072A6CB3436560B3071FC1FD11D9F7E74886742D9BEE0CFD1EA1064C213BB55278B2F12"
plaintext = "%B5452300551227189^HOGAN/PAUL ^08043210000000725000000?\x00\x00\x00\x00"
decrypter = DUKPT::Decrypter.new(bdk, "cbc")
assert_equal plaintext, decrypter.decrypt(ciphertext, ksn)
end
end
Now, you're asking is how the "ciphertext" was created...
Well, first thing we know is that it is based on "plaintext", which is used in the code to verify if decryption works.
The plaintext is 0-padded - which fits the encryption that is being tested by verifying decryption with this DecrypterTest TestCase.
Let's look at the encoding code then...
I found the related encryption code at https://github.com/Shopify/dukpt/blob/master/lib/dukpt/encryption.rb.
As the DecrypterTEst uses "cbc", it becomes apparent that the encrypting uses:
#cipher_type_des = "des-cbc"
#cipher_type_tdes = "des-ede-cbc"
A bit more down that encryption code, the following solves our quest for an answer:
ciphertext = des_encrypt(...
Which shows we're indeed looking at the result of a DES encryption.
Now, DES has a block size of 64 bits. That's (64/8=) 8 bytes binary, or - as the "ciphertext" is a hex-encoded text representation of the bytes - 16 chars hex.
The "ciphertext" is 128 hex chars long, which means it holds (128 hex chars/16 hex chars=) 8 DES blocks with each 64 bits of encrypted information.
Wrapping all this up in a simple answer:
When looking at "ciphertext", you are looking at (8 blocks of) DES encrypted data, which is being represented using a human-readable, hexadecimal (2 hex chars = 1 byte) notation instead of the original binary bytes that DES encryption would produce.
As for the steps involved in "recreating" the ciphertext, I tend to tell you to simply use the relevant parts of the ruby project where you based your question upon. Simply have to look at the sourcecode. The file at "https://github.com/Shopify/dukpt/blob/master/lib/dukpt/encryption.rb" pretty much explains it all and I'm pretty sure all functionality you need can be found at the project's GitHub repository. Alternatively, you can try to recreate it yourself - using the preferred programming language of your choice. You only need to handle 2 things: DES encryption/decryption and bin-to-hex/hex-to-bin translation.
Since this is one of the first topics that come up regarding this I figured I'd share how I was able to encode the ciphertext. This is the first time I've worked with Ruby and it was specifically to work with DUKPT
First I had to get the ipek and pek (same as in the decrypt) method. Then unpack the plaintext string. Convert the unpacked string to a 72 byte array (again, forgive me if my terminology is incorrect).
I noticed in the dukpt gem author example he used the following plain text string
"%B5452300551227189^HOGAN/PAUL ^08043210000000725000000?\x00\x00\x00\x00"
I feel this string is incorrect as there shouldn't be a space after the name (AFAIK).. so it should be
"%B5452300551227189^HOGAN/PAUL^08043210000000725000000?\x00\x00\x00\x00"
All in all, this is the solution I ended up on that can encrypt a string and then decrypt it using DUKPT
class Encrypt
include DUKPT::Encryption
attr_reader :bdk
def initialize(bdk, mode=nil)
#bdk = bdk
self.cipher_mode = mode.nil? ? 'cbc' : mode
end
def encrypt(plaintext, ksn)
ipek = derive_IPEK(bdk, ksn)
pek = derive_PEK(ipek, ksn)
message = plaintext.unpack("H*").first
message = hex_string_from_unpacked(message, 72)
encrypted_cryptogram = triple_des_encrypt(pek,message).upcase
encrypted_cryptogram
end
def hex_string_from_unpacked val, bytes
val.ljust(bytes * 2, "0")
end
end
boomedukpt FFFF9876543210E00008 "%B5452300551227189^HOGAN/PAUL^08043210000000725000000?"
(my ruby gem, the KSN and the plain text string)
2542353435323330303535313232373138395e484f47414e2f5041554c5e30383034333231303030303030303732353030303030303f000000000000000000000000000000000000
(my ruby gem doing a puts on the unpacked string after calling hex_string_from_unpacked)
C25C1D1197D31CAA87285D59A892047426D9182EC11353C0B82D407291CED53DA14FB107DC0AAB9974DB6E5943735BFFE7D72062708FB389E65A38C444432A6421B7F7EDD559AF11
(my ruby gem doing a puts on the encrypted string)
%B5452300551227189^HOGAN/PAUL^08043210000000725000000?
(my ruby gem doing a puts after calling decrypt on the dukpt gem)
Look at this: https://github.com/sgbj/Dukpt.NET, I was in a similar situation where i wondered how to implement dukpt on the terminal when the terminal has its own function calls which take the INIT and KSN to create the first key, so my only problem was to make sure the INIT key was generated the same way on the terminal as it is in the above mentioned repo's code, which was simple enough using ossl encryption library for 3des with ebc and applying the appropriate masks.
I'm learning to do proper crytographic implementations, and I thought as an exercise I would create an encrypted text editor.
My first attempt used a SHA-512 hash of a user-provided password as the key, and it functioned just fine. Though I was storing the IV in the header of the file, unprotected and that had me worried.
Then I read on stackoverflow that I should be using SecretKeyFactory (I'm using Java) to do PBE, and now I additionally need to provide a salt. So now I'm storing the salt in the header as well, but that would seem to ruin the whole purpose of having a salt. So how is this supposed to work? When I have Alice pick a password for her file when she saves, am I supposed to say "Here, memorize this random number along with your password."? I would like for the resulting file to be able to be e-mailed to Bob, so the salt can't be stored locally.
As my app stands, the IV and salt are out in the open. I would like for my user to only have to know the password when they send their file to Bob while remaining cryptographically secure, but I can't find any examples of how this is done.
Thanks for any help!
It is safe to store an IV along with the data, that is how IVs are used. Your method is ok, pick a block cipher, use cipher block chaining and an IV, and you're away.
There are many ways to create a key and iv from a passphrase, but one of the more common ones involves HMAC with SHA-1, in an algorithm that takes some salt and other things into account, to build a sufficiently bit-mixed key and iv.
The technical standard is the PKCS#5 v2.0 PBKDF2 algorithm, to which OpenSSL implements a C interface to a method that can do this, but as far as I know, no command line method.