I have ported an application from Android to desktop that uses AES to encrypt some private data.
Both applications are able to encrypt and decrypt the data for their own use but unable to decrypt the other applications data.
The AES keys, IVs, and algorithms are identical.
The main difference between the two applications is that the android-sdk comes with the BouncyCastle provider already added to the security while the desktop application needed
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
Android app:
public class AesFileIo {
public final static String EOL = "\n";
public static final String AES_ALGORITHM = "AES/CTR/NoPadding";
public static final String PROVIDER = "BC";
private static final SecretKeySpec secretKeySpec =
new SecretKeySpec(AES_KEY_128, "AES");
private static final IvParameterSpec ivSpec = new IvParameterSpec(IV);
public String readAesFile(Context c, String fileName) {
StringBuilder stringBuilder = new StringBuilder();
try {
InputStream is = c.openFileInput(fileName);
Cipher cipher = Cipher.getInstance(AES_ALGORITHM, PROVIDER);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
CipherInputStream cis = new CipherInputStream(is, cipher);
InputStreamReader isr = new InputStreamReader(cis);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append(EOL);
}
is.close();
} catch (java.io.FileNotFoundException e) {
// OK, file probably not created yet
Log.i(this.getClass().toString(), e.getMessage(), e);
} catch (Exception e) {
Log.e(this.getClass().toString(), e.getMessage(), e);
}
return stringBuilder.toString();
}
public void writeAesFile(Context c, String fileName, String theFile) {
try {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM, PROVIDER);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
byte[] encrypted = cipher.doFinal(theFile.getBytes());
OutputStream os = c.openFileOutput(fileName, 0);
os.write(encrypted);
os.flush();
os.close();
} catch (Exception e) {
Log.e(this.getClass().toString(), e.getMessage(), e);
}
}
}
Desktop app:
public class AesFileIo {
private static final String EOL = "\n";
private static final String AES_ALGORITHM = "AES/CTR/NoPadding";
private static final SecretKeySpec secretKeySpec =
new SecretKeySpec(AES_KEY_128, "AES");
private static final IvParameterSpec ivSpec = new IvParameterSpec(IV);
public void AesFileIo() {
Security.addProvider(new org.bouncycastle.jce.provider
.BouncyCastleProvider());
}
public String readFile(String fileName) {
StringBuilder stringBuilder = new StringBuilder();
try {
ObjectInputStream is = new ObjectInputStream(
new FileInputStream(fileName));
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
CipherInputStream cis = new CipherInputStream(is, cipher);
InputStreamReader isr = new InputStreamReader(cis);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append(EOL);
}
is.close();
} catch (java.io.FileNotFoundException e) {
System.out.println("FileNotFoundException: probably OK");
} catch (Exception e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
public void writeFile(String fileName, String theFile) {
try {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
byte[] encrypted = cipher.doFinal(theFile.getBytes());
ObjectOutputStream os = new ObjectOutputStream(
new FileOutputStream(fileName));
os.write(encrypted);
os.flush();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Solved by
Adding proper constructors to initialize SecretKeySpec and IvParameterSpec.
Getting rid of ObjectOutputStream and ObjectInputStream in desktop app.
Android app:
public class AesFileIo {
private static final String EOL = "\n";
private static final String AES_ALGORITHM = "AES/CTR/NoPadding";
private SecretKeySpec secretKeySpec;
private IvParameterSpec ivSpec;
private static final String PROVIDER = "BC";
AesFileIo(byte[] aesKey, byte[] iv) {
ivSpec = new IvParameterSpec(iv);
secretKeySpec = new SecretKeySpec(aesKey, "AES");
}
public String readFile(Context c, String fileName) {
StringBuilder stringBuilder = new StringBuilder();
try {
InputStream is = c.openFileInput(fileName);
Cipher cipher = Cipher.getInstance(AES_ALGORITHM, PROVIDER);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
CipherInputStream cis = new CipherInputStream(is, cipher);
InputStreamReader isr = new InputStreamReader(cis);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append(EOL);
}
is.close();
} catch (java.io.FileNotFoundException e) {
// OK, file probably not created yet
Log.i(this.getClass().toString(), e.getMessage(), e);
} catch (Exception e) {
Log.e(this.getClass().toString(), e.getMessage(), e);
}
return stringBuilder.toString();
}
public void writeFile(Context c, String fileName, String theFile) {
try {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM, PROVIDER);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
byte[] encrypted = cipher.doFinal(theFile.getBytes());
OutputStream os = c.openFileOutput(fileName, 0);
os.write(encrypted);
os.flush();
os.close();
} catch (Exception e) {
Log.e(this.getClass().toString(), e.getMessage(), e);
}
}
}
Desktop app:
public class AesFileIo {
private static final String EOL = "\n";
private static final String AES_ALGORITHM = "AES/CTR/NoPadding";
private SecretKeySpec secretKeySpec;
private IvParameterSpec ivSpec;
AesFileIo(byte[] aesKey, byte[] iv) {
Security.addProvider(new org.bouncycastle.jce.provider
.BouncyCastleProvider());
ivSpec = new IvParameterSpec(iv);
secretKeySpec = new SecretKeySpec(aesKey, "AES");
}
public String readFile(String fileName) {
StringBuilder stringBuilder = new StringBuilder();
try {
FileInputStream fis = new FileInputStream(fileName);
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivSpec);
CipherInputStream cis = new CipherInputStream(fis, cipher);
InputStreamReader isr = new InputStreamReader(cis);
BufferedReader reader = new BufferedReader(isr);
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line).append(EOL);
}
fis.close();
} catch (java.io.FileNotFoundException e) {
System.out.println("FileNotFoundException: probably OK");
} catch (Exception e) {
e.printStackTrace();
}
return stringBuilder.toString();
}
public void writeFile(String fileName, String theFile) {
try {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivSpec);
byte[] encrypted = cipher.doFinal(theFile.getBytes());
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(encrypted);
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Related
i'm trying to do the 7° challeng of cryptopals and i have to decrypt a file Base64 that was encrypted with the AES in ECB mode. So, i found this code that work with the tutoria stirngs, but when i try with the given data in exercise it give me back the error:
Error while decrypting: javax.crypto.BadPaddingException: Given final
block not properly padded. Such issues can arise if a bad key is used
during decryption.
Process finished with exit code 0
this is the code:
public class ES7 {
private static SecretKeySpec secretKey;
private static byte[] key;
public static void main(String[] args) throws InvalidAlgorithmParameterException, NoSuchPaddingException, IllegalBlockSizeException, IOException, NoSuchAlgorithmException, BadPaddingException, InvalidKeyException {
String file = readBase64("C:\\Users\\Huawei\\OneDrive\\Desktop\\Lavoro\\Esercizi\\src\\ES7.txt");
String res = decrypt(file,"YELLOW SUBMARINE"); --> this gave error of key
// final String secretKey = "ssshhhhhhhhhhh!!!!";
// String encryptedString= "Tg2Nn7wUZOQ6Xc+1lenkZTQ9ZDf9a2/RBRiqJBCIX6o=";
// String decryptedString = decrypt(encryptedString, secretKey) ; --> this work
}
public static void setKey(final String myKey) {
MessageDigest sha = null;
try {
key = myKey.getBytes("UTF-8");
sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
secretKey = new SecretKeySpec(key, "AES");
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
e.printStackTrace();
}
}
public static String decrypt(final String strToDecrypt, final String secret) {
try {
setKey(secret);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
return new String(cipher.doFinal(Base64.getDecoder().decode(strToDecrypt)));
} catch (Exception e) {
System.out.println("Error while decrypting: " + e.toString());
}
return null;
}
private static String readBase64(String file) {
String filetext = "";
String line;
try
{
BufferedReader input = new BufferedReader(new FileReader(new File(file)));
while ((line = input.readLine()) != null)
{
filetext += line;
}
input.close();
} catch (IOException e){
e.printStackTrace();
}
return filetext;
}
}
I have been trying for two days to decrypt a file whith the private key containing 'lolilol' after having encrypted it with the public key rsa 4096. I then get padding errors, I tried everything to do, I get the error Javax.crypto.BadPaddingException: Decryption error.
Even after reading the doc on the padding I did not succeed: encryption works fine, but decryption contains an error.
Here is my code:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.Cipher;
import sun.misc.BASE64Encoder;
public class GenerateRSAKeys{
private Key pubKey;
private Key privKey;
public static void main(String[] args)
{
String input = "C:\\Users\\toto\\Desktop\\nomFichier_entrant.ext";
String output = "C:\\Users\\toto\\Desktop\\nomFichier_entrant.ext.enc";
String dec = "C:\\Users\\toto\\Desktop\\nomFichier_entrant.ext.dec";
String publicKeyFilename = "C:\\Users\\toto\\Desktop\\HR_pubkey_prd.pem";
String privateKeyFilename = "C:\\Users\\toto\\Desktop\\PE_privkey_prd.pem";
GenerateRSAKeys generateRSAKeys = new GenerateRSAKeys();
/* if (args.length < 2)
{
System.err.println("Usage: java "+ generateRSAKeys.getClass().getName()+
" Public_Key_Filename Private_Key_Filename");
System.exit(1);
}
publicKeyFilename = args[0].trim();
privateKeyFilename = args[1].trim(); */
generateRSAKeys.generate(publicKeyFilename, privateKeyFilename);
//generateRSAKeys.encrypt(input, output);
generateRSAKeys.encrypt(input, output);
generateRSAKeys.decrypt(output, dec);
}
private void generate (String publicKeyFilename, String privateFilename){
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// Create the public and private keys
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
BASE64Encoder b64 = new BASE64Encoder();
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
/* SecureRandom random = new SecureRandom();
keyGen.initialize(4096, random);
KeyPair pair = keyGen.generateKeyPair();
pubKey = pair.getPublic();
privKey = pair.getPrivate(); */
SecureRandom random = createFixedRandom();
generator.initialize(4096, random);
KeyPair pair = generator.generateKeyPair();
pubKey = pair.getPublic();
privKey = pair.getPrivate();
System.out.println("publicKey : " + b64.encode(pubKey.getEncoded()));
System.out.println("privateKey : " + b64.encode(privKey.getEncoded()));
BufferedWriter out = new BufferedWriter(new FileWriter(publicKeyFilename));
out.write(b64.encode(pubKey.getEncoded()));
out.close();
out = new BufferedWriter(new FileWriter(privateFilename));
out.write(b64.encode(privKey.getEncoded()));
out.close();
}
catch (Exception e) {
System.out.println(e);
}
}
public static SecureRandom createFixedRandom()
{
return new FixedRand();
}
private static class FixedRand extends SecureRandom {
MessageDigest sha;
byte[] state;
FixedRand() {
try
{
this.sha = MessageDigest.getInstance("SHA-1");
this.state = sha.digest();
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException("can't find SHA-1!");
}
}
public void nextBytes(byte[] bytes){
int off = 0;
sha.update(state);
while (off < bytes.length)
{
state = sha.digest();
if (bytes.length - off > state.length)
{
System.arraycopy(state, 0, bytes, off, state.length);
}
else
{
System.arraycopy(state, 0, bytes, off, bytes.length - off);
}
off += state.length;
sha.update(state);
}
}
}
public void encrypt(String input, String output) {
File outputFile;
FileInputStream inputStream;
FileOutputStream outputStream;
Cipher cipher;
byte[] inputBytes;
byte[] outputBytes;
try {
outputFile = new File(output);
inputStream = new FileInputStream(input);
outputStream = new FileOutputStream(outputFile);
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
inputBytes = new byte[(int) input.length()];
inputStream.read(inputBytes);
outputBytes = cipher.doFinal(inputBytes);
outputStream.write(outputBytes);
// System.out.println(new String(inputBytes, "UTF-8"));
System.out.println("encrypt");
System.out.println(new String(outputBytes, "UTF-8"));
System.out.println("fin encrypt");
} catch (Exception e) {
e.printStackTrace();
}
}
public void decrypt(String input, String output) {
File outputFile;
FileInputStream inputStream;
FileOutputStream outputStream;
Cipher cipher;
byte[] inputBytes;
byte[] outputBytes;
try {
outputFile = new File(output);
inputStream = new FileInputStream(input);
outputStream = new FileOutputStream(outputFile);
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privKey);
inputBytes = new byte[(int) input.length()];
inputStream.read(inputBytes);
outputBytes = cipher.doFinal(inputBytes);
outputStream.write(outputBytes);
// System.out.println(new String(inputBytes, "UTF-8"));
System.out.println("decrypt");
System.out.println(new String(outputBytes, "UTF-8"));
System.out.println("fin decrypt");
} catch (Exception e) {
e.printStackTrace();
}
}
}
You have multiple issues in your code:
You're never closing the file streams. If you don't do that, it might happen that no data is actually written. If the ciphertext is not (fully) written then the decryption will obviously fail.
A FileInputStream doesn't give an accurate measure of how much data the underlying file contains. You have to use the File class for that:
File inputFile = new File(input);
FileInputStream inputStream = new FileInputStream(inputFile);
FileOutputStream outputStream = new FileOutputStream(output);
byte[] inputBytes = new byte[(int) inputFile.length()];
When you're reading file contents, you must always check how much you read and use exactly that amount:
int readBytes = inputStream.read(inputBytes);
byte[] outputBytes = cipher.doFinal(inputBytes, 0, readBytes);
Always use a fully qualified Cipher string. Cipher.getInstance("RSA"); may result in different ciphers depending on the default security provider. In OpenJDK it defaults to Cipher.getInstance("RSA/ECB/PKCS1Padding");. Nowadays, you should use OAEP instead of the default PKCS#1 v1.5 padding. So you should probably use Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");.
Here is the full code of those two methods:
public void encrypt(String input, String output) {
File inputFile;
FileInputStream inputStream;
FileOutputStream outputStream;
Cipher cipher;
byte[] inputBytes;
byte[] outputBytes;
try {
System.out.println("encrypt");
cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
inputFile = new File(input);
inputStream = new FileInputStream(inputFile);
outputStream = new FileOutputStream(output);
inputBytes = new byte[(int) input.length()];
int readBytes = inputStream.read(inputBytes);
outputBytes = cipher.doFinal(inputBytes, 0, readBytes);
outputStream.write(outputBytes);
System.out.println("fin encrypt");
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void decrypt(String input, String output) {
File inputFile;
FileInputStream inputStream;
FileOutputStream outputStream;
Cipher cipher;
byte[] inputBytes;
byte[] outputBytes;
try {
System.out.println("decrypt");
cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, privKey);
inputFile = new File(input);
inputStream = new FileInputStream(inputFile);
outputStream = new FileOutputStream(output);
inputBytes = new byte[(int) inputFile.length()];
int readBytes = inputStream.read(inputBytes);
outputBytes = cipher.doFinal(inputBytes, 0, readBytes);
outputStream.write(outputBytes);
System.out.println("Decryption result: " + new String(outputBytes, "UTF-8"));
System.out.println("fin decrypt");
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I have a problem with my code. I want to encrypt a message using a key made from passphrase. Then I want to send it (or use it somewhere, whatever) in String form (the encrypted one), and after that I want to decrypt it only by knowing the passphrase.
I wrote the code below, but I receive either IllegalBlockSizeException or BadPaddingException. I thought that badding would be took care by padding.
Here is my code:
Constructor and initialization:
public class AES_Cipher {
private String keyString;
private byte[] byteKey;
private SecretKey key;
Cipher c;
public AES_Cipher(String keyString){
this.keyString = keyString.toString();
}
public void init() throws InitializtionFailedException{
try{
c = Cipher.getInstance("AES/ECB/PKCS5Padding");
byteKey = keyString.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
byteKey = sha.digest(byteKey);
byteKey = Arrays.copyOf(byteKey, 16);
key = new SecretKeySpec(byteKey, "AES");
}catch(NoSuchAlgorithmException e){
throw new InitializtionFailedException();
}
}
Encrypt:
public String encrypt(String text) throws EncryptionException{
try{
c.init(Cipher.ENCRYPT_MODE, key);
byte[] tmp = c.doFinal( text.getBytes("UTF-8"));
return new String(tmp, "UTF-8");
}catch(IllegalBlockSizeException e){
throw new EncryptionException();
}
}
Decrypt:
public String decrypt(String text) throws DecryptionException{
try{
//byte[] decordedValue = new BASE64Decoder().decodeBuffer(text);
// tried too use it but with poor outcome
//c = Cipher.getInstance("AES/ECB/PKCS5Padding");
c.init(Cipher.DECRYPT_MODE, key);
byte[] tmp1 = text.getBytes("UTF-8");
//byte[] tmp = c.doFinal("aaaaaaaaaaaaaaaa".getBytes());
//this returns BadPaddingException
byte[] tmp = c.doFinal(text.getBytes());
return new String(tmp, "UTF-8");
}catch(IllegalBlockSizeException e){
throw new DecryptionException();
}
}
Of course there are some more exceptions.
Also, I would like to later use this code on android, and It doesn't need to be AES if there is some other Ciphers that are maybe less effective but less troublesome. But not simple XOR if that's not too much too ask.
Thank you in advance.
Ok. Seems to work now thanks to Artjom B.
Constructor and inicialization:
public class AES_Cipher {
private String keyString;
private byte[] byteKey;
private SecretKey key;
Cipher c;
public AES_Cipher(String keyString){
this.keyString = keyString.toString();
}
public void init() throws InitializtionFailedException{
try{
c = Cipher.getInstance("AES/ECB/PKCS5Padding");
byteKey = keyString.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
byteKey = sha.digest(byteKey);
byteKey = Arrays.copyOf(byteKey, 16);
key = new SecretKeySpec(byteKey, "AES");
}catch(NoSuchAlgorithmException e){
throw new InitializtionFailedException();
}
}
Encryption:
public String encrypt(String text) throws EncryptionException{
try{
c.init(Cipher.ENCRYPT_MODE, key);
byte[] textByte = text.getBytes("UTF-8");
byte[] tmp = c.doFinal(textByte);
String return1 = Base64.encodeToString(tmp, Base64.DEFAULT);
return return1;
} // of course there is some exceptions catched down there
Decryption:
public String decrypt(String text) throws DecryptionException{
try{
c.init(Cipher.DECRYPT_MODE, key);
byte[] textByte = Base64.decode(text, Base64.DEFAULT);
byte[] tmp = c.doFinal(textByte);
return new String(tmp, "UTF-8");
}catch(IllegalBlockSizeException e){
Log.d("Exception", "IllegalBlockSizeException");
throw new DecryptionException();
} // wrote DecryptionException myself.
// also there is more Exceptions below
}
I get Exception in thread "main"
javax.crypto.BadPaddingException: Decryption error in the RSA encryption/decryption.
My java classes are Client,Server and go like this
Client
public class Client {
private static SecretKeySpec AES_Key;
private static String key;
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException {
Socket mySocket = null;
PrintWriter out = null;
BufferedReader in = null;
try {
mySocket = new Socket("localhost", 4443);
out = new PrintWriter(mySocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(mySocket.getInputStream()));
} catch (UnknownHostException e) {
System.err.println("Don't know about host");
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: localhost.");
System.exit(1);
}
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String fromServer;
String fromUser, m1;
byte[] input;
System.out.println("Client run ");
int cnt = 0;
while (true) {
// fromServer = in.readLine();
m1 = in.readLine();
//input=in.readLine().getBytes();
if (m1 != null && cnt < 1) {
cnt++;
byte[] m = new BASE64Decoder().decodeBuffer(m1);
PrivateKey privKey = readKeyFromFile("/privateClient.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] plaintext_decrypted = cipher.doFinal(m);
fromServer = new String(plaintext_decrypted, "ASCII");
AES_Key = new SecretKeySpec(fromServer.getBytes(), "AES");
System.out.println("RSA communication ends");
System.out.println("AES communication established");
}
System.out.println("type message :");
//Encrypt msg to send
Cipher AES_Cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
fromUser = stdIn.readLine();
AES_Cipher.init(Cipher.ENCRYPT_MODE, AES_Key);
byte plaintext[] = fromUser.getBytes();
byte[] final_plaintext = AES_Cipher.doFinal(plaintext);
String msg = new BASE64Encoder().encode(final_plaintext);
if (fromUser != null) {
out.println(fromUser);
} else {
break;
}
fromServer = in.readLine();
if (fromServer != null) {
// Decrypt the message received
AES_Cipher.init(Cipher.DECRYPT_MODE, AES_Key);
input = new BASE64Decoder().decodeBuffer(fromServer);
byte plaintext_decrypted[] = AES_Cipher.doFinal(input);
fromServer = new String(plaintext_decrypted, "ASCII");
System.out.println("Client receive :" + fromServer);
} else {
break;
}
}
out.close();
in.close();
stdIn.close();
mySocket.close();
}
static PrivateKey readKeyFromFile(String keyFileName) throws IOException {
InputStream in
= Client.class.getResourceAsStream(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 privKey = fact.generatePrivate(keySpec);
return privKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
static PublicKey readKeyFromFilePb(String keyFileName) throws IOException {
InputStream in
= Client.class.getResourceAsStream(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();
}
}
static byte[] rsaDecrypt(byte[] in) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
PrivateKey privKey = readKeyFromFile("/publicServer.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privKey);
byte[] cipherData = cipher.doFinal(in);
return cipherData;
}
static byte[] rsaEncrypt(byte[] data) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
PublicKey pubKey = readKeyFromFilePb("/privateClient.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
return cipherData;
}
private String toHexString(byte[] block) {
StringBuffer buf = new StringBuffer();
int len = block.length;
for (int i = 0; i < len; i++) {
byte2hex(block[i], buf);
if (i < len - 1) {
buf.append(":");
}
}
return buf.toString();
}
/*
* Converts a byte to hex digit and writes to the supplied buffer
*/
private void byte2hex(byte b, StringBuffer buf) {
char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F'};
int high = ((b & 0xf0) >> 4);
int low = (b & 0x0f);
buf.append(hexChars[high]);
buf.append(hexChars[low]);
}
}
Server
public class Server {
private static SecretKeySpec AES_Key;
private static final String key = "1234567890ABCDEF";
public static PublicKey keycl;
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InstantiationException, IllegalAccessException {
AES_Key = new SecretKeySpec(key.getBytes(), "AES");
//System.out.println(AES_Key);
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(4443);
} catch (IOException e) {
System.err.println("Could not listen on port: 4443.");
System.exit(1);
}
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
clientSocket.getInputStream()));
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String inputLine, outputLine;
System.out.println("Server run ");
int cnt = 0;
byte final_plaintext[];
byte[] AES = key.getBytes();
PublicKey pubKey = readKeyFromFile("/publicClient.key");
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
final_plaintext = cipher.doFinal(AES);
String m = new BASE64Encoder().encode(final_plaintext);
System.out.println(m);
out.println(m);
while ((inputLine = in.readLine()) != null) {
cnt++;
Cipher AES_Cipher = Cipher.getInstance("AES/ECB/PKCS5Padding", "BC");
AES_Cipher.init(Cipher.DECRYPT_MODE, AES_Key);
byte[] input = new BASE64Decoder().decodeBuffer(inputLine);
//System.out.println(input);
byte plaintext_decrypted[] = AES_Cipher.doFinal(input);
inputLine = new String(plaintext_decrypted, "UTF-8");
System.out.println("Server receive : " + inputLine);
System.out.println("type message :");
outputLine = stdIn.readLine();
AES_Cipher.init(Cipher.ENCRYPT_MODE, AES_Key);
byte plaintext[] = outputLine.getBytes();
final_plaintext = AES_Cipher.doFinal(plaintext);
String msg = new BASE64Encoder().encode(final_plaintext);
out.println(msg);
}
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
public static PublicKey readKeyFromFile(String keyFileName) throws IOException {
InputStream in
= Server.class.getResourceAsStream(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();
}
}
public static byte[] rsaEncrypt(byte[] data) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
PublicKey pubKey = readKeyFromFile("/privateServer.key");
System.out.println(pubKey);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
return cipherData;
}
public static byte[] rsaDecrypt(byte[] data) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
PublicKey pubKey = readKeyFromFile("/publicClient.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
return cipherData;
}
private static String toHexString(byte[] block) {
StringBuffer buf = new StringBuffer();
int len = block.length;
for (int i = 0; i < len; i++) {
byte2hex(block[i], buf);
if (i < len - 1) {
buf.append(":");
}
}
return buf.toString();
}
/*
* Converts a byte to hex digit and writes to the supplied buffer
*/
private static void byte2hex(byte b, StringBuffer buf) {
char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'A', 'B', 'C', 'D', 'E', 'F'};
int high = ((b & 0xf0) >> 4);
int low = (b & 0x0f);
buf.append(hexChars[high]);
buf.append(hexChars[low]);
}
}
Generate keys
public class KeyPair {
public KeyPair() {
}
public void GenerateKey(String name) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
java.security.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);
System.out.println(pub);
String publ="public"+name+".key";
String priva="private"+name+".key";
saveToFile(publ, pub.getModulus(),
pub.getPublicExponent());
saveToFile(priva, priv.getModulus(),
priv.getPrivateExponent());
}
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 PublicKey readKeyFromFile(String keyFileName) throws IOException {
InputStream in
= KeyPair.class.getResourceAsStream(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();
}
}
}
public class Main {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeySpecException, IOException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
KeyPair kpC = new KeyPair();
KeyPair kpS = new KeyPair();
kpS.GenerateKey("Server");
kpC.GenerateKey("Client");
}
}
I found it. It was at the
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
at the client code. Before it was (Cipher cipher = Cipher.getInstance("RSA");).
I save and load in sd card a file that contains an ArrayList of serializable object with these two methods
save method
public static void saveUserList(ArrayList<User> userList) {
if (storageAvailable()) {
try {
createFolder();
FileOutputStream userList = new FileOutputStream(
baseDir + File.separator + baseAppDir + File.separator
+ fileName);
ObjectOutputStream oos = new ObjectOutputStream(
userList);
oos.writeObject(userList);
oos.close();
} catch (Exception exc) {
exc.printStackTrace();
}
}
}
load method
public static ArrayList<User> loadUserList() {
if (storageAvailable()) {
ArrayList<User> userList = new ArrayList<User>();
try {
FileInputStream userList = new FileInputStream(baseDir
+ File.separator + baseAppDir + File.separator
+ fileName);
ObjectInputStream oos = new ObjectInputStream(
userList);
userList = (ArrayList<User>) oos.readObject();
oos.close();
} catch (Exception exc) {
exc.printStackTrace();
}
return userList;
} else {
return null;
}
}
Now I want that the method saveUserList encrypts the content of the file during the save according a specific String keyword and the method loadUserList decrypts the file with the same keyword to return the arrayList.
How could I do this?
I have given a look to CipherOutputStream but I haven't understood how should I use this.
The method proposed to use Conceal library
public static void saveUserListCrypted(ArrayList<User> userList) {
if (storageAvailable()) {
try {
createFolder();
Crypto crypto = new Crypto(
new SharedPrefsBackedKeyChain(context),
new SystemNativeCryptoLibrary());
FileOutputStream userList = new FileOutputStream(
baseDir + File.separator + baseAppDir + File.separator
+ fileName);
OutputStream cryptedStream = crypto.getCipherOutputStream(
userList, new Entity("UserList");
ObjectOutputStream oos = new ObjectOutputStream(
cryptedStream);
oos.writeObject(userList);
oos.close();
} catch (Exception exc) {
exc.printStackTrace();
}
}
}
cause this error
this error java.lang.UnsupportedOperationException 02-12 21:29:05.026 2051-2051/com.myapp W/System.err﹕ at com.facebook.crypto.streams.NativeGCMCipherOutputStream.write
Try (adding the appropriate checks and try blocks that I have omitted to make the code more readable) something like this to save
public static void AESObjectEncoder(Serializable object, String password, String path) {
try {
Cipher cipher = null;
cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, fromStringToAESkey(password));
SealedObject sealedObject = null;
sealedObject = new SealedObject(object, cipher);
CipherOutputStream cipherOutputStream = null;
cipherOutputStream = new CipherOutputStream(new BufferedOutputStream(new FileOutputStream(path)), cipher);
ObjectOutputStream outputStream = null;
outputStream = new ObjectOutputStream(cipherOutputStream);
outputStream.writeObject(sealedObject);
outputStream.close();
}
and this to load
public static Serializable AESObjectDedcoder(String password, String path) {
Cipher cipher = null;
Serializable userList = null;
cipher = Cipher.getInstance("AES/CBC/PKCS7Pdding");
//Code to write your object to file
cipher.init(Cipher.DECRYPT_MODE, fromStringToAESkey(password));
CipherInputStream cipherInputStream = null;
cipherInputStream = new CipherInputStream(new BufferedInputStream(new FileInputStream(path)), cipher);
ObjectInputStream inputStream = null;
inputStream = new ObjectInputStream(cipherInputStream);
SealedObject sealedObject = null;
sealedObject = (SealedObject) inputStream.readObject();
userList = (Serializable) sealedObject.getObject(ciper);
return userList;
}
to create a SecretKey from a String you can use this
public static SecretKey fromStringToAESkey(String s) {
//256bit key need 32 byte
byte[] rawKey = new byte[32];
// if you don't specify the encoding you might get weird results
byte[] keyBytes = new byte[0];
try {
keyBytes = s.getBytes("ASCII");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
System.arraycopy(keyBytes, 0, rawKey, 0, keyBytes.length);
SecretKey key = new SecretKeySpec(rawKey, "AES");
return key;
}
NOTE:
this code encrypts and decrypts twice to show the way of use of both sealed object and Cipher streams
I suggest taking a look at Conceal, recently released by facebook: http://facebook.github.io/conceal/
This should be a trivial modification to wrap a Conceal output stream with an ObjectOutputStream used in your current code:
public static void saveUserList(ArrayList<User> userList) {
if (storageAvailable()) {
try {
createFolder();
Crypto crypto = new Crypto(
new SharedPrefsBackedKeyChain(context),
new SystemNativeCryptoLibrary());
FileOutputStream userList = new FileOutputStream(
baseDir + File.separator + baseAppDir + File.separator
+ fileName);
OutputStream cryptedStream = crypto.getCipherOutputStream(
userList, new Entity("UserList");
ObjectOutputStream oos = new ObjectOutputStream(
cryptedStream);
oos.writeObject(userList);
oos.close();
} catch (Exception exc) {
exc.printStackTrace();
}
}
}
I'll leave the restore as an exercise for the reader. ;)
You could simply use AES Encoding:
private static byte[] getEncrypt(final String key, final String message) throws GeneralSecurityException {
final byte[] rawData = key.getBytes(Charset.forName("US-ASCII"));
if (rawData.length != 16) {
// If this is not 16 in length, there's a problem with the key size, nothing to do here
throw new IllegalArgumentException("You've provided an invalid key size");
}
final SecretKeySpec seckeySpec = new SecretKeySpec(rawData, "AES");
final Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
ciph.init(Cipher.ENCRYPT_MODE, seckeySpec, new IvParameterSpec(new byte[16]));
return ciph.doFinal(message.getBytes(Charset.forName("US-ASCII")));
}
private static String getDecrypt(String key, byte[] encrypted) throws GeneralSecurityException {
final byte[] rawData = key.getBytes(Charset.forName("US-ASCII"));
if (rawData.length != 16) {
// If this is not 16 in length, there's a problem with the key size, nothing to do here
throw new IllegalArgumentException("Invalid key size.");
}
final SecretKeySpec seckeySpec = new SecretKeySpec(rawData, "AES");
final Cipher ciph = Cipher.getInstance("AES/CBC/PKCS5Padding");
ciph.init(Cipher.DECRYPT_MODE, seckeySpec, new IvParameterSpec(new byte[16]));
final byte[] decryptedmess = ciph.doFinal(encrypted);
return new String(decryptedmess, Charset.forName("US-ASCII"));
}
Then, for trying it, this example may be valid for you:
final String encrypt = "My16inLengthKey5";
final byte[] docrypt = getEncrypt(encrypt, "This is a phrase to be encrypted!");
final String douncrypt = getDecrypt(encrypt.toString(), docrypt);
Log.d("Decryption", "Decrypted phrase: " + douncrypt);
Of course, douncrypt must match This is a phrase to be encrypted!