I am aware that DES is considered as an insecure algorithm for encryption at the moment. So does that imply that we should stop using the class DESKeySpec in JCA for specifying a key for encryption? More specifically, is the below code snippet insecure due to the usage of DESKeySpec? If yes, why, and how should I rectify it?
public void setPassword(String p) throws FacesException {
byte\[\] s`your text`={(byte)0xA9,(byte)0x9B,(byte)0xC8,(byte)0x32,(byte)0x56,(byte)0x34,(byte)0xE3,(byte)0x03};
try {
KeySpec keySpec=new DESKeySpec(p.getBytes("UTF8"));
SecretKey key=SecretKeyFactory.getInstance("DES").generateSecret(keySpec);
e=Cipher.getInstance(key.getAlgorithm());
d=Cipher.getInstance(key.getAlgorithm());
e.init(Cipher.ENCRYPT_MODE,key);
d.init(Cipher.DECRYPT_MODE,key);
}
catch ( Exception e) {
throw new FacesException("Error set encryption key",e);
}
}
Yes, DES is very insecure, and shouldn't be used in any new projects. Any new project should be using AES unless you have a very strong and informed reason for something else.
However, what you should do about the above code completely depends on what it's being used for. If this code is interoperating with a system that requires DES, you can't just change it without changing the other side as well. Similarly, if you have existing data encrypted in DES, you'll need a way to continue to decrypt that. You can't just swap AES for DES and have exiting encryptions continue to work. There are important systems in the world that still use DES (credit card magnetic stripes being probably the most ubiquitous).
That said, you can't just swap "AES" into the above code and have a secure cryptosystem. You need to choose a proper mode, a random IV, most likely a KDF, and some kind of authentication. Encryption algorithms like DES and AES are very low-level tools that are easy to misuse. They are just one piece of a secure cryptosystem. The proper solution depends on your specific situation, particularly what kinds of interoperability you need.
Related
I would like to be able to encrypt data using public keys, and decrypt the encrypted data using private keys.
Encryption essentially needs to accept inputs:
Clear data to be encrypted
A list of several public keys
The minimum number of private keys corresponding to those public keys that are needed to decrypt the encrypted
How can this be done in NodeJs?
Scenarios
By way of concrete scenarios, where there are 5 users (A - E) with crypto key pairs in the system.
A 1-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey], 1) (1-of-2)
decrypted = crypto_decrypt(encrypted, [A.privateKey])
success: decrypted === clearText
because A.publicKey was used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey])
failure: unable to decrypt
because C.publicKey was not used in encryption
A Y-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey, C.publicKey], 2) (2-of-3)
decrypted = crypto_decrypt(encrypted, [A.privateKey, C.privateKey])
success: decrypted === clearText
because both A.publicKey and C.publicKey was used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey, E.privateKey])
failure: unable to decrypt
because while C.publicKey was used in encryption, E.publicKey was not
Ideally...
At minimum I need to be able to support the 1-of-X scenario, but if Y-of-X is also possible, that would be better
What the actual key pairs are is not so important here, could be RSA, could be any of the elliptic curves. If the method supports a number of different ones, and allows one to pick, that would be better
Preferably not tied to the use of any particular toolset or framework
PGP can do this.
Specifically for node, openpgpjs has a section in the README - https://github.com/openpgpjs/openpgpjs#encrypt-and-decrypt-string-data-with-pgp-keys - which could be condensed into:
const encryptedText = await openpgp.encrypt({ message: clearText, publicKeys });
const decryptedText = await openpgp.decrypt({ message: encryptedText, privateKeys });
However:
for number of keys required to decrypt, it only supports the 1 of many scenario, not the more general some of many scenario you'd ideally want
supports both RSA and many elliptic curve based keys, but the key format is designed for use by PGP, as the name of the library implies (so it is specific to the PGP toolchain)
As noted by Luke Joshua Park in the comments, this sounds like a textbook use case for a secret sharing scheme. Specifically, I would recommend that you:
Generate a random AES (or other symmetric cipher) key. Make sure to use a cryptographically secure RNG (such as Crypto.randomBytes()) for this, since an attacker who can guess this key can also break the entire scheme!
Encrypt the data with this key, using an authenticated encryption mode such as AES-SIV (as provided e.g. by miscreant).
Split the AES key into multiple shares using Shamir's secret sharing scheme with the desired reconstruction threshold. (Some JS implementations I found with a quick Google search include secrets.js, jsss and ThresholdJS.)
Encrypt each share using a different user's public key.
Send each user their encrypted share and a copy of the AES-encrypted data.
Disclaimer: I have not reviewed the security or correctness of any of the APIs or libraries linked above. The cryptographic techniques they claim to use appear to be sound and suitable for this task, but I cannot guarantee that they have been implemented safely and correctly. Caveat emptor.
To decrypt the data, each user can first decrypt their share of the AES key using their private key, and a sufficient number of the decrypted shares can then be combined (using the same implementation of Shamir's secret sharing as used to create them) to reconstruct the original AES key, which can then be used to decrypt (and verify the integrity of) the data.
Note that Shamir's secret sharing implicitly assumes that the users who combine their shares to reconstruct the secret will trust each other and not lie about their shares or otherwise misbehave. If that's not necessarily true, there are various ways for a malicious user to trick the others — perhaps most simply by waiting for everyone else to reveal their share to them and then refusing to reveal their own share to the others. In general, preventing such attacks is all but impossible without the help of some kind of a mutually trusted party.
At the very least, though, using an encryption mode like AES-SIV with built-in authentication should ensure that users will detect if the reconstructed AES key is incorrect, since the decryption will then fail. If you want to be extra sure of this, you may wish to also send each of the users a secure cryptographic hash (e.g. SHA-512) of the AES key, so that they can verify its correctness before attempting decryption.
Due to our customer's demands, user passwords must be kept in some "readable" form in order to allow accounts to be converted at a later date. Unfortunately, just saving hash values and comparing them on authentication is not an option here. Storing plain passwords in the database is not an option either of course, but using an encryption scheme like AES might be one. But in that case, the key to decrypt passwords would have to be stored on the system handling authentication and I'm not quite comfortable with that.
Hoping to get "best of both worlds", my implementation is now using RSA asymmetric encryption to secure the passwords. Passwords are salted and encrypted using the public key. I disabled any additional, internal salting or padding mechanisms. The encrypted password will be the same every time, just like a MD5 or SHA1 hashed password would be. This way, the authentication system needs the public key, only. The private key is not required.
The private key is printed out, sealed and stored offline in the company's safe right after it is created. But when the accounts need to be converted later, it will allow access to the passwords.
Before we deploy this solution, I'd like to hear your opinion on this scheme. Any flaws in design? Any serious drawbacks compared to the symmetric encryption? Anything else we are missing?
Thank you very much in advance!
--
Update:
In response to Jack's arguments below, I'd like to add the relevant implementation details for our RSA-based "hashing" function:
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Cipher rsa = Cipher.getInstance("RSA/None/NoPadding");
rsa.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cryptRaw = rsa.doFinal(saltedPassword.getBytes());
Having quickly skimmed over the paper mentioned by Jack, I think I somewhat understand the importance of preprocessing such as OAEP. Would it be alright to extend my original question and ask if there is a way to apply the needed preprocessing and still have the function return the same output every time for each input, just as a regular hashing function would? I would accept an answer to that "bonus question" here. (Or should I make that a seperate question on SOF?)
--
Update 2:
I'm having a hard time accepting one of the present answers because I feel that none really does answer my question. But I no longer expect any more answers to come, so I'll accept the one that I feel is most constructive.
I'm adding this as another answer because instead of answering the question asked (as I did in the first response) this is a workaround / alternative suggestion.
Simply put:
Use hashes BUT, whenever a user changes their password, also use your public key as follows:
Generate a random symmetric key and use it to encrypt the timestamp, user identifier, and new password.
The timestamp is to ensure you don't mess up later when trying to find the current / most up-to-date password.
Username so that you know which account you're dealing with.
Password because it is a requirement.
Store the encrypted text.
Encrypt the symmetric key using your public key.
Store the public key encrypted symmetric key with the encrypted text.
Destroy the in-memory plaintext symmetric key, leaving only the public key encrypted key.
When you need to 'convert' the accounts using the current password, you use the private key and go through the password change records. For each one:
Using the private key, decrypt the symmetric key.
Using the symmetric key, decrypt the record.
If you have a record for this user already, compare timestamps, and keep the password that is most recent (discarding the older).
Lather, rinse, repeat.
(Frankly I'm probably overdoing things by encrypting the timestamp and not leaving it plaintext, but I'm paranoid and I have a thing for timestamps. Don't get me started.)
Since you only use the public key when changing passwords, speed isn't critical. Also, you don't have to keep the records / files / data where the plaintext password is encrypted on the server the user uses for authentication. This data can be archived or otherwise moved off regularly, as they aren't required for normal operations (that's what the hash is for).
There is not enough information in the question to give any reasonable answer. Anyway since you disable padding there is a good chance that one of the attacks described in the paper
"Why Textbook ElGamal and RSA Encryption are Insecure" by
D. Boneh, A. Joux, and P. Nguyen is applicable.
That is just a wild guess of course. Your proposal could be susceptible to a number of other attacks.
In terms of answering your specific question, my main concern would have been management of the private key but given it's well and truly not accessible via any computer system breach, you're pretty well covered on that front.
I'd still question the logic of not using hashes though - this sounds like a classic YAGNI. A hashing process is deterministic so even if you decided to migrate systems in the future, so long as you can still use the same algorithm, you'll get the same result. Personally, I'd pick a strong hash algorithm, use a cryptographically strong, unique salt on each account and be done with it.
It seems safe enough in terms of what is online but have you given full consideration to the offline storage. How easy will it be for people within your company to get access to the private key? How would you know if someone within your company had accessed the private key? How easy would it be for the private key to be destroyed (e.g. is the safe fireproof/waterproof, will the printed key become illegible over time etc).
You need to look at things such as split knowledge, dual control, tamper evident envelopes etc. As a minimum I think you need to print out two strings of data which when or'd together create the private key and then have one in your office and one in your customers office,
One serious drawback I've not seen mentioned is the speed.
Symmetric encryption is generally much much faster than asymmetric. That's normally fine because most people account for that in their designs (SSL, for example, only uses asymmetric encryption to share the symmetric key and checking certificates). You're going to be doing asymmetric (slow) for every login, instead of cryptographic hashing (quite fast) or symmetric encryption (pretty snappy). I don't know that it will impact performance, but it could.
As a point of comparison: on my machine an AES symmetric stream cipher encryption (aes-128 cbc) yields up to 188255kB/s. That's a lot of passwords. On the same machine, the peak performance for signatures per second (probably the closest approximation to your intended operation) using DSA with a 512 bit key (no longer used to sign SSL keys) is 8916.2 operations per second. That difference is (roughly) a factor of a thousand assuming the signatures were using MD5 sized checksums. Three orders of magnitude.
This direct comparison is probably not applicable directly to your situation, but my intention was to give you an idea of the comparative algorithmic complexity.
If you have cryptographic algorithms you would prefer to use or compare and you'd like to benchmark them on your system, I suggest the 'openssl speed' command for systems that have openssl builds.
You can also probably mitigate this concern with dedicated hardware designed to accelerate public key cryptographic operations.
If you ever played the original startcraft and selected an official map made by Blizzard you would notice a little "Blizz" icon next to the map to let you know that it was official and not made by third-party.
I wish to implement a similar system in my application whereby addons and files can be authenticated to let the user know whether or not they came from me or somebody else.
I know very little about security and would appreciate any help in this matter.
Public key cryptography. The client application has a copy of the official author's public signing key, and verifies a signature applied to the addon/file made with the author's private key.
Mac's answer is absolutely correct. To be more specific, the process generally would go as follows:
Signing:
A hash (e.g. SHA-1) is created from the content.
The hash is then signed using the private key, resulting in a signature (e.g. using DSA or RSA algorithm).
The signature is included with the content. If the content changes, the signature will become invalid.
Verification:
Client calculates a hash from the content.
The signature is decrypted with the known public key of the author (i.e. you).
If the hash inside the signature matches the calculated hash from #1 then it's OK. Otherwise the content was modified / isn't really from the author (i.e. you).
Some considerations:
You need to use a key size large enough to deter brute forcing.
These algorithms require a source of random data - both when generating keys and when signing, for example. If this is violated, then often the private key can be trivially revealed.
"Encrypting the hash with the public key" is a simplistic explanation. For example, with RSA - the hash needs to be padded with other data. On verification, the padding has to be checked as well. Otherwise, the signatures may be able to be forged easily. (See: OpenSSL debacle from a few years ago).
The standard advice is to use a proven, off-the-shelf cryptography library written by those with more experience. You need to be able to feed the library the key pair, and data to be signed/verify and say "sign/verify this" with minimal code involved. If you're worrying about the details of padding, or anything like that - you're probably doing it wrong. See: System.Security.Cryptography namespace in Microsoft .NET (very easy to use), or Microsoft CryptoAPI if you're doing standard Windows C/C++ programming. Other cross-platform libs exist too: pick something that works well on your platform.
To build a secure system, can we assume that encryption guarantees integrity is true before starting a secure programming?
Both in symmetric and public-key
encryption, is my question
well-proofed ?
If no, what are the
vulnerabilities, can you give an
example?
No. This is easy to see if you consider the one-time pad, a simple (theoretically) perfectly secure system.
If you change any bit of the output, a bit of the clear text will change, and the recipient has no way to detect this.
This is an obvious case, but the same conclusion applies to most encryption systems. They only provide for confidentiality, not integrity.
Thus, you may want to add a digital signature. Interestingly, when using public key cryptography, it is not sufficient to sign then encrypt (SE), or to encrypt then sign (ES). Both of these are vulnerable to replay attacks. You have to either sign-encrypt-sign or encrypt-sign-encrypt to have a generally secure solution. This paper explains why in detail.
If you use SE, the recipient can decrypt the message, then re-encrypt it to a different recipient. This then deceives the new recipient about the sender's intended recipient.
If you use ES, an eavesdropper can remove the signature and add their own. Thus, even though they can't read the message, they can take credit for it, pretending to be the original sender.
In short the answer is no. Message Integrity and Secrecy are different, and require different tools.
Lets take a simple coin flip into consideration, and in this case we are betting on the results. The result is a simple bool and I encrypt it using a stream cipher like RC4 which yields 1 encrypted bit and I email it to you. You don't have the key, and I ask you to email me back the answer.
A few attacks can happen in this scenario.
1)An attacker could modify the bit in transit, if it was a 0 there is a 50% chance it will become a 1 and the contrary is true. This is because RC4 produces a prng stream that is XOR'ed with the plain text produce the cipher text, similar to a one time pad.
2)Another possibility is that I could provide you with a different key to make sure your answer is wrong. This is easy to brute force, I just just keep trying keys until I get the proper bit flip.
A solution is to use a block cipher is CMAC Mode. A CMAC is a message authentication code similar to an hmac but it uses a block cipher instead of a message digest function. The secret key (K) is the same key that you use to encrypt the message. This adds n+1 blocks to the cipher text. In my scenario this prevents both attacks 1 and 2. An attacker cannot flip a simple bit because the plain text is padded, even if the message only takes up 1 bit i must transmit a minimum of 1 block using a block cipher. The additional authentication block prevents me from chaining the key, and it also provides integrity from anyone attempting to modify the cipher text in transit (although this would be very difficult to do in practice, the additional layer of security is useful).
WPA2 uses AES-CMAC for these reasons.
If data integrity is a specific concern to you, you should use a cryptographic hash function, combined with an an encryption algorithm.
But it really does come down to using the correct tool for the job. Some encryption algorithms may provide some level of checksum validation built-in, others may not.
Through the years I've come across this scenario more than once. You have a bunch of user-related data that you want to send from one application to another. The second application is expected to "trust" this "token" and use the data within it. A timestamp is included in the token to prevent a theft/re-use attack. For whatever reason (let's not worry about it here) a custom solution has been chosen rather than an industry standard like SAML.
To me it seems like digitally signing the data is what you want here. If the data needs to be secret, then you can also encrypt it.
But what I see a lot is that developers will use symmetric encryption, e.g. AES. They are assuming that in addition to making the data "secret", the encryption also provides 1) message integrity and 2) trust (authentication of source).
Am I right to suspect that there is an inherent weakness here? At face value it does seem to work, if the symmetric key is managed properly. Lacking that key, I certainly wouldn't know how to modify an encrypted token, or launch some kind of cryptographic attack after intercepting several tokens. But would a more sophisticated attacker be able to exploit something here?
Part of it depends on the Encryption Mode. If you use ECB (shame on you!) I could swap blocks around, altering the message. Stackoverflow got hit by this very bug.
Less threatening - without any integrity checking, I could perform a man-in-the-middle attack, and swap all sorts of bits around, and you would receive it and attempt to decrypt it. You'd fail of course, but the attempt may be revealing. There are side-channel attacks by "Bernstein (exploiting a combination of cache and microarchitectural characteristics) and Osvik, Shamir, and Tromer (exploiting cache collisions) rely on gaining statistical data based on a large number of random tests." 1 The footnoted article is by a cryptographer of greater note than I, and he advises reducing the attack surface with a MAC:
if you can make sure that an attacker
who doesn't have access to your MAC
key can't ever feed evil input to a
block of code, however, you
dramatically reduce the chance that he
will be able to exploit any bugs
Yup. Encryption alone does not provide authentication. If you want authentication then you should use an message authentication code such as HMAC or digital signatures (depending on your requirements).
There are quite a large number of attacks that are possible if messages are just encrypted, but not authenticated. Here is just a very simple example. Assume that messages are encrypted using CBC. This mode uses an IV to randomize the ciphertext so that encrypting the same message twice does not result in the same ciphertext. Now look what happens during decryption if the attacker just modifies the IV but leaves the remainder of the ciphertext as is. Only the first block of the decrypted message will change. Furthermore exactly those bits changed in the IV change in the message. Hence the attacker knows exactly what will change when the receiver decrypts the message. If that first block
was for example a timestamp an the attacker knows when the original message was sent, then he can easily fix the timestamp to any other time, just by flipping the right bits.
Other blocks of the message can also be manipulated, though this is a little trickier. Note also, that this is not just a weakness of CBC. Other modes like OFB, CFB have similiar weaknesses. So expecting that encryption alone provides authentication is just a very dangerous assumption
A symmetric encryption approach is as secure as the key. If both systems can be given the key and hold the key securely, this is fine. Public key cryptography is certainly a more natural fit.