From a8a452b21e6707a1ab2a3f95398fc29cdf8d8e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Dvo=C5=99=C3=A1k?= Date: Wed, 6 Sep 2023 21:12:21 +0200 Subject: [PATCH] Fix #524: Include version in the token digest --- .../client/token/ClientTokenGenerator.java | 17 ++++++++++++++++- .../powerauth/crypto/lib/util/TokenUtils.java | 14 +++++++++----- .../server/token/ServerTokenVerifier.java | 17 ++++++++++++++++- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/client/token/ClientTokenGenerator.java b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/client/token/ClientTokenGenerator.java index a2227f6ed..6c8e807e2 100644 --- a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/client/token/ClientTokenGenerator.java +++ b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/client/token/ClientTokenGenerator.java @@ -61,7 +61,22 @@ public byte[] generateTokenTimestamp() { * @throws CryptoProviderException In case cryptography provider is incorrectly initialized. */ public byte[] computeTokenDigest(byte[] nonce, byte[] timestamp, byte[] tokenSecret) throws GenericCryptoException, CryptoProviderException { - return tokenUtils.computeTokenDigest(nonce, timestamp, tokenSecret); + return this.computeTokenDigest(nonce, timestamp, null, tokenSecret); + } + + /** + * Compute the digest of provided token information using given token secret. + * + * @param nonce Token nonce, 16 random bytes. + * @param timestamp Token timestamp, Unix timestamp format encoded as bytes (from string representation). + * @param version Protocol version. + * @param tokenSecret Token secret, 16 random bytes. + * @return Token digest computed using provided data bytes with given token secret. + * @throws GenericCryptoException In case digest computation fails. + * @throws CryptoProviderException In case cryptography provider is incorrectly initialized. + */ + public byte[] computeTokenDigest(byte[] nonce, byte[] timestamp, byte[] version, byte[] tokenSecret) throws GenericCryptoException, CryptoProviderException { + return tokenUtils.computeTokenDigest(nonce, timestamp, version, tokenSecret); } } diff --git a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/util/TokenUtils.java b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/util/TokenUtils.java index 9e53650a4..3f7243117 100644 --- a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/util/TokenUtils.java +++ b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/util/TokenUtils.java @@ -92,14 +92,17 @@ public byte[] convertTokenTimestamp(long timestamp) { * Compute the digest of provided token information using given token secret. * @param nonce Token nonce, 16 random bytes. * @param timestamp Token timestamp, Unix timestamp format encoded as bytes (string representation). + * @param version Protocol version. * @param tokenSecret Token secret, 16 random bytes. * @return Token digest computed using provided data bytes with given token secret. * @throws GenericCryptoException In case digest computation fails. * @throws CryptoProviderException In case cryptography provider is incorrectly initialized. */ - public byte[] computeTokenDigest(byte[] nonce, byte[] timestamp, byte[] tokenSecret) throws GenericCryptoException, CryptoProviderException { - byte[] amp = "&".getBytes(StandardCharsets.UTF_8); - byte[] data = ByteUtils.concat(nonce, amp, timestamp); + public byte[] computeTokenDigest(byte[] nonce, byte[] timestamp, byte[] version, byte[] tokenSecret) throws GenericCryptoException, CryptoProviderException { + final byte[] amp = "&".getBytes(StandardCharsets.UTF_8); + final byte[] data = (version != null) + ? ByteUtils.concat(nonce, amp, timestamp, amp, version) + : ByteUtils.concat(nonce, amp, timestamp); return hmac.hash(tokenSecret, data); } @@ -107,14 +110,15 @@ public byte[] computeTokenDigest(byte[] nonce, byte[] timestamp, byte[] tokenSec * Validate provided token digest for given input data and provided token secret. * @param nonce Token nonce, 16 random bytes. * @param timestamp Token timestamp, Unix timestamp format encoded as bytes (string representation). + * @param version Protocol version. * @param tokenSecret Token secret, 16 random bytes. * @param tokenDigest Token digest, 32 bytes to be validated. * @return Token digest computed using provided data bytes with given token secret. * @throws GenericCryptoException In case digest computation fails. * @throws CryptoProviderException In case cryptography provider is incorrectly initialized. */ - public boolean validateTokenDigest(byte[] nonce, byte[] timestamp, byte[] tokenSecret, byte[] tokenDigest) throws GenericCryptoException, CryptoProviderException { - return SideChannelUtils.constantTimeAreEqual(computeTokenDigest(nonce, timestamp, tokenSecret), tokenDigest); + public boolean validateTokenDigest(byte[] nonce, byte[] timestamp, byte[] version, byte[] tokenSecret, byte[] tokenDigest) throws GenericCryptoException, CryptoProviderException { + return SideChannelUtils.constantTimeAreEqual(computeTokenDigest(nonce, timestamp, version, tokenSecret), tokenDigest); } } diff --git a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/server/token/ServerTokenVerifier.java b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/server/token/ServerTokenVerifier.java index 45c2187b0..899b856f6 100644 --- a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/server/token/ServerTokenVerifier.java +++ b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/server/token/ServerTokenVerifier.java @@ -51,7 +51,22 @@ public byte[] convertTokenTimestamp(long timestamp) { * @throws CryptoProviderException In case cryptography provider is incorrectly initialized. */ public boolean validateTokenDigest(byte[] nonce, byte[] timestamp, byte[] tokenSecret, byte[] tokenDigest) throws GenericCryptoException, CryptoProviderException { - return tokenUtils.validateTokenDigest(nonce, timestamp, tokenSecret, tokenDigest); + return this.validateTokenDigest(nonce, timestamp, null, tokenSecret, tokenDigest); + } + + /** + * Validate provided token digest for given input data and provided token secret. + * @param nonce Token nonce, 16 random bytes. + * @param timestamp Token timestamp, Unix timestamp format encoded as bytes (from string representation). + * @param version Protocol version. + * @param tokenSecret Token secret, 16 random bytes. + * @param tokenDigest Token digest, 32 bytes to be validated. + * @return Token digest computed using provided data bytes with given token secret. + * @throws GenericCryptoException In case digest computation fails. + * @throws CryptoProviderException In case cryptography provider is incorrectly initialized. + */ + public boolean validateTokenDigest(byte[] nonce, byte[] timestamp, byte[] version, byte[] tokenSecret, byte[] tokenDigest) throws GenericCryptoException, CryptoProviderException { + return tokenUtils.validateTokenDigest(nonce, timestamp, version, tokenSecret, tokenDigest); } }