java - 发送方和接收方消息字节内容大小不匹配和 javax.crypto.AEADBadTagException : Tag mismatch in AES-GCM mode

标签 java aes-gcm

我使用了在线的 AES-GCM 示例 java 代码。UDP 客户端必须使用 AES-GCM 模式加密数据并将其发送到服务器。UDP 服务器必须接收并解密它。当我这样做时有两个问题

1.我向服务器发送了“hi”消息(明文为2字节,加密后为18字节)。服务器收到消息后我们执行以下操作

DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
byte[] rec=receivePacket.getData();
String receivedData = new String(rec,0,receivePacket.getLength());
System.out.println(receivePacket.getLength());//18 bytes
System.out.println(receivedData.length);// 30 bytes(how???)

为什么两者大小不一样???

2.然后,当尝试解密30字节数据(?)时,在以下行中出现异常

byte[] plainText = cipher.doFinal(cipherText);  

示例客户端:

class GCMClient
{
    // AES-GCM parameters
    public static final int AES_KEY_SIZE = 128; // in bits
    public static final int GCM_NONCE_LENGTH = 12; // in bytes
    public static final int GCM_TAG_LENGTH = 16; // in bytes
    public static void main(String args[]) throws Exception{        
        DatagramSocket clientSocket = new DatagramSocket();
        InetAddress IPAddress = InetAddress.getByName("192.168.1.8");
        byte[] sendData = new byte[1024];
        byte[] receiveData = new byte[1024];        
        byte[] input = "hi".getBytes(); //2 bytes 

        byte[] keyBytes ="qwertyuiopasdfgh".getBytes();
        SecretKey key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES");       
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
        byte[] nonce = new byte[GCM_NONCE_LENGTH];
        nonce = "poiuytrewqlk".getBytes();;;        
        GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, nonce);
        cipher.init(Cipher.ENCRYPT_MODE, key, spec);
        byte[] aad =  "Whatever I like".getBytes();;
        cipher.updateAAD(aad);
        byte[] cipherText = cipher.doFinal(input); 
        System.out.println(cipherText.length+ "data sent!!!!!!! "); //18 bytes after encryption
        DatagramPacket sendPacket = new DatagramPacket(cipherText, cipherText.length, IPAddress, 9999);
        clientSocket.send(sendPacket);  
        clientSocket.close();     
   }
}

示例服务器:

class GCMServer
{
     // AES-GCM parameters
    public static final int AES_KEY_SIZE = 128; // in bits
    public static final int GCM_NONCE_LENGTH = 12; // in bytes
    public static final int GCM_TAG_LENGTH = 16; // in bytes

    public static void main(String args[]) throws Exception{ 
        try{
            DatagramSocket serverSocket = new DatagramSocket(9999,InetAddress.getByName("192.168.1.8"));
            byte[] receiveData = new byte[1024];
            byte[] sendData = new byte[1024];
            while(true){           
                DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
                receivePacket.setData(new byte[4096]);  
                serverSocket.receive(receivePacket);
                byte[] rec=receivePacket.getData();
                String receivedData = new String(rec,0,receivePacket.getLength());          
                byte[] cipherText = receivedData.getBytes();

                System.out.println("received packet size before convert to bytes "+receivePacket.getLength());//it displays 18
                System.out.println("received packet size after convert to bytes "+cipherText.length);//it display 30 how???? it must be 18          


                byte[] keyBytes ="qwertyuiopasdfgh".getBytes();
                SecretKey key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES");       
                Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "SunJCE");
                byte[] nonce = new byte[GCM_NONCE_LENGTH];
                nonce = "poiuytrewqlk".getBytes();;;        
                GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH * 8, nonce);            
                byte[] aad = "Whatever I like".getBytes();;         
                cipher.init(Cipher.DECRYPT_MODE, key, spec);     
                cipher.updateAAD(aad);      
                byte[] plainText = cipher.doFinal(cipherText);      
                System.out.println("After decryption "+new String(plainText));
            }
        }catch(Exception e){
            System.out.println("Exception caught "+e);//got Exception caught javax.crypto.AEADBadTagException: Tag mismatch!
        }
     }
}

最佳答案

我不知道为什么字节内容大小不同。但是,当我使用以下代码时它解决了

 DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
    serverSocket.receive(receivePacket);
    byte[] rec=receivePacket.getData();
    byte[] cipherText=new byte[receivePacket.getLength()];
    System.arraycopy(rec, 0, cipherText, 0, receivePacket.getLength());

相反

DatagramPacket receivePacket = new DatagramPacket(receiveData, receiveData.length);
serverSocket.receive(receivePacket);
byte[] rec=receivePacket.getData();
String receivedData = new String(rec,0,receivePacket.getLength());

并解决了 javax.crypto.AEADBadTagException: 标签不匹配异常

关于java - 发送方和接收方消息字节内容大小不匹配和 javax.crypto.AEADBadTagException : Tag mismatch in AES-GCM mode,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45962578/

相关文章:

encryption - openssl aes gcm 加密,带身份验证标签;命令行

c++ - AES-gcm 加密的 IV 中是否存在不起作用的值?

java - 在 Java 中以串行方式运行 Cucumber 测试

java - Tomcat 无法启动

java - JSF 托管 bean 在 Tomcat 部署期间导致 java.io.NotSerializableException

java - [sqlite 不匹配] : data type mismatch

安装后找不到java但java程序运行

java - 如何处理 "AES/GCM/NoPadding"的 IV 和身份验证标签?

java - 在 Java 中使用 BouncyCaSTLe 以 block 的形式读取 AES/GCM 编码数据

安卓 : AES Encryption & Decryption using GCM mode in android?