@@ -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