Repository: wultra/powerauth-crypto (java)

Issue:
Update token digest calculation
### Description

Use `KMAC-256` instead of `HmacSha256`.

### Acceptance criteria

_No response_

### Technical specification

_No response_

### QA specification

_No response_

Pull request:
Fix #703: Update token digest calculation

Patch:
diff --git a/powerauth-java-crypto/src/main/java/com/wultra/security/powerauth/crypto/lib/util/TokenUtils.java b/powerauth-java-crypto/src/main/java/com/wultra/security/powerauth/crypto/lib/util/TokenUtils.java
index c634a5e6..b8ce45b4 100644
--- a/powerauth-java-crypto/src/main/java/com/wultra/security/powerauth/crypto/lib/util/TokenUtils.java
+++ b/powerauth-java-crypto/src/main/java/com/wultra/security/powerauth/crypto/lib/util/TokenUtils.java
@@ -19,7 +19,9 @@ package com.wultra.security.powerauth.crypto.lib.util;
 import com.wultra.security.powerauth.crypto.lib.generator.KeyGenerator;
 import com.wultra.security.powerauth.crypto.lib.model.exception.CryptoProviderException;
 import com.wultra.security.powerauth.crypto.lib.model.exception.GenericCryptoException;
+import com.wultra.security.powerauth.crypto.lib.v4.kdf.Kmac;
 
+import javax.crypto.SecretKey;
 import java.nio.charset.StandardCharsets;
 import java.util.UUID;
 
@@ -27,11 +29,15 @@ import java.util.UUID;
  * Class used for computing PowerAuth Token digests.
  *
  * @author Petr Dvorak, petr@wultra.com
+ * @author Roman Strobl, roman.strobl@wultra.com
  */
 public class TokenUtils {
 
-    private final KeyGenerator keyGenerator = new KeyGenerator();
-    private final HMACHashUtilities hmac = new HMACHashUtilities();
+    private static final byte[] DIGEST_KMAC_CUSTOM_BYTES = "PA4DIGEST".getBytes(StandardCharsets.UTF_8);
+
+    private static final KeyGenerator KEY_GENERATOR = new KeyGenerator();
+    private static final KeyConvertor KEY_CONVERTOR = new KeyConvertor();
+    private static final HMACHashUtilities HMAC = new HMACHashUtilities();
 
     /**
      * Generate random token ID. Use UUID format.
@@ -45,11 +51,12 @@ public class TokenUtils {
     /**
      * Generate random token secret, 16 random bytes.
      *
+     * @param length Number of random bytes.
      * @return Random token secret.
      * @throws CryptoProviderException In case key cryptography provider is incorrectly initialized.
      */
-    public byte[] generateTokenSecret() throws CryptoProviderException {
-        return keyGenerator.generateRandomBytes(16);
+    public byte[] generateTokenSecret(int length) throws CryptoProviderException {
+        return KEY_GENERATOR.generateRandomBytes(length);
     }
 
     /**
@@ -59,7 +66,7 @@ public class TokenUtils {
      * @throws CryptoProviderException In case key cryptography provider is incorrectly initialized.
      */
     public byte[] generateTokenNonce() throws CryptoProviderException {
-        return keyGenerator.generateRandomBytes(16);
+        return KEY_GENERATOR.generateRandomBytes(16);
     }
 
     /**
@@ -67,7 +74,7 @@ public class TokenUtils {
      * String representation of timestamp.<br>
      * <br>
      * The timestamp conversion works like this: Long timestamp is converted to String and then, bytes of the
-     * String are extracted usign the UTF-8 encoding.<br>
+     * String are extracted using the UTF-8 encoding.<br>
      * <br>
      * Code: <code>String.valueOf(System.currentTimeMillis()).getBytes(StandardCharsets.UTF_8);</code>
      *
@@ -101,12 +108,24 @@ public class TokenUtils {
     public byte[] computeTokenDigest(byte[] nonce, byte[] timestamp, String version, byte[] tokenSecret) throws GenericCryptoException, CryptoProviderException {
         final byte[] amp = "&".getBytes(StandardCharsets.UTF_8);
         final byte[] data;
+        final byte[] digest;
         switch (version) {
-            case "3.3", "3.2" -> data = ByteUtils.concat(nonce, amp, timestamp, amp, version.getBytes(StandardCharsets.UTF_8));
-            case "3.0", "3.1" -> data = ByteUtils.concat(nonce, amp, timestamp);
+            case "3.3", "3.2" -> {
+                data = ByteUtils.concat(nonce, amp, timestamp, amp, version.getBytes(StandardCharsets.UTF_8));
+                digest = HMAC.hash(tokenSecret, data);
+            }
+            case "3.0", "3.1" -> {
+                data = ByteUtils.concat(nonce, amp, timestamp);
+                digest = HMAC.hash(tokenSecret, data);
+            }
+            case "4.0" -> {
+                data = ByteUtils.concat(nonce, amp, timestamp, amp, version.getBytes(StandardCharsets.UTF_8));
+                final SecretKey secretKey = KEY_CONVERTOR.convertBytesToSharedSecretKey(tokenSecret);
+                digest = Kmac.kmac256(secretKey, data, 32, DIGEST_KMAC_CUSTOM_BYTES);
+            }
             default -> throw new GenericCryptoException("Unsupported version value was specified: " + version);
         }
-        return hmac.hash(tokenSecret, data);
+        return digest;
     }
 
     /**
diff --git a/powerauth-java-crypto/src/main/java/com/wultra/security/powerauth/crypto/server/token/ServerTokenGenerator.java b/powerauth-java-crypto/src/main/java/com/wultra/security/powerauth/crypto/server/token/ServerTokenGenerator.java
index 9c6c349d..6b149960 100644
--- a/powerauth-java-crypto/src/main/java/com/wultra/security/powerauth/crypto/server/token/ServerTokenGenerator.java
+++ b/powerauth-java-crypto/src/main/java/com/wultra/security/powerauth/crypto/server/token/ServerTokenGenerator.java
@@ -17,12 +17,14 @@
 package com.wultra.security.powerauth.crypto.server.token;
 
 import com.wultra.security.powerauth.crypto.lib.model.exception.CryptoProviderException;
+import com.wultra.security.powerauth.crypto.lib.model.exception.GenericCryptoException;
 import com.wultra.security.powerauth.crypto.lib.util.TokenUtils;
 
 /**
  * Server side class used for generating new tokens.
  *
  * @author Petr Dvorak, petr@wultra.com
+ * @author Roman Strobl, roman.strobl@wultra.com
  */
 public class ServerTokenGenerator {
 
@@ -37,12 +39,20 @@ public class ServerTokenGenerator {
     }
 
     /**
-     * Generate random token secret, 16 random bytes.
+     * Generate random token secret, 16 or 32 random bytes depending on the version.
+     * @param version Protocol version.
      * @return Random token secret.
      * @throws CryptoProviderException In case key cryptography provider is incorrectly initialized.
+     * @throws GenericCryptoException In case the protocol version is not supported.
      */
-    public byte[] generateTokenSecret() throws CryptoProviderException {
-        return tokenUtils.generateTokenSecret();
+    public byte[] generateTokenSecret(String version) throws CryptoProviderException, GenericCryptoException {
+        final byte[] tokenSecret;
+        switch (version) {
+            case "3.0", "3.1", "3.2", "3.3" -> tokenSecret = tokenUtils.generateTokenSecret(16);
+            case "4.0" -> tokenSecret = tokenUtils.generateTokenSecret(32);
+            default -> throw new GenericCryptoException("Unsupported protocol version: " + version);
+        }
+        return tokenSecret;
     }
 
 }


Test patch:
diff --git a/powerauth-java-crypto/src/test/java/com/wultra/security/powerauth/crypto/lib/util/TokenUtilsTest.java b/powerauth-java-crypto/src/test/java/com/wultra/security/powerauth/crypto/lib/util/TokenUtilsTest.java
new file mode 100644
index 00000000..2eccacf1
--- /dev/null
+++ b/powerauth-java-crypto/src/test/java/com/wultra/security/powerauth/crypto/lib/util/TokenUtilsTest.java
@@ -0,0 +1,114 @@
+/*
+ * PowerAuth Crypto Library
+ * Copyright 2025 Wultra s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.wultra.security.powerauth.crypto.lib.util;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.wultra.security.powerauth.crypto.lib.model.exception.CryptoProviderException;
+import com.wultra.security.powerauth.crypto.lib.model.exception.GenericCryptoException;
+import com.wultra.security.powerauth.crypto.lib.v4.sharedsecret.SharedSecretEcdheTest;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.Security;
+import java.util.Base64;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Test of token utility methods.
+ *
+ * @author Roman Strobl, roman.strobl@wultra.com
+ */
+public class TokenUtilsTest {
+
+    private static final TokenUtils TOKEN_UTILS = new TokenUtils();
+    private static final ObjectMapper MAPPER = new ObjectMapper();
+
+    static {
+        Security.addProvider(new BouncyCastleProvider());
+    }
+
+    @Test
+    public void testTokenDigestV30() throws CryptoProviderException, GenericCryptoException {
+        final byte[] tokenSecret = TOKEN_UTILS.generateTokenSecret(16);
+        final byte[] timestamp = TOKEN_UTILS.generateTokenTimestamp();
+        final byte[] nonce = TOKEN_UTILS.generateTokenNonce();
+        final byte[] tokenDigest = TOKEN_UTILS.computeTokenDigest(nonce, timestamp, "3.0", tokenSecret);
+        assertTrue(TOKEN_UTILS.validateTokenDigest(nonce, timestamp, "3.0", tokenSecret, tokenDigest));
+    }
+
+    @Test
+    public void testTokenDigestV31() throws CryptoProviderException, GenericCryptoException {
+        final byte[] tokenSecret = TOKEN_UTILS.generateTokenSecret(16);
+        final byte[] timestamp = TOKEN_UTILS.generateTokenTimestamp();
+        final byte[] nonce = TOKEN_UTILS.generateTokenNonce();
+        final byte[] tokenDigest = TOKEN_UTILS.computeTokenDigest(nonce, timestamp, "3.1", tokenSecret);
+        assertTrue(TOKEN_UTILS.validateTokenDigest(nonce, timestamp, "3.1", tokenSecret, tokenDigest));
+    }
+
+    @Test
+    public void testTokenDigestV32() throws CryptoProviderException, GenericCryptoException {
+        final byte[] tokenSecret = TOKEN_UTILS.generateTokenSecret(16);
+        final byte[] timestamp = TOKEN_UTILS.generateTokenTimestamp();
+        final byte[] nonce = TOKEN_UTILS.generateTokenNonce();
+        final byte[] tokenDigest = TOKEN_UTILS.computeTokenDigest(nonce, timestamp, "3.2", tokenSecret);
+        assertTrue(TOKEN_UTILS.validateTokenDigest(nonce, timestamp, "3.2", tokenSecret, tokenDigest));
+    }
+
+    @Test
+    public void testTokenDigestV33() throws CryptoProviderException, GenericCryptoException {
+        final byte[] tokenSecret = TOKEN_UTILS.generateTokenSecret(16);
+        final byte[] timestamp = TOKEN_UTILS.generateTokenTimestamp();
+        final byte[] nonce = TOKEN_UTILS.generateTokenNonce();
+        final byte[] tokenDigest = TOKEN_UTILS.computeTokenDigest(nonce, timestamp, "3.3", tokenSecret);
+        assertTrue(TOKEN_UTILS.validateTokenDigest(nonce, timestamp, "3.3", tokenSecret, tokenDigest));
+    }
+
+    @Test
+    public void testTokenDigestV40() throws CryptoProviderException, GenericCryptoException {
+        final byte[] tokenSecret = TOKEN_UTILS.generateTokenSecret(32);
+        final byte[] timestamp = TOKEN_UTILS.generateTokenTimestamp();
+        final byte[] nonce = TOKEN_UTILS.generateTokenNonce();
+        final byte[] tokenDigest = TOKEN_UTILS.computeTokenDigest(nonce, timestamp, "4.0", tokenSecret);
+        assertTrue(TOKEN_UTILS.validateTokenDigest(nonce, timestamp, "4.0", tokenSecret, tokenDigest));
+    }
+
+    private static Stream<Map<String, String>> jsonDataTokenDigestV40_Provider() throws IOException {
+        final InputStream stream = SharedSecretEcdheTest.class.getResourceAsStream("/com/wultra/security/powerauth/crypto/lib/v4/token/Token_Digest_Test_Vectors.json");
+        final Map<String, List<Map<String, String>>> testData = MAPPER.readValue(stream, new TypeReference<>() {});
+        return testData.get("token_digest_test_vectors").stream();
+    }
+
+    @ParameterizedTest
+    @MethodSource("jsonDataTokenDigestV40_Provider")
+    public void testVectorsTokenDigestV40(Map<String, String> vector) throws Exception {
+        final byte[] tokenSecret = Base64.getDecoder().decode(vector.get("tokenSecret"));
+        final byte[] nonce = Base64.getDecoder().decode(vector.get("nonce"));
+        final byte[] timestamp = Base64.getDecoder().decode(vector.get("timestamp"));
+        final byte[] tokenDigest = Base64.getDecoder().decode(vector.get("tokenDigest"));
+        assertTrue(TOKEN_UTILS.validateTokenDigest(nonce, timestamp, "4.0", tokenSecret, tokenDigest));
+    }
+
+}
diff --git a/powerauth-java-crypto/src/test/resources/com/wultra/security/powerauth/crypto/lib/v4/token/Token_Digest_Test_Vectors.json b/powerauth-java-crypto/src/test/resources/com/wultra/security/powerauth/crypto/lib/v4/token/Token_Digest_Test_Vectors.json
new file mode 100644
index 00000000..ac9c2bda
--- /dev/null
+++ b/powerauth-java-crypto/src/test/resources/com/wultra/security/powerauth/crypto/lib/v4/token/Token_Digest_Test_Vectors.json
@@ -0,0 +1,604 @@
+{
+  "token_digest_test_vectors": [
+    {
+      "tokenSecret": "GTminer6ABUm2t1OAY/3rI7V7YGH99zsjTWIgbvTzyo=",
+      "timestamp": "MTczODkyNzQ4NjUwNA==",
+      "nonce": "LzjsEkjde5gg3O/7xX+Vkg==",
+      "tokenDigest": "BvQusfbGcMMbMc2xyP+zMlgFZNmEgjS7hwRwghJyRyA="
+    },
+    {
+      "tokenSecret": "4EndlGXlxTQfO6dAb67tUmF1oYtJptg4hsZIp44s5Xc=",
+      "timestamp": "MTczODkyNzQ4NjUxOQ==",
+      "nonce": "NkZqsMlyg9xJPcjI0HcMag==",
+      "tokenDigest": "+9RRrjZcDy4PvHDnugvgomBzMavjhPE6C4KyJhCBdEM="
+    },
+    {
+      "tokenSecret": "Ej3dUNmnBuP9/wxKG7/H9gY6qgLdlJDxpIsrH52nO+0=",
+      "timestamp": "MTczODkyNzQ4NjUyNA==",
+      "nonce": "pEn5NasM3nC9OscIRuKhzw==",
+      "tokenDigest": "GbK2O3ovVcUeI3149AxxhtWgzkd3qilSBDWzrQ1fP5I="
+    },
+    {
+      "tokenSecret": "gCqIzHtFuipkxLASAbEKx2FAh2oKksRerYjpfCjecz0=",
+      "timestamp": "MTczODkyNzQ4NjUyOA==",
+      "nonce": "KJHkmF5dvdmXuIHqE0ELKw==",
+      "tokenDigest": "BUuqHTbuFYvJuF8wz9hMtHjy0RBMaejD2NhlfVJWPeQ="
+    },
+    {
+      "tokenSecret": "2K/s4kXdRR9FfeSJ37z93oXGhSR4XM1zGEnEVTfDzj8=",
+      "timestamp": "MTczODkyNzQ4NjUzMg==",
+      "nonce": "/ln7O02za49rCu1XpLMiZA==",
+      "tokenDigest": "tcaOMi9BDdZq9dwV3Z80qFX2NHckVOShjPikL7Qjzgs="
+    },
+    {
+      "tokenSecret": "VI0xZDEijCm9F9sfzp9eudNpMoZ8+V4VQ4mhJnOOzqE=",
+      "timestamp": "MTczODkyNzQ4NjUzNQ==",
+      "nonce": "2kKL2eVf7sgTXNmdKDzBcg==",
+      "tokenDigest": "uXwLvJDnA2632x583Wy3enYX219P+DvfCbyRKtmAQRo="
+    },
+    {
+      "tokenSecret": "xnkOExX7Si0tWO/freSTc5r+nZHdnQfwIEGncSm/UGE=",
+      "timestamp": "MTczODkyNzQ4NjUzOA==",
+      "nonce": "r6xyXcTjmHu+KfNxHypngQ==",
+      "tokenDigest": "0EyEIvENL2lTWIPLyr9kWLpQpFKD7lwZpOFTxZfQ0Sk="
+    },
+    {
+      "tokenSecret": "SRdusB9VZgpM+p1QH3ZGc+QnZ7H9JzX1VsOdC0C1DHk=",
+      "timestamp": "MTczODkyNzQ4NjU0MA==",
+      "nonce": "wvOy2GsebIoy1qQ8chSYHQ==",
+      "tokenDigest": "/1BUK45rN8/Yugo2nDB7QNY2LhSvHb3Rucgdj7K72kE="
+    },
+    {
+      "tokenSecret": "v/LlRmQXeoqlXstMe41+cINq+kHAfIoc3Crs5PTLmKQ=",
+      "timestamp": "MTczODkyNzQ4NjU0Mw==",
+      "nonce": "Wej0Tmtd5te7hOZB5CQ57A==",
+      "tokenDigest": "o4m5Y4WJ0p965GfI/KoFO1wpzVwlqHkNc5g1uP9D4rY="
+    },
+    {
+      "tokenSecret": "bKr9lt72jOHW9HJAOQnBJaQ9G+na4H9JvQEGJ+UcnTE=",
+      "timestamp": "MTczODkyNzQ4NjU0Ng==",
+      "nonce": "d8EQD5f8BEZAC1uz5E/8ZQ==",
+      "tokenDigest": "MDy6USqfyG2n0hZQ1lz3PMNqts8slST5pWoOwD6gnf8="
+    },
+    {
+      "tokenSecret": "pUbk5my50xoI8YP8fzMIxw48pDXS7t2FWhpx+p/qpLY=",
+      "timestamp": "MTczODkyNzQ4NjU0OA==",
+      "nonce": "hys0mn85g+hjgE0Dek/Vjg==",
+      "tokenDigest": "Aa4eMokv2QAqEKGHF9NNuwaLbEbM9MnBCsgLsgQncaE="
+    },
+    {
+      "tokenSecret": "3LZwFCpmCQVnZFDKM5YfxkMde3ExHmTB4MDX14cyXpw=",
+      "timestamp": "MTczODkyNzQ4NjU1MQ==",
+      "nonce": "Yc8BghNiQsWSaZXa2dSicQ==",
+      "tokenDigest": "8u6G3C6KR/yUy52rKR5Ca2Ir+lKtwmE0B2kl2r09/lI="
+    },
+    {
+      "tokenSecret": "7jmDpBbl5vTU+7VsBxi6aU4C59tPdONcoYPcOeLv9xM=",
+      "timestamp": "MTczODkyNzQ4NjU1Mw==",
+      "nonce": "tj+OQoHzdFYOnCVfr3OV4Q==",
+      "tokenDigest": "IJxrDHfmbitNpv+J83SGg83yj30iQD7uqwy/cpqbdnY="
+    },
+    {
+      "tokenSecret": "s767wHI59xRPJ4+EcABjPW5vlhYw09495gmbg45BV4Y=",
+      "timestamp": "MTczODkyNzQ4NjU1Ng==",
+      "nonce": "U1AKO/p9BGNCOhPv6Mz6sw==",
+      "tokenDigest": "QygLAUw68DLHmlhcCc7N1PSJwoVddQj5amTPWXpm91o="
+    },
+    {
+      "tokenSecret": "HX3QNotJb3yE3bD/TMpoRIOWzeY5lHMv74kyP6mCh8I=",
+      "timestamp": "MTczODkyNzQ4NjU1OA==",
+      "nonce": "zndJa29SMoTjKv1A+QTVYA==",
+      "tokenDigest": "sH/tks5urctNpg5QQdT0ut091tVifrF6sfrQV65iFMA="
+    },
+    {
+      "tokenSecret": "TfaJ5sshcrOocuK/i5ZwQ5iFQM8wXxKs7IwgPeWM73E=",
+      "timestamp": "MTczODkyNzQ4NjU2MQ==",
+      "nonce": "yun3bGbcaAthhIJvjtgMKQ==",
+      "tokenDigest": "IbE+661DDCjWn4Zwa0pXT9YFufVEf4Qs+SXefHIFpgg="
+    },
+    {
+      "tokenSecret": "vFQ+zGi8ATB9QIts39VNIif/hDacGUl87jgmFlzJdMs=",
+      "timestamp": "MTczODkyNzQ4NjU2NA==",
+      "nonce": "HwFWeC5XPO+Ak3dnHVqhKA==",
+      "tokenDigest": "W2chz9alW2ojaVtsUxs5306jFQy/BjOALL02JzRwhI0="
+    },
+    {
+      "tokenSecret": "wEc79n2zb9iCWjWVCPCk435IUpEy/800rEin0jQgsJ8=",
+      "timestamp": "MTczODkyNzQ4NjU2Nw==",
+      "nonce": "pR8Ipfc3WTY6mss/EAumpA==",
+      "tokenDigest": "IEX511iyt/CgwR+EcWwbTovMqEs2XdIYNfc7yJiB5vI="
+    },
+    {
+      "tokenSecret": "0R15BT40w+s2Fy8GCc/+eL3jAs75VoJa+WmhpkS6A5M=",
+      "timestamp": "MTczODkyNzQ4NjU2OQ==",
+      "nonce": "oQPRIBqNQyLRrhgG1hljKw==",
+      "tokenDigest": "cD/DbC1fYrzQ+8GtDy5AJX1hfV8crM6ETzmqR+iV5ok="
+    },
+    {
+      "tokenSecret": "U1uj9nUsdw0KVQg8zCeddZY3IRdQ6sLTEO4hmnaOfrk=",
+      "timestamp": "MTczODkyNzQ4NjU3MQ==",
+      "nonce": "kpFYv3xVklyG0qXNHoHWkA==",
+      "tokenDigest": "ccEPyDGmqLDG6x8nXDJgfY8qIETieBpcM8dRM6Qouqg="
+    },
+    {
+      "tokenSecret": "zhv7ra1xC52N9AS6CkbdK3KFPYuDFqlzZmW+HGdwMyQ=",
+      "timestamp": "MTczODkyNzQ4NjU3Mw==",
+      "nonce": "d9+qByd7l/fK+hCU94m5/w==",
+      "tokenDigest": "UN0p9L9yxoq0o2FteUGpDujAhddAu3cAorN83lfk+gA="
+    },
+    {
+      "tokenSecret": "Ybo7gWVxfCAsgv724GLoFrGPPNEsQ+loH8gl24hHM08=",
+      "timestamp": "MTczODkyNzQ4NjU3Ng==",
+      "nonce": "i6XNxtYik2djGSjIYPTedA==",
+      "tokenDigest": "jzU3Ax3GLdDUMXwGak0+9ZpRKZzgmhpTPxf5IyTLY2w="
+    },
+    {
+      "tokenSecret": "rnPZiAdfvMEhcySRmsHGAgS5p5dE+ZRBeROrnvlaEkw=",
+      "timestamp": "MTczODkyNzQ4NjU3OA==",
+      "nonce": "S4XfyYC8Lt1pgbVPqpiEgw==",
+      "tokenDigest": "JNJk35RFUKOUL8jsy6KugObr8WcXx0F2OuQIH8gamiM="
+    },
+    {
+      "tokenSecret": "ZYam2mcVoA9wLNiG6SVLI5fiP7IOw2EiMdjaTB8F8kc=",
+      "timestamp": "MTczODkyNzQ4NjU4MA==",
+      "nonce": "VcOlUY7JOe2Fk0jMZ0uafQ==",
+      "tokenDigest": "kEt2Ya6AIJyQg2s5TVMEbpiLb1IvBp4ABLYj1vS+C0o="
+    },
+    {
+      "tokenSecret": "oTm2Il5X3PcPltQB/AepEt87VAQ4E25I2zPxb2JGwvg=",
+      "timestamp": "MTczODkyNzQ4NjU4Mg==",
+      "nonce": "szs6QA9jqPw36KtMKq1xbw==",
+      "tokenDigest": "R7CYTO5thg5zDmvfw3gcbTC4HyLEADEmT6fQ/DYZvq8="
+    },
+    {
+      "tokenSecret": "CCcN9zfiiaB2778qzSW8kb8zCGHGrCbQ10Zhpzc1/ks=",
+      "timestamp": "MTczODkyNzQ4NjU4NA==",
+      "nonce": "9vtGI+ctpnSxSEYB/RgVZg==",
+      "tokenDigest": "y9Ojh+uwnRoTGSzP0SAREJew9KbkZb2oajWqjSDNk9U="
+    },
+    {
+      "tokenSecret": "D4LGHBMBCyY3gMClpnasIIsgBGk161Wj5gTmvj6odQE=",
+      "timestamp": "MTczODkyNzQ4NjU4Ng==",
+      "nonce": "+Ndqdi44/53D6OjNQl7Pew==",
+      "tokenDigest": "nc5ySnIfzZF75MBpNn4P2aiOhHC9muY/3q8zHbD7QRo="
+    },
+    {
+      "tokenSecret": "CD/k9HaD6bXJV0drgW1f8HdwBa7bO5/sivwkqnHPUYM=",
+      "timestamp": "MTczODkyNzQ4NjU4OA==",
+      "nonce": "T0MgfeJWntRc3B8cD3rh2A==",
+      "tokenDigest": "k6+RRaKD/SBJzRNmMjYmXlKLyE8aafWg1aSgQXEREjo="
+    },
+    {
+      "tokenSecret": "Dm4RWmJ6G6oEq7CwF5G0tnZm8Tbtuf/zD+bDIPcyQv4=",
+      "timestamp": "MTczODkyNzQ4NjU5MA==",
+      "nonce": "iMYjWQO0IEZWjUFlnI6gww==",
+      "tokenDigest": "OPlJtMC+AK8GCRGD8Z0BcxVsQhQUU19g2RBUdzyUMbs="
+    },
+    {
+      "tokenSecret": "Pgv/rkCk1bOkAHcb/DR+OszBr67Ce5qdkL1lYfPBlL0=",
+      "timestamp": "MTczODkyNzQ4NjU5Mg==",
+      "nonce": "wGqg9NjqaSLiK9TXx4W7Xw==",
+      "tokenDigest": "eu0bGyN99p77vaTnzMHW9mymkESMr2aHVgAC/XHqLiI="
+    },
+    {
+      "tokenSecret": "iNMvPBvMNYXH9nY7k0bAFT3TcEpzfVIahFfpC6rlc7A=",
+      "timestamp": "MTczODkyNzQ4NjU5NA==",
+      "nonce": "0B4h3NXXjhH+B3JI9zgpvA==",
+      "tokenDigest": "GJ3rlDWkPUJR5e3b/WzbvoQtOhIWjt84wt7z4NJ4Tms="
+    },
+    {
+      "tokenSecret": "k56vymZSlWYgv+FZHdX/1KJtIA3PMl7EiDK8T5zXbuQ=",
+      "timestamp": "MTczODkyNzQ4NjU5Ng==",
+      "nonce": "K6y2dCGtayVfRPcHgAb75A==",
+      "tokenDigest": "HLZQZQJaQsBnWnWyvK8TwaB7xRLS4J7P6En4drNPQ/Q="
+    },
+    {
+      "tokenSecret": "U8S2PuKVaRp88As1Ykpbw43VhuwlzreXNk3JuFDdPTE=",
+      "timestamp": "MTczODkyNzQ4NjU5OA==",
+      "nonce": "fcM2I+Xyt9SrIskMCBuyKw==",
+      "tokenDigest": "p8qPIbvwBjxZVXFkZbjImBNrkkExbEvuDLsvhGhsCq4="
+    },
+    {
+      "tokenSecret": "cCtUtW1jjS5clAZR1UP0Uchqh4aJo2HwFy37hGcBlxM=",
+      "timestamp": "MTczODkyNzQ4NjYwMA==",
+      "nonce": "nJU/S/Cdcyo1FQMWCGEzqQ==",
+      "tokenDigest": "BN+JN8lYkffWp2fumibDnjOuXGz+6pDjyA/x3ShKuNM="
+    },
+    {
+      "tokenSecret": "BjLC+yfO1c9Vi0G3R/JHuQTh+Dars7U0d1b1QjMUqxU=",
+      "timestamp": "MTczODkyNzQ4NjYwMQ==",
+      "nonce": "7Xbc8B4LDYayFS/q3tvMVQ==",
+      "tokenDigest": "uj+a5q7rgGzukB+OBbJLJ3uahdhvsE4KNNR3VzJg7C0="
+    },
+    {
+      "tokenSecret": "q1hIIp+bOCvJsoznhfC8TB7g/WOQ+ncx5sjvvmc9bJo=",
+      "timestamp": "MTczODkyNzQ4NjYwMw==",
+      "nonce": "38AWYzoTAu6Chz5uQRCCsg==",
+      "tokenDigest": "mgP85Ne6rjS381s1mkZHKUQja48/NKDwoIGfAgMcEHM="
+    },
+    {
+      "tokenSecret": "hF7cPAeaBs22utZQaSRLSAnLT+O0GpgGBbX4+L/DYWA=",
+      "timestamp": "MTczODkyNzQ4NjYwNQ==",
+      "nonce": "LopFwszteMvpaLnQCVDNmA==",
+      "tokenDigest": "JliNmfAhcp+yH7OQ9I1jQO93duikX25E31f99LAb8G0="
+    },
+    {
+      "tokenSecret": "NhiSKFz7YW+TSGc+Se8l+qdp+VcepBoG0NFuWzBtHv4=",
+      "timestamp": "MTczODkyNzQ4NjYwNw==",
+      "nonce": "ZGQ1N34tHBHO/b8RjjkeIQ==",
+      "tokenDigest": "m+Ew5KjZNWSeihvKrcrMTmgeqRNVK13oYyvZ0qHm5O4="
+    },
+    {
+      "tokenSecret": "L1Cm5elpW02jGw0r4mS3is79I0jzHIhfoxa9h1fI2kM=",
+      "timestamp": "MTczODkyNzQ4NjYwOQ==",
+      "nonce": "hXHsk/yXck32vMs71C2kmw==",
+      "tokenDigest": "URf7eLO+gFPHG2ih3Lj/YPFHiBDs7AA42YwZ1LLDMQ0="
+    },
+    {
+      "tokenSecret": "8LbcADMiF5319Vm5f+kLfHjYMoPG/9Pusx1Ga22v4Zk=",
+      "timestamp": "MTczODkyNzQ4NjYxMQ==",
+      "nonce": "lB2UTxk4EUK8Ymkmz/NZ1Q==",
+      "tokenDigest": "32cv2HSH6bpQuVfQCFJBHHsXKFkhTVTIoTpBkxn6BIE="
+    },
+    {
+      "tokenSecret": "GIbEaqo4t96fjF8YX2fKspGofCEYVLaqJ6CvmQesnmk=",
+      "timestamp": "MTczODkyNzQ4NjYxMg==",
+      "nonce": "2wLrJQjv/yBywdKTmikrNA==",
+      "tokenDigest": "VKGRpmV0wJ/hCyb7Oy0N/fdObiRtpISTp7MbFymiDm8="
+    },
+    {
+      "tokenSecret": "s8ixJeaPCY08dhOKboZKIopvgUS1TaNF09eJ+xIA5Qs=",
+      "timestamp": "MTczODkyNzQ4NjYxNA==",
+      "nonce": "ImsqzauVjlNYfS5/eHNQ6g==",
+      "tokenDigest": "VEix9E/2BmVZDGn+2WLljrP59/thd6Og2Vy/yMPOfDM="
+    },
+    {
+      "tokenSecret": "vzoC99o0btvpvMlcDFQJV6RUmnwWFHYdRTuP11qQbnQ=",
+      "timestamp": "MTczODkyNzQ4NjYxNg==",
+      "nonce": "SLNkDo32VjNdktaqN8hjGw==",
+      "tokenDigest": "MXCgpcQkSA/bZDu+NUn1SM/+UeJYKto7v01ji4EDCk8="
+    },
+    {
+      "tokenSecret": "kzqhkQ9Uz02Bfq8qMYiM+y6tcXM/L2d9WJzy4yz2T14=",
+      "timestamp": "MTczODkyNzQ4NjYxOA==",
+      "nonce": "5DM7IJOTj6FZCwKdvwNldA==",
+      "tokenDigest": "b88xNMeY6iAkDL90kvVLSKlZyqz7IgzosV2s5O2R+JA="
+    },
+    {
+      "tokenSecret": "oLKcosBQrVGtvvbg05kQK/KrgufEJPmXx8vhcG9JzUQ=",
+      "timestamp": "MTczODkyNzQ4NjYyMA==",
+      "nonce": "ma0Muc8w26p6m1XG54vDvQ==",
+      "tokenDigest": "unblBLyB4RXY55vmxe+kSJ7qghZGFHznoeong12QC4o="
+    },
+    {
+      "tokenSecret": "sikVf4h9o+LIs6ioowKztMBzPFJVoCia4QpHmzsaDS4=",
+      "timestamp": "MTczODkyNzQ4NjYyMQ==",
+      "nonce": "dIv9UT4YevY4tK1p2Ed4+A==",
+      "tokenDigest": "Nwe0y6dhUPrn4D+OYX2inSwwySs2a8Ov+PdVobFsRdU="
+    },
+    {
+      "tokenSecret": "9e1edmhK/76voDyk6UUfxx7PnzN2lz5Xb3HwzYh7CyA=",
+      "timestamp": "MTczODkyNzQ4NjYyMw==",
+      "nonce": "U7w2mds6sZ16IT4eHNZUOg==",
+      "tokenDigest": "tw0axVVSG89AKPjCsKbnPptQOQlnXf/Nv9fbCp3GnLM="
+    },
+    {
+      "tokenSecret": "0HNURFOMq2Bo3xS43in9F840x1wfloIffbbWOCstoSk=",
+      "timestamp": "MTczODkyNzQ4NjYyNQ==",
+      "nonce": "jnnNCSTKQqtk+4vA7YxR5Q==",
+      "tokenDigest": "ZJWKMVyu/4DgueE48grP7UiXeebhW9/VX+4gVzzljvs="
+    },
+    {
+      "tokenSecret": "6kJVJdRU7z7xcZhCDwZ6A28HivZwyXx8R72kcUO7eGs=",
+      "timestamp": "MTczODkyNzQ4NjYyNw==",
+      "nonce": "OLgS5cVfkmm18Uec7bGeYg==",
+      "tokenDigest": "etw9UTLqkoKG5dju0M4coZ598ipnlgCecGJDuue7pE0="
+    },
+    {
+      "tokenSecret": "rmYdkOA48TUuj8Gr346paxlvcn939Oj+zJ+eAnTnsdo=",
+      "timestamp": "MTczODkyNzQ4NjYyOA==",
+      "nonce": "dYZ2gh2ed7R0tJGqUfNw0A==",
+      "tokenDigest": "xdNLOjHgtnFh5vs939Vq8XhTZG2nlOT6qgazFT6VosQ="
+    },
+    {
+      "tokenSecret": "kyv/38E9S7deWEVNbcWALFwY8p4mrTA/i+F8tgOE7iA=",
+      "timestamp": "MTczODkyNzQ4NjYzMA==",
+      "nonce": "38UsMgB7j3AiyBJjaMW97g==",
+      "tokenDigest": "NSsMBakEoz3BBOMTXAtdOJcUhrhWMzVsN++mgQWiSFc="
+    },
+    {
+      "tokenSecret": "BaF4iyCMG6SDgZbjtOu05bHfZNyCSIbJP56CgQT4wDE=",
+      "timestamp": "MTczODkyNzQ4NjYzMg==",
+      "nonce": "IczchU654G8CewbbZhN5Iw==",
+      "tokenDigest": "+NqCvmRWs5l3Wz9qZrqX0uoHqC8KRC9+8q2FzMws2Rs="
+    },
+    {
+      "tokenSecret": "yvrS21SCU7sewV1cUsqegy/NY1zilojmB75n3qhwxwY=",
+      "timestamp": "MTczODkyNzQ4NjYzNA==",
+      "nonce": "y4ulYXCB/guJlwo2rxY8jw==",
+      "tokenDigest": "SKofbD2ll2s6KCy5V8v1VxaRlc/X4ixD+tV9GyMQb5Q="
+    },
+    {
+      "tokenSecret": "kyf75bg++/iXGHDxRyGX/kkcpaI7CwFVyB8Fule2lHo=",
+      "timestamp": "MTczODkyNzQ4NjYzNg==",
+      "nonce": "5Ny77qn9Eixd73c3CTeeeA==",
+      "tokenDigest": "/TdvDZNagRZTRbUo2qRRaGQrgZ2xYdzlaH+8i4D8hmw="
+    },
+    {
+      "tokenSecret": "x65yrpvu0bZafNDoW7d475j7IKhc9WXpijmDWZt+uk4=",
+      "timestamp": "MTczODkyNzQ4NjYzOA==",
+      "nonce": "9xMTmNwzOj9VzGxaFQhzBw==",
+      "tokenDigest": "qXwjCOG5J+xGW2N9gxHvpxaUXlZqBl1bnggz7cvx1dc="
+    },
+    {
+      "tokenSecret": "zm77cOpgCVCR1bX+QCHefcFyaPKPdK9kudAFVfZlr7c=",
+      "timestamp": "MTczODkyNzQ4NjY0MA==",
+      "nonce": "KgAXJpWvcmJKEbHE00Uxiw==",
+      "tokenDigest": "9PNEvpAG8y/7AEl3su1q4uvOzFuifTGWhN5V6v0QPgI="
+    },
+    {
+      "tokenSecret": "XV0MBOHqf0d8XevjnQ/WeT+3/oRU29AbmcFYzOdcJhQ=",
+      "timestamp": "MTczODkyNzQ4NjY0MQ==",
+      "nonce": "5jc+z6PFSVDZQE9p9NVm+Q==",
+      "tokenDigest": "ymglypgylqhwxF2X0ANu26Ka3cMz8G31OlI6N+UIW0c="
+    },
+    {
+      "tokenSecret": "knt30HVgM9BZ/bxCQ3lIWwkY0hMlYj1wTWypclcBGro=",
+      "timestamp": "MTczODkyNzQ4NjY0Mw==",
+      "nonce": "7UCWL33e8RFb1umYNRYUfg==",
+      "tokenDigest": "Vpw9kyFA3nDydHUpt9jRIA1DvHZvech2k/Mf7Ehx42o="
+    },
+    {
+      "tokenSecret": "leraYhdOst8wAbLfiE3sJBBoUdHYz28OaspA29xqxrU=",
+      "timestamp": "MTczODkyNzQ4NjY0NA==",
+      "nonce": "PNU11814qcjJl0VVuTy4Xw==",
+      "tokenDigest": "AZ4zj/2ff/56BODgcSc6wVA1XjTnum9wV5xkhsWDuUM="
+    },
+    {
+      "tokenSecret": "FTR+efLwPgPY1zxnVTviDg/roZdnGxXnc9vRHquYXnI=",
+      "timestamp": "MTczODkyNzQ4NjY0Ng==",
+      "nonce": "HcBW5d87tFW/1UdvVWrODg==",
+      "tokenDigest": "WyWEzR6/VXJusiEshS0nlWVQVGMpp7GQNX43KPHFIZ0="
+    },
+    {
+      "tokenSecret": "cxXZkp354XUu4ujCrjWP4NdYtArGETmLnr5JEn1UMIk=",
+      "timestamp": "MTczODkyNzQ4NjY0OA==",
+      "nonce": "Vzpy4l3S3qeNaetANXCx4g==",
+      "tokenDigest": "ci44AXmzu0DQ7plvL+CO6+XsBWR+qBDF/DTiLCfW8N4="
+    },
+    {
+      "tokenSecret": "94a8ISor8+PQ2tVCQkHm19cdfU/DPClspL5PFiS9xeA=",
+      "timestamp": "MTczODkyNzQ4NjY0OQ==",
+      "nonce": "Z87Z1cNs2159G+6Wj6Pflg==",
+      "tokenDigest": "Di97/+pB/hdRGmxZcsWqzAXCeRT6v53h/QVnurreuWk="
+    },
+    {
+      "tokenSecret": "wI7KyIZO8CXYp6DMlQ3hce9gjL5hs7+4noGUMvkNxmw=",
+      "timestamp": "MTczODkyNzQ4NjY1Mg==",
+      "nonce": "221ghEJfEL2FewT6zv8+PA==",
+      "tokenDigest": "IYL/5HHQfLqGnlnjh+TWdUKUse+rxrGJieFCpXoAxL4="
+    },
+    {
+      "tokenSecret": "nOCHItM3Ls1+SQMVv9XlMwI8SYzLDeyF72QXSewqtU0=",
+      "timestamp": "MTczODkyNzQ4NjY1NA==",
+      "nonce": "HVtsinlRCvVM+6/rOIBXhg==",
+      "tokenDigest": "5hUu0uQBCk+7TBHK233DaXF6MKNBlOvUjsrowdk6Dh0="
+    },
+    {
+      "tokenSecret": "bvLW6xTaWrzOipNjP4pYWvSQD7kflLyCGC+rfAzVBJM=",
+      "timestamp": "MTczODkyNzQ4NjY1NQ==",
+      "nonce": "c1P30fbUYGmMI5qs0t69tQ==",
+      "tokenDigest": "bb8wJ9hQ5Z/W9mkVCO05X7l1N9ZcByZcxBQhEIyCkKU="
+    },
+    {
+      "tokenSecret": "JWd1rvwkorGh+3mM+oKBhVY2pNVQVVqB1VNokGI3bsw=",
+      "timestamp": "MTczODkyNzQ4NjY1Nw==",
+      "nonce": "G8GidK4yew//mYahq8mIzw==",
+      "tokenDigest": "M/+2NZn558ssFQFx2Ly2eDZZ+cbPyQhq9Ep/G0q1RSE="
+    },
+    {
+      "tokenSecret": "kxobMG2yo1eHGtz70/gy8/5O7lpORRpAwYCBS282xNc=",
+      "timestamp": "MTczODkyNzQ4NjY1OQ==",
+      "nonce": "1eRqBU7Y52qvp+/zd9pKPA==",
+      "tokenDigest": "9XNTKUzmuhWn75oEqLZgTExsD3V+7A2sS32UrDEFfWo="
+    },
+    {
+      "tokenSecret": "AQSvBRXWaMWpMAuKrBf3E5HgEx7pyMPOTSJ+YfXJZdE=",
+      "timestamp": "MTczODkyNzQ4NjY2MA==",
+      "nonce": "mEkQBFWE8seGA/3D4qmMKA==",
+      "tokenDigest": "Q/9fs4WGCtdX8qDBt0llKKw84OWowpiRpXpuWE4IGAg="
+    },
+    {
+      "tokenSecret": "9d0Cd+WHlyXO28MX9zD50Rmcs2S8ZintIN5Ha1d75es=",
+      "timestamp": "MTczODkyNzQ4NjY2Mg==",
+      "nonce": "k/G2/5CW5U7WaTT7wVJqEw==",
+      "tokenDigest": "ktmZw8nYGusfL9E16tRehdpD/RBtq9dDL4TEYIc5cNk="
+    },
+    {
+      "tokenSecret": "3yY+XmLcIGSDGuxN5O1rAiULSPaNloPKhTaY3WgoVZU=",
+      "timestamp": "MTczODkyNzQ4NjY2Mw==",
+      "nonce": "foTDn8gqUE6jcYjNWIZqaQ==",
+      "tokenDigest": "ZItl1zCaa5vZHAuMV1u+3woMpZaYGV0eqJ1PreDica4="
+    },
+    {
+      "tokenSecret": "9HmWRT4LQexnxfkwjsxYQ/dQcmvitBl/DpG7twXYR7k=",
+      "timestamp": "MTczODkyNzQ4NjY2NA==",
+      "nonce": "139sqy8BsB4eNqDdZcDO9g==",
+      "tokenDigest": "eQ07hdy0Gfuh3nU6js4dZoKkzRVBEXbv9TgegBZuDuc="
+    },
+    {
+      "tokenSecret": "v6jk5y3oT2w38s+D1IlufNZeuBdfIs+j7M/ebprcYxU=",
+      "timestamp": "MTczODkyNzQ4NjY2Ng==",
+      "nonce": "FMiQ8KSSAAvCF4pq6xF/rg==",
+      "tokenDigest": "PaKbeeG8h2e2vTOnlP35049C5fO8AbEkJrNs9h7mA2s="
+    },
+    {
+      "tokenSecret": "TQ1QH/YefGa+oLt9NR1XkouqUjDibObcqgvVSG5/SiA=",
+      "timestamp": "MTczODkyNzQ4NjY2Nw==",
+      "nonce": "b0SFczwS8Uv84gYhiittxA==",
+      "tokenDigest": "MyHSTxU49kQD98mbT+hW4bGsq2UvRxVm5B9AaNtmHew="
+    },
+    {
+      "tokenSecret": "ClFzdcVEpeY82hsqVVYQsFfRfHPFrLQBqrOyQ8WV3kM=",
+      "timestamp": "MTczODkyNzQ4NjY2OQ==",
+      "nonce": "0ekly+sXqGYN2gjuNQEp+A==",
+      "tokenDigest": "4HeS6kNCaiuqQfXolgFMdSDBRRz4aNJQFSH0im4NUFc="
+    },
+    {
+      "tokenSecret": "LHzFyPt+RPtkLks4rVdi8mIgm/Z5BqXU1hY/nwJP7ho=",
+      "timestamp": "MTczODkyNzQ4NjY3MA==",
+      "nonce": "OV2+H9QxrRd74BZWnq7BQg==",
+      "tokenDigest": "nFWe6i2FLSczJuBUbP8+/3keFnjyXhzAST06qZ4WMzY="
+    },
+    {
+      "tokenSecret": "dAQMszmCmE2DWEUIoOvFwd3Cdt/vg1SrC1w+FoZKPZM=",
+      "timestamp": "MTczODkyNzQ4NjY3Mg==",
+      "nonce": "SbDoElDdrIDZyD9oSCxBKA==",
+      "tokenDigest": "6/CmDU0QUkHGVKb8+93F+K0gO2FqV4NXSp/v8maRJkU="
+    },
+    {
+      "tokenSecret": "X1etweH4di0xpUij7jszh3B//tIKDAl5s6Zf6ocoN2k=",
+      "timestamp": "MTczODkyNzQ4NjY3Mw==",
+      "nonce": "107WQGyd7+rqcSDwoZAIJw==",
+      "tokenDigest": "TGZCsWP8H55fQLg//jkvSgmnghI8GiSiHWNR9gm1P2o="
+    },
+    {
+      "tokenSecret": "nouwvkmPj6JrG/Hl9uUc9BoIWuSJnYSM86G/o5xtlwY=",
+      "timestamp": "MTczODkyNzQ4NjY3NA==",
+      "nonce": "NMSDVgrYzca9paL2oY2oCA==",
+      "tokenDigest": "5xTf0dhFA9eJ5iaf3eMSS2mB91e6JbhoPz45sO+xkJk="
+    },
+    {
+      "tokenSecret": "xMYdIOr3TmuKWzP/4cTq7rSYJR8c496/jzlrXQk/t9M=",
+      "timestamp": "MTczODkyNzQ4NjY3Ng==",
+      "nonce": "LHLqSjI5CtMEZNM/KYqkxQ==",
+      "tokenDigest": "jrah+khPmlAGUjz0Xf6Epk9DtdfLKs/V+cgrNLwE9bI="
+    },
+    {
+      "tokenSecret": "65k9GB6V+F2E3xCcUELJ30glkOnFsTOF6H3oBgi3j4s=",
+      "timestamp": "MTczODkyNzQ4NjY3Nw==",
+      "nonce": "NnOAEmoMfVcqd/83YdPF2g==",
+      "tokenDigest": "KWcc1UcACgj1Meb+pYFOg0riSIzoJsxSj3LvlADI+Qk="
+    },
+    {
+      "tokenSecret": "85YRU4mg2XAs/teWXMx3YExeFfSYCrIyVgzwpnDz13I=",
+      "timestamp": "MTczODkyNzQ4NjY3OQ==",
+      "nonce": "FL0vOx+tmTDItdRm45DQXA==",
+      "tokenDigest": "u8uDqqwjcTyprIoqKr/VXSqWNcTJ/01ksvZSJZZfkAw="
+    },
+    {
+      "tokenSecret": "GDmIYFPzbRDTxqjU+1zwObzV+w+TKquBJ1OGq8EqRrM=",
+      "timestamp": "MTczODkyNzQ4NjY4MA==",
+      "nonce": "uzmhFTtioftS+dN5sLB2+A==",
+      "tokenDigest": "xDCgAomUnI8p8t94r4rXpKMK49kL1hV5tLXeR5epBWw="
+    },
+    {
+      "tokenSecret": "pk4MA22Y0o5A+7MM/WYW5d1X5InRx/QZNSpL+ILGK/U=",
+      "timestamp": "MTczODkyNzQ4NjY4Mg==",
+      "nonce": "1UIFMzl20tP1jF8HVUmAjg==",
+      "tokenDigest": "F/oXj45OJ7D0SxKvNn97rDCwm2xMsQPVyNt7FcsaO1I="
+    },
+    {
+      "tokenSecret": "qnBvp1OseYs6pMbv9qsLypxuGkx1zsNlGBztfRp6R50=",
+      "timestamp": "MTczODkyNzQ4NjY4NA==",
+      "nonce": "VSfkIzU12A46YyBtyYGa/A==",
+      "tokenDigest": "7F+Oz7hwzHNSt/dQHTGFirIeSKH4tlcwYKd0gEe7KYM="
+    },
+    {
+      "tokenSecret": "zorXwLFzGtEX1E768vhWOmRqeg8tV5w0Dbwpga4c+nc=",
+      "timestamp": "MTczODkyNzQ4NjY4NQ==",
+      "nonce": "+rUdLlJrGLQCC0DzMsRseA==",
+      "tokenDigest": "SIxylzvvifo6AA07xLD878TbbfrcUHOcgbxHvdSbmqo="
+    },
+    {
+      "tokenSecret": "FW9O1jXDCLpt7+K0ymQiDR7BsxwRyvzemO0DS6sdvOo=",
+      "timestamp": "MTczODkyNzQ4NjY4Nw==",
+      "nonce": "IK6jPLgj++SljxDxekm7ug==",
+      "tokenDigest": "Ib+cm0Ez0biG4WcIHGyq95douUaN8HVtKvoYCuVQ3pI="
+    },
+    {
+      "tokenSecret": "hK+ssCHAbxRtsrM/95pcS+zpKNhvT0WSkH3y2kO5BOE=",
+      "timestamp": "MTczODkyNzQ4NjY4OA==",
+      "nonce": "5jlvQl5obAnp4Wh2pSQtKA==",
+      "tokenDigest": "eS5oAiM8l2DwfqqWrlqVFH0104aJ9+LWXqZCpARmCAg="
+    },
+    {
+      "tokenSecret": "tzXOCs7/zwRVHG9x7CzefbzxrJFyRZOc6BSoqToOl20=",
+      "timestamp": "MTczODkyNzQ4NjY5MA==",
+      "nonce": "Dr8bNwNATBLE3gaO7JetxA==",
+      "tokenDigest": "sz7TLvRz4A4Nq2gsTgcFp3oF81AlPu2ClHxTzUZDRXs="
+    },
+    {
+      "tokenSecret": "2y1bUTUB3JvNPItDtVXafrnxio+NDUlgkj7cGhiyoJg=",
+      "timestamp": "MTczODkyNzQ4NjY5MQ==",
+      "nonce": "x+fYX303g2y7KO0c9JkWBA==",
+      "tokenDigest": "YDsddBWP2THltHBXKmpZ0T8T/0IfHiQoaJlCgluytw4="
+    },
+    {
+      "tokenSecret": "mvk5rKoF2apsh1lG9FuR5hDB5o8EYIwrvKD8Qp9HTvI=",
+      "timestamp": "MTczODkyNzQ4NjY5Mw==",
+      "nonce": "JSPEufixiHBQK2+IOuFFuA==",
+      "tokenDigest": "QorAXThdcc/9BpFNnVCJf67oO2hslERAFZZ2BfxT2ok="
+    },
+    {
+      "tokenSecret": "9NfLvOAR+xHsUrtantEGOq26MjBNBULM5onSWH0jpMM=",
+      "timestamp": "MTczODkyNzQ4NjY5NQ==",
+      "nonce": "C5AE3jl0V756+sSjSN38NA==",
+      "tokenDigest": "/pFP93fp3XOicnlpFXSMpOfabHsMuY9LiZflxnIUc5w="
+    },
+    {
+      "tokenSecret": "GTqwpZOL94m932NcYNe/+MqcZQ96TocFx/Y7OTLVhkY=",
+      "timestamp": "MTczODkyNzQ4NjY5Ng==",
+      "nonce": "t+c0KTq6hSbCtTh2jp5J7A==",
+      "tokenDigest": "b+1ZDh1QsHJopTrJ8J4rbAC+MLXpWO69PsSIVzY9Ybc="
+    },
+    {
+      "tokenSecret": "QCa12QQ+nlmmjVjbZK7nXYcq0TnHHSxvB6CUCW3mtVU=",
+      "timestamp": "MTczODkyNzQ4NjY5Nw==",
+      "nonce": "oCs+aLljfkvjl8Vy7bCgpA==",
+      "tokenDigest": "nWtwy+O5BMGZU6DPY7yXau3223mDFGwkjpEF05VLd4A="
+    },
+    {
+      "tokenSecret": "U1HGPXI2eC6BNiuh01bLLBri8PvPomSUNG+3ODbe15Q=",
+      "timestamp": "MTczODkyNzQ4NjY5OQ==",
+      "nonce": "i15pRc4o0ByTO2+OGOaS3w==",
+      "tokenDigest": "fJlpXJs4FJbnkP+vgfN2KDaHnEc5Awkf1xK+e7eYcrI="
+    },
+    {
+      "tokenSecret": "U/B0dhzScxW4onGb89r5Y/mPrbcFtr99EtLbtcVniy0=",
+      "timestamp": "MTczODkyNzQ4NjcwMA==",
+      "nonce": "hs0TXaNJ4vZsReeaQqYW/g==",
+      "tokenDigest": "0y5tS7DDRFKtNkkYljQAanucOc7gav2fIlhcYKWSQLo="
+    },
+    {
+      "tokenSecret": "WAnqV9RBmPCnZ0+Cl0YdJ/6xfIdOJV8r20H6LI+ffZs=",
+      "timestamp": "MTczODkyNzQ4NjcwMQ==",
+      "nonce": "6k4LWzJag16KqCW7PgVVeA==",
+      "tokenDigest": "oeKpG3VgSI3Aed/HPwaD3fxr4iDJO0bSQMr003dLC+Y="
+    },
+    {
+      "tokenSecret": "j9uALYVUwW92LhbT/opHYgMQe86J0ZiuaIamdH353mI=",
+      "timestamp": "MTczODkyNzQ4NjcwMg==",
+      "nonce": "IqYb83byw08tkZjwzSJ3nQ==",
+      "tokenDigest": "502dhdYPi9JC00zU1GT+ulKx4HhPwecSJ99Uwj/ZiWI="
+    },
+    {
+      "tokenSecret": "JLvos4/ku6pitP2/AAvIvp7PhuPYLvRH1eRp/I9dDrQ=",
+      "timestamp": "MTczODkyNzQ4NjcwMw==",
+      "nonce": "D/aPK8at1Bg2D3FnNgn/Mg==",
+      "tokenDigest": "YTfwUSIaysJG3gDjObX1EX8etVr4DMxFlDOZVLuFQK0="
+    },
+    {
+      "tokenSecret": "jTeAVoJlMKMe3HD8NqoIsLI8vRG+OtpSSrCCKTtF2Gg=",
+      "timestamp": "MTczODkyNzQ4NjcwNQ==",
+      "nonce": "5ZCiFoNswxCExLrlPF4DRA==",
+      "tokenDigest": "S234y1bX7UW451TZFdrh82zR6sQo0lv+qPdchk9skP0="
+    },
+    {
+      "tokenSecret": "D3L5PIid7Xc2gVODiAHBYnOWFwOMkL8U0NayTB+5IiQ=",
+      "timestamp": "MTczODkyNzQ4NjcwNg==",
+      "nonce": "tcbnDyMQs4cDdtsWSTK59A==",
+      "tokenDigest": "MwFW6nhnNJlRHctMyYwFY/88QSg7dWpAhiwqBY4A4Lo="
+    }
+  ]
+}
\ No newline at end of file