RSA - Encrypt in Android / Decrypt in PHP - java

I encrypt a word in java and I have trouble decrypting it in php.
here is how I create the keys in android:
public void GenerateAndSaveToFile(){
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
//////////////////////////
String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
File myDir = new File(root + "/keys");
myDir.mkdirs();
File file = new File (myDir, "private.key");
FileOutputStream fileout1 = new FileOutputStream(file);
ObjectOutputStream oout1 = new ObjectOutputStream(fileout1);
oout1.writeObject(priv.getModulus());
oout1.writeObject( priv.getPrivateExponent());
oout1.close();
///////////////////////
File file2 = new File (myDir, "public.key");
FileOutputStream fileout2 = new FileOutputStream(file2);
ObjectOutputStream oout2 = new ObjectOutputStream(new BufferedOutputStream(fileout2));
oout2.writeObject(pub.getModulus());
oout2.writeObject( pub.getPublicExponent());
oout2.close();
}
catch (Exception ex){
Exception e = ex;
}
}
here is how I encrypt the word with generated public key in android:
byte[] u1Encrypted = RSAEncrypt(String.valueOf(inputEmail.getText()).getBytes());
public byte[] RSAEncrypt(byte[] data) {
try {
PublicKey pubKey = ReadPublicKey();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
return cipherData;
}
catch (Exception ex)
{
Exception e = ex;
return null;
}
}
private PublicKey ReadPublicKey() throws IOException {
try {
AssetManager assetManager = getAssets();
InputStream in = assetManager.open("public.key");
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
catch (Exception ex)
{
Exception e = ex;
return null;
}
}
then I convert the encrypted string to base64 in android:
String u1EncryptedBase64 = Base64.encodeToString(u1Encrypted, Base64.DEFAULT);
and in php I decode the base64 string:
$encryptedString = base64_decode(u1EncryptedBase64);
get the private key:
$keytmp = fopen("../../../private.key", "r") or die("Unable to open file!");
$key = fread($keytmp,filesize("../../../private.key"));
$res = openssl_get_privatekey($key);
and finally I try to decrypt the string in php:
if (openssl_private_decrypt($encryptedString, $decrypted, $res)) {
echo $decrypted;
}
else
{
echo "problem";
}
and error I get is:
Warning: openssl_private_decrypt(): key parameter is not a valid private key ...
please guide me how to accompolish this task.
thanks

I can show you how i have done encryption in my android and decryption in php. It worked wonderfully fine.May be you can get some help from this. In android the code is like:
final private static String RSA_public_key="MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEApeRuOhn71+wcRtlN6JoW\n" +
"JLrVE5HKLPukFgpMdguNskBwDOPrrdYKP1e3rZMHN9oVB/QTTpkQM4CrGYlstUmT\n" +
"u5nEfdsH4lHRxe3qhi9+zOknWKJCnW4Cq70oITCAK08BIJ/4ZcGM1SUyv1+0u1aB\n" +
"cx6g1aKhthttRjNpck2LBaHVolt7Z4FTb5SdZMwJKRyEv8fuP6yyR0CJGEbQKZKA\n" +
"ODNKyqJ42sVzUQ2AMQIWdhkFdAFahKCL4MChGvKU6F20cHdvokyxXJjU3sZobjNf\n" +
"i+8FzH9hd7y8kmi4o3AKP69p5asgflXoXHpo135i3NzZqlNJ+Bs9pY+90u9iLScp\n" +
"JwIBAw==";
static String enccriptData(String txt)
{
String encoded = "";
byte[] encrypted = null;
try {
byte[] publicBytes = Base64.decode(RSA_public_key, Base64.DEFAULT);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); //or try with "RSA"
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
encrypted = cipher.doFinal(txt.getBytes());
encoded = Base64.encodeToString(encrypted, Base64.DEFAULT);
}
catch (Exception e) {
e.printStackTrace();
}
return encoded;
}
I have paste that encoded string that is returned in the above function in below $string. This is the code for php:
<?php
$string="W39VlV1Q96QzDIR/jINzaEL7rh2Z+Z90uxJ1DtaSfkVKzIgt2TIkxsuRY+A2icwPtTdq6+9j1Xb009KT+ck2KD+dot3wPL5UaHqApbZSi6UZan/nDbFCNJdffTlTWsPS2ThEefeMMSs8HE2ORSt42D8cxYlogOvkvlLr60cHYKwfC1itLSqPuYR+C/gPAf6yCteLbj//EkJp8TemlmPi0eSsH492FgrmBqiTOS4LzpzsPFpSI4KJbuM2dvqp5jkt7MnpR1laILmyC37fA5XPUQmEQChoG5eSbMxqO7SPboYC1BH9ATy6uTS1MGXGDzJ2FSJ41MMRV1Ul/4UNFVA8Ng==";
$encryptedString = base64_decode($string);
$key="-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCl5G46GfvX7BxG
2U3omhYkutUTkcos+6QWCkx2C42yQHAM4+ut1go/V7etkwc32hUH9BNOmRAzgKsZ
iWy1SZO7mcR92wfiUdHF7eqGL37M6SdYokKdbgKrvSghMIArTwEgn/hlwYzVJTK/
X7S7VoFzHqDVoqG2G21GM2lyTYsFodWiW3tngVNvlJ1kzAkpHIS/x+4/rLJHQIkY
RtApkoA4M0rKonjaxXNRDYAxAhZ2GQV0AVqEoIvgwKEa8pToXbRwd2+iTLFcmNTe
xmhuM1+L7wXMf2F3vLySaLijcAo/r2nlqyB+VehcemjXfmLc3NmqU0n4Gz2lj73S
72ItJyknAgEDAoIBAG6YSXwRUo/yvYSQ3psRZBh8jg0L3B39GA6xiE6yXnbVoAiX
8nPkBtTlJR5iBM/muK/4DN8QtXerHLuw8yOGYn0RLak8r+w2i9lJRwQfqd3wxOXB
gb5JVx0oxWt1qseKAMBqpZkrszjDdyo/zdI5q6IUazkXFnlnni7M8PbeXK5q0PE6
0XclC1W79jX71D8d24SITAfXDqaXOwObSn9dadw1gsxx8fPd6Fr7ZTS0AddxJZN2
jNK14xkv2rkxdP1W529gnCVQUhju5SPJS5QwphI7KyfH7wTHnBOhbhp3FpaVKPz0
biLwZ6D0xgR6reZofz+t1cvDOha54wC4ZZYJyTsCgYEA0blJn8zxAHDSj8z/01zz
dc1qdYfdlf9gEWgr+APS9XSowGg+CdQN2W0XwySlpPoMZyCKM/aH0DNcl11yynpL
Mkm5MU2V2T+VKWXwUNHrGXSVRJkgLu+iD1Pt0oGPfS9qRYydG5TBjQEVrBrh4Jtk
KdsMBA82mgxEdFqtERbTpi0CgYEAyn85oWfYwf4oHEbSd218RauRBqwMhk39nyqx
6Gaza/k6Ri+5hBjqvVt8pT1Obrji5fZFU1IH5wecQae1mvIQJv+tVBy+XPedU8Mo
Jj3/TPwBAHezTADvQyEIwPot6y5lZt2fX7Urv+n1k7XkfWfb8O/ChTc/zHc0dPct
uLVE1SMCgYEAi9Dbv932AEs3CoiqjOiiTojxo6/pDqpAC5rH+q03Tk3F1ZrUBo1e
kPNlLMMZGKay72sGzU8FNXeTD5Oh3FGHdtvQy4kOkNUOG5lK4IvyEPhjgxDAH0ps
Cjfz4au0/h+cLl2+EmMrs1YOcryWlbztcTyyrV95vAgtouceC2SNGXMCgYEAhv97
wO/l1qlwEtnhpPOoLnJgrx1drt6pFMchRZnM8qYm2XUmWBCcfjz9w340SdCXQ/mD
jOFamgUS1m/OZ0wKxKpzjWh+6KUTjSzFbtP/iKgAqvp3iACfghYF1fwenMmY7z5q
P84dKpv5DSPtqO/n9fUsWM9/3aTNo09z0HjYjhcCgYEAoN+1/ZzonPWDIY/u+7bW
e8BkcuBVpMZe7qBYHeVix89yvyuVE+erKqurnG7fN7YIDX8V1OcVP+qHw8fJNQKL
wd03nNIIJyTPXodgty3HYjBUe8fVn/8P+JOv2U7bJCkUGlFeyZIMZWEsYd8t5794
3fotiYXOUug9bFtnGHRyY7I=
-----END PRIVATE KEY-----";
openssl_private_decrypt($encryptedString, $decrypted, $key);
$string1=$decrypted;
echo $string1;
?>
The private and public keys are made for each other.

Related

Openssl equivalent command to decrypt for java encrypted base64 file aes

By referring this im able to implement file encryption in java.
And after encryption im encoding the file with base64(note: I do not want to use other libraries, ex: Base64InputStream)
Content of original file is "hello".getBytes(UTF_8);
With below command im able to decrypt(without base64 data)
openssl enc -nosalt -aes-256-cbc -d -in file.crypt -out file.txt -k abcdefghijklmop -md sha1
But im unable to provide base64 encoded file to openssl, tried below commands:
openssl enc -nosalt -aes-256-cbc -d -base64 -in file.base64 -out file.txt -k abcdefghijklmop -md sha1
bad decrypt
base64 file.base64 | openssl enc -d -a -aes-256-cbc > decrypted -k abcdefghijklmop -md sha1
bad magic number
Encryption java code:
static String password = "abcdefghijklmop";
public static void encryptNew(String path) {
try {
Log.e("test", "encrypt start " + path);
FileInputStream fis = new FileInputStream(path);
FileOutputStream fos = new FileOutputStream(path.concat(".crypt"));
byte[] hash = new byte[0];
byte[] keyAndIv = new byte[0];
for (int i = 0; i < 3 && keyAndIv.length < 48; i++) {
final byte[] hashData = array_concat(hash, password.getBytes(UTF_8));
final MessageDigest md = MessageDigest.getInstance("SHA-1");
hash = md.digest(hashData);
keyAndIv = array_concat(keyAndIv, hash);
}
final byte[] keyValue = Arrays.copyOfRange(keyAndIv, 0, 32);
final byte[] iv = Arrays.copyOfRange(keyAndIv, 32, 48);
final SecretKeySpec secretKeySpec = new SecretKeySpec(keyValue, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
int b;
byte[] d = new byte[8];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
cos.flush();
cos.close();
fis.close();
} catch (Exception e) {
e.printStackTrace();
}
encodeFile(path.concat(".crypt"));
}
Encode file code:
public void encodeFile(String path) {
FileOutputStream stream = null;
FileReader fr = null;
try {
stream = new FileOutputStream(path.concat(".base64"),true);
fr = new FileReader(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
BufferedReader br=new BufferedReader(fr);
String line;
while((line=br.readLine())!=null)
{
String encoded = android.util.Base64.encodeToString(line.getBytes(), android.util.Base64.DEFAULT);
stream.write(encoded.getBytes());
}
} catch (IOException e) { e.printStackTrace(); } finally { try { fr.close(); stream.close(); } catch (IOException e) {e.printStackTrace();}}}
Please suggest on correct openssl command to decrypt java(aes encrypted -> base64 encoded) file.

AES Encryption in android and decryption in php and vice versa

I am trying to learn AES by testing my code against https://aesencryption.net. I previously had an error in Base64.encodeBase64String and also Base64.decodeBase64 // encode/decode Base64. So I manipulated Base64 somehow to resolve the error. Now in my app the text is encrypted and decrypted properly, I think. But when I try to encrypt or decrypt the same text server-side (at aesencryption.net), the site is not able to decrypt my encrypted string. Please help.
Following is my code :
public class MainActivity extends AppCompatActivity {
static final String TAG = "SymmetricAlgorithmAES";
private static SecretKeySpec secretKey ;
private static byte[] key ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Original text
// {"type":"Success","httpCode":"200","code":"200","message":{"pin":"11111"},"extra":""}
String theTestText = "hi";
TextView tvorig = (TextView)findViewById(R.id.tvorig);
tvorig.setText("\n[ORIGINAL]:\n" + theTestText + "\n");
final String strPssword = "android";
setKey(strPssword);
// Encode the original data with AES
byte[] encodedBytes = null;
try {
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE,secretKey);
encodedBytes = c.doFinal(theTestText.getBytes());
} catch (Exception e) {
Log.e(TAG, "AES encryption error");
}
TextView tvencoded = (TextView)findViewById(R.id.tvencoded);
tvencoded.setText("[ENCODED]:\n" +
Base64.encodeToString(encodedBytes, Base64.DEFAULT) + "\n");
Log.d(TAG, Base64.encodeToString(encodedBytes, Base64.DEFAULT));
// Decode the encoded data with AES
byte[] decodedBytes = null;
try {
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.DECRYPT_MODE, secretKey);
decodedBytes = c.doFinal(encodedBytes);
} catch (Exception e) {
Log.e(TAG, "AES decryption error");
}
TextView tvdecoded = (TextView)findViewById(R.id.tvdecoded);
tvdecoded.setText("[DECODED]:\n" + new String(decodedBytes) + "\n");
}
public static void setKey(String myKey){
MessageDigest sha = null;
try {
key = myKey.getBytes("UTF-8");
System.out.println(key.length);
sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
System.out.println(key.length);
System.out.println(new String(key,"UTF-8"));
secretKey = new SecretKeySpec(key, "AES");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
Thanks in advance.
I do something like this which actually works ;)
public class AESCrypter {
private final Cipher cipher;
private final SecretKeySpec key;
private AlgorithmParameterSpec spec;
public AESCrypter(String password) throws Exception
{
// hash password with SHA-256 and crop the output to 128-bit for key
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update(password.getBytes("UTF-8"));
byte[] keyBytes = new byte[32];
System.arraycopy(digest.digest(), 0, keyBytes, 0, keyBytes.length);
cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
key = new SecretKeySpec(keyBytes, "AES");
spec = getIV();
}
public AlgorithmParameterSpec getIV()
{
byte[] iv = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, };
IvParameterSpec ivParameterSpec;
ivParameterSpec = new IvParameterSpec(iv);
return ivParameterSpec;
}
public String encrypt(String plainText) throws Exception
{
cipher.init(Cipher.ENCRYPT_MODE, key, spec);
byte[] encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
String encryptedText = new String(Base64.encode(encrypted, Base64.DEFAULT), "UTF-8");
return encryptedText;
}
public String decrypt(String cryptedText) throws Exception
{
cipher.init(Cipher.DECRYPT_MODE, key, spec);
byte[] bytes = Base64.decode(cryptedText, Base64.DEFAULT);
byte[] decrypted = cipher.doFinal(bytes);
String decryptedText = new String(decrypted, "UTF-8");
return decryptedText;
}
}
Call this class like this :
try {
AESCrypter _crypt = new AESCrypter("password");
String output = "";
String plainText = "top secret message";
output = _crypt.encrypt(plainText); //encrypt
System.out.println("encrypted text=" + output);
output = _crypt.decrypt(output); //decrypt
System.out.println("decrypted text=" + output);
} catch (Exception e) {
e.printStackTrace();
}
And for iPhone (Code is here) : https://github.com/Gurpartap/AESCrypt-ObjC
Hope this code works for you too :)
The PHP code uses CBC mode by default while your Java code does not specify the same, and leaves it to the underlying implementation. If I recall correctly its probably ECB/PKCS5Padding. Your PHP implementation is using 'CBC' with no padding (mcrypt doesn't support padding by default but you can do so manually).
Its very important be be very specific about mode, padding, and charset when working with different platforms else you will run into different defaults.
Try initializing your cipher as follows: Cipher.getInstance("AES/CBC/NoPadding");
fun encrypt(encrypted: String): String? {
try {
val secretKey = "secretKey" //The secret key, 32 bytes string.
val ivKey = "ivKey" // The initialization vector, 16 bytes string.
val iv = IvParameterSpec(hashIV.toByteArray(Charsets.UTF_8))
val skySpec = SecretKeySpec(hashKey.toByteArray(Charsets.UTF_8), "AES-256-CBC")
val cipher: Cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING")
cipher.init(Cipher.ENCRYPT_MODE, skySpec, iv)
val original: ByteArray = cipher.doFinal(encrypted.toByteArray())
return Base64.encode(
Base64.encodeToString(original, Base64.NO_WRAP).toByteArray(charset("UTF-8")),
Base64.NO_WRAP
).decodeToString()
} catch (ex: Exception) {
ex.printStackTrace()
}
return null
}
fun decrypt(encrypted: String?): String? {
try {
val secretKey = "secretKey" //The secret key, 32 bytes string.
val ivKey = "ivKey" // The initialization vector, 16 bytes string.
val iv = IvParameterSpec(hashIV.toByteArray(Charsets.UTF_8))
val skySpec = SecretKeySpec(hashKey.toByteArray(Charsets.UTF_8), algorithm)
val cipher: Cipher = Cipher.getInstance(transformation)
cipher.init(Cipher.DECRYPT_MODE, skySpec, iv)
val original: ByteArray = cipher.doFinal(
Base64.decode(
Base64.decode(encrypted, Base64.NO_WRAP),
Base64.NO_WRAP
)
)
return original.decodeToString()
} catch (ex: Exception) {
ex.printStackTrace()
}
return null
}
openssl_encrypt

Android javax.crypto.BadPaddingException: pad block corrupted

I am trying to decrypt a file using the following code:
Uri targURI = Uri.parse("content://xxxx/yyy.txt");
try {
InputStream content = getContentResolver().openInputStream(targURI);
BufferedReader reader1 = new BufferedReader(new InputStreamReader(content));
String line1;
String text = "";
while ((line1 = reader1.readLine()) != null) {
text+=line1;
}
Log.i("FILE ENCRYPTED", text);
String DECRYPTED = "";
DECRYPTED = decrypt(text);
Log.i("FILE DECRYPTED:", DECRYPTED);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public String decrypt(String paramString) throws Exception {
String md5_pin1 = "";
String md5_pin = MD5(md5_pin1);
SecretKeySpec keySpec = new SecretKeySpec(md5_pin.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] paramString1 = Base64.decode(paramString.getBytes(), 0);
byte[] paramstring2 = cipher.doFinal(paramString1);
String decoded = new String(paramstring2, "UTF-8");
return decoded;
}
#NonNull
public static String MD5(String paramString) throws Exception {
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
digest.update(paramString.getBytes());
byte messageDigest[] = digest.digest();
StringBuffer hexString = new StringBuffer();
int i=0;
while( i < messageDigest.length) {
String str = Integer.toHexString( messageDigest[i] & 0xFF );
if (str.length() == 1) {
hexString.append("0");
}
hexString.append(str);
i += 1;
}
return hexString.toString();
}
as it is showed the file is accessed using a content provider, and stored in a String variable, and actually the correct string value is stored (encrypted data).
The way to decrypt it is to get a seed (empty space in this case), and then use MD5 digest, then use that value to encrypt/decrypt the cleartext.
However whenever the code reaches: String decoded = new String(paramstring2, "UTF-8"); the error message: pad block corrupted is thrown.
Any ideas what I am doing wrong?
Avoid using default padding for cipher as it may be different on different environment.
Try the following code:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Also use the same padding for encrypting the file.
You can use the following methods:
private static byte[] encrypt(byte[] data, byte[] key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = new byte[cipher.getBlockSize()];
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), ivParams);
return cipher.doFinal(data);
}
private static byte[] decrypt(byte[] encrypted, byte[] key) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] ivByte = new byte[cipher.getBlockSize()];
IvParameterSpec ivParamsSpec = new IvParameterSpec(ivByte);
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), ivParamsSpec);
return cipher.doFinal(encrypted);
}
This was not a problem related to coding.
Please disregard this question

RSA encrypt share data between 2 client

Is it possible to encrypt a file with 2 RSA key (private key from pair A and public key from pair B), so that user B can open the file with his private key and A's public key?
I have code build in java and I still try encrypt it manually so I know my program work or not but when I try encrypt my data in second time's my data broken and didn't encrypt at all.
it's my code :
public static void main(String[] args) throws Exception {
generateKeys();
RSA.rsaEncrypt("AES.key","RSA(AES).key");
RSA.rsaDecrypt("RSA(AES).key","AES(RSA).key");
}
public static void generateKeys() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
PublicKey publicKey = kp.getPublic();
PrivateKey privateKey = kp.getPrivate();
System.out.println("keys created");
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(publicKey,
RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(privateKey,
RSAPrivateKeySpec.class);
saveToFile("publicA.key", pub.getModulus(), pub.getPublicExponent());
saveToFile("privateA.key", priv.getModulus(), priv.getPrivateExponent());
System.out.println("keys saved");
}
public static void saveToFile(String fileName, BigInteger mod,
BigInteger exp) throws IOException {
ObjectOutputStream fileOut = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream(fileName)));
try {
fileOut.writeObject(mod);
fileOut.writeObject(exp);
} catch (Exception e) {
throw new IOException("Unexpected error");
} finally {
fileOut.close();
System.out.println("Closed writing file.");
}
}
// Return the saved key
static Key readKeyFromFile(String keyFileName) throws IOException {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(
in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
KeyFactory fact = KeyFactory.getInstance("RSA");
if (keyFileName.startsWith("publicB")) {
return fact.generatePublic(new RSAPublicKeySpec(m, e));
} else {
return fact.generatePrivate(new RSAPrivateKeySpec(m, e));
}
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
System.out.println("Closed reading file.");
}
}
// Use this PublicKey object to initialize a Cipher and encrypt some data
public static void rsaEncrypt(String file_loc, String file_des)
throws Exception {
byte[] data = new byte[32];
int i;
System.out.println("start encyption");
Key pubKey = readKeyFromFile("publicB.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
FileInputStream fileIn = new FileInputStream(file_loc);
FileOutputStream fileOut = new FileOutputStream(file_des);
CipherOutputStream cipherOut = new CipherOutputStream(fileOut, cipher);
// Read in the data from the file and encrypt it
while ((i = fileIn.read(data)) != -1) {
cipherOut.write(data, 0, i);
}
// Close the encrypted file
cipherOut.close();
fileIn.close();
System.out.println("encrypted file created");
}
// Use this PublicKey object to initialize a Cipher and decrypt some data
public static void rsaDecrypt(String file_loc, String file_des)
throws Exception {
byte[] data = new byte[32];
int i;
System.out.println("start decyption");
Key priKey = readKeyFromFile("privateB.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
FileInputStream fileIn = new FileInputStream(file_loc);
CipherInputStream cipherIn = new CipherInputStream(fileIn, cipher);
FileOutputStream fileOut = new FileOutputStream(file_des);
// Write data to new file
while ((i = cipherIn.read()) != -1) {
fileOut.write(i);
}
// Close the file
fileIn.close();
cipherIn.close();
fileOut.close();
System.out.println("decrypted file created");
}
If you want to ensure that the information really came from A, you should sign with A key pair, not encrypt it twice. In a nutshell:
Data -> Encrypt with B public Key -> Encrypted data -> Sign with A private key
Then send it to B who will verify A sign with A public key then open the encrypted data with his own private key.
With this method, you ll have:
- Privacy: encrypted with B public key, only B can open it.
- Non repudiation: Using A private key to sign, only A could have done it.
- Data integrity: When sign it and using a good hash function, you can check the received data for alteration.
Cheers.

Issues in RSA encryption in Java class

public class MyEncrypt {
public void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
try {
oout.writeObject(mod);
oout.writeObject(exp);
} catch (Exception e) {
throw new IOException("Unexpected error", e);
} finally {
oout.close();
}
}
public static void main(String[] args) throws Exception {
MyEncrypt myEncrypt = new MyEncrypt();
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(128);
KeyPair kp = kpg.genKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
myEncrypt.saveToFile("public.key", pub.getModulus(), pub.getPublicExponent());
myEncrypt.saveToFile("private.key", priv.getModulus(), priv.getPrivateExponent());
String encString = myEncrypt.bytes2String(myEncrypt.rsaEncrypt("pritesh".getBytes()));
System.out.println("encrypted : " + encString);
String decString = myEncrypt.bytes2String(myEncrypt.rsaDecrypt(encString.getBytes()));
System.out.println("decrypted : " + decString);
}
PublicKey readKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey pubKey = fact.generatePrivate(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
public byte[] rsaEncrypt(byte[] data) throws Exception {
byte[] src = new byte[] { (byte) 0xbe, (byte) 0xef };
PublicKey pubKey = this.readKeyFromFile("public.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
return cipherData;
}
public byte[] rsaDecrypt(byte[] data) throws Exception {
byte[] src = new byte[] { (byte) 0xbe, (byte) 0xef };
PrivateKey pubKey = this.readPrivateKeyFromFile("private.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
return cipherData;
}
private String bytes2String(byte[] bytes) {
StringBuilder string = new StringBuilder();
for (byte b: bytes) {
String hexString = Integer.toHexString(0x00FF & b);
string.append(hexString.length() == 1 ? "0" + hexString : hexString);
}
return string.toString();
}
}
I am getting this error:
Exception in thread "main" java.security.InvalidParameterException: RSA keys must be at least 512 bits long
at sun.security.rsa.RSAKeyPairGenerator.initialize(RSAKeyPairGenerator.java:70)
at java.security.KeyPairGenerator$Delegate.initialize(KeyPairGenerator.java:631)
at java.security.KeyPairGenerator.initialize(KeyPairGenerator.java:340)
at MyEncrypt.main(MyEncrypt.java:42)
I have make this class from http://www.javamex.com/tutorials/cryptography/rsa_encryption_2.shtml example
public class MyEncrypt {
static final String HEXES = "0123456789ABCDEF";
byte[] buf = new byte[1024];
public void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
try {
oout.writeObject(mod);
oout.writeObject(exp);
} catch (Exception e) {
throw new IOException("Unexpected error", e);
} finally {
oout.close();
}
}
public static void main(String[] args) throws Exception {
MyEncrypt myEncrypt = new MyEncrypt();
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
myEncrypt.saveToFile("public.key", pub.getModulus(), pub.getPublicExponent());
myEncrypt.saveToFile("private.key", priv.getModulus(), priv.getPrivateExponent());
String encString = myEncrypt.rsaEncrypt("pritesh");
System.out.println("encrypted : " + encString);
String decString = myEncrypt.rsaDecrypt(encString);
System.out.println("decrypted : " + decString);
String main_file_path = "resume.doc";
String main_encrypt_file_path = "encrypt.doc";
String main_decrypt_file_path = "decrypt.doc";
myEncrypt.rsaEncrypt(new FileInputStream(main_file_path),new FileOutputStream(main_encrypt_file_path));
// Decrypt
myEncrypt.rsaDecrypt(new FileInputStream(main_encrypt_file_path),new FileOutputStream(main_decrypt_file_path));
}
PublicKey readKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey pubKey = fact.generatePrivate(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
public String rsaEncrypt(String plaintext) throws Exception {
PublicKey pubKey = this.readKeyFromFile("public.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] ciphertext = cipher.doFinal(plaintext.getBytes("UTF-8"));
return this.byteToHex(ciphertext);
}
public void rsaEncrypt(InputStream in, OutputStream out) throws Exception {
try {
PublicKey pubKey = this.readKeyFromFile("public.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
// Bytes written to out will be encrypted
out = new CipherOutputStream(out, cipher);
// Read in the cleartext bytes and write to out to encrypt
int numRead = 0;
while ((numRead = in.read(buf)) >= 0){
out.write(buf, 0, numRead);
}
out.close();
}
catch (java.io.IOException e){
e.printStackTrace();
}
}
public void rsaDecrypt(InputStream in, OutputStream out) throws Exception {
try {
PrivateKey pubKey = this.readPrivateKeyFromFile("private.key");
Cipher dcipher = Cipher.getInstance("RSA");
dcipher.init(Cipher.DECRYPT_MODE, pubKey);
// Bytes read from in will be decrypted
in = new CipherInputStream(in, dcipher);
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
public String rsaDecrypt(String hexCipherText) throws Exception {
PrivateKey pubKey = this.readPrivateKeyFromFile("private.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pubKey);
String plaintext = new String(cipher.doFinal(this.hexToByte(hexCipherText)), "UTF-8");
return plaintext;
}
public static String byteToHex( byte [] raw ) {
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder( 2 * raw.length );
for ( final byte b : raw ) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
public static byte[] hexToByte( String hexString){
int len = hexString.length();
byte[] ba = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
ba[i/2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i+1), 16));
}
return ba;
}
}
It works well with text file but giving issue on files like docx and video any idea?
The error says it all: you're initializing with a keyset of 128 and RSA expects at least 512.
You have more than one problem:
Java does not support RSA keys of size less than 512. 2048 bit is a better choice. So change the key length:
kpg.initialize(2048);
String.getBytes() is not the inverse operation to your bytes2String(). After encrypting you convert the bytes to a hexadecimal string. But then you convert this hexadecimal string to its ASCII representation before decrypting, which yields a byte-array that is too long. Instead, use something like this to convert the hexadecimal string back:
private byte[] string2bytes(String s) {
int len = s.length();
byte[] res = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
res[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return res;
}
and then call that instead of String.getBytes():
// Note, this line is not completely fixed yet
String decString =
myEncrypt.bytes2String(
myEncrypt.rsaDecrypt(
myEncrypt.string2bytes(encString)
)
);
Finally you have the opposite problem. Your bytes2String() method does not reverse the String.getBytes() operation. You encrypted the output of "pritesh".getBytes(), so that is what you got out of the decrypt operation. Now you have to convert that back to a String. The String(byte[])-constructor will do that for you:
String decString =
new String(
myEncrypt.rsaDecrypt(
myEncrypt.string2bytes(encString)
)
);
Final ans
public class MyEncrypt {
public static final int AES_Key_Size = 128;
Cipher pkCipher, aesCipher;
byte[] aesKey;
SecretKeySpec aeskeySpec;
public static void main(String[] args) throws Exception {
//MyEncrypt.createRSAKeys(); //call to generated RSA keys
MyEncrypt secure = new MyEncrypt();
// to encrypt a file
secure.makeKey();
secure.saveKey(new File("keys/ase.key"), "keys/public.key");
secure.encrypt(new File("test/sample.pdf"), new File("test/encrypt_sample.pdf"));
// to decrypt it again
secure.loadKey(new File("keys/ase.key"), "keys/private.key");
secure.decrypt(new File("test/encrypt_sample.pdf"), new File("test/decrypted_sample.pdf"));
}
/**
* Constructor: creates ciphers
*/
public MyEncrypt() throws GeneralSecurityException {
// create RSA public key cipher
pkCipher = Cipher.getInstance("RSA");
// create AES shared key cipher
aesCipher = Cipher.getInstance("AES");
}
public static void createRSAKeys() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512);
KeyPair kp = kpg.genKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
saveToFile("keys/public.key", pub.getModulus(), pub.getPublicExponent());
saveToFile("keys/private.key", priv.getModulus(), priv.getPrivateExponent());
System.out.println("RSA public & private keys are generated");
}
private static void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
try {
oout.writeObject(mod);
oout.writeObject(exp);
} catch (Exception e) {
throw new IOException("Unexpected error", e);
} finally {
oout.close();
}
}
/**
* Creates a new AES key
*/
public void makeKey() throws NoSuchAlgorithmException {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(AES_Key_Size);
SecretKey key = kgen.generateKey();
aesKey = key.getEncoded();
aeskeySpec = new SecretKeySpec(aesKey, "AES");
}
/**
* Encrypts the AES key to a file using an RSA public key
*/
public void saveKey(File out, String publicKeyFile) throws IOException, GeneralSecurityException {
try {
// read public key to be used to encrypt the AES key
byte[] encodedKey = new byte[(int)publicKeyFile.length()];
new FileInputStream(publicKeyFile).read(encodedKey);
// create public key
//X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
//KeyFactory kf = KeyFactory.getInstance("RSA");
//PublicKey pk = kf.generatePublic(publicKeySpec);
PublicKey pk = this.readPublicKeyFromFile(publicKeyFile);
// write AES key
pkCipher.init(Cipher.ENCRYPT_MODE, pk);
CipherOutputStream os = new CipherOutputStream(new FileOutputStream(out), pkCipher);
os.write(aesKey);
os.close();
} catch (Exception e) {
//throw new Exception("Saving key exception", e);
}
}
private PublicKey readPublicKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
private PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey pubKey = fact.generatePrivate(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
/**
* Decrypts an AES key from a file using an RSA private key
*/
public void loadKey(File in, String privateKeyFile) throws GeneralSecurityException, IOException {
try {
// read private key to be used to decrypt the AES key
byte[] encodedKey = new byte[(int)privateKeyFile.length()];
new FileInputStream(privateKeyFile).read(encodedKey);
// create private key
//PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey);
//KeyFactory kf = KeyFactory.getInstance("RSA");
//PrivateKey pk = kf.generatePrivate(privateKeySpec);
PrivateKey pk = this.readPrivateKeyFromFile(privateKeyFile);
// read AES key
pkCipher.init(Cipher.DECRYPT_MODE, pk);
aesKey = new byte[AES_Key_Size/8];
CipherInputStream is = new CipherInputStream(new FileInputStream(in), pkCipher);
is.read(aesKey);
aeskeySpec = new SecretKeySpec(aesKey, "AES");
} catch (Exception e) {
}
}
/**
* Encrypts and then copies the contents of a given file.
*/
public void encrypt(File in, File out) throws IOException, InvalidKeyException {
aesCipher.init(Cipher.ENCRYPT_MODE, aeskeySpec);
FileInputStream is = new FileInputStream(in);
CipherOutputStream os = new CipherOutputStream(new FileOutputStream(out), aesCipher);
copy(is, os);
os.close();
}
/**
* Decrypts and then copies the contents of a given file.
*/
public void decrypt(File in, File out) throws IOException, InvalidKeyException {
aesCipher.init(Cipher.DECRYPT_MODE, aeskeySpec);
CipherInputStream is = new CipherInputStream(new FileInputStream(in), aesCipher);
FileOutputStream os = new FileOutputStream(out);
copy(is, os);
is.close();
os.close();
}
/**
* Copies a stream.
*/
private void copy(InputStream is, OutputStream os) throws IOException {
int i;
byte[] b = new byte[1024];
while((i=is.read(b))!=-1) {
os.write(b, 0, i);
}
}
}

Categories