我有一个由SJCL服务器端加密的字符串,需要使用任何可用的库在Android中解密。我尝试了BouncyCastle,直到遇到无法从PBKDF2生成密钥的问题。现在,我正在使用SpongyCastle,但仍然遇到问题。到目前为止,这是我的代码,用于生成密钥和解密字符串:
private static byte[] decrypt(SecretKey key, byte[] encrypted, byte[] iv) throws Exception {
IvParameterSpec ivSpec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/CCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
public static SecretKey generateKey(char[] passphraseOrPin, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
// Number of PBKDF2 hardening rounds to use. Larger values increase
// computation time. You should select a value that causes computation
// to take >100ms.
final int iterations = 1000;
// Generate a 128-bit key
final int outputKeyLength = 128;
/*SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
KeySpec keySpec = new PBEKeySpec(passphraseOrPin, salt, iterations, outputKeyLength);
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);*/
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(passphraseOrPin), salt, iterations);
KeyParameter key = (KeyParameter) generator.generateDerivedMacParameters(outputKeyLength);
SecretKey secretKey = new SecretKeySpec(key.getKey(), "AES");
return secretKey;
}
这是我在函数中的调用方式:
char[] key = * put PBKDF2 password here *;
// Generate key from password
SecretKey decryptionKey = null;
try {
decryptionKey = generateKey(key, decodedObject.get("salt").getAsString().getBytes());
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
byte[] decryptedTicketBytes = null;
// Decrypt the ticket
try {
decryptedTicketBytes = decrypt(decryptionKey, decodedObject.get("ct").getAsString().getBytes(), decodedObject.get("iv").getAsString().getBytes());
} catch (Exception e) {
Log.e(TAG, e.getMessage());
}
经过解码的对象是来自SJCL的字符串,该字符串在通过具有UTF-8的JsonParser运行并被Base64解码之后。我拿了它,并使用密码在SJCL Demo中运行了它,并解密了字符串,没有问题。我一定在这里缺少一些简单的东西。
我得到的错误是在cipher.doFinal步骤上,如下所示:
java.security.InvalidKeyException: nonce must have length from 7 to 13 octets
我不认为SJCL在其密码上不使用填充,因此我尝试在getInstance上使用“ AES / CCM / PKCS5Padding”,但随后出现此错误:
javax.crypto.NoSuchPaddingException: Only NoPadding can be used with AEAD modes.
TLDR:我正在寻找在Android中解密SJCL字符串的最简单方法。建议将不胜感激。
谢谢!
最佳答案
尽管这不是用Java完成的,但实际上是在Android中完成的。我知道这不是我想要的解决方案,但它有效并且是解决方案。
您可以使用WebView在Android中运行SJCL来解密文件。您需要一个WebView JavaScript可以与之通信的接口。
public static class JavaScriptInterface {
Context mContext;
/** Instantiate the interface and set the context */
JavaScriptInterface(Context c) {
mContext = c;
}
//This is the function that is callable from the Javascript.
@JavascriptInterface
public void doJavaStuff(String dycryptedData)
{
//Do what you want with the decrypted data
}
}
从那里您将需要创建一个方法来使用SJCL获取脚本
public static String getSJCL() { return "<script>\n" + "SJCL_HERE" + "<script>\n";
然后创建HTML以运行代码。所有这些都可以通过.html文件和.script文件来完成,但是我希望我的密钥和加密文件是动态的。
public static String getHtmlForDecrypting(String encryptedData, String key) {
return "<html>\n" +
" <head>\n" +
getSJCL() +
" <script type=\"text/javascript\">\n" +
" function displaymessage()\n" +
" {\n" +
" var obj = " + encryptedData + ";\n" +
" var objString = JSON.stringify(obj);\n" +
" var data = sjcl.decrypt(\"" + key + "\", objString);\n" +
" JSInterface.doJavaStuff(data);\n" +
" }\n" +
" </script>\n" +
" </head>\n" +
" <body onload=\"displaymessage()\"></body>\n" +
"</html>\n";
}
接下来创建解密方法。
private static WebView wv;
private static JavaScriptInterface JSInterface;
private static String key1 = "YOURKEY";
public static void decrypt(Context context, String data) {
JSInterface = new JavaScriptInterface(context);
wv = new WebView(context);
wv.addJavascriptInterface(JSInterface, "JSInterface");
wv.getSettings().setJavaScriptEnabled(true);
wv.loadData(getHtmlForDecrypting(data, key1), "text/html", null);
}
关于android - 在Android中解密SJCL加密的字符串,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25127629/