I am currently currently using Rijndael 256-bit in CBC mode to encrypt some data which needs to be sent elsewhere. In order to enhance security, I'm taking a randomly generated SHA-256 hash and using a formula to chop off different parts it to use the encryption key and initialization vector (of course, the hash is sent with the data). The formula to generate the key and IV is fairly basic, and because the code is written in PHP, it's coded into a user-accessible page. What I'm wondering is: is this more or less safe than having one constant key and/or IV?
This is probably NOT the way you wish to go. In essence, it will take a good hacker not to long to figure out your mathematical formula for manipulating the HASH to generate your key and IV. Thus you are essentially sending the keys to the kingdom along with the kingdom itself.
Generally the way this type of operation is done, is to generate a session key (could be the same way you are doing it now), but use a public key encryption method to encrypt that session key. Then you use the public key encryption method to send the session key to the location your data is to be sent. The receiver has the public key and can encrypt the comm. channel session key.
Now both sides have the comm. channel session key and your REAL data can be encrypted using this key as the session key has not been sent in the clear.
Rijindael is an example of a symmetric crypto algorithm, where public key crypto algorithms are asymmetric. Examples of public key crypto algorithms are RSA, ECDSA (Crypto), etc....
On generating short-use keys. Have a long term key. Agree a date format with the receiver. Each day concatenate your long term key with the day's date and hash it with SHA-256 to generate a day key for use on that date only:
dayKey <- SHA256("my very secret long term key" + "2012-06-27")
The receiver will have all the information they need to generate exactly the same key at their end. Any attacker will know the date, but will not know the long term key.
You will need to agree protocols for around midnight and a few other details.
Change the long term key every month or two, depending on the amount of encrypted data you are passing. The more data you pass, the more often you need to change the long term key.
Related
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 am trying to design the system where I need to store users' secret values in database (private and public key strings). The storing of secrets itself will be done with the help of HashiCorp Vault. But I have one more requirement that disallows to store two equal pairs (private key + public key).
As far as I am not able to check keys uniqueness before storing I have to store hash of the original secrets. My idea to to calculate SHA hash from secret data and compare it with already saved hashes. So, I wonder is it working solution and can I use this digest as an external ID for accessing data (because hash imply the uniqueness of the data entry). Hope for your help.
My idea to to calculate SHA hash from secret data and compare it with already saved hashes
I'd assume cryptographic hash is best option you have when there is no other unique identifier
(because hash imply the uniqueness of the data entry)
And that's wrong assumption. Regardless cryptographic hashes are designed to have negligible collision probability (probability that two inputs are having the same hash value), principially there is still some (very small) probability.
For controlled (formated) inputs I'd say the collision probability is so miniscule, that you could boldly use the hashes as unique identifiers, but prepare to handle a very seldom case that a collision occurs (probably you could post it and become famous)
calculate SHA hash from secret data
Concerning security - it is very hard (=impossible) to compute the input value based on its hash (assuming cryptographic hash currently considered as secure)
Beware of the space size - if you have say 1000 known values, it is trival to check which secret value has certain hash. Assuming you store keypairs, it should be ok
If I am using Rijndael CBC mode, I have no idea why we would need salt.
My understanding is even if people know the password, but he cannot get the data without IV.
So from my perspective, password + IV seem to be sufficent secure.
Do I get anything wrong?
Yes, you need all of these things.
Salt (and an "iteration count") is used to derive a key from the password. Refer to PKCS #5 for more information. The salt and iteration count used for key derivation do not have to be secret. The salt should be unpredictable, however, and is best chosen randomly.
CBC mode requires an initialization vector. This is a block of random data produced for each message by a cryptographic random number generator. It serves as the dummy initial block of ciphertext. Like the key-derivation salt, it doesn't have to be kept secret, and is usually transmitted along with the cipher text.
The password, and keys derived from it, must be kept secret. Even if an attacker has the parameters for key derivation and encryption, and the ciphertext, he can do nothing without the key.
Update:
Passwords aren't selected randomly; some passwords are much more likely than others. Therefore, rather than generating all possible passwords of a given length (exhaustive brute-force search), attackers maintain a list of passwords, ordered by decreasing probability.
Deriving an encryption key from a password is relatively slow (due to the iteration of the key derivation algorithm). Deriving keys for a few million passwords could take months. This would motivate an attacker to derive the keys from his most-likely-password list once, and store the results. With such a list, he can quickly try to decrypt with each key in his list, rather than spending months of compute time to derive keys again.
However, each bit of salt doubles the space required to store the derived key, and the time it takes to derive keys for each of his likely passwords. A few bytes of salt, and it quickly becomes infeasible to create and store such a list.
Salt is necessary to prevent pre-computation attacks.
An IV (or nonce with counter modes) makes the same plain text produce different cipher texts. The prevents an attacker from exploiting patterns in the plain text to garner information from a set of encrypted messages.
An initialization vector is necessary to hide patterns in messages.
One serves to enhance the security of the key, the other enhances the security of each message encrypted with that key. Both are necessary together.
First things first: Rijndael does not have a "password" in CBC mode. Rijndael in CBC mode takes a buffer to encrypt or decrypt, a key, and an IV.
A "salt" is typically used for encrypting passwords. The salt is added to the password that is encrypted and stored with the encrypted value. This prevents someone from building a dictionary of how all passwords encrypt---you need to build a dictionary of how all passwords encrypt for all salts. That was actually possible with the old Unix password encryption algorithm, which only used a 12-bit salt. (It increased the work factor by 4096). With a 128-bit salt it is not possible.
Someone can still do a brute-force attack on a specific password, of course, provided that they can retrieve the encrypted password.
However, you have an IV, which does pretty much the same thing that a Salt does. You don't need both. Or, rather, the IV is your salt.
BTW, these days we call "Rijndael" AES.
A salt is generally used when using a hash algorithm. Rijndael is not a hash, but a two-way encryption algorithm. Ergo, a salt is not necessarily needed for encrypting the data. That being said, a salted hash of a password may be used as the Key for encrypting data. For what you're looking for, you might wish to look at hybrid cryptosystems.
The Key should be considered private and not transmitted with your encrypted data while the IV may be transmitted with the encrypted data.
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.
When passing symetrically encrypted data in a URL or possibly storing encrypted data in a cookie, is it resonable and/or nessassary and/or possible to also pass the Symetric Encryption IV (Salt) in the same URL? Is the idea of using Salt even valid in a stateless environment such as the web?
(I understand how salt works in a database given a list of names or accounts etc. but we can't save the salt given that we are passing data in a stateless environment.
Assuming a server side password that is used to encrypt data and then decrypt data, how can Salt be used? I guess a separate IV could be passed in the query string but is publicly exposing the salt ok?
Or can one generate a key and IV from the hash of a "password". Assuming the IV and Key come from non-overlapping areas of the hash, is this ok? (I realize that the salt / key will always be the same for a given password.)
EDIT: Typically using AES.
It is encouraged to generate random IVs for each encryption routine, and they can be passed along safely with the cipher text.
Edit:
I should probably ask what type of information you're storing and why you're using a salt with AES encryption, since salts are typically used for hashing, not symmetric encryption. If the salt is publicly available, it defeats the purpose of having it.
What you really need to do is ensure the strength of your key, because if an attacker has the salt, IV, and cipher text, a brute-force attack can easily be done on weaker keys.
You should not generate an initialization vector from the secret key. The initialization vector should be unpredictable for a given message; if you generated it from the key (or a password used to generate a key), the IV will always be the same, which defeats its purpose.
The IV doesn't need to be secret, however. It's quite common to send it with the ciphertext, unprotected. Incorporating the IV in the URL is a lot easier than trying to keep track of the IV for a given link in some server-side state.
Salt and IVs have distinct applications, but they do act in similar ways.
Cryptographic "salt" is used in password-based key derivation algorithms; storing a hashed password for authentication is a special case of this function. Salt causes the same password to yield different hashes, and thwarts "dictionary attacks", where a hacker has pre-computed hash values for common passwords, and built a "reverse-lookup" index so that they can quickly discover a password for a given hash. Like an IV, the salt used is not a secret.
An initialization vector is used with block ciphers like DES and AES in a feedback mode like CBC. Each block is combined with the next block when it is encrypted. For example, under CBC, the previous block cipher text is XOR-ed with the plain text of the current block before encryption. The IV is randomly generated to serve as a dummy initial block to bootstrap the process.
Because a different IV is (or should be, at least) chosen for each message, when the same message is encrypted with the same key, the resulting cipher text is different. In that sense, an IV is very similar to a salt. A cryptographic random generator is usually the easiest and most secure source for a salt or an IV, so they have that similarity too.
Cryptography is very easy to mess up. If you are not confident about what you are doing, you should consider the value of the information you are protecting, and budget accordingly to get the training or consultation you need.