Thursday, August 27, 2015

RSA Encryption/Decryption for Longer Strings

Previously we did see how we can encrypt/decrypt messages using RSA public/private keys here.
But it seems that there is a limit to the actual message that can be encrypted/decrypted using the method described there and that is based on the key length being used while generating the KeyPair.

The limit is seen as for RSA n bit key length , encryption limit = n/8 - 11
and for decryption , limit = n/8

So for RSA 1024 bit, max (1024/8 -11) = 117 bytes can be encrypted, and 128 bytes can be decrypted.
Similarly, for RSA 2048 bit, max (2048/8 -11) = 245 bytes can be encrypted and 256 bytes can be decrypted at a time.

So if one tries to use perform "RSAEncryption(publickey , message) , where if the message length is more than 117 (for 1024 bit RSA) or 245 (for 2048 bit RSA), then it turns out that the encryption will fail.
Same happens if one tries to perform "RSADecryption(privatekey , encryptedMessage)" ,  where if the encrypted message length is more than 128(for 1024 bit RSA) or 256 (for 2048 bit RSA), then the decryption will fail as well.


Does that mean long strings cannot be encrypted/decrypted by using RSA?

No.In case you want to encrypt/decrypt a message whose size is more than the limit specified as above, it needs to be handles separately rather than the approach used in previous post.
It has to be divided in block sizes based on the limit specified above, and then encryption/decyption can be performed on that block size.

Encrypting Long Message using N bit RSA


int KEY_LENGTH = N;(change it to key length used for Generating Keys i.e 1024/2048)

byte[] perfomRSAEncryption(PublicKey publicKey , byte[] message) {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE , publicKey);
int  limit = KEY_LENGTH/8 -11;
int position = 0;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
while(position < message.length) {
if(message.length - position < limit)
limit = message.length - position;
 byte[] data = cipher.doFinal(message , position , limit);
byteArrayOutputStream.write(data);
position += limit;
}

return byteArrayOutputStream.toByteArray();
}

Decrypting Long Message using N bit RSA


int KEY_LENGTH = N;(change it to key length used for Generating Keys i.e 1024/2048)

byte[] perfomRSADecryption(PublicKey publicKey , byte[] encryptedMessage) {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE , publicKey);
int  limit = KEY_LENGTH/8;
int position = 0;
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
while(position < encryptedMessage.length) {
if(encryptedMessage.length - position < limit)
limit = encryptedMessage.length - position;
 byte[] data = cipher.doFinal(encryptedMessage , position , limit);
byteArrayOutputStream.write(data);
position += limit;
}

return byteArrayOutputStream.toByteArray();



 

Encryption/Decryption in Android - Asymmetric

As previously explained about the Asymmetric encryption in the post here, lets look into implementing Asymmetric Encryption in Android.

Among the various asymmetric algorithms present, the most widely used algorithm is the RSA Algorithm.
Since this is asymmetric, we need to generate a public/private key pair and remember that public key is used for encryption, however private key is used for decryption.So whoever is  having "Public Key", can encrypt the message, but it can only be decrypted by the person who is having the "Private Key".

We need  following in order to perform encryption/decryption:-

a. KeyPair (java.security), which contains the Public/Private key pair
b.  KeyPairGenerator (java.security), to generate the KeyPair
c. Algorithm type:- to be used by KeyGenerator to generate SecretKey(RSA)
d. Key_Length :- The size of the key in bits


Generating a Public/Private KeyPair


KeyPair generateRSAKey() {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048) ;//key length as 2048 bit
return keyPairGenerator.generateKeyPair()
}

so Public key can be obtained by keyPair.getPublic();
and Private key by keyPair.getPrivate();
Again it is recommended to save the keys in encoded byte[] form using
keyPair.getPublic().getEncoded() -------------------Public Key
keyPair.getPrivate().getEncoded()-------------------Private Key


Regenerating the Keys from encoded byte[]


PublicKey decodePublicKey(byte[] encodedKey) {
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey) ;
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
return keyFactory.generatePublic(keySpec);
}

PublicKey decodePrivateKey(byte[] encodedKey) {
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey) ;
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 
return keyFactory.generatePrivate(keySpec);
}

Encrypting Message using RSA Public Key


byte[] performRSAEncryption(PublicKey publicKey , byte[] message) {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE , publicKey);
return cipher.doFinal(message);


Decrypting Message using RSA Private Key


byte[] performRSADecryption(PrivateKey privateKey , byte[] message) {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE , publicKey);
return cipher.doFinal(message);
}

Encryption/Decryption in Android - Symmetric

We all have at some point in our life, have used encryption to prevent the misuse/illegal access of some confidential data.
Encryption is basically the process of encoding the data in such a way that only some authorized parties can decode it and read/process it.

There are two basic techniques of encrypting information:-
  • Symmetric Encryption

  • Asymmetric Encryption


What is Symmetric encryption?

Symmetric encryption is the oldest technique used for encrypting data, where a "SecretKey" is used to modify the original data in such a way that it can be recreated using the same SecretKey.
 The SecretKey could be any random set of characters, or numbers.

What is asymmetric encryption?

The problem with "Symmetric encryption" is that, the SecretKey needs to be kept in a safe place, or else if it is leaked, anyone can easily decrypt the information that you were trying to hide.
Suppose you wanted to encrypt a piece of information like your bank details using a SecretKey and you have to transfer this information to your family. Then while exchanging these information(encrypted message + SecretKey) over internet, you need to make sure that they dont fall into the hands of wrong people, or else they can easily get the actual piece of information you were trying to hide.So how do we prevent such cases?
Asymmetric encryption is the answer to such questions.
In Asymmetric encryption,  a pair of keys is used(public/private).
The public key is used for just encrypting the data and the private key is used for decrypting the data.So whoever has the public key can encrypt any piece of information using it, but only the person who has the private key, can decrypt the message.


 In this post we will deep dive into performing symmetric encryption in Android.


We need  following in order to perform encryption/decryption:-
a. SecretKey (javax.crypto), which is needed to perform both encryption and decryption
b.  KeyGenerator (javax.crypto), to generate the SecretKey
c. Algorithm type:- to be used by KeyGenerator to generate SecretKey(such as AES/DES)
d. Key_Length :- The size of the key in bits



Generate a SecretKey


SecretKey generateSecretKey() {
 SecureRandom secureRandom = new SecureRandom();
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256 , secureRandom);//use key size as 256

//generate the secretkey from the keygenerator
return  keyGenerator.generateKey();
}

The above function returns the SecretKey of 256 bit length, using AES algorithm.
Once the SecretKey is generated, save it to some secure storage.
However, in practice, the secretkey is not directly saved, rather its byte[] encoded form is saved.The byte[] encoded secret key by using the below method :-

byte[] generateSecretKey() {
 SecureRandom secureRandom = new SecureRandom();
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256 , secureRandom);//use key size as 256

//generate the secretkey from the keygenerator
SecretKey secretKey =  keyGenerator.generateKey();
return secretKey.getEncoded();
}

So this way, save the encoded secret key to a file and we will see now how to encrypt data using this generated SecretKey.But before that, we need to regenerate the SecretKey from its byte[] encoded form.This can be done by creating a SecretKeySpec object and using the same algorithm type, which was used during key generation.Following code illustrates this :-

byte[] encodedSecretKey = generateSecretKey();
SecretKey secretKey = new SecretKeySpec(encodedSecretKey , "AES");


Encrypting Data using SecretKey

Encryption/Decryption is perfomed using Cipher(javax.crypto).

byte[] encryptData(SecretKey secretKey ,  byte[] originalData) {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE , secretKey);
return cipher.doFinal();
}


Decrypting Data using SecretKey


byte[] decryptData(SecretKey secretKey ,  byte[] modifedData) {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE , secretKey);
return cipher.doFinal();
}



Summary


Encrypting data :-

byte[] secretKey = generateKey();
byte[] encryptedMessage = encryptData(secretKey , "secret message".getBytes())


Decrypting data:-

byte[] secretKey = getSavedEncodedSecretKey();
byte[] decryptedMessage = decryptData(secretKey , encryptedMessage);