diff --git a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/generator/IdentifierGenerator.java b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/generator/IdentifierGenerator.java
index 222352004..b38730602 100644
--- a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/generator/IdentifierGenerator.java
+++ b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/generator/IdentifierGenerator.java
@@ -16,7 +16,6 @@
*/
package io.getlime.security.powerauth.crypto.lib.generator;
-import com.google.common.io.BaseEncoding;
import io.getlime.security.powerauth.crypto.lib.encryptor.ecies.kdf.KdfX9_63;
import io.getlime.security.powerauth.crypto.lib.model.RecoveryInfo;
import io.getlime.security.powerauth.crypto.lib.model.RecoverySeed;
@@ -24,6 +23,7 @@
import io.getlime.security.powerauth.crypto.lib.model.exception.GenericCryptoException;
import io.getlime.security.powerauth.crypto.lib.util.CRC16;
import io.getlime.security.powerauth.crypto.lib.util.KeyConvertor;
+import org.bouncycastle.util.encoders.Base32;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -79,17 +79,6 @@ public String generateActivationId() {
return UUID.randomUUID().toString();
}
- /**
- * Generate a new string of a default length (5) with characters from Base32 encoding.
- *
- * @return New string with Base32 characters of a given length.
- * @throws CryptoProviderException In case key cryptography provider is incorrectly initialized.
- */
- private String generateBase32Token() throws CryptoProviderException {
- byte[] randomBytes = keyGenerator.generateRandomBytes(BASE32_KEY_LENGTH);
- return BaseEncoding.base32().omitPadding().encode(randomBytes).substring(0, BASE32_KEY_LENGTH);
- }
-
/**
* Generate version 3.0 or higher activation code. The format of activation code is "ABCDE-FGHIJ-KLMNO-PQRST".
*
@@ -170,8 +159,8 @@ public boolean validateActivationCode(String activationCode) {
return false;
}
- // Decode the Base32 value
- byte[] activationCodeBytes = BaseEncoding.base32().decode(activationCode.replace("-", ""));
+ final String activationCodeBase32 = fetchActivationCodeBase32(activationCode);
+ final byte[] activationCodeBytes = Base32.decode(activationCodeBase32);
// Verify byte array length
if (activationCodeBytes.length != ACTIVATION_CODE_BYTES_LENGTH) {
@@ -190,6 +179,32 @@ public boolean validateActivationCode(String activationCode) {
return expectedChecksum == actualChecksum;
}
+ /**
+ * Remove hyphens and calculate padding.
+ *
+ * When {@code ACTIVATION_CODE_BYTES_LENGTH = 12}, the Base32 padding is always {@code ====}, but this method is safe to change the length in the future.
+ *
+ * @param activationCode activation code with hyphens
+ * @return base32 with padding
+ */
+ private static String fetchActivationCodeBase32(final String activationCode) {
+ final String activationCodeWithoutHyphens = activationCode.replace("-", "");
+ // The activation code does not contain the padding, but it must be present in the Base32 value to be valid.
+ final String activationCodePadding = switch (activationCodeWithoutHyphens.length() % 8) {
+ case 2:
+ yield "======";
+ case 4:
+ yield "====";
+ case 5:
+ yield "===";
+ case 7:
+ yield "=";
+ default:
+ yield "";
+ };
+ return activationCodeWithoutHyphens + activationCodePadding;
+ }
+
/**
* Generate recovery code and PUK.
* @return Recovery code and PUK.
@@ -367,9 +382,9 @@ private String generatePuk(SecretKey recoveryPukBaseKey, byte[] indexBytes) thro
* @param activationCodeBytes Raw activation code bytes.
* @return Base32 String representation of activation code.
*/
- private String encodeActivationCode(byte[] activationCodeBytes) {
- // Generate Base32 representation from 12 activation code bytes, without padding characters.
- String base32Encoded = BaseEncoding.base32().omitPadding().encode(activationCodeBytes);
+ private String encodeActivationCode(final byte[] activationCodeBytes) {
+ // Padding may be ignored; ACTIVATION_CODE_BYTES_LENGTH is set to 12 and the following substring takes only the first 20 characters.
+ final String base32Encoded = Base32.toBase32String(activationCodeBytes);
// Split Base32 string into 4 groups, each one contains 5 characters. Use "-" as separator.
return base32Encoded.substring(0, BASE32_KEY_LENGTH)
diff --git a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/totp/Totp.java b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/totp/Totp.java
index a0599c0c6..bcd0991ac 100644
--- a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/totp/Totp.java
+++ b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/totp/Totp.java
@@ -16,7 +16,6 @@
*/
package io.getlime.security.powerauth.crypto.lib.totp;
-import com.google.common.base.Strings;
import io.getlime.security.powerauth.crypto.lib.model.exception.CryptoProviderException;
import org.bouncycastle.util.Arrays;
import org.slf4j.Logger;
@@ -268,7 +267,7 @@ private static long countTimeSteps(final Instant instant, final Duration stepLen
}
private static String padWithZeros(final String source, final int length) {
- return Strings.padStart(source, length, '0');
+ return String.format("%1$" + length + "s", source).replace(' ', '0');
}
/**
diff --git a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/util/SignatureUtils.java b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/util/SignatureUtils.java
index 316b2297e..f944470d5 100644
--- a/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/util/SignatureUtils.java
+++ b/powerauth-java-crypto/src/main/java/io/getlime/security/powerauth/crypto/lib/util/SignatureUtils.java
@@ -16,7 +16,6 @@
*/
package io.getlime.security.powerauth.crypto.lib.util;
-import com.google.common.base.Joiner;
import io.getlime.security.powerauth.crypto.lib.config.DecimalSignatureConfiguration;
import io.getlime.security.powerauth.crypto.lib.config.PowerAuthConfiguration;
import io.getlime.security.powerauth.crypto.lib.config.SignatureConfiguration;
@@ -164,7 +163,7 @@ private String computePowerAuthDecimalSignature(byte[] data, List sig
signatureStringComponents[i] = String.format("%0" + signatureDecimalLength + "d", number);
}
// Join components with dash.
- return Joiner.on("-").join(signatureStringComponents);
+ return String.join("-", signatureStringComponents);
}
/**
diff --git a/powerauth-java-crypto/src/test/java/io/getlime/security/powerauth/crypto/activation/PowerAuthRecoveryCodeTest.java b/powerauth-java-crypto/src/test/java/io/getlime/security/powerauth/crypto/activation/IdentifierGeneratorTest.java
similarity index 87%
rename from powerauth-java-crypto/src/test/java/io/getlime/security/powerauth/crypto/activation/PowerAuthRecoveryCodeTest.java
rename to powerauth-java-crypto/src/test/java/io/getlime/security/powerauth/crypto/activation/IdentifierGeneratorTest.java
index 464b50979..360db676c 100644
--- a/powerauth-java-crypto/src/test/java/io/getlime/security/powerauth/crypto/activation/PowerAuthRecoveryCodeTest.java
+++ b/powerauth-java-crypto/src/test/java/io/getlime/security/powerauth/crypto/activation/IdentifierGeneratorTest.java
@@ -20,23 +20,25 @@
import io.getlime.security.powerauth.crypto.lib.generator.KeyGenerator;
import io.getlime.security.powerauth.crypto.lib.model.RecoveryInfo;
import io.getlime.security.powerauth.crypto.lib.model.RecoverySeed;
-import io.getlime.security.powerauth.crypto.lib.model.exception.CryptoProviderException;
-import io.getlime.security.powerauth.crypto.lib.model.exception.GenericCryptoException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import javax.crypto.SecretKey;
-import java.security.*;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Security;
import java.util.HashSet;
import static org.junit.jupiter.api.Assertions.*;
/**
+ * Test for {@link IdentifierGenerator}.
*
* @author Roman Strobl, roman.strobl@wultra.com
*/
-public class PowerAuthRecoveryCodeTest {
+class IdentifierGeneratorTest {
private final IdentifierGenerator identifierGenerator = new IdentifierGenerator();
@@ -50,7 +52,7 @@ public static void setUp() {
}
@Test
- public void testRecoveryCodeDerivation() throws CryptoProviderException, InvalidKeyException, GenericCryptoException {
+ void testRecoveryCodeDerivation() throws Exception {
// Number of PUKs to test
int pukCount = 100;
@@ -89,4 +91,12 @@ public void testRecoveryCodeDerivation() throws CryptoProviderException, Invalid
}
}
+ @Test
+ void testGenerateActivationCode() throws Exception {
+ final String result = identifierGenerator.generateActivationCode(new byte[10]);
+
+ // Base32 is AAAAAAAAAAAAAAAAAAAA====
+ assertEquals("AAAAA-AAAAA-AAAAA-AAAAA", result);
+ }
+
}
diff --git a/powerauth-java-crypto/src/test/java/io/getlime/security/powerauth/crypto/lib/totp/TotpTest.java b/powerauth-java-crypto/src/test/java/io/getlime/security/powerauth/crypto/lib/totp/TotpTest.java
index 9f2b7f80a..24e77f7d8 100644
--- a/powerauth-java-crypto/src/test/java/io/getlime/security/powerauth/crypto/lib/totp/TotpTest.java
+++ b/powerauth-java-crypto/src/test/java/io/getlime/security/powerauth/crypto/lib/totp/TotpTest.java
@@ -36,7 +36,6 @@
* Test for {@link Totp}.
*
* @author Lubos Racansky, lubos.racansky@wultra.com
- *
*/
class TotpTest {
diff --git a/powerauth-java-http/pom.xml b/powerauth-java-http/pom.xml
index abd76bead..df3382081 100644
--- a/powerauth-java-http/pom.xml
+++ b/powerauth-java-http/pom.xml
@@ -28,7 +28,7 @@
io.getlime.security
powerauth-crypto-parent
- 1.6.0
+ 1.7.0
@@ -37,10 +37,6 @@
powerauth-java-crypto
${project.version}
-