RSA file Encryption and Decryption
843810Feb 4 2004 — edited Feb 5 2004Dear all,
I try to use the RSA approach to encrypt a file and to decrypt a file. However, there are some errors.
In the decryption part, i use the Chinese Remainder Theorem (CRT) for enhancing the speed.
First, i try to read all bytes from a file being encrypted and then convert each byte into BigInteger and do the encryption. However, during the conversion, there are some bytes become negative BigInteger. when these negative BigInteger convert to bytes, a large number are got which are not same as the original byte value. If the BigInteger is positive sign, then the conversion is correct.
I dunno what's wrong with it. Hope you can help to find the bugs.
Also, i want to know is there any java API which can help me to encrypt and decrypt the file so that i can just call the function without implementation by myself.
Thanks a lot
The following is my code.
-----------------------------------------------------------------------------------------------------------------------------------------
import java.security.*;
import java.security.interfaces.RSAPublicKey;
import java.security.interfaces.RSAPrivateCrtKey; // For Chinese Remainder Theorem
import java.security.spec.InvalidKeySpecException;
import java.math.BigInteger;
import java.io.*;
import java.security.spec.PKCS8EncodedKeySpec; // for encoded private key
import java.security.spec.X509EncodedKeySpec; // for encoded public key
import java.security.spec.RSAKeyGenParameterSpec;
import java.security.KeyFactory;
/*
* Credit :
* Neal R. Wagner URL: http://www.cs.utsa.edu/~wagner/laws/ARSAFast.html
* The Chinese Remainder Theorem implementation is implemented by Neal R. Wagner
*/
/*
* MyRSAKey
* - It creates two keys ie public and private key
* - but don't initialize them by constructor
* - when a user calls getRSAKey, it first tries to
* - get the key from file. If the file doesn't exist,
* - then it will create two keys using keyPairBGenerator.
*/
class MyRSAKey {
//instance
private RSAPublicKey publicKey = null; // static as CP only has one key Pair
private RSAPrivateCrtKey privateKey = null; // using Chinese Remainder Theorem
//method
/*
* Function: genKey()
* usage: Generate a public key and a private key using RSA algorithm
* initialize both publicKey and privateKey field.
*/
public void genKeys()
{
FileInputStream fin = null;
KeyPairGenerator keyGen = null;
SecureRandom random = null;
try
{
// create the keyPairGenerator for RSA
keyGen = KeyPairGenerator.getInstance("RSA");
// initialize the keyPairGenerator using algorithm-independent approach
random = SecureRandom.getInstance("SHA1PRNG", "SUN");
//keyGen.initialize(1024, random); // Either of one
RSAKeyGenParameterSpec keySpec = new RSAKeyGenParameterSpec(1024,RSAKeyGenParameterSpec.F0);
keyGen.initialize(keySpec, random);
// generate a pair of keys
KeyPair pair = keyGen.generateKeyPair();
publicKey = (RSAPublicKey)pair.getPublic();
privateKey = (RSAPrivateCrtKey)pair.getPrivate();
// Generate a private key as defined in the PKCS#1 standard,
// using the Chinese Remainder Theorem (CRT) information values
System.out.println("Generate Key process completed");
}
catch (Exception e) {
System.out.println("No such Random/KeyPairGenerator algorithm or provider");
System.exit(0);
}
}
/*
* Function: saveKey()
* usage: Save two keys into files "publicAns1.key" & "privateAns1.key" respectively
* if no such file, then throw IOException
* return: RSAPublicKey
*/
public void saveKeys() {
FileOutputStream fout = null;
try
{
// saving public key using X.509 encoding scheme
fout = new FileOutputStream("publicAns1.key");
fout.write(publicKey.getEncoded());
fout.close();
// saving private key using PKCs8 encoding scheme
fout = new FileOutputStream("privateAns1.key");
fout.write(privateKey.getEncoded());
fout.close();
System.out.println("Saving process completed");
}
catch (IOException e) {
System.out.println("#ERROR : Writing file problem");
System.exit(0);
}
}
/*
* Function: getBothKeys()
* usage: Get both public and private key from the file "publicAns1.key" & "privateAns1.key" respectively.
* If either of them fails getting from files, generate a new pair of key
*/
public void getBothKeys()
{
try
{
readPublicKey();
readPrivateKey();
}
catch (IOException e) { // If either public or private key cannot be obtained from files, generate a new pair of keys
// may be make a dialog box for GUI to display "No key files find"
System.out.println("No Key files found, Generate a key pair now");
genKeys();
saveKeys();
}
}
/*
* Function: readPublicKey()
* usage: Get the public key from a file "publicAns1.key"
* if no such file, then throw IOException
* initialize publicKey field.
*/
public void readPublicKey() throws IOException {
FileInputStream fin = null;
File f = new File("publicAns1.key");
byte[] keyData = new byte[(int)f.length()];
try
{
// read the public key
fin = new FileInputStream("publicAns1.key");
fin.read(keyData);
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(keyData);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
publicKey = (RSAPublicKey)keyFactory.generatePublic(pubKeySpec);
fin.close();
System.out.println("Public File byte " + f.length());
System.out.println("Read Public file complete");
}
catch (NoSuchAlgorithmException e) {System.out.println("#ERROR : No such Public key Algorithm");System.exit(0);}
catch (InvalidKeySpecException e) {System.out.println("#ERROR : Invalid Public key specalization");System.exit(0);}
}
/*
* Function: readPrivateKey()
* usage: Get the private key from a file "privateAns1.key"
* if no such file, then throw IOException
* initialize privateKey field.
*/
public void readPrivateKey() throws IOException {
FileInputStream fin = null;
File f = new File("privateAns1.key"); // for getting number of byte of the file
byte[] keyData = new byte[(int)f.length()];
try
{
// read the public key
fin = new FileInputStream("privateAns1.key");
fin.read(keyData);
PKCS8EncodedKeySpec priKeySpec = new PKCS8EncodedKeySpec(keyData);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
privateKey = (RSAPrivateCrtKey)keyFactory.generatePrivate(priKeySpec);
fin.close();
System.out.println("Private File byte " + f.length());
System.out.println("Read Private file complete");
}
catch (NoSuchAlgorithmException e) {System.out.println("#ERROR : No such Private key Algorithm"); System.exit(0);}
catch (InvalidKeySpecException e) {System.out.println("#ERROR : Invalid Private key specalization"); System.exit(0);}
}
public RSAPublicKey getPublicKey() {
return publicKey;
}
public RSAPrivateCrtKey getPrivateKey() {
return privateKey;
}
public void testing() {
System.out.println("public Modulus " + publicKey.getModulus());
System.out.println("private Modulus " + privateKey.getModulus());
//System.out.println("Alogrithm " + publicKey.getAlgorithm());
//System.out.println("Alogrithm " + privateKey.getAlgorithm());
//System.out.println("Alogrithm " + publicKey.getEncoded());
//System.out.println("Alogrithm " + privateKey.getEncoded());
//System.out.println("Alogrithm " + publicKey.getFormat());
//System.out.println("Alogrithm " + privateKey.getFormat());
System.out.println("public Exponent " + publicKey.getPublicExponent());
System.out.println("private Exponent " + privateKey.getPrivateExponent());
}
/*
* Function: publicKeyEncrypt(BigInteger beingEncrypted)
* Parameter: BigInteger[] beingEncrypted
* Usage: Use the RSA equation to encrypt the BigInteger
* Return: BigInteger[]
*/
public BigInteger[] publicKeyEncrypt(BigInteger[] beingEncrypted) {
// Create the array for storing the encrypted value and return later
BigInteger[] encryptedArr = new BigInteger[beingEncrypted.length];
BigInteger modulus = publicKey.getModulus();
BigInteger exponent = publicKey.getPublicExponent();
for (int i=0; i<beingEncrypted.length; i++ )
{
encryptedArr[i] = beingEncrypted.modPow(exponent,modulus);
}
System.out.println("Encryption Process Completed");
return encryptedArr;
}
// Use this method first, May be modified to the Fast Decryption later
public BigInteger[] privateKeyDecrypt(BigInteger[] beingDecrytped) {
// Create the array for storing the encrypted value and return later
BigInteger[] decryptedArr = new BigInteger[beingDecrytped.length];
BigInteger modulus = privateKey.getModulus();
BigInteger exponent = privateKey.getPrivateExponent();
// calculate the required coefficient for CRT
final BigInteger c2 = privateKey.getPrimeP().modInverse(privateKey.getPrimeQ());
BigInteger value1 = null , value2 = null, value3 = null;
for (int i=0; i<beingDecrytped.length; i++ )
{
value1 = beingDecrytped[i].modPow(privateKey.getPrimeExponentP(), privateKey.getPrimeP());
value2 = beingDecrytped[i].modPow(privateKey.getPrimeExponentQ(), privateKey.getPrimeQ());
value3 = ((value2.subtract(value1)).multiply(c2)).remainder(privateKey.getPrimeQ());
if (value3.compareTo(BigInteger.ZERO) < 0)
value3 = value3.add(privateKey.getPrimeQ());
decryptedArr[i] = value1.add(value3.multiply(privateKey.getPrimeP()));
System.out.println("Decryption : "+ i +": " + decryptedArr[i]);//testing
}
System.out.println("Decryption Process Completed");
return decryptedArr;
}
public static void main(String[] main) {
MyRSAKey test = new MyRSAKey();
test.getBothKeys();
// Test Encryption/Decryption
// Encryption
FileInputStream fin = null;
FileOutputStream fout = null;
File f = new File("logo.gif");
BigInteger[] encypted = null;
byte[] fileData = new byte[(int)f.length()];
System.out.println("f.length " + f.length() +" (int)f.length " + (int)f.length());
System.out.println("byte array length " + fileData.length);
try
{
fin = new FileInputStream("logo.gif");
//fout = new FileOutputStream("Encrypted.jpg");
fin.read(fileData);
// testing
byte[] tmp = new byte[1];
BigInteger[] beingEncrypted = new BigInteger[(int)f.length()];
for (int i=0;i<f.length() ;i++ )
{
tmp[0] = fileData[i];
beingEncrypted[i] = new BigInteger(tmp);
System.out.println("Original: " + i +": "+ beingEncrypted[i]);
}
encypted = test.publicKeyEncrypt(beingEncrypted);
//fout.write(result);
fin.close();
//fout.close();
}
catch (IOException e)
{
}
// Decryption
//f = new File("Encrypted.jpg");
//fileData = new byte[(int)f.length()];
//try
//{
//fin = new FileInputStream("Encrypted.jpg");
//fout = new FileOutputStream("Decrypted.jpg");
//fin.read(fileData);
BigInteger[] decrypted = test.privateKeyDecrypt(encypted);
//fout.write(result);
//fin.close();
//fout.close();
//}
//catch (IOException e)
//{
//}
/*
Integer i1 = new Integer(3009098098);
Integer i2 = new Integer(2280980890980);
byte[] b1 = new byte[1];
b1[0] = i1.byteValue();
byte[] b2 = new byte[1];
b2[0] = i2.byteValue();
BigInteger bi1 = new BigInteger(b1);
BigInteger bi2 = new BigInteger(b2);
byte bc1 = bi1.byteValue();
byte bc2 = bi2.byteValue();
System.out.println("b1 " + b1[0] + " b2 " + b2[0] );
System.out.println("bc1 " + bc1 + " bc2 " + bc2);
*/
}
};