Java Crypto API equivalent to Ruby's OpenSSL (via encrypted_strings library) - java

I am trying to decrypt an encrypted message that is encrypted in a Ruby web app using the encrypted_strings RubyGem library.
The encryption client code looks like this:
cipher = EncryptedStrings::SymmetricCipher.new(:passphrase => "abcdefgh"*2)
cipher.encrypt("howdy")
=> "jEUQrH58Ulk=\n"
The default symmetric cipher algorithm appears to be DES-EDE3-CBC (although the documentation for the RubyGem disagrees, but I will go with what the code says). So on the Java side I tried the following which I found online as an example of DES-EDE3-CBC usage of the Java Cryptography API:
import javax.crypto.spec.DESedeKeySpec
import javax.crypto.spec.IvParameterSpec
import javax.crypto.Cipher
import javax.crypto.SecretKeyFactory
...
DESedeKeySpec k;
Cipher c;
...
k = new DESedeKeySpec("abcdefghabcdefgh".getBytes());
c = Cipher.getInstance("DESede/CBC/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, k);
decrypted = c.doFinal("jEUQrH58Ulk=\n".getBytes());
When I do this on the Java side I get the following:
Wrong key size
I also tried using the Java Crypto API with an initialization vector but didn't know what I should set the bytes to since I am not doing this on the Ruby side via the encrypted_strings library and it appears to be set in the C code interfacing with OpenSSL.
Any pointers would be much appreciated.
I am using the bouncy castle JCA provider. I also tried DES/ECB/PKCS5Padding (which corresponds with the documented default algorithm in the RubyGems documentation eventhough the code appeared to be referencing the previously mentioned algorithm, DES-EDE3-CBC).
I have tried reading around the Java crypto API, but the documents all seem to have the same code samples and not very many new clues. My sources include:
http://www.angelfire.com/tx4/cus/notes/javaxcrypto.html
http://docs.oracle.com/javase/6/docs/technotes/guides/security/crypto/CryptoSpec.html

I'll post it as an answer. With DESede you can use either 192 bit DES ABC keys or 128 bit ABA keys. Many versions of Java only accept 192 bit (24 byte) DES ABC keys. DES ABA keys is where the first and last key of the encrypt, decrypt, encrypt (EDE) operation is the same; in other words, it's the same as DESede with ABC, where C=A.
So to create such a key, you can copy the first 8 bytes (in your case 8 ASCII characters - using characters directly as key is wrong) of your key and concatenate them at the end. This would result in "abcdefghabcdefghabcdefgh".getBytes("ASCII"). Note that you should always indicate the character encoding, as the platform might as well use UTF-16 as default character encoding, resulting in a key of double the size.

Related

Nodejs cipher.setAAD(buffer) vs Java chiper.updateAAD(byte[]), will i get the same authTag?

I am working on a project in Nodejs which suppose to encrypt plaintext and send the encrypted text to the Java program, and java side is able to decrypt it. Before decrypting it, java side needs to verify the authTag first.
I am using the build-in Nodejs crypto, the cipher.setAAD function only takes a buffer as a parameter, which actually is unsigned 8-bit Array (Uint8Array). However, Java cipher.updateAAD uses byteArray which is signed byte array.
Both AAD are generated from the same hex string.
So am I able to get the same authTag?
Thanks a lot.
Java byte is signed but the bytes in the arrays used in Java crypto -- not just AAD but also plaintext, ciphertext, hashes/MACs/signatures, keys, certificates, etc, etc, and also OS-level I/O like File{Input,Output}Stream -- are taken modulo 256, effectively making them unsigned -- and the values you put in them should be in the range 0..255 converted to byte.
Note the Java decrypt operation for an AEAD cipher doesn't give you the authtag; instead you give it the ciphertext PLUS authtag and IT does the comparison, throwing an exception if there is a mismatch.
Also note the only AEAD mode supported by 'normal' Java (with the Sun-now-Oracle and OpenJDK providers) is GCM (with AES). BouncyCastle also supports CCM, and I don't know about IBM or others like Android. Your nodejs-crypto link says it supports only GCM, which surprises me since it uses OpenSSL underneath and that supports both GCM and CCM since OpenSSL 1.0.1.
Assuming you use a mode supported on both sides, these modes are standardized and deterministic, so if you use the same key, nonce, plaintext or ciphertext as applicable, and AAD yes they will produce/expect the same tag and interoperate.

ccrypt will not decrypt ccrypt-j encrypted files

I've been trying to fix ccrypt-j, a pure-java implementation of the linux ccrypt command. I found there is some problem with the initialization vector (IV) which makes ccrypt not decrypt anything but its own output.
I modified both libraries so that the same nonce is always fed to both implementations of the Rijndael engine, however, the output IV is always different between implementations, i.e. both libraries always have the same result (because Rijndael is deterministic), but those results are always different.
I know the problem is only the way ccrypt generates the IV since:
ccrypt-j-encrypted can be decrypted from ccrypt-j
If I substitute the IV (first 32 bytes of the encrypted files) with that of a ccrypt-encrypted file, ccrypt will decrypt it just fine.
Ccrypt uses its own implementation of Rijndael coded in C, while ccrypt-j uses Bouncy Castle's implementation.
EDIT: 04/01/2016
Because the IV is constructed before any data is encrypted (actually, any data is even read) I believe the problem has to be in the way Rjindael is initialized in both Bouncy Castle and ccrypt's own implementation. I'll try to do the same sequence in both implementations and see what I get.
One half-answer
if you look at the old ccrypt, there are some explanations about IV. if I resume, 4 bytes are fixed - magic number -, it si c051 for a while. Issues about securities are also discussed:
magic number : see that
http://ccrypt.sourceforge.net/faq.html
ccrypt comes from emacs / jka-compr:
http://www.opensource.apple.com/source/emacs/emacs-51/emacs/lisp/jka-compr.el
In ccrypt, the seed is constructed as follows: first, a nonce is
contructed by hashing a combination of the host name, current time,
process id, and an internal counter into a 28-byte value, using a
cryptographic hash function. The nonce is combined with a fixed
four-byte "magic number", and the resulting 32-byte value is encrypted
by one round of the Rijndael block cipher with the given key. This
encrypted block is used as the seed and appended to the beginning of
the ciphertext. The use of the magic number allows ccrypt to detect
non-matching keys before decryption.
magic number there: http://ccrypt.sourcearchive.com/documentation/1.7-7/ccryptlib_8c-source.html
It seems magic number doesnt change (same from 1.1 to 1.10, before, I dont know).
So what ?
ccrypt is designed to be compatible with precedent versions (emacs , ...). It can crypt and decrypt, and is widely used.
Then problem come from ccrypt-j.
what one can see on sourceforge is 2 important things :
1 compatibility
Encrypting a file using ccrypt-j
TODO
Decrypting a file using ccrypt-j
TODO
so what works really ?
2 in fact, it uses bouncy castle, which is well used, and surely implements standards well.
So conclusion ?
you cant hope ccrypt will change.
then: you can decrypt ccrypt by ccrypt-j
but if you want to decrypt by ccrypt, you have to limit ccrypt-j
I doubt about your assertion, because it would be magical !
If I substitute the IV (first 32 bytes of the encrypted files) with
that of a ccrypt-encrypted file, ccrypt will decrypt it just fine.
But if it works, why not use that ? (ccrypt-j can also decrypt ?)
last advice: contact ccrypt-j support
hope it helps

Android: decrypt AES with 128 bit key size and 128 bit block size - Block cipher mode: CBC-CS1

I need to decrypt some data (on Android) that is encrypted with the following specs:
AES with 128 bit key size and 128 bit block size
Block cipher mode: CBC-CS1 (CBC with ciphertext stealing, variant 1, as specified in [CBCCS])
Didn't find much information on Internet and all the AES decryption methods I've tried so far don't work.
The main problem seem to be the implementation of CBC-CS1, is it supported or should I implement myself?
Thanks,
Dem
It seems you should be able to use new NISTCTSBlockCipher(NISTCTSBlockCipher.CS1, aes) if you want. One thing is probably making a difference: you should directly feed it the AES block cipher, e.g.:
AESFastEngine aes = new AESFastEngine();
NISTCTSBlockCipher aescbccts = new NISTCTSBlockCipher(NISTCTSBlockCipher.CS1, aes);
which is different from CTSBlockCipher which seems to expect CBCBlockCipher (for CBC + CTS operation anyway).
If you do feed it CBC then you - funny enough - end up with double CBC = ECB again:
CTB_n = E(CTB_n-1 XOR CTB_n-1 XOR PTB_n) = E(PTB_n).
From WikiPedia:
The numbering here is taken from Dworkin, who describes them all. The third is the most popular, and described by Daemen and Schneier; Meyer describes a related, but incompatible scheme (with respect to bit ordering and key use).
I just verified that Bouncy implements CS3. So it seems you should be able to use CTSBlockCipher (as ArtjomB suggests), but only after swapping the (partial) last and first to last block.
Alternatively you may simply rewrite the CTSBlockCipher, Bouncy Castle has a very permissive license.

Difference between DESede and TripleDES for cipher.getInstance()

I am trying to get TripleDES encryption working in Java. From the Wikipedia article under Keying Options, I want to use option 1, where All three keys are independent.
From the Cipher docs it says to go to the reference guide here, but it still isn't clear to me.
I am working on getting examples running, and use both of these lines in different projects:
Cipher c = Cipher.getInstance("DESede");
Cipher cipher = Cipher.getInstance("TripleDES/ECB/PKCS5Padding");
Both compile fine, so what's the difference? Should I be using one over the other? Do both of these work for using three separate keys?
"TripleDES" is simply an alias for "DESede" in the Sun JCE provider – both return the exact same cipher. "DESede" is the standard name which should work on every Java platform, but in practice, "TripleDES" is probably pretty widely supported too.
According to this page, the SunJCE Triple DES implementation supports options #1 and #2:
Keysize must be equal to 112 or 168.
A keysize of 112 will generate a Triple DES key with 2 intermediate keys, and a keysize of 168 will generate a Triple DES key with 3 intermediate keys.
You should always specify the mode of operation and the padding when instantiating a cipher to make your intents clear. Otherwise the implementation is free to make the choice, which can be confusing.

Check encryption key correctness in JAVA

I'm using BouncyCastle to encrypt/decrypt some files using AES and PKCS5 padding in CBC mode :
Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
Now two questions:
How can I check that the provided key for decrypting data is correct or not ?
How Can I check encrypted input is untouched (e.g. not changed by user using an HEX editor)?
Thanks
You can use an AEAD mode, like CCM or GCM, in place of CBC. These modes authenticate an encrypted message, so if the wrong key is used, or the cipher text has been altered, you can detect it. You wouldn't be able to distinguish these cases though.
There is support in Java 7's cryptography API for GCM, but the SunJCE provider that ships with Oracle's Java implementation doesn't support it yet. You can get support through third-party providers like BouncyCastle.
You can achieve the same things if you use additional cryptographic services, like a digital signature or message authentication code.
Encryption is not just about the algorithm and the encryption key, it's also a lot about
the system organization.
In general, you can't determine that the key is correct. Any key can be used to decrypt the
data that's supposed to be decrypted, but it's up to some other mechanism to tell you if that
is the "correct" result.
In general, you can't determine if the data to be decrypted is untouched, except through some
external check. It's a property of most encryption systems that changing any of the encrypted
data would change the decrypted output drastically, probably into something you'd interpret
as garbage.
You should add a MAC which first verifies the integrity of the message, and only then you should decrypt it. A common choice of MAC is HMAC with whatever hash function you prefer, such as SHA-2.
Instead of doing this yourself, it's often a good idea to use an authenticated cipher. AES-GCM is a common choice. But you need to be really careful to never reuse an IV in that case.
The JCE ciphers are usually very basic. If you need a full featured protection including integrity and key testing, you need to combine them. And as usual it is better to not device that yourself. So better opt for a more high level format like PKCS7/12 or PGP.
Depending on the Padding used some ciphers will give you a PaddingException when you try to decrypt it with the wrong key. For stronger integrity check I would use a padding consiting of HMAC bytes.
A pretty complete method is included in the JCE, it is the AESWrap algorithm. It requires padded data but will ensure integrity. It is best combined with a length byte as described in RFC 3537. Note, that this is only intended for smaller amounts of secrets (like symmetric keys). The RFC3537 padding is restricted to 255 bytes.
To use this with a password derived key, you can use this:
char[] pass = ... // your password
byte[] codeBytes = ... // up to 255 bytes you want to protect
// generate wrapping key from password
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[16]; rand.nextBytes(salt);
SecretKey kek = f.generateSecret(new PBEKeySpec(pass, salt, 1000, 128));
kek = new SecretKeySpec(password.getEncoded(), "AES"); // convert into AES
// RFC3537 padding (lengthbyte)
byte[] wrappedCodeBytes = new byte[codeBytes + 1 % 8];
System.arraycopy(codeBytes,0,wrappedCodeBytes,1,wrappedCodeBytes.length);
paddedCodeBytes[0]=(byte)codeBytes.length;
byte[] pad = new byte[paddedCodeBytes.length - codeBytes.length -1]; rand.nextBytes(pad);
System.arraycopy(pad,0,paddedCodeBytes,codeBytes.length+1,pad.length);
// AESWrap is WRAP_MODE:needs a SecretKey
SecretKey paddedCodeKey = new SecretKeySpec(paddedCodeBytes, "RAW");
// now wrap the password with AESWrap kek is 128 bit
Cipher c = Cipher.getInstance("AESWrap"); // default IV
c.init(Cipher.WRAP_MODE, kek);
byte[] result = c.warp(paddedCodeKey);
The unwrapping is left for the reader as an exercise :) The example code uses 128bit keysize, since more entropy cant be expected from the PBKDF2 anyway.
Note that this will detect wrong passwords with high probability, and some critics will see this as a weakness of AESWrap.
Take a look at this tutorial on BC encryption, specifically the InitCiphers methods, and in detail at the second code block which specifies the actual type of cipher.
How can I check that the provided key for decrypting data is correct or not?
According to JCE Javadocs, specifically the constructor of Class SecretKeySpec:
This constructor does not check if the given bytes indeed specify a secret key of the specified algorithm. For example, if the algorithm is DES, this constructor does not check if key is 8 bytes long, and also does not check for weak or semi-weak keys. In order for those checks to be performed, an algorithm-specific key specification class (in this case: DESKeySpec) should be used.
Note that Interface KeySpec lists all implementing classes, basically a list of validation options.
How Can I check encrypted input is untouched (e.g. not changed by user using an HEX editor)?
Indeed. That's a good one. 'Input' is pretty generic. Do you mean the actual content to decrypt? Well, if it's munged I believe it will not decrypt properly. Does that make sense?
IFF you are talking about the case of a key with parity bits being altered, as described in item (6) at the Bouncy Castle FAQ, you will have to do an actual parity check on the key. Only the first 56 bytes of the key are used for the encryption ops, and the last 8 bytes are reserved for parity checking. So, essentially, the last part of the 'key' can be changed and the first part is still useful. To detect whether either the parity or the key have been altered, you would run a parity check. I found this little ditty on doing a parity check. And, for more info on how parity is set in these keys, see comments in the JDK7 Crypto Provider source for Class DESKeyGenerator by Jan Luehe (near bottom) which discuss parity setting.
I recently had some interaction with BC, and I hope this info helps.

Categories

Resources