我正在使用Android应用程序,该应用程序需要在应用程序和服务器(.NET)之间创建安全通道,第一步是我们创建共享密钥,该应用程序生成密钥对(EC)并将公钥发送到服务器,然后服务器创建自己的密钥对并将公钥发送到应用程序,并保存基于应用程序的公钥和服务器私钥创建的共享密钥,然后服务器将自己的公钥,salt和iv发送回应用程序,然后该应用执行密钥协商,结果是android应用和服务器都具有基于公钥-私钥创建的字符串。
稍后,当android应用想要向服务器发送一些加密的消息时,我将生成的密钥,salt和iv并创建密钥,以便能够使用Cipher
来加密消息。
问题是,即使应用程序和服务器具有完全相同的切细密钥,盐和iv,由于某种原因,Android生成的SecretKey
与服务器不同(我们在调试模式下进行了检查,以查看共享密钥盐和iv相同)。
这是我用来创建密钥的代码:
byte[] sharedSecretBytes = Base64.decode(sharedSecretBase64, Base64.DEFAULT);
byte[] ivBytes = Base64.decode(ivBase64, Base64.DEFAULT);
byte[] saltBytes = Base64.decode(saltBase64, Base64.DEFAULT);
String sharedSecret = new String(sharedSecretBytes, "UTF-8");
//i tried to use different encoding, no luck.
//String sharedSecretAscii = new String(sharedSecretBytes, "ASCII");
char[] charArray = sharedSecret .toCharArray();
PBEKeySpec keySpec = new PBEKeySpec(charArray, saltBytes, 1000, 256);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
SecretKey key = secretKeyFactory.generateSecret(keySpec);
//here the keyBytes are not the same as generated in the server.
byte[] keyBytes = key.getEncoded();
//i saw in some tutorial somene do this, not sure why because we can provide the key as is to the cipher,
//the problem is that both not working.
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getEncoded(), "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(logNumber.getBytes("UTF-8"));
String asString = Base64.encodeToString(encrypted, Base64.NO_WRAP);
我还尝试在Android和服务器端将硬编码的共享机密发布为“ 123abc”,并且实际上它起作用了,所以我唯一的猜测是,如果sharedSecret包含转换sharedSecrte.toCharArray()
的问题,奇怪的字符会导致Java生成错误的秘密密钥吗?
我们还在iOS应用程序上进行工作,该过程完全相同,并且没有问题可以生成正确的密钥。
答案 0 :(得分:0)
最后,唯一按预期运行的方法是使用Bouncy Castle库 我所做的是:
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
generator.init(sharedSecretBytes, saltBytes, 1000);
byte[] dk = ((KeyParameter) generator.generateDerivedParameters(256)).getKey();
SecretKeySpec secretKeySpec = new SecretKeySpec(dk, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
byte[] encrypted = cipher.doFinal(logNumber.getBytes("UTF-8"));
仍然不明白为什么本地java.security会引起麻烦。