加密/解密:HMAC标签与解密方法不符 [英] Encryption/decryption: HMAC tags don't match in decryption method

查看:211
本文介绍了加密/解密:HMAC标签与解密方法不符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试对加密/解密消息的加密和解密方法进行编码。



在加密方法中,它将占用一个字符串。它将以公共密钥读取并在RSA密码中使用。然后,该消息将使用具有AES密钥和IV的AES密码进行加密。然后,使用HMAC密钥通过密文加密的AES生成HMAC标签。 AES密钥和HMAC密钥由RSA密码连接在一起并加密。该方法将返回一个JSONObject,它包含:RSA密文,AES密文,AES IV和HMAC标签。它们是被转换成十六进制字符串的字节数组。



在decrypt方法中,它将占用将被解析的JSON对象。它将读入将用于RSA密码的私钥。 RSA密码将用于解密连接的密钥。一旦解密,密钥将被分离为AES密钥和HMAC密钥。然后,将在AES密文上生成新的HMAC标签。比较加密和新标签的标签。如果它们相等,则解密AES密文并获取消息。



当我运行我的代码时,没有错误,但它不会解密,因为2个标签不匹配我不知道为什么。



公钥和私钥是 .der .pem 文件。



请帮助我。谢谢!

  import java.security。*; 
import java.security.spec。*;
import javax.crypto。*;
import java.io. *;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import org.json。*;
import javax.xml.bind.DatatypeConverter;

public class CryptographicTools
{
/ **
*此方法加密消息
* @param message要加密的字符串消息
* @返回一个JSONObject
* /
public JSONObject encryptMessage(String message)
{
JSONObject output = new JSONObject(); //实例化JSONObject

尝试
{
//读入公钥
byte [] publicKeyBytes = readKeyFromFile(public.der); // pem convert to der

//将字节转换为公钥
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(publicKeyBytes); //编码字节
KeyFactory keyFactory = KeyFactory.getInstance(RSA); //将密钥设为RSA实例

//初始化RSA对象和公钥
密码RSAObject = Cipher.getInstance(RSA / ECB / OAEPWithSHA-256AndMGF1Padding); // with OAEP
RSAObject.init(Cipher.ENCRYPT_MODE,keyFactory.generatePublic(publicSpec)); //使用生成的公钥创建RSA加密密钥

//生成256位AES密钥
KeyGenerator keyGen = KeyGenerator.getInstance(AES); //生成AES密钥
keyGen.init(256); //生成256位的密钥
SecretKey AESKey = keyGen.generateKey(); //生成256位的AES密钥

//创建AES IV
SecureRandom randomByteGenerator =新的SecureRandom(); //安全生成器为IV
byte []生成随机Bye AESKeyIVArray = new byte [16];
randomByteGenerator.nextBytes(AESKeyIVArray); //获取iv
的随机字节IvParameterSpec AES_IV =新的IvParameterSpec(AESKeyIVArray); //对象为AES对象

//初始化AES对象
密码AESObject = Cipher.getInstance(AES / CBC / PKCS5Padding);
AESObject.init(Cipher.ENCRYPT_MODE,AESKey,AES_IV); //告诉AES对象加密

//加密消息与AES
byte [] AESciphertext = AESObject.doFinal(message.getBytes());

//生成256位HMAC密钥
字节[] SHA256KeyArray =新字节[32]; // 256位
randomByteGenerator.nextBytes(SHA256KeyArray); //生成随机键
SecretKeySpec HMACKeySpec = new SecretKeySpec(SHA256KeyArray,HmacSHA256); // make key
Mac HMAC = Mac.getInstance(HmacSHA256); //初始化HMAC
HMAC.init(HMACKeySpec); //将密钥加密
byte [] HMACTag = HMAC.doFinal(AESciphertext); //生成HMAC标签

//连接AES和HMAC密钥
byte [] AESKeyByte = AESKey.getEncoded(); ///将AESKey转换为字节数组
byte [] HMACKeySpecByte = HMACKeySpec.getEncoded(); ///转HMAXKey到字节数组
byte [] concatenatedKeys = new byte [AESKeyByte.length + HMACKeySpecByte.length]; //连接键的新数组

//在新数组中组合键
System.arraycopy(AESKeyByte,0,concatenatedKeys,0,AESKeyByte.length);
System.arraycopy(HMACKeySpecByte,0,concatenatedKeys,AESKeyByte.length,HMACKeySpecByte.length);

//使用RSA对象加密密钥
byte [] RSAciphertext = RSAObject.doFinal(concatenatedKeys);

//将RSA密文,AES密文,AES_IV和HMAC标签放在JSon
//中保存byte []作为字符串,以十六进制
output.put(RSAciphertext,DatatypeConverter .printHexBinary(RSAciphertext));
output.put(AESciphertext,DatatypeConverter.printHexBinary(AESciphertext));
output.put(AES_IV,DatatypeConverter.printHexBinary(AES_IV.getIV()));
output.put(HMACTag,DatatypeConverter.printHexBinary(HMACTag));
}
catch(异常e)
{
System.out.println(Error:+ e.toString()+ e.getMessage()); //错误消息
}

返回输出; //返回为JSON对象
}

/ **
*此方法解密消息
* @param jsonObjectEncrypted
* @return message as string
* /
public String decrypt(JSONObject jsonObjectEncrypted)
{
String message =;
try
{
//从JSON获取RSA密文
String RSACiphertextString = jsonObjectEncrypted.getString(RSAciphertext);
byte [] restoredRSAciphertext = DatatypeConverter.parseHexBinary(RSACiphertextString); //将十六进制字符串转换为字节数组

//从JSON恢复AES密文
String AESCiphertextString = jsonObjectEncrypted.getString(AESciphertext);
byte [] restoredAESciphertext = DatatypeConverter.parseHexBinary(AESCiphertextString); //将十六进制字符串转换为字节数组

//从JSON中恢复AES IV
字符串AES_IVString = jsonObjectEncrypted.get(AES_IV)。toString();
byte [] recoverAES_IV = DatatypeConverter.parseHexBinary(AES_IVString); //将十六进制字符串转换为字节数组
//从JSON中恢复HMACTag
String HMACTagString = jsonObjectEncrypted.getString(HMACTag);
byte [] recoverHMACTag = DatatypeConverter.parseHexBinary(HMACTagString); //将十六进制字符串转换为字节数组

//读入私钥
byte [] privateKeyBytes = readKeyFromFile(private.der); // pem convert to der

//将字节转换为私钥
PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);

//初始化RSA对象和私钥
密码RSAObject = Cipher.getInstance(RSA / ECB / OAEPWithSHA-256AndMGF1Padding); // with OAEP
RSAObject.init(Cipher.DECRYPT_MODE,keyFactory.generatePrivate(privateSpec)); //使用生成的私钥创建RSA加密密钥

//使用RSA对象解密连接密钥
byte [] concatenatedKeys = RSAObject.doFinal(restoredRSAciphertext);

//拆分连接的键
byte [] AESKey = new byte [concatenatedKeys.length / 2];
byte [] HMACKey = new byte [concatenatedKeys.length / 2];
System.arraycopy(concatenatedKeys,0,AESKey,0,AESKey.length); //将一半拷贝到AESKey
System.arraycopy(concatenatedKeys,AESKey.length,HMACKey,0,HMACKey.length); //将其他一半复制到HMACKey

//生成HMACTag
SecretKeySpec HMACKeySpec = new SecretKeySpec(HMACKey,HmacSHA256); // make key
Mac HMAC = Mac.getInstance(HmacSHA256);
HMAC.init(HMACKeySpec); //使用HMAC键初始化
byte [] newHMACTag = HMAC.doFinal(restoredAESciphertext); //使用AES加密生成HMACTag

如果(recoverHMACTag.equals(newHMACTag))//如果标签相等则加密消息
{
//初始化AES对象
密码AESObject = Cipher.getInstance(AES / CBC / PKCS5Padding);
AESObject.init(Cipher.DECRYPT_MODE,新的SecretKeySpec(AESKey,AES),新的IvParameterSpec(recoverAES_IV)); //告诉AES对象加密
message = new String(AESObject.doFinal(restoredAESciphertext),US-ASCII); //加密AES密文并保存为字符串

}
else
{
System.out.println(消息无法解密);
}


}
catch(异常e)
{
System.out.println(Error:+ e.toString ()+:+ e.getMessage()); //错误消息
}

返回消息; //返回纯文本
}

/ **
*此方法将文件中的一个键的字节从文件读入字节数组
* @param fileName类型的键
* @return字节数组
* @throws IOException
* /
public byte [] readKeyFromFile(String fileName)throws IOException
{
return Files。 readAllBytes(Paths.get(文件名));
}

}


解决方案

Java数组不实现 .equals()帮助)。尝试更换此支票:

  recoverHMACTag.equals(newHMACTag)

由这一个:

  java.util.Arrays.equals( recoverHMACTag,newHMACTag)

我不能说这是所有可能是导致它出错,但这是我要检查的第一件事。


I'm trying to code encryption and decryption methods that will encrypt/decrypt a message.

In the encrypt method, it will take in a string. It will read in a public key and be used in a RSA cipher. Then, the message will be encrypted with an AES Cipher that has a AES Key and IV. Then, a HMAC tag will be generated with the ciphertext encrypted AES by using a HMAC key. The AES Key and HMAC key are concatenated together and encrypted by RSA Cipher. The method will return a JSONObject that contains: RSA ciphertext, AES ciphertext, the AES IV, and HMAC tag. They are byte arrays that are converted into hex strings.

In the decrypt method, it will take in the JSON Object, which will be parsed. It will read in a private key that will be used in a RSA cipher. The RSA cipher will be used to decrypt the concatenated keys. Once decrypted the keys will be separated to AES Key and HMAC key. Then, new HMAC tag will be generated on the AES Ciphertext. Compare the tag from the encryption and the new tag. If they are equal, then decrypt the AES ciphertext and get the message.

When I run my code, there are no errors, but it does not decrypt because the 2 tags don't match. I don't know why.

The public and private keys are .der files that were converted from .pem files.

Please help me. Thanks!

import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import org.json.*;
import javax.xml.bind.DatatypeConverter;

public class CryptographicTools 
{
    /**
     * This method encrypts a message
     * @param message String message to be encrypted
     * @return a JSONObject 
     */
    public JSONObject encryptMessage(String message)
    {
        JSONObject output = new JSONObject(); // instantiate JSONObject

        try
        {
            //read in public key
            byte[] publicKeyBytes = readKeyFromFile("public.der");//pem convert to der

            //turn bytes into public key
            X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(publicKeyBytes); //encodes the bytes
            KeyFactory keyFactory = KeyFactory.getInstance("RSA"); //make the key a RSA instance

            //initialize RSA object and public key
            Cipher RSAObject = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); //with OAEP   
            RSAObject.init(Cipher.ENCRYPT_MODE, keyFactory.generatePublic(publicSpec)); //create RSA encryption cipher with a generated public key

            //generate 256-bit AES key
            KeyGenerator keyGen = KeyGenerator.getInstance("AES");//generate AES Key
            keyGen.init(256); //generate a key with 256 bits
            SecretKey AESKey = keyGen.generateKey(); //generate AES key with 256 bits

            //Create AES IV
            SecureRandom randomByteGenerator = new SecureRandom();//secure generator to generate random byes for  IV
            byte[] AESKeyIVArray = new byte[16];
            randomByteGenerator.nextBytes(AESKeyIVArray);//get random bytes for iv
            IvParameterSpec AES_IV = new IvParameterSpec(AESKeyIVArray); //iv object for AES object

            //initialize AES object
            Cipher AESObject = Cipher.getInstance("AES/CBC/PKCS5Padding");
            AESObject.init(Cipher.ENCRYPT_MODE, AESKey, AES_IV); //tell the AES object to encrypt

            //encrypt message with AES
            byte[] AESciphertext = AESObject.doFinal(message.getBytes());

            //generate 256-bit HMAC key
            byte[] SHA256KeyArray = new byte[32];//256 bits
            randomByteGenerator.nextBytes(SHA256KeyArray);//generate random bits for key
            SecretKeySpec HMACKeySpec = new SecretKeySpec (SHA256KeyArray,"HmacSHA256"); //make the key
            Mac HMAC = Mac.getInstance("HmacSHA256"); //initialize HMAC
            HMAC.init(HMACKeySpec);//put key in cipher
            byte [] HMACTag = HMAC.doFinal(AESciphertext);//generate HMAC tag

            //concatenate AES and HMAC keys
            byte[] AESKeyByte = AESKey.getEncoded();///turn AESKey to byte array
            byte[] HMACKeySpecByte = HMACKeySpec.getEncoded();///turn HMAXKey to byte array
            byte[] concatenatedKeys = new byte[AESKeyByte.length + HMACKeySpecByte.length];//new array for concatenated keys

            //combine keys in new array
            System.arraycopy(AESKeyByte, 0, concatenatedKeys, 0, AESKeyByte.length);
            System.arraycopy(HMACKeySpecByte, 0, concatenatedKeys, AESKeyByte.length, HMACKeySpecByte.length);

            //encrypt keys with RSA object
            byte[] RSAciphertext = RSAObject.doFinal(concatenatedKeys);

            //put RSA ciphertext, AES ciphertext, AES_IV and HMAC tag in JSon
            //save byte[] as Strings in hex
            output.put("RSAciphertext", DatatypeConverter.printHexBinary(RSAciphertext));
            output.put("AESciphertext", DatatypeConverter.printHexBinary(AESciphertext));
            output.put("AES_IV", DatatypeConverter.printHexBinary(AES_IV.getIV()));
            output.put("HMACTag", DatatypeConverter.printHexBinary(HMACTag));
        }
        catch (Exception e)
        {
            System.out.println("Error: " + e.toString() +e.getMessage()); //error message
        }

        return output; //return as JSON Object
    }

    /**
     * This method decrypts a message
     * @param jsonObjectEncrypted
     * @return message as string
     */
    public String decrypt (JSONObject jsonObjectEncrypted)
    {
        String message="";
        try
        {
            //recover RSA ciphertext from JSON
            String RSACiphertextString=jsonObjectEncrypted.getString("RSAciphertext");
            byte[] recoveredRSAciphertext = DatatypeConverter.parseHexBinary(RSACiphertextString); //convert hex string to byte array

            //recover AES ciphertext from JSON
            String AESCiphertextString=jsonObjectEncrypted.getString("AESciphertext");
            byte[] recoveredAESciphertext = DatatypeConverter.parseHexBinary(AESCiphertextString); //convert hex string to byte array

            //recover AES IV from JSON
            String AES_IVString=jsonObjectEncrypted.get("AES_IV").toString();
            byte[] recoveredAES_IV = DatatypeConverter.parseHexBinary(AES_IVString); //convert hex string to byte array
            //recover HMACTag from JSON
            String HMACTagString=jsonObjectEncrypted.getString("HMACTag");
            byte[] recoveredHMACTag = DatatypeConverter.parseHexBinary(HMACTagString); //convert hex string to byte array

            //read in private key
            byte[] privateKeyBytes = readKeyFromFile("private.der");//pem convert to der

            //turn bytes into private key
            PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");

            //initialize RSA object and private key
            Cipher RSAObject = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); //with OAEP   
            RSAObject.init(Cipher.DECRYPT_MODE, keyFactory.generatePrivate(privateSpec)); //create RSA encryption cipher with a generated private key

            //Decrypt concatenated keys with RSA object
            byte[] concatenatedKeys = RSAObject.doFinal(recoveredRSAciphertext);

            //split the concatenated keys
            byte[] AESKey = new byte[concatenatedKeys.length/2];
            byte[] HMACKey = new byte[concatenatedKeys.length/2];
            System.arraycopy(concatenatedKeys, 0,AESKey,0,AESKey.length); //Copy half into AESKey
            System.arraycopy(concatenatedKeys, AESKey.length,HMACKey,0,HMACKey.length); //Copy Other half into HMACKey

            //generate HMACTag
            SecretKeySpec HMACKeySpec = new SecretKeySpec (HMACKey,"HmacSHA256"); //make the key
            Mac HMAC = Mac.getInstance("HmacSHA256");
            HMAC.init(HMACKeySpec);//initialize with HMAC Key
            byte [] newHMACTag = HMAC.doFinal(recoveredAESciphertext); //generate HMACTag with AES Ciphertext

            if(recoveredHMACTag.equals(newHMACTag)) //encrypt message if tags are equal
            {
                //initialize AES object
                Cipher AESObject = Cipher.getInstance("AES/CBC/PKCS5Padding");
                AESObject.init(Cipher.DECRYPT_MODE, new SecretKeySpec (AESKey,"AES"), new IvParameterSpec(recoveredAES_IV)); //tell the AES object to encrypt
                message = new String (AESObject.doFinal(recoveredAESciphertext), "US-ASCII");//encrypt AES ciphertext and save as string

            }
            else
            {
                System.out.println("Message cannot be decrypted.");
            }


        }
        catch (Exception e)
        {
            System.out.println("Error: "+e.toString()+": "+e.getMessage()); //error message
        }

        return message; //return plaintext
    }

    /**
     * This method reads bytes of a key from a file  into a byte array
     * @param fileName type of key
     * @return byte array
     * @throws IOException
     */
    public byte[] readKeyFromFile(String fileName) throws IOException
    {
        return Files.readAllBytes(Paths.get(fileName));
    }

}

解决方案

The Java array doesn't implement .equals() the way you'd want it to (info). Try replacing this check:

recoveredHMACTag.equals(newHMACTag)

by this one:

java.util.Arrays.equals(recoveredHMACTag, newHMACTag)

I can't say that's all that could be causing it to go wrong, but it's the first thing I would check.

这篇关于加密/解密:HMAC标签与解密方法不符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆