android 中的 RSA / 非对称解密
RSA / Asymmetric decryption in android
编辑:根据评论重构代码,按照建议验证 Base64
我正在尝试解码 Android 中的 RSA 加密字符串,但未成功。
// Retrieve the key from server
// Looks counter intuitive, but, the retrieval happens on trusted Intranet.
URL keyUrl = new URL(keyUri);
URLConnection keyConn = keyUrl.openConnection();
InputStream keyStream = keyConn.getInputStream();
// Create the keystore and load the key
KeyStore pkcsStore = KeyStore.getInstance("PKCS12");
pkcsStore.load(keyStream, "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(pkcsStore, "password".toCharArray());
// Retrieve the key from keystore
String clientKeyAlias = pkcsStore.aliases().nextElement();
Key clientKey = pkcsStore.getKey(clientKeyAlias, "password".toCharArray());
Log.d(TAG, String.format("Algorithm: %s Format: %s ", clientKey.getAlgorithm(), clientKey.getFormat()));
// Retrieve the public key from keystore
Certificate certificate = pkcsStore.getCertificate(clientKeyAlias);
PublicKey clientPublicKey = certificate.getPublicKey();
// Let's make sure the certificate/key stored in pkcsStore are valid
String plainText = "Whosebug is Amazing!";
Log.d(TAG, String.format("Encrypting string '%s' to validate cert/key pair stored in pkcs store", plainText));
byte[] plainTextBytes = plainText.getBytes("UTF-8");
// Let's get the cipher instance
Cipher testCipher = Cipher.getInstance(clientKey.getAlgorithm());
testCipher.init(Cipher.ENCRYPT_MODE, clientPublicKey);
byte[] encryptedTextBytes = testCipher.doFinal(plainTextBytes);
testCipher.init(Cipher.DECRYPT_MODE, clientKey);
byte[] decryptedTextBytes = testCipher.doFinal(encryptedTextBytes);
String decryptedPlainText = new String(decryptedTextBytes, "UTF-8");
Log.d(TAG, "Decrypted plainText " + decryptedPlainText);
// Retrieve the encrypted data from server
URL symUrl = new URL(symUri);
URLConnection connection = symUrl.openConnection();
int contentLength = connection.getContentLength();
Log.d(TAG, "Content length " + contentLength);
InputStream is = connection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
// Validate the base64 string matches the data on server
String payLoad = br.readLine().trim(); // Trim the line in case echo there is a newline character
String base64StringOnServer = "nMdLvh+PDH1DimjQV0kTYU9E5tJA9VA2ADlcCQVkYwYZQWRFdT57bW4oDvlpGJ1KzJ/N3smyV5N7xlpNJo6HXans+cCImZI5MaZ9prEc3gUtIlwDWj80e0L+5YaRSIshXjPKvurjhwmppz+IAuh5Aq/c3ZdE2nbFn+L+2Ih91nsl6WV1diCEBw6pUIMtdPh8nXmQfp3ZbDKHt3VnSkoLLhPXYbYaTOaTuhAJZhszE5ejpB0sQ78d/1WbmPU1MnGCrUSOkM6s22fT3aTyzxo3IjmzXBWhz32tCbOBagmAsyaHlLHbQ2pQoxI9cR0hcZAc/IyEFKrVSJnFA03P/QzkhQ==";
Log.d(TAG, "Base64 as stored on the server: " + base64StringOnServer);
Log.d(TAG, "Base64 received from server: " + payLoad);
if (base64StringOnServer.equals(payLoad)) {
Log.d(TAG, "Base64 string comparision passed");
}
// Get the byte array of payload
byte[] data = Base64.decode(payLoad, Base64.DEFAULT);
// Decipher the data
Cipher cipher = Cipher.getInstance(clientKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, clientKey);
byte[] decryptedKeyBytes = cipher.doFinal(data);
// Validate the decrypted data
String decryptedKey = new String (decryptedKeyBytes, "UTF-8");
Log.d(TAG, "Decrypted Key: " + decryptedKey);
这里是加密数据的openssl命令
openssl rsautl -encrypt -pubin -inkey rsakey.pub -in key.txt | base64 -w 0 > enc_base64.txt
我已经通过在源中使用私钥进行验证来解密负载,如下所示。
cat key.base64 | base64 --decode | openssl rsautl -decrypt -inkey rsakey.key
上面显示的代码运行良好,没有异常,但解密的有效负载无效。
以下是摘自 Logcat
// Base64 decode flag Base64.NO_WRAP
Algorithm: RSA Format: PKCS#8
Encrypting string 'Whosebug is Amazing!' to validate cert/key pair stored in pkcs store
Decrypted plainText Whosebug is Amazing!
Content length 344
Base64 as stored on the server: nMdLvh+PDH1DimjQV0kTYU9E5tJA9VA2ADlcCQVkYwYZQWRFdT57bW4oDvlpGJ1KzJ/N3smyV5N7xlpNJo6HXans+cCImZI5MaZ9prEc3gUtIlwDWj80e0L+5YaRSIshXjPKvurjhwmppz+IAuh5Aq/c3ZdE2nbFn+L+2Ih91nsl6WV1diCEBw6pUIMtdPh8nXmQfp3ZbDKHt3VnSkoLLhPXYbYaTOaTuhAJZhszE5ejpB0sQ78d/1WbmPU1MnGCrUSOkM6s22fT3aTyzxo3IjmzXBWhz32tCbOBagmAsyaHlLHbQ2pQoxI9cR0hcZAc/IyEFKrVSJnFA03P/QzkhQ==
Base64 received from server: nMdLvh+PDH1DimjQV0kTYU9E5tJA9VA2ADlcCQVkYwYZQWRFdT57bW4oDvlpGJ1KzJ/N3smyV5N7xlpNJo6HXans+cCImZI5MaZ9prEc3gUtIlwDWj80e0L+5YaRSIshXjPKvurjhwmppz+IAuh5Aq/c3ZdE2nbFn+L+2Ih91nsl6WV1diCEBw6pUIMtdPh8nXmQfp3ZbDKHt3VnSkoLLhPXYbYaTOaTuhAJZhszE5ejpB0sQ78d/1WbmPU1MnGCrUSOkM6s22fT3aTyzxo3IjmzXBWhz32tCbOBagmAsyaHlLHbQ2pQoxI9cR0hcZAc/IyEFKrVSJnFA03P/QzkhQ==
Base64 string comparision passed
Decrypted Key: )|~`!��u�� zU.�縉)���#9�]���Q�����Ő�A�f*(A�%U�/;�%2��j0I$dI*,'@�E�t@�P�=-C��VR�o06p�4op9�k�q >�qq�>V�~Y���R�O���t2�S�֖E���&�rP�Q��L����2�;7��}�g�Wpٟ$P�N0�k�w��ň1����0�2��2�jҗ/�}r:*g"ոm���[����1234567812345678
// Base64 decode flag Base64.DEFAULT
Algorithm: RSA Format: PKCS#8
Encrypting string 'Whosebug is Amazing!' to validate cert/key pair stored in pkcs store
Decrypted plainText Whosebug is Amazing!
Content length 344
Base64 as stored on the server: nMdLvh+PDH1DimjQV0kTYU9E5tJA9VA2ADlcCQVkYwYZQWRFdT57bW4oDvlpGJ1KzJ/N3smyV5N7xlpNJo6HXans+cCImZI5MaZ9prEc3gUtIlwDWj80e0L+5YaRSIshXjPKvurjhwmppz+IAuh5Aq/c3ZdE2nbFn+L+2Ih91nsl6WV1diCEBw6pUIMtdPh8nXmQfp3ZbDKHt3VnSkoLLhPXYbYaTOaTuhAJZhszE5ejpB0sQ78d/1WbmPU1MnGCrUSOkM6s22fT3aTyzxo3IjmzXBWhz32tCbOBagmAsyaHlLHbQ2pQoxI9cR0hcZAc/IyEFKrVSJnFA03P/QzkhQ==
Base64 received from server: nMdLvh+PDH1DimjQV0kTYU9E5tJA9VA2ADlcCQVkYwYZQWRFdT57bW4oDvlpGJ1KzJ/N3smyV5N7xlpNJo6HXans+cCImZI5MaZ9prEc3gUtIlwDWj80e0L+5YaRSIshXjPKvurjhwmppz+IAuh5Aq/c3ZdE2nbFn+L+2Ih91nsl6WV1diCEBw6pUIMtdPh8nXmQfp3ZbDKHt3VnSkoLLhPXYbYaTOaTuhAJZhszE5ejpB0sQ78d/1WbmPU1MnGCrUSOkM6s22fT3aTyzxo3IjmzXBWhz32tCbOBagmAsyaHlLHbQ2pQoxI9cR0hcZAc/IyEFKrVSJnFA03P/QzkhQ==
Base64 string comparision passed
Decrypted Key: )|~`!��u�� zU.�縉)���#9�]���Q�����Ő�A�f*(A�%U�/;�%2��j0I$dI*,'@�E�t@�P�=-C��VR�o06p�4op9�k�q >�qq�>V�~Y���R�O���t2�S�֖E���&�rP�Q��L����2�;7��}�g�Wpٟ$P�N0�k�w��ň1����0�2��2�jҗ/�}r:*g"ոm���[����1234567812345678
缺少一些细节,但立即跳出的一个错误是:
Cipher cipher = Cipher.getInstance(clientKey.getAlgorithm());
Key.getAlgorithm()
没有 return 足够的信息用作 Cipher.getInstance()
的参数。它可能 return 没有抛出异常,但结果将不正确。相反,始终将完整的转换字符串“algorithm/mode/padding”指定为 Cipher.getInstance()
的参数。如果您确实按照 openssl
指示的那样加密了数据,那么这将是正确的行:
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
编辑:根据评论重构代码,按照建议验证 Base64
我正在尝试解码 Android 中的 RSA 加密字符串,但未成功。
// Retrieve the key from server
// Looks counter intuitive, but, the retrieval happens on trusted Intranet.
URL keyUrl = new URL(keyUri);
URLConnection keyConn = keyUrl.openConnection();
InputStream keyStream = keyConn.getInputStream();
// Create the keystore and load the key
KeyStore pkcsStore = KeyStore.getInstance("PKCS12");
pkcsStore.load(keyStream, "password".toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(pkcsStore, "password".toCharArray());
// Retrieve the key from keystore
String clientKeyAlias = pkcsStore.aliases().nextElement();
Key clientKey = pkcsStore.getKey(clientKeyAlias, "password".toCharArray());
Log.d(TAG, String.format("Algorithm: %s Format: %s ", clientKey.getAlgorithm(), clientKey.getFormat()));
// Retrieve the public key from keystore
Certificate certificate = pkcsStore.getCertificate(clientKeyAlias);
PublicKey clientPublicKey = certificate.getPublicKey();
// Let's make sure the certificate/key stored in pkcsStore are valid
String plainText = "Whosebug is Amazing!";
Log.d(TAG, String.format("Encrypting string '%s' to validate cert/key pair stored in pkcs store", plainText));
byte[] plainTextBytes = plainText.getBytes("UTF-8");
// Let's get the cipher instance
Cipher testCipher = Cipher.getInstance(clientKey.getAlgorithm());
testCipher.init(Cipher.ENCRYPT_MODE, clientPublicKey);
byte[] encryptedTextBytes = testCipher.doFinal(plainTextBytes);
testCipher.init(Cipher.DECRYPT_MODE, clientKey);
byte[] decryptedTextBytes = testCipher.doFinal(encryptedTextBytes);
String decryptedPlainText = new String(decryptedTextBytes, "UTF-8");
Log.d(TAG, "Decrypted plainText " + decryptedPlainText);
// Retrieve the encrypted data from server
URL symUrl = new URL(symUri);
URLConnection connection = symUrl.openConnection();
int contentLength = connection.getContentLength();
Log.d(TAG, "Content length " + contentLength);
InputStream is = connection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
// Validate the base64 string matches the data on server
String payLoad = br.readLine().trim(); // Trim the line in case echo there is a newline character
String base64StringOnServer = "nMdLvh+PDH1DimjQV0kTYU9E5tJA9VA2ADlcCQVkYwYZQWRFdT57bW4oDvlpGJ1KzJ/N3smyV5N7xlpNJo6HXans+cCImZI5MaZ9prEc3gUtIlwDWj80e0L+5YaRSIshXjPKvurjhwmppz+IAuh5Aq/c3ZdE2nbFn+L+2Ih91nsl6WV1diCEBw6pUIMtdPh8nXmQfp3ZbDKHt3VnSkoLLhPXYbYaTOaTuhAJZhszE5ejpB0sQ78d/1WbmPU1MnGCrUSOkM6s22fT3aTyzxo3IjmzXBWhz32tCbOBagmAsyaHlLHbQ2pQoxI9cR0hcZAc/IyEFKrVSJnFA03P/QzkhQ==";
Log.d(TAG, "Base64 as stored on the server: " + base64StringOnServer);
Log.d(TAG, "Base64 received from server: " + payLoad);
if (base64StringOnServer.equals(payLoad)) {
Log.d(TAG, "Base64 string comparision passed");
}
// Get the byte array of payload
byte[] data = Base64.decode(payLoad, Base64.DEFAULT);
// Decipher the data
Cipher cipher = Cipher.getInstance(clientKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, clientKey);
byte[] decryptedKeyBytes = cipher.doFinal(data);
// Validate the decrypted data
String decryptedKey = new String (decryptedKeyBytes, "UTF-8");
Log.d(TAG, "Decrypted Key: " + decryptedKey);
这里是加密数据的openssl命令
openssl rsautl -encrypt -pubin -inkey rsakey.pub -in key.txt | base64 -w 0 > enc_base64.txt
我已经通过在源中使用私钥进行验证来解密负载,如下所示。
cat key.base64 | base64 --decode | openssl rsautl -decrypt -inkey rsakey.key
上面显示的代码运行良好,没有异常,但解密的有效负载无效。
以下是摘自 Logcat
// Base64 decode flag Base64.NO_WRAP
Algorithm: RSA Format: PKCS#8
Encrypting string 'Whosebug is Amazing!' to validate cert/key pair stored in pkcs store
Decrypted plainText Whosebug is Amazing!
Content length 344
Base64 as stored on the server: nMdLvh+PDH1DimjQV0kTYU9E5tJA9VA2ADlcCQVkYwYZQWRFdT57bW4oDvlpGJ1KzJ/N3smyV5N7xlpNJo6HXans+cCImZI5MaZ9prEc3gUtIlwDWj80e0L+5YaRSIshXjPKvurjhwmppz+IAuh5Aq/c3ZdE2nbFn+L+2Ih91nsl6WV1diCEBw6pUIMtdPh8nXmQfp3ZbDKHt3VnSkoLLhPXYbYaTOaTuhAJZhszE5ejpB0sQ78d/1WbmPU1MnGCrUSOkM6s22fT3aTyzxo3IjmzXBWhz32tCbOBagmAsyaHlLHbQ2pQoxI9cR0hcZAc/IyEFKrVSJnFA03P/QzkhQ==
Base64 received from server: nMdLvh+PDH1DimjQV0kTYU9E5tJA9VA2ADlcCQVkYwYZQWRFdT57bW4oDvlpGJ1KzJ/N3smyV5N7xlpNJo6HXans+cCImZI5MaZ9prEc3gUtIlwDWj80e0L+5YaRSIshXjPKvurjhwmppz+IAuh5Aq/c3ZdE2nbFn+L+2Ih91nsl6WV1diCEBw6pUIMtdPh8nXmQfp3ZbDKHt3VnSkoLLhPXYbYaTOaTuhAJZhszE5ejpB0sQ78d/1WbmPU1MnGCrUSOkM6s22fT3aTyzxo3IjmzXBWhz32tCbOBagmAsyaHlLHbQ2pQoxI9cR0hcZAc/IyEFKrVSJnFA03P/QzkhQ==
Base64 string comparision passed
Decrypted Key: )|~`!��u�� zU.�縉)���#9�]���Q�����Ő�A�f*(A�%U�/;�%2��j0I$dI*,'@�E�t@�P�=-C��VR�o06p�4op9�k�q >�qq�>V�~Y���R�O���t2�S�֖E���&�rP�Q��L����2�;7��}�g�Wpٟ$P�N0�k�w��ň1����0�2��2�jҗ/�}r:*g"ոm���[����1234567812345678
// Base64 decode flag Base64.DEFAULT
Algorithm: RSA Format: PKCS#8
Encrypting string 'Whosebug is Amazing!' to validate cert/key pair stored in pkcs store
Decrypted plainText Whosebug is Amazing!
Content length 344
Base64 as stored on the server: nMdLvh+PDH1DimjQV0kTYU9E5tJA9VA2ADlcCQVkYwYZQWRFdT57bW4oDvlpGJ1KzJ/N3smyV5N7xlpNJo6HXans+cCImZI5MaZ9prEc3gUtIlwDWj80e0L+5YaRSIshXjPKvurjhwmppz+IAuh5Aq/c3ZdE2nbFn+L+2Ih91nsl6WV1diCEBw6pUIMtdPh8nXmQfp3ZbDKHt3VnSkoLLhPXYbYaTOaTuhAJZhszE5ejpB0sQ78d/1WbmPU1MnGCrUSOkM6s22fT3aTyzxo3IjmzXBWhz32tCbOBagmAsyaHlLHbQ2pQoxI9cR0hcZAc/IyEFKrVSJnFA03P/QzkhQ==
Base64 received from server: nMdLvh+PDH1DimjQV0kTYU9E5tJA9VA2ADlcCQVkYwYZQWRFdT57bW4oDvlpGJ1KzJ/N3smyV5N7xlpNJo6HXans+cCImZI5MaZ9prEc3gUtIlwDWj80e0L+5YaRSIshXjPKvurjhwmppz+IAuh5Aq/c3ZdE2nbFn+L+2Ih91nsl6WV1diCEBw6pUIMtdPh8nXmQfp3ZbDKHt3VnSkoLLhPXYbYaTOaTuhAJZhszE5ejpB0sQ78d/1WbmPU1MnGCrUSOkM6s22fT3aTyzxo3IjmzXBWhz32tCbOBagmAsyaHlLHbQ2pQoxI9cR0hcZAc/IyEFKrVSJnFA03P/QzkhQ==
Base64 string comparision passed
Decrypted Key: )|~`!��u�� zU.�縉)���#9�]���Q�����Ő�A�f*(A�%U�/;�%2��j0I$dI*,'@�E�t@�P�=-C��VR�o06p�4op9�k�q >�qq�>V�~Y���R�O���t2�S�֖E���&�rP�Q��L����2�;7��}�g�Wpٟ$P�N0�k�w��ň1����0�2��2�jҗ/�}r:*g"ոm���[����1234567812345678
缺少一些细节,但立即跳出的一个错误是:
Cipher cipher = Cipher.getInstance(clientKey.getAlgorithm());
Key.getAlgorithm()
没有 return 足够的信息用作 Cipher.getInstance()
的参数。它可能 return 没有抛出异常,但结果将不正确。相反,始终将完整的转换字符串“algorithm/mode/padding”指定为 Cipher.getInstance()
的参数。如果您确实按照 openssl
指示的那样加密了数据,那么这将是正确的行:
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");