Android AES/GCM加解密传递IV参数及解密实现问题求助
Android 加解密IV参数传递与功能实现
我正在开发Android加解密相关功能,希望能得到代码相关的帮助。我需要在加密、解密流程中传递IV(初始向量)参数:
加密函数初始实现
我最初尝试将加密后的密文与IV分别做Base64编码后用分号拼接输出,代码如下:
encryptedText.setText(Base64.encodeToString(vals, Base64.DEFAULT) + ";" + (Base64.encodeToString(encryptionIv, Base64.DEFAULT)));
从运行结果来看该逻辑运行正常,完整加密代码如下:
public void encryptString(String alias) { try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null); String initialText = startText.getText().toString(); if(initialText.isEmpty()) { Toast.makeText(this, "请在'初始文本'输入框内输入内容", Toast.LENGTH_LONG).show(); return; } Cipher inCipher = Cipher.getInstance("AES/GCM/NoPadding"); inCipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] src= initialText.getBytes("UTF-8"); byte[] iv = inCipher.getIV(); assert iv.length == 12; byte[] cipherText = inCipher.doFinal(src); assert cipherText.length == src.length + 16; byte[] message = new byte[12 + src.length + 16]; ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CipherOutputStream cipherOutputStream = new CipherOutputStream( outputStream, inCipher); cipherOutputStream.write(src); cipherOutputStream.close(); byte [] vals = outputStream.toByteArray(); encryptedText.setText(Base64.encodeToString(vals, Base64.DEFAULT)); } catch (Exception e) { Toast.makeText(this, "发生异常:" + e.getMessage(), Toast.LENGTH_LONG).show(); Log.e(TAG, Log.getStackTraceString(e)); } }
能否帮忙提供可以正常运行的解密示例?感谢。
更新内容
我参考示例调整了IV传递逻辑,当前加密代码如下(RSA方案):
public void encryptString(String alias) { try { KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null); RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey(); String initialText = startText.getText().toString(); if(initialText.isEmpty()) { Toast.makeText(this, "请在'初始文本'组件内输入内容", Toast.LENGTH_LONG).show(); return; } Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "AndroidOpenSSL"); inCipher.init(Cipher.ENCRYPT_MODE, publicKey); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CipherOutputStream cipherOutputStream = new CipherOutputStream( outputStream, inCipher); cipherOutputStream.write(initialText.getBytes("UTF-8")); cipherOutputStream.close(); byte [] vals = outputStream.toByteArray(); encryptedText.setText(Base64.encodeToString(vals, Base64.DEFAULT)); } catch (Exception e) { Toast.makeText(this, "发生异常:" + e.getMessage(), Toast.LENGTH_LONG).show(); Log.e(TAG, Log.getStackTraceString(e)); } }
最新更新
加密代码
我调整为AES/GCM方案,将12位IV拼接在密文前组合后再Base64编码输出,代码如下:
public void encryptString(String alias) { try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null); String initialText = startText.getText().toString(); if(initialText.isEmpty()) { Toast.makeText(this, "请在'初始文本'输入框内输入内容", Toast.LENGTH_LONG).show(); return; } Cipher inCipher = Cipher.getInstance("AES/GCM/NoPadding"); inCipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] src= initialText.getBytes("UTF-8"); byte[] iv = inCipher.getIV(); assert iv.length == 12; byte[] cipherText = inCipher.doFinal(src); assert cipherText.length == src.length + 16; byte[] message = new byte[12 + src.length + 16]; System.arraycopy(iv, 0, message, 0, 12); System.arraycopy(cipherText, 0, message, 12, cipherText.length); encryptedText.setText(Base64.encodeToString(message, Base64.DEFAULT)); } catch (Exception e) { Toast.makeText(this, "发生异常:" + e.getMessage(), Toast.LENGTH_LONG).show(); Log.e(TAG, Log.getStackTraceString(e)); } }
解密代码(无法正常运行)
public void decryptString(String alias) { try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null); String cipherText = encryptedText.getText().toString(); byte[] src = cipherText.getBytes(); byte[] message = new byte[12 + src.length + 16]; Cipher output = Cipher.getInstance("AES/GCM/NoPadding"); GCMParameterSpec params = new GCMParameterSpec(128, message, 0, 12); output.init(Cipher.DECRYPT_MODE, secretKey, params); CipherInputStream cipherInputStream = new CipherInputStream( new ByteArrayInputStream(Base64.decode(cipherText, 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(); } String finalText = new String(bytes, 0, bytes.length, "UTF-8"); decryptedText.setText(finalText); } catch (Exception e) { Toast.makeText(this, "发生异常:" + e.getMessage(), Toast.LENGTH_LONG).show(); Log.e(TAG, Log.getStackTraceString(e)); } }
运行时报错,能否帮忙排查问题?
最终解决方案
加密函数
public void encryptString(String alias) { try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null); String initialText = startText.getText().toString(); if(initialText.isEmpty()) { Toast.makeText(this, "请在'初始文本'输入框内输入内容", Toast.LENGTH_LONG).show(); return; } Cipher inCipher = Cipher.getInstance("AES/GCM/NoPadding"); inCipher.init(Cipher.ENCRYPT_MODE, secretKey); byte[] src= initialText.getBytes("UTF-8"); byte[] iv = inCipher.getIV(); assert iv.length == 12; byte[] cipherText = inCipher.doFinal(src); assert cipherText.length == src.length + 16; byte[] message = new byte[12 + src.length + 16]; System.arraycopy(iv, 0, message, 0, 12); System.arraycopy(cipherText, 0, message, 12, cipherText.length); encryptedText.setText(Base64.encodeToString(message, Base64.DEFAULT)); } catch (Exception e) { Toast.makeText(this, "发生异常:" + e.getMessage(), Toast.LENGTH_LONG).show(); Log.e(TAG, Log.getStackTraceString(e)); } }
解密函数
public void decryptString(String alias) { try { KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); SecretKey secretKey = (SecretKey) keyStore.getKey(alias, null); String cipherText = encryptedText.getText().toString(); Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); byte[] nonceCiphertextTag = Base64.decode(cipherText, Base64.DEFAULT); GCMParameterSpec params = new GCMParameterSpec(128, nonceCiphertextTag, 0, 12); cipher.init(Cipher.DECRYPT_MODE, secretKey, params); byte[] decrypted = cipher.doFinal(nonceCiphertextTag, 12, nonceCiphertextTag.length - 12); String finalText = new String(decrypted, 0, decrypted.length, "UTF-8"); decryptedText.setText(finalText); } catch (Exception e) { Toast.makeText(this, "发生异常:" + e.getMessage(), Toast.LENGTH_LONG).show(); Log.e(TAG, Log.getStackTraceString(e)); } }
非常感谢@Topaco的帮助。
内容的提问来源于stack exchange,提问作者Xshell
相关产品推荐
相关产品推荐

