From 434bc5606f2473d2fb4e9b9ad9b8e5ae31c49f5c Mon Sep 17 00:00:00 2001 From: Peter Teufl Date: Wed, 25 Nov 2015 19:13:39 +0100 Subject: [PATCH] minor changes to new encryption methods (CFB, CTR, ECB emulation) --- .../asitplus/regkassen/core/DemoCashBox.java | 40 +- .../regkassen/core/base/util/AESUtil.java | 486 +++++++++--------- 2 files changed, 264 insertions(+), 262 deletions(-) diff --git a/regkassen-core/src/main/java/at/asitplus/regkassen/core/DemoCashBox.java b/regkassen-core/src/main/java/at/asitplus/regkassen/core/DemoCashBox.java index 6ca756a..9a67794 100644 --- a/regkassen-core/src/main/java/at/asitplus/regkassen/core/DemoCashBox.java +++ b/regkassen-core/src/main/java/at/asitplus/regkassen/core/DemoCashBox.java @@ -288,7 +288,7 @@ protected void updateTurnOverCounterAndAddToDataToBeSigned(ReceiptRepresentation //ATTENTION: changes made to procedure on how to sum up/round values for turnover counter //PREV: sum up values, round them, add them to turnover counter - //NOW: to simplify procedures: turnover counter changed to €-cent. before: 100€ were represented as 100, now + //NOW: to simplify procedures: turnover counter changed to �-cent. before: 100� were represented as 100, now //they are represented as 10000 double tempSum = 0.0; tempSum += sumTaxTypeNormal; @@ -297,7 +297,7 @@ protected void updateTurnOverCounterAndAddToDataToBeSigned(ReceiptRepresentation tempSum += sumTaxTypeBesonders; tempSum += sumTaxTypeNull; - //NEW METHOD: convert sum to €-cent and add to turnover counter + //NEW METHOD: convert sum to �-cent and add to turnover counter turnoverCounter += (tempSum * 100); //OLD METHOD: DO NOT USE @@ -332,13 +332,20 @@ protected void updateTurnOverCounterAndAddToDataToBeSigned(ReceiptRepresentation //support selected AES modes of operation only. Please refer to //https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation for more details //on different modes of operation for block ciphers - String base64EncryptedTurnOverValue = AESUtil.encryptCTR(concatenatedHashValue, turnoverCounter, cashBoxParameters.getTurnoverKeyAESkey()); - //String base64EncryptedTurnOverValue = AESUtil.encryptCFB(concatenatedHashValue, turnoverCounter, cashBoxParameters.getTurnoverKeyAESkey()); - //String base64EncryptedTurnOverValue = AESUtil.encryptECB(concatenatedHashValue, turnoverCounter, cashBoxParameters.getTurnoverKeyAESkey()); - + String base64EncryptedTurnOverValue1 = AESUtil.encryptCTR(concatenatedHashValue, turnoverCounter, cashBoxParameters.getTurnoverKeyAESkey()); + String base64EncryptedTurnOverValue2 = AESUtil.encryptCFB(concatenatedHashValue, turnoverCounter, cashBoxParameters.getTurnoverKeyAESkey()); + String base64EncryptedTurnOverValue3 = AESUtil.encryptECB(concatenatedHashValue, turnoverCounter, cashBoxParameters.getTurnoverKeyAESkey()); + if (!base64EncryptedTurnOverValue1.equals(base64EncryptedTurnOverValue2)) { + System.out.println("ENCRYPTION ERROR IN METHOD updateTurnOverCounterAndAddToDataToBeSigned, MUST NOT HAPPEN"); + System.exit(-1); + } + if (!base64EncryptedTurnOverValue1.equals(base64EncryptedTurnOverValue3)) { + System.out.println("ENCRYPTION ERROR IN METHOD updateTurnOverCounterAndAddToDataToBeSigned, MUST NOT HAPPEN"); + System.exit(-1); + } //set encrypted turnovervalue in data-to-be-signed datastructure - receiptRepresentationForSignature.setEncryptedTurnoverValue(base64EncryptedTurnOverValue); + receiptRepresentationForSignature.setEncryptedTurnoverValue(base64EncryptedTurnOverValue1); //THE FOLLOWING CODE IS ONLY FOR DEMONSTRATION PURPOSES //decryption and reconstruction of the turnover value @@ -354,13 +361,22 @@ protected void updateTurnOverCounterAndAddToDataToBeSigned(ReceiptRepresentation //support selected AES modes of operation only. Please refer to //https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation for more details //on different modes of operation for block ciphers - long testPlainOverTurnOverReconstructed = AESUtil.decryptCTR(concatenatedHashValue, base64EncryptedTurnOverValue, cashBoxParameters.getTurnoverKeyAESkey()); - //long testPlainOverTurnOverReconstructed = AESUtil.decryptCFB(concatenatedHashValue, base64EncryptedTurnOverValue, cashBoxParameters.getTurnoverKeyAESkey()); - //long testPlainOverTurnOverReconstructed = AESUtil.decryptECB(concatenatedHashValue, base64EncryptedTurnOverValue, cashBoxParameters.getTurnoverKeyAESkey()); - + long testPlainOverTurnOverReconstructed1 = AESUtil.decryptCTR(concatenatedHashValue, base64EncryptedTurnOverValue1, cashBoxParameters.getTurnoverKeyAESkey()); + long testPlainOverTurnOverReconstructed2 = AESUtil.decryptCFB(concatenatedHashValue, base64EncryptedTurnOverValue2, cashBoxParameters.getTurnoverKeyAESkey()); + long testPlainOverTurnOverReconstructed3 = AESUtil.decryptECB(concatenatedHashValue, base64EncryptedTurnOverValue3, cashBoxParameters.getTurnoverKeyAESkey()); + if (testPlainOverTurnOverReconstructed1 != testPlainOverTurnOverReconstructed2) { + System.out.println("DECRYPTION ERROR IN METHOD updateTurnOverCounterAndAddToDataToBeSigned, MUST NOT HAPPEN"); + System.exit(-1); + } + + if (testPlainOverTurnOverReconstructed1 != testPlainOverTurnOverReconstructed3) { + System.out.println("DECRYPTION ERROR IN METHOD updateTurnOverCounterAndAddToDataToBeSigned, MUST NOT HAPPEN"); + System.exit(-1); + } - if (turnoverCounter != testPlainOverTurnOverReconstructed) { + if (turnoverCounter != testPlainOverTurnOverReconstructed1) { System.out.println("DECRYPTION ERROR IN METHOD updateTurnOverCounterAndAddToDataToBeSigned, MUST NOT HAPPEN"); + System.exit(-1); } } catch (NoSuchProviderException | IllegalBlockSizeException | NoSuchPaddingException | InvalidKeyException | NoSuchAlgorithmException | InvalidAlgorithmParameterException | BadPaddingException e) { e.printStackTrace(); diff --git a/regkassen-core/src/main/java/at/asitplus/regkassen/core/base/util/AESUtil.java b/regkassen-core/src/main/java/at/asitplus/regkassen/core/base/util/AESUtil.java index 534f682..f31d8a0 100644 --- a/regkassen-core/src/main/java/at/asitplus/regkassen/core/base/util/AESUtil.java +++ b/regkassen-core/src/main/java/at/asitplus/regkassen/core/base/util/AESUtil.java @@ -17,19 +17,14 @@ package at.asitplus.regkassen.core.base.util; +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; import java.nio.ByteBuffer; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; - /** * Util class for AES encryption and decryption with different modes of operation */ @@ -42,59 +37,56 @@ public class AESUtil { * @param turnoverCounter * @param symmetricKey */ - public static String encryptECB(byte[] concatenatedHashValue, Long turnoverCounter, SecretKey symmetricKey) - throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, - IllegalBlockSizeException, BadPaddingException { - - // extract bytes 0-15 from hash value - ByteBuffer byteBufferIV = ByteBuffer.allocate(16); - byteBufferIV.put(concatenatedHashValue); - byte[] IV = byteBufferIV.array(); - - // prepare data - // here, 8 bytes are used for the turnover counter (more then enough for - // every possible turnover...), however - // the specification only requires 5 bytes at a minimum - // bytes 0-7 are used for the turnover counter, which is represented by - // 8-byte - // two-complement, Big Endian representation (equal to Java LONG), bytes - // 8-15 are set to 0 - // negative values are possible (very rare) - ByteBuffer byteBufferData = ByteBuffer.allocate(16); - byteBufferData.putLong(turnoverCounter); - byte[] data = byteBufferData.array(); - - // prepare AES cipher with ECB mode, NoPadding is essential for the - // decryption process. Padding could not be reconstructed due - // to storing only 8 bytes of the cipher text (not the full 16 bytes) - // (or 5 bytes if the mininum turnover length is used) - // - // Note: Due to the use of ECB mode, no IV is defined for initializing - // the cipher. In addition, the data is not enciphered directly. Instead, - // the computed IV is encrypted. The result is subsequently XORed - // bitwise with the data to compute the cipher text. - Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding", "BC"); - cipher.init(Cipher.ENCRYPT_MODE, symmetricKey); - byte[] intermediateResult = cipher.doFinal(IV); - - byte[] result = new byte[data.length]; - - // xor encryption result with data - for (int i = 0; i < data.length; i++) { - - result[i] = (byte) (((int) data[i]) ^ ((int) intermediateResult[i])); - } - - byte[] encryptedTurnOverValue = new byte[8]; // or 5 bytes if min. - - // turnover length is used - System.arraycopy(result, 0, encryptedTurnOverValue, 0, encryptedTurnOverValue.length); - - // encode result as BASE64 - String base64EncryptedTurnOverValue = CashBoxUtils.base64Encode(encryptedTurnOverValue, false); - - return base64EncryptedTurnOverValue; - } + public static String encryptECB(byte[] concatenatedHashValue, Long turnoverCounter, SecretKey symmetricKey) + throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, + IllegalBlockSizeException, BadPaddingException { + + // extract bytes 0-15 from hash value + ByteBuffer byteBufferIV = ByteBuffer.allocate(16); + byteBufferIV.put(concatenatedHashValue); + byte[] IV = byteBufferIV.array(); + + // prepare data + // here, 8 bytes are used for the turnover counter (more then enough for + // every possible turnover...), however + // the specification only requires 5 bytes at a minimum + // bytes 0-7 are used for the turnover counter, which is represented by + // 8-byte + // two-complement, Big Endian representation (equal to Java LONG), bytes + // 8-15 are set to 0 + // negative values are possible (very rare) + ByteBuffer byteBufferData = ByteBuffer.allocate(16); + byteBufferData.putLong(turnoverCounter); + byte[] data = byteBufferData.array(); + + // prepare AES cipher with ECB mode, NoPadding is essential for the + // decryption process. Padding could not be reconstructed due + // to storing only 8 bytes of the cipher text (not the full 16 bytes) + // (or 5 bytes if the mininum turnover length is used) + // + // Note: Due to the use of ECB mode, no IV is defined for initializing + // the cipher. In addition, the data is not enciphered directly. Instead, + // the computed IV is encrypted. The result is subsequently XORed + // bitwise with the data to compute the cipher text. + Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding", "BC"); + cipher.init(Cipher.ENCRYPT_MODE, symmetricKey); + byte[] intermediateResult = cipher.doFinal(IV); + + byte[] result = new byte[data.length]; + + // xor encryption result with data + for (int i = 0; i < data.length; i++) { + result[i] = (byte) (((int) data[i]) ^ ((int) intermediateResult[i])); + } + + byte[] encryptedTurnOverValue = new byte[8]; + + // turnover length is used + System.arraycopy(result, 0, encryptedTurnOverValue, 0, encryptedTurnOverValue.length); + + // encode result as BASE64 + return CashBoxUtils.base64Encode(encryptedTurnOverValue, false); + } /** * method for AES decryption in ECB mode @@ -102,103 +94,101 @@ public static String encryptECB(byte[] concatenatedHashValue, Long turnoverCount * @param concatenatedHashValue * @param base64EncryptedTurnOverValue * @param symmetricKey - */ - public static long decryptECB(byte[] concatenatedHashValue, String base64EncryptedTurnOverValue, SecretKey symmetricKey) - throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, - InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + */ + public static long decryptECB(byte[] concatenatedHashValue, String base64EncryptedTurnOverValue, SecretKey symmetricKey) + throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, + InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { - // extract bytes 0-15 from hash value - ByteBuffer byteBufferIV = ByteBuffer.allocate(16); - byteBufferIV.put(concatenatedHashValue); - byte[] IV = byteBufferIV.array(); + // extract bytes 0-15 from hash value + ByteBuffer byteBufferIV = ByteBuffer.allocate(16); + byteBufferIV.put(concatenatedHashValue); + byte[] IV = byteBufferIV.array(); - byte[] encryptedTurnOverValue = CashBoxUtils.base64Decode(base64EncryptedTurnOverValue, false); - int lengthOfEncryptedTurnOverValue = encryptedTurnOverValue.length; + byte[] encryptedTurnOverValue = CashBoxUtils.base64Decode(base64EncryptedTurnOverValue, false); + int lengthOfEncryptedTurnOverValue = encryptedTurnOverValue.length; - // prepare AES cipher with ECB mode - // - // Note: Due to the use of ECB mode, no IV is defined for initializing - // the cipher. In addition, the data is not enciphered directly. Instead, - // the IV computed above is encrypted again. The result is subsequently XORed - // bitwise with the cipher text to retrieve the plain data. - Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding", "BC"); - cipher.init(Cipher.ENCRYPT_MODE, symmetricKey); - byte[] intermediateResult = cipher.doFinal(IV); - - byte[] result = new byte[encryptedTurnOverValue.length]; + // prepare AES cipher with ECB mode + // + // Note: Due to the use of ECB mode, no IV is defined for initializing + // the cipher. In addition, the data is not enciphered directly. Instead, + // the IV computed above is encrypted again. The result is subsequently XORed + // bitwise with the cipher text to retrieve the plain data. + Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding", "BC"); + cipher.init(Cipher.ENCRYPT_MODE, symmetricKey); + byte[] intermediateResult = cipher.doFinal(IV); - // XOR decryption result with data - for (int i = 0; i < encryptedTurnOverValue.length; i++) { + byte[] result = new byte[encryptedTurnOverValue.length]; - result[i] = (byte) (((int) encryptedTurnOverValue[i]) ^ ((int) intermediateResult[i])); - } + // XOR decryption result with data + for (int i = 0; i < encryptedTurnOverValue.length; i++) { + result[i] = (byte) (((int) encryptedTurnOverValue[i]) ^ ((int) intermediateResult[i])); + } - // extract relevant bytes from decryption result - byte[] testPlainTurnOverValue = new byte[lengthOfEncryptedTurnOverValue]; - System.arraycopy(result, 0, testPlainTurnOverValue, 0, lengthOfEncryptedTurnOverValue); + // extract relevant bytes from decryption result + byte[] testPlainTurnOverValue = new byte[lengthOfEncryptedTurnOverValue]; + System.arraycopy(result, 0, testPlainTurnOverValue, 0, lengthOfEncryptedTurnOverValue); - // create java LONG out of ByteArray - ByteBuffer testPlainTurnOverValueByteBuffer = ByteBuffer.wrap(testPlainTurnOverValue); - long testPlainOverTurnOverReconstructed = testPlainTurnOverValueByteBuffer.getLong(); + // create java LONG out of ByteArray + ByteBuffer testPlainTurnOverValueByteBuffer = ByteBuffer.wrap(testPlainTurnOverValue); - return testPlainOverTurnOverReconstructed; + return testPlainTurnOverValueByteBuffer.getLong(); - } + } /** - * method for AES encryption in CFB mode + * method for AES encryption in CFB mode (for the first block CFB and CTR are exactly the same * * @param concatenatedHashValue * @param turnoverCounter * @param symmetricKey - */ - public static String encryptCFB(byte[] concatenatedHashValue, Long turnoverCounter, SecretKey symmetricKey) - throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, - InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { - - // extract bytes 0-15 from hash value - ByteBuffer byteBufferIV = ByteBuffer.allocate(16); - byteBufferIV.put(concatenatedHashValue); - byte[] IV = byteBufferIV.array(); - - // prepare data - // here, 8 bytes are used for the turnover counter (more then enough for - // every possible turnover...), however - // the specification only requires 5 bytes at a minimum - // bytes 0-7 are used for the turnover counter, which is represented by - // 8-byte - // two-complement, Big Endian representation (equal to Java LONG), bytes - // 8-15 are set to 0 - // negative values are possible (very rare) - ByteBuffer byteBufferData = ByteBuffer.allocate(16); - byteBufferData.putLong(turnoverCounter); - byte[] data = byteBufferData.array(); - - // prepare AES cipher with CFB mode, NoPadding is essential for the - // decryption process. Padding could not be reconstructed due - // to storing only 8 bytes of the cipher text (not the full 16 bytes) - // (or 5 bytes if the mininum turnover length is used) - IvParameterSpec ivSpec = new IvParameterSpec(IV); - - // TODO provider independent - Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding", "BC"); - cipher.init(Cipher.ENCRYPT_MODE, symmetricKey, ivSpec); - - // encrypt the turnover value with the prepared cipher - byte[] encryptedTurnOverValueComplete = cipher.doFinal(data); - - // extract bytes that will be stored in the receipt (only bytes 0-7) - byte[] encryptedTurnOverValue = new byte[8]; // or 5 bytes if min. - // turnover length is - // used - System.arraycopy(encryptedTurnOverValueComplete, 0, encryptedTurnOverValue, 0, encryptedTurnOverValue.length); - - // encode result as BASE64 - String base64EncryptedTurnOverValue = CashBoxUtils.base64Encode(encryptedTurnOverValue, false); - - return base64EncryptedTurnOverValue; - - } + */ + public static String encryptCFB(byte[] concatenatedHashValue, Long turnoverCounter, SecretKey symmetricKey) + throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, + InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + + // extract bytes 0-15 from hash value + ByteBuffer byteBufferIV = ByteBuffer.allocate(16); + byteBufferIV.put(concatenatedHashValue); + byte[] IV = byteBufferIV.array(); + + // prepare data + // here, 8 bytes are used for the turnover counter (more then enough for + // every possible turnover...), however + // the specification only requires 5 bytes at a minimum + // bytes 0-7 are used for the turnover counter, which is represented by + // 8-byte + // two-complement, Big Endian representation (equal to Java LONG), bytes + // 8-15 are set to 0 + // negative values are possible (very rare) + ByteBuffer byteBufferData = ByteBuffer.allocate(16); + byteBufferData.putLong(turnoverCounter); + byte[] data = byteBufferData.array(); + + // prepare AES cipher with CFB mode, NoPadding is essential for the + // decryption process. Padding could not be reconstructed due + // to storing only 8 bytes of the cipher text (not the full 16 bytes) + // (or 5 bytes if the mininum turnover length is used) + IvParameterSpec ivSpec = new IvParameterSpec(IV); + + // TODO provider independent + Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding", "BC"); + cipher.init(Cipher.ENCRYPT_MODE, symmetricKey, ivSpec); + + // encrypt the turnover value with the prepared cipher + byte[] encryptedTurnOverValueComplete = cipher.doFinal(data); + + // extract bytes that will be stored in the receipt (only bytes 0-7) + byte[] encryptedTurnOverValue = new byte[8]; // or 5 bytes if min. + // turnover length is + // used + System.arraycopy(encryptedTurnOverValueComplete, 0, encryptedTurnOverValue, 0, encryptedTurnOverValue.length); + + // encode result as BASE64 + String base64EncryptedTurnOverValue = CashBoxUtils.base64Encode(encryptedTurnOverValue, false); + + return base64EncryptedTurnOverValue; + + } /** * method for AES decryption in CFB mode @@ -206,38 +196,37 @@ public static String encryptCFB(byte[] concatenatedHashValue, Long turnoverCount * @param concatenatedHashValue * @param base64EncryptedTurnOverValue * @param symmetricKey - */ - public static long decryptCFB(byte[] concatenatedHashValue, String base64EncryptedTurnOverValue, SecretKey symmetricKey) - throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, - InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + */ + public static long decryptCFB(byte[] concatenatedHashValue, String base64EncryptedTurnOverValue, SecretKey symmetricKey) + throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, + InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + + // extract bytes 0-15 from hash value + ByteBuffer byteBufferIV = ByteBuffer.allocate(16); + byteBufferIV.put(concatenatedHashValue); + byte[] IV = byteBufferIV.array(); - // extract bytes 0-15 from hash value - ByteBuffer byteBufferIV = ByteBuffer.allocate(16); - byteBufferIV.put(concatenatedHashValue); - byte[] IV = byteBufferIV.array(); + byte[] encryptedTurnOverValue = CashBoxUtils.base64Decode(base64EncryptedTurnOverValue, false); + int lengthOfEncryptedTurnOverValue = encryptedTurnOverValue.length; - byte[] encryptedTurnOverValue = CashBoxUtils.base64Decode(base64EncryptedTurnOverValue, false); - int lengthOfEncryptedTurnOverValue = encryptedTurnOverValue.length; - - // prepare AES cipher with CFB mode - IvParameterSpec ivSpec = new IvParameterSpec(IV); + // prepare AES cipher with CFB mode + IvParameterSpec ivSpec = new IvParameterSpec(IV); - // TODO provider independent - Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding", "BC"); - cipher.init(Cipher.DECRYPT_MODE, symmetricKey, ivSpec); - byte[] testPlainTurnOverValueComplete = cipher.doFinal(encryptedTurnOverValue); + // TODO provider independent + Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding", "BC"); + cipher.init(Cipher.DECRYPT_MODE, symmetricKey, ivSpec); + byte[] testPlainTurnOverValueComplete = cipher.doFinal(encryptedTurnOverValue); - // extract relevant bytes from decryption result - byte[] testPlainTurnOverValue = new byte[lengthOfEncryptedTurnOverValue]; - System.arraycopy(testPlainTurnOverValueComplete, 0, testPlainTurnOverValue, 0, lengthOfEncryptedTurnOverValue); + // extract relevant bytes from decryption result + byte[] testPlainTurnOverValue = new byte[lengthOfEncryptedTurnOverValue]; + System.arraycopy(testPlainTurnOverValueComplete, 0, testPlainTurnOverValue, 0, lengthOfEncryptedTurnOverValue); - // create java LONG out of ByteArray - ByteBuffer testPlainTurnOverValueByteBuffer = ByteBuffer.wrap(testPlainTurnOverValue); - long testPlainOverTurnOverReconstructed = testPlainTurnOverValueByteBuffer.getLong(); + // create java LONG out of ByteArray + ByteBuffer testPlainTurnOverValueByteBuffer = ByteBuffer.wrap(testPlainTurnOverValue); - return testPlainOverTurnOverReconstructed; + return testPlainTurnOverValueByteBuffer.getLong(); - } + } /** * method for AES encryption in CTR mode @@ -245,56 +234,55 @@ public static long decryptCFB(byte[] concatenatedHashValue, String base64Encrypt * @param concatenatedHashValue * @param turnoverCounter * @param symmetricKey - */ - public static String encryptCTR(byte[] concatenatedHashValue, Long turnoverCounter, SecretKey symmetricKey) - throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, - InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { - - // extract bytes 0-15 from hash value - ByteBuffer byteBufferIV = ByteBuffer.allocate(16); - byteBufferIV.put(concatenatedHashValue); - byte[] IV = byteBufferIV.array(); - - // prepare data - // here, 8 bytes are used for the turnover counter (more then enough for - // every possible turnover...), however - // the specification only requires 5 bytes at a minimum - // bytes 0-7 are used for the turnover counter, which is represented by - // 8-byte - // two-complement, Big Endian representation (equal to Java LONG), bytes - // 8-15 are set to 0 - // negative values are possible (very rare) - ByteBuffer byteBufferData = ByteBuffer.allocate(16); - byteBufferData.putLong(turnoverCounter); - byte[] data = byteBufferData.array(); - - // prepare AES cipher with CTR/ICM mode, NoPadding is essential for the - // decryption process. Padding could not be reconstructed due - // to storing only 8 bytes of the cipher text (not the full 16 bytes) - // (or 5 bytes if the mininum turnover length is used) - IvParameterSpec ivSpec = new IvParameterSpec(IV); - - // TODO provider independent - Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC"); - cipher.init(Cipher.ENCRYPT_MODE, symmetricKey, ivSpec); - - // encrypt the turnover value with the prepared cipher - byte[] encryptedTurnOverValueComplete = cipher.doFinal(data); - - // extract bytes that will be stored in the receipt (only bytes 0-7) - // cryptographic NOTE: this is only possible due to the use of the CTR - // mode, would not work for ECB/CBC etc. modes - byte[] encryptedTurnOverValue = new byte[8]; // or 5 bytes if min. - // turnover length is - // used - System.arraycopy(encryptedTurnOverValueComplete, 0, encryptedTurnOverValue, 0, encryptedTurnOverValue.length); - - // encode result as BASE64 - String base64EncryptedTurnOverValue = CashBoxUtils.base64Encode(encryptedTurnOverValue, false); - - return base64EncryptedTurnOverValue; - - } + */ + public static String encryptCTR(byte[] concatenatedHashValue, Long turnoverCounter, SecretKey symmetricKey) + throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, + InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + + // extract bytes 0-15 from hash value + ByteBuffer byteBufferIV = ByteBuffer.allocate(16); + byteBufferIV.put(concatenatedHashValue); + byte[] IV = byteBufferIV.array(); + + // prepare data + // here, 8 bytes are used for the turnover counter (more then enough for + // every possible turnover...), however + // the specification only requires 5 bytes at a minimum + // bytes 0-7 are used for the turnover counter, which is represented by + // 8-byte + // two-complement, Big Endian representation (equal to Java LONG), bytes + // 8-15 are set to 0 + // negative values are possible (very rare) + ByteBuffer byteBufferData = ByteBuffer.allocate(16); + byteBufferData.putLong(turnoverCounter); + byte[] data = byteBufferData.array(); + + // prepare AES cipher with CTR/ICM mode, NoPadding is essential for the + // decryption process. Padding could not be reconstructed due + // to storing only 8 bytes of the cipher text (not the full 16 bytes) + // (or 5 bytes if the mininum turnover length is used) + IvParameterSpec ivSpec = new IvParameterSpec(IV); + + // TODO provider independent + Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC"); + cipher.init(Cipher.ENCRYPT_MODE, symmetricKey, ivSpec); + + // encrypt the turnover value with the prepared cipher + byte[] encryptedTurnOverValueComplete = cipher.doFinal(data); + + // extract bytes that will be stored in the receipt (only bytes 0-7) + // cryptographic NOTE: this is only possible due to the use of the CTR + // mode, would not work for ECB/CBC etc. modes + byte[] encryptedTurnOverValue = new byte[8]; // or 5 bytes if min. + // turnover length is + // used + System.arraycopy(encryptedTurnOverValueComplete, 0, encryptedTurnOverValue, 0, encryptedTurnOverValue.length); + + // encode result as BASE64 + + return CashBoxUtils.base64Encode(encryptedTurnOverValue, false); + + } /** * method for AES decryption in CTR mode @@ -303,37 +291,35 @@ public static String encryptCTR(byte[] concatenatedHashValue, Long turnoverCount * @param base64EncryptedTurnOverValue * @param symmetricKey */ - public static long decryptCTR(byte[] concatenatedHashValue, String base64EncryptedTurnOverValue, SecretKey symmetricKey) - throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, - InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { - - // extract bytes 0-15 from hash value - ByteBuffer byteBufferIV = ByteBuffer.allocate(16); - byteBufferIV.put(concatenatedHashValue); - byte[] IV = byteBufferIV.array(); - - byte[] encryptedTurnOverValue = CashBoxUtils.base64Decode(base64EncryptedTurnOverValue, false); - int lengthOfEncryptedTurnOverValue = encryptedTurnOverValue.length; - - // prepare AES cipher with CTR/ICM mode - IvParameterSpec ivSpec = new IvParameterSpec(IV); - - // TODO provider independent - Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC"); - cipher.init(Cipher.DECRYPT_MODE, symmetricKey, ivSpec); - byte[] testPlainTurnOverValueComplete = cipher.doFinal(encryptedTurnOverValue); - - // extract relevant bytes from decryption result - byte[] testPlainTurnOverValue = new byte[lengthOfEncryptedTurnOverValue]; - System.arraycopy(testPlainTurnOverValueComplete, 0, testPlainTurnOverValue, 0, lengthOfEncryptedTurnOverValue); - - // create java LONG out of ByteArray - ByteBuffer testPlainTurnOverValueByteBuffer = ByteBuffer.wrap(testPlainTurnOverValue); - long testPlainOverTurnOverReconstructed = testPlainTurnOverValueByteBuffer.getLong(); - - return testPlainOverTurnOverReconstructed; - - } - - + public static long decryptCTR(byte[] concatenatedHashValue, String base64EncryptedTurnOverValue, SecretKey symmetricKey) + throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, InvalidKeyException, + InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { + + // extract bytes 0-15 from hash value + ByteBuffer byteBufferIV = ByteBuffer.allocate(16); + byteBufferIV.put(concatenatedHashValue); + byte[] IV = byteBufferIV.array(); + + byte[] encryptedTurnOverValue = CashBoxUtils.base64Decode(base64EncryptedTurnOverValue, false); + int lengthOfEncryptedTurnOverValue = encryptedTurnOverValue.length; + + // prepare AES cipher with CTR/ICM mode + IvParameterSpec ivSpec = new IvParameterSpec(IV); + + // TODO provider independent + Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding", "BC"); + cipher.init(Cipher.DECRYPT_MODE, symmetricKey, ivSpec); + byte[] testPlainTurnOverValueComplete = cipher.doFinal(encryptedTurnOverValue); + + // extract relevant bytes from decryption result + byte[] testPlainTurnOverValue = new byte[lengthOfEncryptedTurnOverValue]; + System.arraycopy(testPlainTurnOverValueComplete, 0, testPlainTurnOverValue, 0, lengthOfEncryptedTurnOverValue); + + // create java LONG out of ByteArray + ByteBuffer testPlainTurnOverValueByteBuffer = ByteBuffer.wrap(testPlainTurnOverValue); + return testPlainTurnOverValueByteBuffer.getLong(); + + } + + }