在执行 getKey() 时,将密钥存储在令牌 USB 上会给出不同的密钥(几个不同的字节)
Storing secret key on token USB gives different key (few different bytes) when doing getKey()
我正在尝试在加密 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
令牌上存储的密钥(STORE KEY)和我使用getKey()
获得的密钥(FINAL KEY)不同。怎么可能?
如果您需要任何其他可能遗漏的信息,请通知我。
谢谢。
您的 USB 令牌只是调整 3DES 密钥的奇偶校验。每个字节的每个低端位都是(三重)DES 的奇偶校验位。
如果最高7位相加是偶数需要设置,如果是奇数则不设置。如果将所有位加在一起,最后每个字节都应该有奇偶校验。所以第一个字节的值为 0x57
或 0b0101011_1
并且在最高位置有 4 位,所以最后一位必须是 1
- 但它已经设置,所以不需要调整。第二个字节,0xAF
或0b1010111_1
最高位有5位,所以最后一位需要是0
。不是这样的,所以调整为0b1010111_0
或0xAE
.
如果您想要相同的值,那么您可以使用 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;
}
我正在尝试在加密 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
令牌上存储的密钥(STORE KEY)和我使用getKey()
获得的密钥(FINAL KEY)不同。怎么可能?
如果您需要任何其他可能遗漏的信息,请通知我。
谢谢。
您的 USB 令牌只是调整 3DES 密钥的奇偶校验。每个字节的每个低端位都是(三重)DES 的奇偶校验位。
如果最高7位相加是偶数需要设置,如果是奇数则不设置。如果将所有位加在一起,最后每个字节都应该有奇偶校验。所以第一个字节的值为 0x57
或 0b0101011_1
并且在最高位置有 4 位,所以最后一位必须是 1
- 但它已经设置,所以不需要调整。第二个字节,0xAF
或0b1010111_1
最高位有5位,所以最后一位需要是0
。不是这样的,所以调整为0b1010111_0
或0xAE
.
如果您想要相同的值,那么您可以使用 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;
}