【问题标题】:AES-256-GCM decodeAES-256-GCM 解码
【发布时间】:2021-09-23 03:56:56
【问题描述】:

我尝试使用java7实现AES-256-GCM解码 我在 GCM 中遇到了 mac 检查失败响应 请大家帮帮我,谢谢大家。

import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

  public static void main(String[] args) throws Exception {
    String iv = "35d117c42d1c1835420b6b9942dd4f1b"; // utf-8
    String key = "3a7bd3e2360a3d29eea436fcfb7e44c7"; // utf-8
    String hexCipherString = "07a604fc0c143a6e"; // hex
    String hexAuthTagString = "984e81176ff260717beb184db3d73753"; //hex

    byte[] decodedCipherHexBtye = Hex.decodeHex(hexCipherString.toCharArray());
    byte[] base64Cipher = Base64.decodeBase64(decodedCipherHexBtye);
    byte[] decodedAuthTagHex = Hex.decodeHex(hexAuthTagString.toCharArray());
    byte[] base64AuthTag = Base64.decodeBase64(decodedAuthTagHex);

    SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
    byte[] gcmIv = iv.getBytes("UTF-8");

    Security.addProvider(new BouncyCastleProvider());
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
    GCMParameterSpec params = new GCMParameterSpec(base64AuthTag.length * Byte.SIZE, gcmIv);
    cipher.init(Cipher.DECRYPT_MODE, skeySpec, params);
    cipher.updateAAD(base64AuthTag);
    byte[] result = cipher.doFinal(base64Cipher);
    System.out.println(Base64.encodeBase64(result));
  }

期待Base64Encode的预期结果:dGVzdA==

【问题讨论】:

  • 您是否尝试过通过Base64解码将keyiv转换为byte[]

标签: java


【解决方案1】:

如何解决安全警告注释以实现安全代码。

警告中的核心问题是每次加密都需要一个随机生成的 IV(一组真正随机的字节)

当您制作 Cypher 时,这里有一个使用 Java 8 Oracle SE 的具体示例

       val cipher = Cipher.getInstance("some scheme", "some provider");

那么当我们安全地使用 Cypher 时,我们需要一个真正的随机初始化向量 IV 来正确解决这个警告也指向我们的问题,

事实证明,至少在 Oracle Java 8 中这很容易,

使用上述密码

    cipher.getIV()

密码对象的实例方法是安全的see

一般与IvParameterSpec一起使用

    ivParams = IvParameterSpec( cipher.getIV())
    cipher.init(Cipher.ENCRYPT_MODE, key, ivParams);

【讨论】:

    【解决方案2】:

    我找到了解决办法,修改代码如下:

      public static void main(String[] args) throws Exception {
        String iv = "35d117c42d1c1835420b6b9942dd4f1b"; // utf-8
        String key = "3a7bd3e2360a3d29eea436fcfb7e44c7"; // utf-8
        String hexCipherString = "07a604fc0c143a6e"; // hex
        String hexAuthTagString = "984e81176ff260717beb184db3d73753"; //hex
    
        byte[] decodedCipherHexBtye = Hex.decodeHex(hexCipherString.toCharArray());
        byte[] decodedAuthTagHex = Hex.decodeHex(hexAuthTagString.toCharArray());
    
        SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
        byte[] gcmIv = iv.getBytes("UTF-8");
    
        Security.addProvider(new BouncyCastleProvider());
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
        GCMParameterSpec params = new GCMParameterSpec(decodedAuthTagHex.length * Byte.SIZE, gcmIv);
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, params);
        cipher.update(decodedCipherHexBtye);
        byte[] result = cipher.doFinal(decodedAuthTagHex);
        
        System.out.println(new String(result));
      }
    

    参考这篇文章 Tag mismatch error in AES-256-GCM Decryption using Java

    【讨论】:

    • 安全警告static/fixed初始化向量的使用使得AES GCM模式下的加密不安全,做不要在生产中使用它。为每个加密生成一个随机生成的 IV,并将其与密文一起发送。
    【解决方案3】:

    这是使用 AES-256 进行加密和解密的最简单方法。

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
         String decryptedData = AESUtils.decrypt("Your Encrypted Data");
         System.out.println(decryptedData);
    }
    
    public class AESUtils {
    private static final String ENCRYPTION_KEY = "RwcmlVpg";
    private static final String ENCRYPTION_IV = "5183666c72eec9e4";
    
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static String encrypt(String src) {
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, makeKey(), makeIv());
            byte[] origignal= Base64.encode(cipher.doFinal(src.getBytes()),Base64.DEFAULT);
            return new String(origignal);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    @RequiresApi(api = Build.VERSION_CODES.O)
    public static String decrypt(String src) {
        String decrypted = "";
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, makeKey(), makeIv());
            byte[] decode = Base64.decode(src, Base64.NO_WRAP);
            decrypted= new String(cipher.doFinal(decode), "UTF-8");
        } catch (Exception e) {
            Log.v("AES Exception", String.valueOf(e));
    
            throw new RuntimeException(e);
        }
        return decrypted;
    }
    
    static AlgorithmParameterSpec makeIv() {
        try {
            return new IvParameterSpec(ENCRYPTION_IV.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    static Key makeKey() {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] key = md.digest(ENCRYPTION_KEY.getBytes("UTF-8"));
            return new SecretKeySpec(key, "AES");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
    
        return null;
    }
    }
    

    【讨论】:

    • 安全警告使用静态IV会使您的完全加密UNSECURE - 请不要使用此代码。使用随机生成的 IV 并将其添加到密文中,谢谢。
    猜你喜欢
    • 2021-06-04
    • 1970-01-01
    • 2021-01-10
    • 1970-01-01
    • 2018-10-29
    • 2019-02-27
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    相关资源
    最近更新 更多