Skip to content

Commit 5af45ad

Browse files
committed
Improve comments
1 parent 5242529 commit 5af45ad

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

src/main/java/com/adyen/terminal/security/NexoCrypto.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,24 +52,40 @@ public class NexoCrypto {
5252
private volatile NexoDerivedKey nexoDerivedKey;
5353

5454
public NexoCrypto(SecurityKey securityKey) throws NexoCryptoException {
55+
// Validate security key to ensure it has the necessary properties
5556
validateSecurityKey(securityKey);
5657
this.securityKey = securityKey;
5758
}
5859

60+
/**
61+
* Encrypts the SaleToPOI message using the provided message header and security key.
62+
*
63+
* @param saleToPoiMessageJson the JSON string representing the SaleToPOI message
64+
* @param messageHeader the message header for encryption
65+
* @return encrypted SaleToPOISecuredMessage
66+
*/
5967
public SaleToPOISecuredMessage encrypt(String saleToPoiMessageJson, MessageHeader messageHeader) throws GeneralSecurityException {
6068
NexoDerivedKey derivedKey = getNexoDerivedKey();
6169
byte[] saleToPoiMessageByteArray = saleToPoiMessageJson.getBytes(StandardCharsets.UTF_8);
70+
71+
// Generate a random initialization vector (IV) nonce
6272
byte[] ivNonce = generateRandomIvNonce();
73+
74+
// Perform AES encryption
6375
byte[] encryptedSaleToPoiMessage = crypt(saleToPoiMessageByteArray, derivedKey, ivNonce, Cipher.ENCRYPT_MODE);
76+
77+
// Generate HMAC for message authentication
6478
byte[] encryptedSaleToPoiMessageHmac = hmac(saleToPoiMessageByteArray, derivedKey);
6579

80+
// Populate security trailer with metadata and HMAC
6681
SecurityTrailer securityTrailer = new SecurityTrailer();
6782
securityTrailer.setKeyVersion(securityKey.getKeyVersion());
6883
securityTrailer.setKeyIdentifier(securityKey.getKeyIdentifier());
6984
securityTrailer.setHmac(encryptedSaleToPoiMessageHmac);
7085
securityTrailer.setNonce(ivNonce);
7186
securityTrailer.setAdyenCryptoVersion(securityKey.getAdyenCryptoVersion());
7287

88+
// Construct the secured message with the encrypted content and security trailer
7389
SaleToPOISecuredMessage saleToPoiSecuredMessage = new SaleToPOISecuredMessage();
7490
saleToPoiSecuredMessage.setMessageHeader(messageHeader);
7591
saleToPoiSecuredMessage.setNexoBlob(new String(Base64.encodeBase64(encryptedSaleToPoiMessage)));
@@ -78,18 +94,37 @@ public SaleToPOISecuredMessage encrypt(String saleToPoiMessageJson, MessageHeade
7894
return saleToPoiSecuredMessage;
7995
}
8096

97+
/**
98+
* Decrypts the SaleToPOI secured message.
99+
*
100+
* @param saleToPoiSecuredMessage the encrypted message
101+
* @return the decrypted SaleToPOI message as a JSON string
102+
*/
81103
public String decrypt(SaleToPOISecuredMessage saleToPoiSecuredMessage) throws GeneralSecurityException, NexoCryptoException {
82104
NexoDerivedKey derivedKey = getNexoDerivedKey();
105+
106+
// Decode the encrypted blob
83107
byte[] encryptedSaleToPoiMessageByteArray = Base64.decodeBase64(saleToPoiSecuredMessage.getNexoBlob().getBytes());
108+
109+
// Retrieve the nonce (IV) from the security trailer
84110
byte[] ivNonce = saleToPoiSecuredMessage.getSecurityTrailer().getNonce();
111+
112+
// Decrypt the message
85113
byte[] decryptedSaleToPoiMessageByteArray = crypt(encryptedSaleToPoiMessageByteArray, derivedKey, ivNonce, Cipher.DECRYPT_MODE);
86114

115+
// Validate HMAC to ensure message integrity
87116
byte[] receivedHmac = saleToPoiSecuredMessage.getSecurityTrailer().getHmac();
88117
validateHmac(receivedHmac, decryptedSaleToPoiMessageByteArray, derivedKey);
89118

90119
return new String(decryptedSaleToPoiMessageByteArray, StandardCharsets.UTF_8);
91120
}
92121

122+
/**
123+
* Validates the security key to ensure all required fields are present.
124+
*
125+
* @param securityKey the security key to validate
126+
* @throws NexoCryptoException if the security key is invalid
127+
*/
93128
private void validateSecurityKey(SecurityKey securityKey) throws NexoCryptoException {
94129
if (securityKey == null
95130
|| securityKey.getPassphrase() == null
@@ -101,6 +136,11 @@ private void validateSecurityKey(SecurityKey securityKey) throws NexoCryptoExcep
101136
}
102137
}
103138

139+
/**
140+
* Lazily initializes and retrieves the derived key material for encryption/decryption.
141+
*
142+
* @return the derived key material
143+
*/
104144
private NexoDerivedKey getNexoDerivedKey() throws GeneralSecurityException {
105145
if (nexoDerivedKey == null) {
106146
synchronized (this) {
@@ -112,13 +152,17 @@ private NexoDerivedKey getNexoDerivedKey() throws GeneralSecurityException {
112152
return nexoDerivedKey;
113153
}
114154

155+
/**
156+
* Performs AES encryption/decryption using the derived key and provided IV.
157+
*/
115158
private byte[] crypt(byte[] bytes, NexoDerivedKey dk, byte[] ivNonce, int mode)
116159
throws NoSuchAlgorithmException, NoSuchPaddingException,
117160
IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException {
118161

119162
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
120163
SecretKeySpec secretKeySpec = new SecretKeySpec(dk.getCipherKey(), "AES");
121164

165+
// Derive the actual IV by XORing the derived IV with the nonce
122166
byte[] iv = dk.getIv();
123167
byte[] actualIV = new byte[NEXO_IV_LENGTH];
124168
for (int i = 0; i < NEXO_IV_LENGTH; i++) {
@@ -130,6 +174,9 @@ private byte[] crypt(byte[] bytes, NexoDerivedKey dk, byte[] ivNonce, int mode)
130174
return cipher.doFinal(bytes);
131175
}
132176

177+
/**
178+
* Generates an HMAC for message authentication.
179+
*/
133180
private byte[] hmac(byte[] bytes, NexoDerivedKey derivedKey) throws NoSuchAlgorithmException, InvalidKeyException {
134181
Mac mac = Mac.getInstance("HmacSHA256");
135182
SecretKeySpec s = new SecretKeySpec(derivedKey.getHmacKey(), "HmacSHA256");
@@ -138,6 +185,9 @@ private byte[] hmac(byte[] bytes, NexoDerivedKey derivedKey) throws NoSuchAlgori
138185
return mac.doFinal(bytes);
139186
}
140187

188+
/**
189+
* Validates the HMAC of a decrypted message to ensure data integrity.
190+
*/
141191
private void validateHmac(byte[] receivedHmac, byte[] decryptedMessage, NexoDerivedKey derivedKey) throws NexoCryptoException, InvalidKeyException, NoSuchAlgorithmException {
142192
byte[] hmac = hmac(decryptedMessage, derivedKey);
143193
boolean valid = MessageDigest.isEqual(hmac, receivedHmac);
@@ -147,12 +197,16 @@ private void validateHmac(byte[] receivedHmac, byte[] decryptedMessage, NexoDeri
147197
}
148198
}
149199

200+
/**
201+
* Generates a random IV nonce using a secure random number generator.
202+
*/
150203
private byte[] generateRandomIvNonce() {
151204
byte[] ivNonce = new byte[NEXO_IV_LENGTH];
152205
SecureRandom secureRandom;
153206
try {
154207
secureRandom = SecureRandom.getInstance("NativePRNGNonBlocking");
155208
} catch (NoSuchAlgorithmException e) {
209+
// Fallback to default SecureRandom implementation
156210
secureRandom = new SecureRandom();
157211
}
158212
secureRandom.nextBytes(ivNonce);

0 commit comments

Comments
 (0)