Actually, I don't think we use AES in authenticated mode, here is how it is called, using the BouncyCastle library:
public static byte[] aesEncrypt(byte[] plaintext, byte[] key) {
try {
byte[] iv = new byte[16];
secureRandom.get().nextBytes(iv);
PaddedBufferedBlockCipher aes = new PaddedBufferedBlockCipher(new CBCBlockCipher(
new AESEngine()));
CipherParameters ivAndKey = new ParametersWithIV(new KeyParameter(key), iv);
aes.init(true, ivAndKey);
byte[] output = new byte[aes.getOutputSize(plaintext.length)];
int ciphertextLength = aes.processBytes(plaintext, 0, plaintext.length, output, 0);
ciphertextLength += aes.doFinal(output, ciphertextLength);
byte[] result = new byte[iv.length + ciphertextLength];
System.arraycopy(iv, 0, result, 0, iv.length);
System.arraycopy(output, 0, result, iv.length, ciphertextLength);
return result;
} catch (InvalidCipherTextException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
where the shared key is obtained as:
public static byte[] getSharedKey(byte[] myPrivateKey, byte[] theirPublicKey) {
return sha256().digest(getSharedSecret(myPrivateKey, theirPublicKey));
}
private static byte[] getSharedSecret(byte[] myPrivateKey, byte[] theirPublicKey) {
try {
byte[] sharedSecret = new byte[32];
Curve25519.curve(sharedSecret, myPrivateKey, theirPublicKey);
return sharedSecret;
} catch (RuntimeException e) {
Logger.logMessage("Error getting shared secret", e);
throw e;
}
}
However, after encryption, the full list of ciphertexts that each participant sends to the next becomes a part of the transaction bytes that are signed by this participant (using his regular private key, as derived from the secret phrase without additional nonces, as done for all Nxt transactions). So modifying anything inside the encrypted payload will invalidate the transaction and it will no longer be acceptable in the blockchain. And the transaction that the next participant submits, includes the hash of this previous transaction, so is only valid as a response for this specific encrypted payload.
Note that we use the same method for encrypting messages between Nxt accounts, with the difference that the shared key is derived adding a random nonce for each message, and the regular secret phrase, same for every transaction of this account, is used:
public static byte[] getSharedKey(byte[] myPrivateKey, byte[] theirPublicKey, byte[] nonce) {
byte[] dhSharedSecret = getSharedSecret(myPrivateKey, theirPublicKey);
for (int i = 0; i < 32; i++) {
dhSharedSecret[i] ^= nonce[i];
}
return sha256().digest(dhSharedSecret);
}
and after the AES encryption step, same as above, the encrypted text becomes part of the transaction bytes that are signed by the sender.