Confused about AES cipher version - java

I'm trying to implement AES256 encryption into an android app. Data is coming from a server encrypted, I've been using the Android library JNCryptor to decrypt the data. It successfully does this, but it's very slow. I wanted to try Facebook's Conceal library because it reports having faster encryption and decryption speeds. My first implementation was decrypting a string from the server with the Conceal library. My problem comes when I try to pass the byte[] of the encrypted string to the decrypt function in Conceal.
ByteArrayInputStream bin = new ByteArrayInputStream(Base64.decode(encStr, Base64.DEFAULT));
InputStream cryptoStream = null;
try {
cryptoStream = crypto.getCipherInputStream(bin, new Entity("test"));
...
The crash comes because the given cipher version, which is found by getting the first byte of the byte [] does not equal the expected Conceal cipher version number 1.
I then looked at the encryption side of Conceal and saw this is just a number set during the encryption.
To double-check I then looked over the JNCryptor source code and saw it sets and looks for Cipher Version numbers 2 and 3.
I guess my questions are: What is the significance of the Cipher Version number? Would I be able to get the Conceal library to decrypt this data or are they just encrypted in totally different ways?

They are completely unrelated. For instance, Conceal seems to use GCM mode of encryption (which includes authentication) and RNCrypt uses AES in CBC mode and HMAC for authentication. Besides that it uses passwords and PBKDF2 instead of keys directly (although implementations like JNCryptor may include shortcuts to use keys directly - thanks Duncan).
Both are relatively minimalistic proprietary cryptographic formats, and both use AES. That's where he comparison ends.

Related

How to decrypt data in Java that was encrypted in Obj-c

I am encrypting in ojb-c with SecKeyEncryptedData and trying to decrypt in Java with javax.Cipher and hitting a problem.
I recently moved to doing long blocks and have needed to use a symmetric encryption with the AES key encrypted with the asymmetric key pair. I am having problems decoding.
I have the iOS key kSecKeyAlgorithmRSAEncryptionPKCS1 working for asymmetric data matched with Cipher.getInstance("RSA/ECB/PKCS1Padding") in Java. This decodes the short blocks.
As I need to send longer blocks, and am trying to switch to kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM on iOS and it encrypts fine, but i cannot find the method to use in Cipher to decrypt it and do not understand if it needs to be done in 2 steps in the cloud in Java.
OBJ-C:
SecKeyAlgorithm algorithm = kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM;
NSData* cipherText = nil;
cipherText = (NSData*)CFBridgingRelease( // ARC takes ownership
SecKeyCreateEncryptedData(self.pubKey, algorithm,
(__bridge CFDataRef)data, &error));
Java:
try {
cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, priv);
byte[] dog = decoder.decode(encString);
dec = cipher.doFinal(dog);
res = new String(dec);
} // handle errors
The decode obviously fails.
So my question is in 2 parts.
is there a Cipher type that will do the decode needed or do i need to break out the encrypted AES key and decrypt it first?
If i need to break it up, how long is that encrypted AES key part of the data block and, if you know the ciphers for that it would be fantastic.
is there a Cipher type that will do the decode needed
You may read the Cipher documentation. I believe you are looking for RSA/ECB/OAEPWithSHA-256AndMGF1Padding
I see the designation doesn't exacly match with the Obj-C name, but this is a common standard so it may worth a try
As I need to send longer blocks, and am trying to switch to kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM
You may try to search for "hybrid encryption". Asymmetric ciphers are VERY slow comparing to symmetric ciphers and intended to encrypt only limited amount of data.
Some implementation may encrypt longer data anyway (for each 256 bit input providing 2048 o 4096 bit output), Java will simply complain and stop
So proper encryption would be
encrypt data with a radom key (DEK - data encryption key) using a symmetric cipher
encrypt the DEK using an asymmetric public key
If the kSecKeyAlgorithmRSAEncryptionOAEPSHA512AESGCM would be not counterpart (compatible) with RSA/ECB/OAEPWithSHA-256AndMGF1Padding, you may still use the PKCS#1 1.5 padding (the old one) with this approach.
Edit: this asnwer may be useful when working with OAEP too RSA/ECB/OAEPWithSHA-256AndMGF1Padding but with MGF1 using SHA-256?

Breaking down RSA/ECB/OAEPWithSHA-256AndMGF1Padding

Java has a mode called RSA/ECB/OAEPWithSHA-256AndMGF1Padding. What does that even mean?
RFC3447, Public-Key Cryptography Standards (PKCS) #1: RSA Cryptography Specifications Version 2.1, section 7.1.2 Decryption operation says Hash and MGF are both options for RSAES-OAEP-DECRYPT. MGF is it's own function, defined in Section B.2.1 MGF1 and that has it's own Hash "option" as well.
Maybe the Hash "option" in RSAES-OAEP-DECRYPT and MGF1 are supposed to be the same or maybe they're not, it is unclear to me. If they are then I guess when you have RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING that means sha256 should be used for both. But if they're not supposed to be the same then you could have sha256 used for RSAES-OAEP-DECRYPT and, for example, sha1 used for MGF1. And if that's the case then what function is sha256 supposed to be used for? And what hash algorithm is supposed to be used for the other function?
And what does ECB mean in this context? ECB is a symmetric block cipher mode. Electronic Code Book. Maybe it's supposed to mean how Java deals with plaintext's that are larger than the modulo? Like maybe splits the plaintext into chunks that are as big as the modulo and then encrypts each one with RSA and concatenates them together? I'm just guessing..
The default for OAEP is to use SHA-1 for MGF1 (but see the edit on the end of this answer). Note that the hash chosen doesn't have that much impact on the security of OAEP, so mostly it will be left to this default.
We can easily test this by testing it against "OAEPPadding" and OAEPParameterSpec:
// --- we need a key pair to test encryption/decryption
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024); // speedy generation, but not secure anymore
KeyPair kp = kpg.generateKeyPair();
RSAPublicKey pubkey = (RSAPublicKey) kp.getPublic();
RSAPrivateKey privkey = (RSAPrivateKey) kp.getPrivate();
// --- encrypt given algorithm string
Cipher oaepFromAlgo = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING");
oaepFromAlgo.init(Cipher.ENCRYPT_MODE, pubkey);
byte[] ct = oaepFromAlgo.doFinal("owlstead".getBytes(StandardCharsets.UTF_8));
// --- decrypt given OAEPParameterSpec
Cipher oaepFromInit = Cipher.getInstance("RSA/ECB/OAEPPadding");
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-1"), PSpecified.DEFAULT);
oaepFromInit.init(Cipher.DECRYPT_MODE, privkey, oaepParams);
byte[] pt = oaepFromInit.doFinal(ct);
System.out.println(new String(pt, StandardCharsets.UTF_8));
The code will fail with a padding related exception if you substitute "SHA-256" for the MGF1 as parameter.
The reason why the extended algorithm is needed at all is compatibility with other Cipher algorithms. Code written for e.g. "RSA/ECB/PKCS1Padding" doesn't use any parameters, let alone OAEP parameters. So without the longer string OAEP cannot function as drop in replacement.
The mode of operation "ECB" doesn't mean anything in this context, it should have been "None" or it should have been left out completely. You can only encrypt a single block using the RSA implementation of the SunRSA provider.
If you want to encrypt more data, create a random (AES) symmetric key and encrypt that using OAEP. Then use the AES key to encrypt your specific data. This is called a hybrid cryptosystem as it uses both asymmetric and symmetric primitives to encrypt data.
Note that OAEP is not supported in JDK 7 (1.7) or earlier. OAEP is included in the implementation requirements for Java runtimes since Java 8:
RSA/ECB/OAEPWithSHA-1AndMGF1Padding (1024, 2048)
RSA/ECB/OAEPWithSHA-256AndMGF1Padding (1024, 2048)
Some protocols may require you to use SHA-256 or SHA-512 within the padding, as SHA-1 is being deprecated for most use - even if it is not directly vulnerable for this kind of purpose.
EDIT: this was written mostly with Java in mind. By now many other libraries seem to take a somewhat different approach and use the same hash for the (mostly empty) label and MGF1 - which does make more sense. If you have an invalid OAEP ciphertext you should first make sure that the right "default" is being used. It is impossible to wrong any library implementation for choosing their own default; in the end it is up to the protocol to define the hashes used. Unfortunately no mandatory default exists - which is especially a problem if protocol owners forget to fully specify a configuration for the algorithms.

Matching BlowfishJ Java implementation to dren blowfish javascript implementation; encryption values after 8-bytes are different

I'm having some issues with correlating the BlowsfishJ Java implementation (BlowfishJ Javadoc) to the dren Blowfish JavaScript implementation (dren Blowfish page).
On the Java side, I'm using Blowfish CBC, with a zero IV and the key is somekey. The plaintext is WillThisEQ.
On the JavaScript side, I PRESUME dren's implementation is using CBC and a zero IV, as well. The key is somekey and the plaintext is WillThisEQ, as well.
Here's the JavaScript code:
var bf = new Blowfish('some key');
var ciphertext = bf.encrypt('WillThisEQ');
var plaintext = bf.decrypt(ciphertext);
For the ciphertext, The first 8-bytes match for both implementations (WillThis). However, any subsequent bytes do NOT match (EQ000000). The IV is factored into the first block (Block Cipher Modes Wikipedia page). So, I don't think that's the problem.
How can I these two implementations to match?
Thank you very much for any help.
Your answer is at the very top of the dren BlowFish page you linked to:
You need to impliment your own cipher-block chaining if you want to encrypt anything longer than 8 bytes.
So no, it's not doing CBC. You could try the ECB version of BlowfishJ, but the security is much worse.
Here is Dojo version of Blowfish. Works for me.
http://sladex.org/blowfish.js/

Symmetric Encryption between .NET and Java

I am using a 3rd party platform to create a landing page, it is a business requirement that I use this particular platform.
On their page I can encrypt data and send it to my server through a request parameter when calling a resource on my site. This is done through an AES Symmetric Encryption.
I need to specify a password, salt (which must be a hex value) and an initialization vector (but be 16 characters).
Their backend is a .NET platform. I know this because if I specify an IV longer than it expects the underlying exception is:
System.Security.Cryptography.CryptographicException: Specified initialization vector (IV) does not match the block size for this algorithm.
Source: mscorlib
So for example, on their end I specify:
EncryptSymmetric("Hello World","AES","P4ssw0rD","00010203040506070809", "000102030405060708090A0B0C0D0E0F")
Where the inputs are: plain text, algorithm, pass phrase, salt, and IV respectively.
I get the value: eg/t9NIMnxmh412jTGCCeQ==
If I try and decrypt this on my end using the JCE or the BouncyCastle provider I get (same algo,pass phrase, salt & IV, with 1000 iterations): 2rrRdHwpKGRenw8HKG1dsA== which is completely different.
I have looked at many different Java examples online on how to decrypt AES. One such demo is the following: http://blogs.msdn.com/b/dotnetinterop/archive/2005/01/24/java-and-net-aes-crypto-interop.aspx
How can I decrypt a AES Symmetric Encryption that uses a pass phrase, salt and IV, which was generated by the .NET framework on a Java platform?
I don't necessarily need to be able to decrypt the contents of the encryption string if I can generate the same signature on the java side and compare (if it turns out what is really being generated here is a hash).
I'm using JDK 1.5 in production so I need to use 1.5 to do this.
As a side note, a lot of the example in Java need to specify an repetition count on the java side, but not on the .NET side. Is there a standard number of iterations I need to specify on the java side which matches the default .NET output.
It all depends on how the different parts/arguments of the encryption are used.
AES is used to encrypt bytes. So you need to convert the string to a byte array. So you need to know the encoding used to convert the string. (UTF7, UTF8, ...).
The key in AES has some fixed sizes. So you need to know, how to come from a passphrase to an AES key with the correct bitsize.
Since you provide both salt and IV, I suppose the salt is not the IV. There is no standard way to handle the Salt in .Net. As far as I remember a salt is mainly used to protect against rainbow tables and hashes. The need of a Salt in AES is unknown to me.
Maybe the passphrase is hashed (you did not provide the method for that) with the salt to get an AES key.
The IV is no secret. The easiest method is to prepend the encrypted data with the IV. Seen the length of the encrypted data, this is not the case.
I don't think your unfamiliarity of .Net is the problem here. You need to know what decisions the implementer of the encryption made, to come from your parameters to the encrypted string.
As far as I can see, it is the iteration count which is causing the issue. With all things the same (salt,IV,iterations), the .Net implementation generates the same output as the Java implementation. I think you may need to ask the 3rd party what iterations they are using

How to implement Java 256-bit AES encryption with CBC

I've read the following threads and they've helped a little, but I'm looking for a little more info.
How to write AES/CBC/PKCS5Padding encryption and decryption with Initialization Vector Parameter for BlackBerry
Java 256bit AES Encryption
Basically, what I am doing is writing a program that will encrypt a request to be sent over TCP/IP, and then decrypted by a server program. The encryption will need to be AES, and doing some research I found out I need to use CBC and PKCS5Padding. So basically I need a secret key and an IV as well.
The application I'm developing is for a phone, so I want to use the java security packages to keep the size down. I've got the design done, but unsure of the implementation of the IV and the shared key.
Here's some code:
// My user name
byte[] loginId = "login".getBytes();
byte[] preSharedKey128 = "ACME-1234AC".getBytes();
byte[] preSharedKey192 = "ACME-1234ACME-1234A".getBytes();
// 256 bit key
byte[] preSharedKey256 = "ACME-1234ACME-1234ACME-1234".getBytes();
byte[] preSharedKey = preSharedKey256;
// Initialization Vector
// Required for CBC
byte[] iv ={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
IvParameterSpec ips = new IvParameterSpec(iv);
byte[] encodedKey = new byte[loginId.length + preSharedKey.length];
System.arraycopy(loginId, 0, encodedKey, 0, loginId.length);
System.arraycopy(preSharedKey, 0, encodedKey, loginId.length, preSharedKey.length);
// The SecretKeySpec provides a mechanism for application-specific generation
// of cryptography keys for consumption by the Java Crypto classes.
// Create a key specification first, based on our key input.
SecretKey aesKey = new SecretKeySpec(encodedKey, "AES");
// Create a Cipher for encrypting the data using the key we created.
Cipher encryptCipher;
encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Initialize the Cipher with key and parameters
encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey, ips);
// Our cleartext
String clearString = "33,8244000,9999,411,5012022517,0.00,0,1,V330";
byte[] cleartext = clearString.getBytes();
// Encrypt the cleartext
byte[] ciphertext = encryptCipher.doFinal(cleartext);
// Now decrypt back again...
// Decryption cipher
Cipher decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
// Initialize PBE Cipher with key and parameters
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey, ips);
// Decrypt the cleartext
byte[] deciphertext = decryptCipher.doFinal(ciphertext);
In a nutshell what it should do is encrypt some message that can decrypted by the server without the server needing to get a key or IV from the phone. Is there a way I could do this where I could secure the IV and key on the phone, and still have the key and IV known by the server as well? Feel free to tell me to make things more clear if they're not.
There are a few problems with the code. First of all, you really should use a key generator to generate secret keys. Just using some text directly might work for some algorithms, but others have weak keys and so forth that need to be tested.
Even if you want to do password-based encryption, the password should be run through a key-derivation algorithm to produce a key, as shown in my answer to the question that you cited already.
Also, you shouldn't use the no-arg getBytes() method of String. This is platform dependent. If all of the strings that you are encoding contain only characters from the US-ASCII character set, make it clear by specifying that encoding explicitly. Otherwise, if the phone and server platforms use different character encodings, the key and IV won't turn out the same.
For CBC mode, it's best to use a new IV for every message you send. Usually, CBC IVs are generated randomly. Other modes like CFB and OFB require unique IVs for every message. IVs are usually sent with along the ciphertext—IVs don't need to be kept secret, but many algorithms will break if a predictable IV is used.
The server doesn't need to get the secret or IV directly from the phone. You can configure the server with the secret key (or password, from which the secret key is derived), but in many applications, this would be a bad design.
For example, if the application is going to be deployed to the phones of multiple people, it isn't a good idea for them to use the same secret key. One malicious user can recover the key and break the system for everyone.
A better approach is to generate new secret keys at the phone, and use a key agreement algorithm to exchange the key with the server. Diffie-Hellman key agreement can be used for this, or the secret key can be encrypted with RSA and sent to the server.
Update:
Diffie-Hellman in "ephemeral-static" mode (and "static-static" mode too, though that's less desirable) is possible without an initial message from the server to the phone, as long as the server's public key is embedded in the application.
The server public key doesn't pose the same risk as embedding a common secret key in the phone. Since it is a public key, the threat would be an attacker getting his hands on (or remotely hacking into) the phone and replacing the real public key with a fake key that allows him to impersonate the server.
Static-static mode could be used, but it's actually more complicated and a little less secure. Every phone would need its own unique key pair, or you fall back into the secret key problem. At least there would be no need for the server to keep track of which phone has which key (assuming there is some authentication mechanism at the application level, like a password).
I don't know how fast phones are. On my desktop, generating an ephemeral key pair takes about 1/3 of a second. Generating Diffie-Hellman parameters is very slow; you'd definitely want to re-use the parameters from the server key.
Done similar projects in a midlet before, I have following advice for you:
There is no secure way to store shared secret on the phone. You can use it but this falls into a category called Security through Obscurity. It's like a "key under mat" kind of security.
Don't use 256-bit AES, which is not widely available. You might have to install another JCE. 128-bit AES or TripleDES are still considered secure. Considering #1, you shouldn't worry about this.
Encryption using a password (different for each user) is much more secure. But you shouldn't use password as the key like you are showing in the example. Please use PBEKeySpec (password-based encryption) to generate the keys.
If you are just worried about MITM (man-in-the-middle) attacks, use SSL.

Categories