I just want to confirm my understanding of how AES works.
If company#1 is encrypting the data, and sending this data to company#2 to decrypt, and let's presume that one of them uses C# and the other Java.
As long as both are using the same shared secret key, is there anything else setting/configuration wise both parties should agree upon to make sure the data is correctly encryption and decrypted?
There is a lot that both have to agree upon:
shared secret key
How long is it? (Is key padding required?)
Is the actual key derived from another key or password with an additional salt?
Which key derivation function is used and what are their parameters? PBKDF2, bcrypt, scrypt, ...
Is the IV derived together with the key? (usually by requesting key size + IV size output from the key derivation function)
cipher characteristics:
block cipher like AES, Triple DES, Twofish, Rijndael, ...
cipher parameters such as block size in case it is variable
mode of operation like CBC, CTR, CFB, ...
for IV-based modes: How is the IV generated? Is it generated randomly and put into the container format or is it derived together with the key from a password and therefore doesn't need to be put into the ciphertext container?
for nonce-based modes like CTR: How big is the nonce (sometimes referred to as IV)?
for parametrized modes like CFB: How big is a segment?
padding mode like PKCS#7 padding (which is also referred to as PKCS#5 padding), ZeroPadding, ...
authentication (if any):
as mode of operation like GCM, EAX, SIV, ...
as separate encrypt-then-MAC/MAC-then-encrypt/encrypt-and-MAC scheme with a MAC like HMAC-SHA256, CMAC, HKDF, GHASH, ...
encoding of each component like Hex, Base32, Base64 or simply binary (no encoding)
Is everything encoded together into a textual format from the finished binary format or are the components encoded separately and concatenated together?
format:
Where to put IV/nonce/salt (if any)? (usually before the actual ciphertext)
Where to put authentication tag (if any)? (usually after the actual ciphertext)
Is Cryptographic Message Syntax applicable?
Related
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?
I'm trying to calculate HMAC with iv (without any additional key).
I need to pass it at the 'init' level. I know that usually there is no need in passing the iv, since there are default ivs for hmac/sha. But if I don't want to use the defaults, and want to supply my own iv how is it possible to implement in java? I've tried using javax, but it's MAC init accepts only the signing key.
For example:
Mac hmac = Mac.getInstance("HmacSHA1");
byte[] hmacKeyBytes = key.getBytes();
SecretKeySpec secretKey = new SecretKeySpec(hmacKeyBytes, "HmacSHA1");
hmac.init(secretKey);
I want to init with some iv value. But don't know how.
I'm referring to initial value used to start the hash/hmac iterated process. Usually it is some arbitrary number, not exposed to the user. I want to be able to change this default initialization vector for hash functions/ find some way to supply my own iv. How can I do it?
Thank you!
The HMAC takes the initial parameter only the key. Effectively - the same content should have the same authentication tag, so IV is not needed/desired by definition.
As far I recall from my cryptography classes having non-static IV would lead to vulnerabilities with MAC/HMAC for some algorithm implementations, but I don't recall details anymore (you could ask in the Cryptography section of the stackoverflow https://crypto.stackexchange.com/).
If you really want having a sort of IV, you can still prepend the IV to the content.
HMAC-SHA1 is called a message authentication code (MAC). This object takes as input a key K, and an arbitrary-length message X, and outputs a tag T. Basically, a MAC is secure if it's hard to find a new input X and a tag T such that HMAC-SHA1(K, M) = T, for an unknown key K.
My guess is that you're wondering what to do with the IV, because you're ushing HMAC-SHA1 with some sort of encryption scheme? AES-CTR encryption, for example, uses an IV. In this case, you must encrypt the ciphertext and IV. So in pseudocode:
(IV, C) := AES-CTR(K1, M) # Maybe the output is a string with the IV prepended
T := HMAC-SHA1(K2, (IV, C))
return (IV, C, T)
By the way, HMAC-SHA1 is no longer considered secure. Consider using something like HMAC-SHA256.
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
Talking about javax.crypto.Cipher
I was trying to encrypt data using Cipher.getInstance("RSA/None/NoPadding", "BC") but I got the exception:
ArrayIndexOutOfBoundsException: too much data for RSA block
Looks like is something related to the "NoPadding", so, reading about padding, looks like CBC is the best approach to use here.
I found at google something about "RSA/CBC/PKCS#7", what is this "PKCS#7"? And why its not listed on sun's standard algorithm names?
Update:
I'm wondering, if is a padding problem, why this example run just fine?
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import javax.crypto.Cipher;
/**
* Basic RSA example.
*/
public class BaseRSAExample
{
public static void main(
String[] args)
throws Exception
{
byte[] input = new byte[] { (byte)0xbe, (byte)0xef };
Cipher cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
// create the keys
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
new BigInteger("d46f473a2d746537de2056ae3092c451", 16),
new BigInteger("11", 16));
RSAPrivateKeySpec privKeySpec = new RSAPrivateKeySpec(
new BigInteger("d46f473a2d746537de2056ae3092c451", 16),
new BigInteger("57791d5430d593164082036ad8b29fb1", 16));
RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(pubKeySpec);
RSAPrivateKey privKey = (RSAPrivateKey)keyFactory.generatePrivate(privKeySpec);
// encryption step
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherText = cipher.doFinal(input);
// decryption step
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] plainText = cipher.doFinal(cipherText);
}
}
Update 2:
I realized that even if I use just Cipher.getInstance("RSA", "BC") it throws the same exception.
If you use a block cipher, you input must be an exact multiple of the block bit length.
In order to encipher arbitrary length data, you need first to pad you data to a multiple of the block length. This can be done with any method, but there are a number of standards. PKCS7 is one which is quite common, you can see an overview on the wikipedia article on padding.
Since block cipers operate on blocks, you also need to come up with a way of concatenating the encrypted blocks. This is very important, since naive techniques greatly reduce the strength of the encryption. There is also a wikipedia article on this.
What you did was to try to encrypt (or decrypt) data of a length which didn't match the block length of the cipher, and you also explicitly asked for no padding and also no chaining mode of operation.
Consequently the block cipher could not be applied to your data, and you got the reported exception.
UPDATE:
As a response to your update and GregS's remark, I would like to acknowledge that GregS was right (I did not know this about RSA), and elaborate a bit:
RSA does not operate on bits, it operates on integer numbers. In order to use RSA you therefore need to convert your string message into an integer m: 0 < m < n, where n is the modulus of the two distinct primes chosen in the generation process. The size of a key in the RSA algorithm typically refers to n. More details on this can be found on the wikipedia article on RSA.
The process of converting a string message to an integer, without loss (for instance truncating initial zeroes), the PKCS#1 standard is usually followed. This process also adds some other information for message integrity (a hash digest), semantical security (an IV) ed cetera. With this extra data, the maximum number of bytes which can be supplied to the RSA/None/PKCS1Padding is (keylength - 11). I do not know how PKCS#1 maps the input data to the output integer range, but
my impression is that it can take any length input less than or equal to keylength - 11 and produce a valid integer for the RSA encryption.
If you use no padding, your input will simply be interpreted as a number. Your example input, {0xbe, 0xef} will most probably be interpreted as {10111110 +o 11101111} = 1011111011101111_2 = 48879_10 = beef_16 (sic!). Since 0 < beef_16 < d46f473a2d746537de2056ae3092c451_16, your encryption will succeed. It should succeed with any number less than d46f473a2d746537de2056ae3092c451_16.
This is mentioned in the bouncycastle FAQ. They also state the following:
The RSA implementation that ships with
Bouncy Castle only allows the
encrypting of a single block of data.
The RSA algorithm is not suited to
streaming data and should not be used
that way. In a situation like this you
should encrypt the data using a
randomly generated key and a symmetric
cipher, after that you should encrypt
the randomly generated key using RSA,
and then send the encrypted data and
the encrypted random key to the other
end where they can reverse the process
(ie. decrypt the random key using
their RSA private key and then decrypt
the data).
RSA is a one-shot asymmetric encryption with constraints. It encrypts a single "message" in one go, but the message has to fit within rather tight limits based on the public key size. For a typical 1024 bit RSA key, the maximum input message length (with RSA as described in the PKCS#1 standard) is 117 bytes, no more. Also, with such a key, the encrypted message has length 128 bytes, regardless of the input message length. As a generic encryption mechanism, RSA is very inefficient, and wasteful of network bandwidth.
Symmetric encryption systems (e.g. AES or 3DES) are much more efficient, and they come with "chaining modes" which allow them to process input messages of arbitrary length. But they do not have the "asymmetric" property of RSA: with RSA, you can make the encryption key public without revealing the decryption key. That's the whole point of RSA. With symmetric encryption, whoever has the power to encrypt a message also has all the needed information to decrypt messages, hence you cannot make the encryption key public because it would make the decryption key public as well.
Thus it is customary to use an hybrid system, in which a (big) message is symmetrically encrypted (with, e.g., AES), using a symmetric key (which is an arbitrary short sequence of random bytes), and have that key encrypted with RSA. The receiving party then uses RSA decryption to recover that symmetric key, and then uses it to decrypt the message itself.
Beyond the rather simplistic description above, cryptographic systems, in particular hybrid systems, are clock full of little details which, if not taken care of, may make your application extremely weak against attackers. So it is best to use a protocol with an implementation which already handles all that hard work. PKCS#7 is such a protocol. Nowadays, it is standardized under the name of CMS. It is used in several places, e.g. at the heart of S/MIME (a standard for encrypting and signing emails). Another well-known protocol, meant for encrypting network traffic, is SSL (now standardized under the name of TLS, and often used in combination with HTTP as the famous "HTTPS" protocol).
Java contains an implementation of SSL (see javax.net.ssl). Java does not contain a CMS implementation (at least not in its API) but Bouncy Castle has some code for CMS.
This error indicates that the input data size is greater than the key modulus size. You will need a bigger key size to encrypt the data. If changing the key length is not an option, alternatively you may need to investigate if you are really expecting that big input data.
RSA can only be used to encrypt, when the number of bits being used to encrypt is greater then the size of the thing you are tying to encrypt + 11 bytes
Public-Key Cryptography Standards - PKCS
Scroll down a bit and you'll see it. It's not an cypher algortihm (like RSA) or a cypher mode like CBC, but a description of the way the certificate is encoded as bytes (i.e., a data structure syntax). You can find the spec for it here.
PKCS#7 is listed (referring to your link). It's encoding is PKCS7
Description
A PKCS#7 SignedData object, with the
only significant field being
certificates.
Use java.security.cert.CertificateFactory or CertPath when using PKCS7.
RSA is a block cipher. It encrypts block of the same key size.
Therefore, BouncyCastle RSA gives an exception if you try to encrypt a block
which is longer than the key size.
That's all I can tell you so far.
You should not encrypt your data using RSA directly. Encrypt your data with a random symmetric key (i.e. AES/CBC/PKCS5Padding) and encrypt the symmetric key using RSA/None/PKCS1Padding.
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.