AES key wrapping using another AES key and unwrapping to get the original key (RFC 3394 and RFC 5649)

54 Views Asked by At

I am trying AES key wrapping using another AES key and unwrapping to get the original key (RFC 3394 and RFC 5649). The way of wrapping and unwrapping the key is as follows:

Key wrapping

  1. Convert into byte[]
  2. Wrap using AES
  • Get Cipher instance Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
  • Generate IvParameterSpec
  • Create a SecretKey object from the wrapper key SecretKey secretKey = new SecretKeySpec(wrapperKey, "AES");
  • Initialize the cipher for encryption cipher.init(Cipher.WRAP_MODE, secretKey, iv);
  • Perform wrapping byte[] wrappedKey = cipher.wrap(new SecretKeySpec(keyToWrap, "AES"));
  • return wrapped key

Key unwrapping

  1. Convert wrapped key to byte[]
  2. Unwrap using AES
  • Get Cipher instance Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
  • Extract IV (16 bytes)
  • Create a SecretKey object from the wrapper key SecretKey secretKey = new SecretKeySpec(wrapperKey, "AES");
  • Initialize the cipher for encryption cipher.init(Cipher.UNWRAP_MODE, secretKey , iv);
  • Perform unwrapping Key unwrappedKey = cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);

Problem

The issue I am facing while unwrapping is that I am not getting the original key back and the difference is caused by first 16 bytes in byte array which is the size of IV. I debugged but couldn't find the reason causing this.

Dependencies used

SunJCE: Cipher.AES -> com.sun.crypto.provider.AESCipher$General aliases: [Rijndael]

Below is the output.

1. Original Key: 00112233445566778899aabbccddeeff

Original Key in byte[] : [-45, 77, 117, -37, 109, -9, -29, -114, 121, -21, -82, -5, -13, -49, 125, 105, -90, -37, 113, -57, 93, 121, -25, -33]

Original IV : [-76, 50, 106, -33, -77, -80, -90, 53, -11, -91, 17, 25, -21, -63, -57, 17]

2.

Wrapped Key : gxLT9+PTn8rikNLJnK1RcpNqFIL/fG7EPLVsIr5mwOA=

wrapped key in byte[] : [113, 0, 125, 123, 85, 97, 65, 123, 118, 91, -22, -117, 62, 37, 117, -11, -119, 98, -128, 16, -85, -51, -47, 109, -15, -65, 123, -89, -92, -81, -78, 38]

IV from wrapped key : [113, 0, 125, 123, 85, 97, 65, 123, 118, 91, -22, -117, 62, 37, 117, -11]

3.

Unwrapped Key: RhzNRM6VgeHUTAkIpYfHnqbbccddeeff

Unwrapped Key byte[]: [22, 127, 98, 127, -117, 38, 4, -64, -6, 21, 85, 105, 38, 43, -49, -115, -90, -37, 113, -57, 93, 121, -25, -33]

=============================================

Diff seems to be due to 16 bytes (the size of IV)

org key : [-45, 77, 117, -37, 109, -9, -29, -114, 121, -21, -82, -5, -13, -49, 125, 105, -90, -37, 113, -57, 93, 121, -25, -33]

output key : [22, 127, 98, 127, -117, 38, 4, -64, -6, 21, 85, 105, 38, 43, -49, -115, -90, -37, 113, -57, 93, 121, -25, -33]

Adding code :

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Base64;

public class KeyWrapping {

    public static void main(String[] args) throws Exception {

        String originalKeyHex = "00112233445566778899aabbccddeeff";
        String wrappingKeyHex = "000102030405060708090a0b0c0d0e0f";

        // converting hex strings to byte arrays
        byte[] originalKey = hexStringToByteArray(originalKeyHex);
        byte[] wrapperKey = hexStringToByteArray(wrappingKeyHex);

        // Encrypt the key
        byte[] wrappedKey = aesKeyWrapEncrypt(originalKey, wrapperKey);

        // Decrypt the key
        byte[] unwrappedKey = aesKeyWrapDecrypt(wrappedKey, wrapperKey);

        // Display results
        System.out.println("Original Key: " + byteArrayToHexString(originalKey));
        System.out.println("Wrapped Key : " + byteArrayToHexString(wrappedKey));
        System.out.println("Unwrapped Key: " + byteArrayToHexString(unwrappedKey));
    }

    // AES Key Wrap Encryption
    private static byte[] aesKeyWrapEncrypt(byte[] keyToWrap, byte[] wrapperKey) throws Exception {
    
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        // Generate a random Initialization Vector (IV)
        SecureRandom random = new SecureRandom();
        byte[] ivBytes = new byte[16];
        random.nextBytes(ivBytes);
        IvParameterSpec iv = new IvParameterSpec(ivBytes);

        // Create a SecretKey object from the wrapper key
        SecretKey secretKey = new SecretKeySpec(wrapperKey, "AES");

        // Initialize the cipher for encryption
        cipher.init(Cipher.WRAP_MODE, secretKey, iv);


        // Encrypt the key
        byte[] wrappedKey = cipher.wrap(new SecretKeySpec(keyToWrap, "AES"));

        return wrappedKey;

    }

    // AES Key Wrap Decryption
    private static byte[] aesKeyWrapDecrypt(byte[] wrappedKey, byte[] wrappingKey) throws Exception {

        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

        // Extract the Initialization Vector (IV) from the wrapped key
        byte[] ivBytes = new byte[16];
        System.arraycopy(wrappedKey, 0, ivBytes, 0, ivBytes.length);
        IvParameterSpec iv = new IvParameterSpec(ivBytes);

        // Create a SecretKey object from the wrapping key
        SecretKey secretKey = new SecretKeySpec(wrappingKey, "AES");

        // Initialize the cipher for decryption
        cipher.init(Cipher.UNWRAP_MODE, secretKey, iv);

        // Decrypt the key
        Key unwrappedKey = cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);

        return unwrappedKey.getEncoded();
    }



    // Helper method to convert byte array to hex string
    private static String byteArrayToHexString(byte[] array) {
        return Base64.getEncoder().encodeToString(array);
    }

    // Helper method to convert hex string to byte array
    private static byte[] hexStringToByteArray(String hexString) {
        return Base64.getDecoder().decode(hexString);
    }
}

Update :

Thanks @President James K. Polk for pointing out the exact issue. It worked with below fix.

    // AES Key Wrap Encryption
    private static byte[] aesKeyWrapEncrypt(byte[] keyToWrap, byte[] wrapperKey) throws Exception {
...

            byte[] wrappedKey = cipher.wrap(new SecretKeySpec(keyToWrap, "AES"));
    
            // prepending the IV to the wrapped key
            byte[] result = new byte[ivBytes.length + wrappedKey.length];
            System.arraycopy(ivBytes, 0, result, 0, ivBytes.length);
            System.arraycopy(wrappedKey, 0, result, ivBytes.length, wrappedKey.length); 
...
0

There are 0 best solutions below