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");).
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 want to be able to encrypt and decrypt strings over a simple client and server using an echo model architecture with a specified port.
The way the client and server communicate is as follows:
The client is run first and generates a key pair, prints out its public key to the console, and waits for an input (which will be server's public key via copy and paste)
The server is then run and does the same also. Printing out its public key and waits for the client's public key (also copy and paste.)
Copy and paste (client public key) is done to the server first, which then starts the server listening on port 4444.
The client is then also started with copy and paste (server public key), sending a string over port 4444.
encrypted with the server’s public key.
The strings are to be encrypted by the client, sent, and received by the server who will decrypt the strings. An additional feature I am thinking to add should allow multiple strings to be encrypted and decrypted (done by a while loop).
My console for the client seems to be able to send the strings (converted to bytes, then sent) just fine by using out.write() and out.flush(), but has trouble reading the encrypted bytes using (while data is not empty... in.read().
The exception thrown is Exception in thread "main" javax.crypto.BadPaddingException: Decryption error
My client code:
public class EchoClient {
private Socket clientSocket;
private DataOutputStream out;
private DataInputStream in;
private PrivateKey generateKeyPairClient() throws NoSuchAlgorithmException {
final KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
final KeyPair kp = kpg.generateKeyPair();
final PublicKey clientPublicKey = kp.getPublic();
System.out.println(clientPublicKey);
System.out.println("Client Public Key (Encoded) is " + Base64.getEncoder().encodeToString(clientPublicKey.getEncoded()));
return kp.getPrivate();
}
private PublicKey obtainServerPublicKey() {
System.out.println("Please enter the servers's public key below:");
Scanner sc = new Scanner(System.in);
String key = sc.next();
sc.close();
PublicKey serverPublicKey = null;
try{
byte[] byteKey = Base64.getDecoder().decode(key.getBytes());
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
serverPublicKey = kf.generatePublic(X509publicKey);
}
catch(Exception e){
System.out.println("The public key you entered for the server is not valid, please try again");
}
return serverPublicKey;
}
private void startConnection(String ip, int port) {
try {
clientSocket = new Socket(ip, port);
out = new DataOutputStream(clientSocket.getOutputStream());
in = new DataInputStream(clientSocket.getInputStream());
} catch (IOException e) {
System.out.println("Error when initializing connection");
}
}
private void sendPlainTextToEncryptedText(String original, PublicKey serverPublicKey, PrivateKey clientPrivateKey) {
try {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, serverPublicKey);
byte[] originalBytes = original.getBytes(StandardCharsets.UTF_8);
byte[] cipherTextBytes = cipher.doFinal(originalBytes);
System.out.println("Client will send the ciphertext: "+ Util.bytesToHex(cipherTextBytes));
out.write(cipherTextBytes);
out.flush();
} catch (Exception e) {
System.out.println("There was a problem when trying to encrypt/decrypt, please try again");
e.printStackTrace();
return;
}
}
private void stopConnection() {
try {
in.close();
out.close();
clientSocket.close();
} catch (IOException e) {
System.out.println("error when closing");
}
}
public static void main(String[] args) throws NoSuchAlgorithmException {
EchoClient client = new EchoClient();
PrivateKey clientPrivateKey = client.generateKeyPairClient();
PublicKey serverPublicKey = client.obtainServerPublicKey();
System.out.println("Key Exchange Complete for Client");
client.startConnection("127.0.0.1", 4444);
client.sendPlainTextToEncryptedText("everyone", serverPublicKey, clientPrivateKey);
client.stopConnection();
}
}
My server code:
public class EchoServer {
private ServerSocket serverSocket;
private Socket clientSocket;
private DataOutputStream out;
private DataInputStream in;
private PrivateKey generateKeyPairServer() throws NoSuchAlgorithmException {
final KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
final KeyPair kp = kpg.generateKeyPair();
final PublicKey serverPublicKey = kp.getPublic();
System.out.println(serverPublicKey);
System.out.println("Server Public Key (Encoded) is " + Base64.getEncoder().encodeToString(serverPublicKey.getEncoded()));
return kp.getPrivate();
}
private PublicKey obtainClientPublicKey() {
System.out.println("Please enter the clients's public key below:");
Scanner sc = new Scanner(System.in);
String key = sc.next();
sc.close();
PublicKey clientPublicKey = null;
try{
byte[] byteKey = Base64.getDecoder().decode(key.getBytes());
X509EncodedKeySpec X509publicKey = new X509EncodedKeySpec(byteKey);
KeyFactory kf = KeyFactory.getInstance("RSA");
clientPublicKey = kf.generatePublic(X509publicKey);
}
catch(Exception e){
System.out.println("The public key you entered for the client is not valid, please try again");
}
return clientPublicKey;
}
public void start(int port) {
try {
serverSocket = new ServerSocket(port);
clientSocket = serverSocket.accept();
out = new DataOutputStream(clientSocket.getOutputStream());
in = new DataInputStream(clientSocket.getInputStream());
} catch (IOException e) {
System.out.println("Error when establishing/accepting server connection");
}
}
private void receiveEncryptedTextToPlainText(PrivateKey serverPrivateKey) throws UnsupportedEncodingException, IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
byte[] data = new byte[8];
#SuppressWarnings("unused")
int numBytes;
while ((numBytes = in.read(data)) != -1) {
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, serverPrivateKey);
byte[] decryptedBytes = cipher.doFinal(data);
String text = new String(decryptedBytes, StandardCharsets.UTF_8);
System.out.println("Server has recieved the plain text: "+ text);
}
stop();
}
public void stop() {
try {
in.close();
out.close();
clientSocket.close();
serverSocket.close();
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, UnsupportedEncodingException, IOException, IllegalBlockSizeException, BadPaddingException {
EchoServer server = new EchoServer();
PrivateKey serverPrivateKey = server.generateKeyPairServer();
//Sorry for the mis-named var, will rename in code
PublicKey serverPublicKey = server.obtainClientPublicKey();
System.out.println("Key Exchange Complete for Server");
System.out.println("Now waiting for incoming connection...");
server.start(4444);
server.receiveEncryptedTextToPlainText(serverPrivateKey);
server.stop();
}
}
The Util assist class
import java.io.UnsupportedEncodingException;
public class Util {
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
return sb.toString();
}
public static String strToHex(String s) {
s = "failed decoding";
try {
s = Util.bytesToHex(s.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
System.out.println("Unsupported Encoding Exception");
}
return s;
}
}
The console outputs:
I'm not sure at to what might be wrong here, any advice?
I have noted two things which I think may be the cause:
Note: I am copying and pasting public keys (converting them to strings and back to public key objects - may be a problem...)
Note 2: The transfer of bytes over the socket in a size of 8 bytes might be problematic for longer strings
You must read all cipher-data before decrypt it. At EchoServer:
private void receiveEncryptedTextToPlainText(PrivateKey serverPrivateKey) throws UnsupportedEncodingException, IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
byte[] data = new byte[8];
ByteArrayOutputStream cipherData = new ByteArrayOutputStream();
#SuppressWarnings("unused")
int numBytes;
while ((numBytes = in.read(data)) != -1) {
cipherData.write(data, 0, numBytes);
}
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, serverPrivateKey);
byte[] decryptedBytes = cipher.doFinal(cipherData.toByteArray());
String text = new String(decryptedBytes, StandardCharsets.UTF_8);
System.out.println("Server has recieved the plain text: " + text);
stop();
}
I wanted to try out the code from Java In A Nutshell book (3rd edition), but when I'm trying to run it, I'm getting java.lang.ArrayIndexOutOfBoundsException: 1 error. I found that info:
Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.
but unfortunately I am still not able to find and fix it
package tripledes;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.security.spec.*;
import java.io.*;
public class TripleDES {
public static void main(String[] args) {
try {
try {
Cipher c = Cipher.getInstance("DESede");
} catch (Exception e) {
System.err.println("Installing SunJCE provicer");
Provider sunjce = new com.sun.crypto.provider.SunJCE();
Security.addProvider(sunjce);
}
File keyfile = new File(args[1]);
if (args[0].equals("-g")) {
System.out.println("Generating key. This may take some time...");
System.out.flush();
SecretKey key = generateKey();
writeKey(key, keyfile);
System.out.println("Done");
System.out.println("Secret key written to " + args[1] + ". Protect that file!");
} else if (args[0].equals("-e")) {
SecretKey key = readKey(keyfile);
encrypt(key, System.in, System.out);
} else if (args[0].equals("-d")) {
SecretKey key = readKey(keyfile);
decrypt(key, System.in, System.out);
}
} catch (Exception e) {
System.err.println(e);
System.err.println("Usage: java " + TripleDES.class.getName() + "-d|-e|-g <keyfile>");
}
}
public static SecretKey generateKey() throws NoSuchAlgorithmException {
KeyGenerator keygen = KeyGenerator.getInstance("DESede");
return keygen.generateKey();
}
public static void writeKey(SecretKey key, File f) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("DESede");
DESedeKeySpec keyspec = (DESedeKeySpec) keyfactory.getKeySpec(key, DESedeKeySpec.class);
byte[] rawkey = keyspec.getKey();
FileOutputStream out = new FileOutputStream(f);
out.write(rawkey);
out.close();
}
public static SecretKey readKey(File f) throws IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
DataInputStream in = new DataInputStream(new FileInputStream(f));
byte[] rawkey = new byte[(int) f.length()];
in.readFully(rawkey);
in.close();
DESedeKeySpec keyspec = new DESedeKeySpec(rawkey);
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("DESede");
SecretKey key = keyfactory.generateSecret(keyspec);
return key;
}
public static void encrypt(SecretKey key, InputStream in, OutputStream out)
throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IOException {
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
CipherOutputStream cos = new CipherOutputStream(out, cipher);
byte[] buffer = new byte[2048];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
cos.write(buffer, 0, bytesRead);
}
cos.close();
java.util.Arrays.fill(buffer, (byte) 0);
}
public static void decrypt(SecretKey key, InputStream in, OutputStream out)
throws NoSuchAlgorithmException, InvalidKeyException, IOException, IllegalBlockSizeException,
NoSuchPaddingException, BadPaddingException {
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] buffer = new byte[2048];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(cipher.update(buffer, 0, bytesRead));
}
out.write(cipher.doFinal());
out.flush();
}
}
Could be when you access the args array. Such as:
File keyfile = new File(args[1]);
If you have no arguments to your program then this would be an ArrayIndexOutOfBoundsException.
Dears,
I need help to understand why decryptString doesn't work and throw "java.security.InvalidKeyException: Need RSA private or public key". When call encrypt method, i use public key by the private key/certificate.
Thanks for any help!
public class KeysHandler {
/***
* Generate and store in AndroidKeyStore a security KeyPair keys.
* #param alias - Alias to create the key.
* #return KeyPair object with: private and public key.
*/
public static KeyPair generateKeyPair(String alias) {
KeyPair kp = null;
if (alias != null) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, "AndroidKeyStore");
kpg.initialize(new KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN |
KeyProperties.PURPOSE_VERIFY |
KeyProperties.PURPOSE_ENCRYPT |
KeyProperties.PURPOSE_DECRYPT)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
.build());
kp = kpg.generateKeyPair();
} catch (NoSuchProviderException | NoSuchAlgorithmException | InvalidAlgorithmParameterException ex) {
kp = null;
}
}
return kp;
}
public static String encryptString(String alias, String textToEncrypt) {
String cipheredText = null;
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
// Encrypt the text
if(textToEncrypt != null && textToEncrypt.length() > 0) {
Cipher input = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
input.init(Cipher.ENCRYPT_MODE, privateKeyEntry.getCertificate().getPublicKey());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(
outputStream, input);
cipherOutputStream.write(textToEncrypt.getBytes("UTF-8"));
cipherOutputStream.close();
byte[] vals = outputStream.toByteArray();
cipheredText = Base64.encodeToString(vals, Base64.DEFAULT);
}
} catch (Exception e) {
cipheredText = null;
}
return cipheredText;
}
public static String decryptString(String alias, String cipheredText) {
String clearText = null;
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL");
output.init(Cipher.DECRYPT_MODE, privateKeyEntry.getPrivateKey());
CipherInputStream cipherInputStream = new CipherInputStream(
new ByteArrayInputStream(Base64.decode(cipheredText, Base64.DEFAULT)), output);
ArrayList<Byte> values = new ArrayList<>();
int nextByte;
while ((nextByte = cipherInputStream.read()) != -1) {
values.add((byte)nextByte);
}
byte[] bytes = new byte[values.size()];
for(int i = 0; i < bytes.length; i++) {
bytes[i] = values.get(i).byteValue();
}
clearText = new String(bytes, 0, bytes.length, "UTF-8");
} catch (Exception e) {
clearText = null;
}
return clearText;
}
}
Try omitting the cipher provider:
Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding");
Secondly, you can instantiate the provider first to make sure that works, then pass it along as the second argument to Cipher.getInstance(). The second argument can be either a String (provider name) or a Provider (object). Using the second might make debugging easier.
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();
}
}
}