在执行getKey()时,将秘密密钥存储在令牌USB上会提供不同的密钥(几个不同的字节)

时间:2018-08-29 15:32:33

标签: java cryptography keystore pkcs#11 secret-key

我正在尝试在加密USB令牌上存储对称密钥(SecretKey,它是三重DES密钥,ECB模式)。我使用以下代码来做到这一点:

private void storeSecretKey( SecretKey secretKey, String alias ) throws StoreException {
    try {
        log.info("Format: " + secretKey.getFormat());
        log.info("Alg: " + secretKey.getAlgorithm());
        log.info("STORE KEY (bytes): " + Arrays.toString( secretKey.getEncoded()));
        log.info("STORE KEY: " + ArrayUtils.convertToHexString( secretKey.getEncoded(), false, false));

        myKeyStore.setKeyEntry(alias, secretKey, tokenPIN.toCharArray(), null);

        myKeyStore.store(null);

        Key key = myKeyStore.getKey(alias, tokenPIN.toCharArray());

        log.info("Format: " + key.getFormat());
        log.info("Alg: " + key.getAlgorithm());
        log.info("FINAL KEY (bytes): " + Arrays.toString( key.getEncoded()));
        log.info("FINAL KEY: " + ArrayUtils.convertToHexString( key.getEncoded(), false, false));
    }
    catch ( KeyStoreException e ) {
        throw new StoreException( "Unable to store encryption key", e );
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (UnrecoverableEntryException e) {
        e.printStackTrace();
    }
}

我得到以下日志记录:

INFO: Format: RAW
INFO: Alg: DESede
INFO: STORE KEY (bytes): [87, -81, -89, -62, 5, -116, -46, 111, -85, -52, -28, -85, -26, -57, -26, -58, -66, -52, -16, 30, 89, -45, 61, -86]
INFO: STORE KEY: 57afa7c2058cd26fabcce4abe6c7e6c6beccf01e59d33daa

INFO: Format: RAW
INFO: Alg: DESede
INFO: FINAL KEY (bytes): [87, -82, -89, -62, 4, -116, -45, 110, -85, -51, -27, -85, -26, -57, -26, -57, -65, -51, -15, 31, 88, -45, 61, -85]
INFO: FINAL KEY: 57aea7c2048cd36eabcde5abe6c7e6c7bfcdf11f58d33dab

存储在令牌上的密钥(存储密钥)和我使用getKey()获得的密钥(最终密钥)不同。怎么会呢?

如果您还需要其他任何信息,请告知我。

谢谢。

1 个答案:

答案 0 :(得分:4)

您的USB令牌只需调整3DES密钥的奇偶校验。每个字节的每个低端位都是(三重)DES的奇偶校验位。

如果最高的7位加起来是偶数,则需要设置;如果数字是奇数,则需要设置。最后,如果将所有位加在一起,则每个字节应具有奇校验。因此,具有值0x570b0101011_1的第一个字节在最高位置具有4位,因此最后一位必须为1-但已被设置,因此无需进行调整。第二个字节0xAF0b1010111_1在最高位置有5位,因此最后一位需要为0。并非如此,因此将其调整为0b1010111_00xAE

如果要具有相同的值,则可以使用SecretKeyFactory而不是直接使用随机数生成器来构造(三重)DES密钥。 SecretKeyFactory还将为您调整奇偶校验-无需自己编程。我建议这样做,因为其他实现可以拒绝位数为偶数的字节(尽管通常调整或忽略了这些位)。正如James所指出的那样,(三重)DES在加密/解密过程中不使用最低位。


这将创建正确编码的三重DES密钥(有效168位,已编码192位)。这些也称为DES ABC密钥,因为这三个DES密钥都是不同的(很有可能)。

public static SecretKey generate192Bit3DESKey() {
    KeyGenerator keyGen;
    try {
        keyGen = KeyGenerator.getInstance("DESede");
    } catch (NoSuchAlgorithmException e) {
        throw new IllegalStateException("DESede functionality is required for Java, but it is missing");
    }

    // NOTE: this is the effective key size excluding parity bits
    // use 112 for two key (ABA) triple DES keys (not recommended)
    keyGen.init(168);

    // this does adjust parity
    SecretKey desABCKey = keyGen.generateKey();
    return desABCKey;
}

如果您的数据之后需要调整,则可以使用它(只有for循环,没有其他分支):

public static byte[] adjustDESParity(final byte[] keyData) {
    for (int i = 0; i < keyData.length; i++) {
        // count the bits, and XOR with 1 if even or 0 if already odd 
        keyData[i] ^= (Integer.bitCount(keyData[i]) % 2) ^ 1;
    }
    return keyData;
}