diff --git a/README.md b/README.md index 046647e9..2563c8ed 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ alternative for the cases when using a real Key Vault is not practical or imposs ### Warning! -> Lowkey Vault is NOT intended as a [Azure Key Vault](https://azure.microsoft.com/en-us/services/key-vault/) replacement. Please do not attempt using it instead of the real service in production as it is not using any security measures to keep your secrets safe. +> Lowkey Vault is NOT intended as an [Azure Key Vault](https://azure.microsoft.com/en-us/services/key-vault/) replacement. Please do not attempt using it instead of the real service in production as it is not using any security measures to keep your secrets safe. ### Valid use-cases @@ -54,7 +54,7 @@ I have an app using Azure Key Vault and: ### Docker 1. Pull the most recent version from ```nagyesta/lowkey-vault``` -2. ```docker run lowkey-vault: -p 8443:8443``` +2. ```docker run --rm -p 8443:8443 nagyesta/lowkey-vault:``` 3. Use ```https://localhost:8443``` as key vault URI when using the [Azure Key Vault Key client](https://docs.microsoft.com/en-us/azure/key-vault/keys/quick-create-java) or the [Azure Key Vault Secret client](https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-java) diff --git a/lowkey-vault-client/src/main/java/com/github/nagyesta/lowkeyvault/http/management/LowkeyVaultManagementClient.java b/lowkey-vault-client/src/main/java/com/github/nagyesta/lowkeyvault/http/management/LowkeyVaultManagementClient.java index 571f2632..b45b0c71 100644 --- a/lowkey-vault-client/src/main/java/com/github/nagyesta/lowkeyvault/http/management/LowkeyVaultManagementClient.java +++ b/lowkey-vault-client/src/main/java/com/github/nagyesta/lowkeyvault/http/management/LowkeyVaultManagementClient.java @@ -2,6 +2,7 @@ import lombok.NonNull; +import java.io.IOException; import java.net.URI; import java.util.List; import java.util.function.Supplier; @@ -26,4 +27,8 @@ VaultModel createVault(@NonNull URI baseUri, boolean purge(@NonNull URI baseUri); void timeShift(@NonNull TimeShiftContext context); + + String unpackBackup(byte[] backup) throws IOException; + + byte[] compressBackup(String backup) throws IOException; } diff --git a/lowkey-vault-client/src/main/java/com/github/nagyesta/lowkeyvault/http/management/impl/LowkeyVaultManagementClientImpl.java b/lowkey-vault-client/src/main/java/com/github/nagyesta/lowkeyvault/http/management/impl/LowkeyVaultManagementClientImpl.java index 92f3cc0b..865de4ed 100644 --- a/lowkey-vault-client/src/main/java/com/github/nagyesta/lowkeyvault/http/management/impl/LowkeyVaultManagementClientImpl.java +++ b/lowkey-vault-client/src/main/java/com/github/nagyesta/lowkeyvault/http/management/impl/LowkeyVaultManagementClientImpl.java @@ -14,10 +14,16 @@ import org.apache.http.HttpHeaders; import reactor.util.annotation.Nullable; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.function.Function; import java.util.function.Supplier; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; import static com.azure.core.http.ContentType.APPLICATION_JSON; import static com.github.nagyesta.lowkeyvault.http.management.impl.ResponseEntity.VAULT_MODEL_LIST_TYPE_REF; @@ -129,6 +135,30 @@ public void timeShift(@NonNull final TimeShiftContext context) { sendRaw(request); } + @Override + public String unpackBackup(final byte[] backup) throws IOException { + final byte[] nonNullBackup = Optional.ofNullable(backup) + .orElseThrow(() -> new IllegalArgumentException("Backup cannot be null")); + //noinspection LocalCanBeFinal + try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(nonNullBackup); + GZIPInputStream gzipInputStream = new GZIPInputStream(byteArrayInputStream)) { + final String json = new String(gzipInputStream.readAllBytes()); + return objectReader.readTree(json).toPrettyString(); + } + } + + @Override + public byte[] compressBackup(@NonNull final String backup) throws IOException { + //noinspection LocalCanBeFinal + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream)) { + gzipOutputStream.write(backup.getBytes(StandardCharsets.UTF_8)); + gzipOutputStream.flush(); + gzipOutputStream.finish(); + return byteArrayOutputStream.toByteArray(); + } + } + String vaultModelAsString(final URI baseUri, final RecoveryLevel recoveryLevel, final Integer recoverableDays) { try { return objectWriter.writeValueAsString(new VaultModel(baseUri, recoveryLevel, recoverableDays, null, null)); diff --git a/lowkey-vault-client/src/test/java/com/github/nagyesta/lowkeyvault/http/management/impl/LowkeyVaultManagementClientImplTest.java b/lowkey-vault-client/src/test/java/com/github/nagyesta/lowkeyvault/http/management/impl/LowkeyVaultManagementClientImplTest.java index 1392cb3a..bb716b6e 100644 --- a/lowkey-vault-client/src/test/java/com/github/nagyesta/lowkeyvault/http/management/impl/LowkeyVaultManagementClientImplTest.java +++ b/lowkey-vault-client/src/test/java/com/github/nagyesta/lowkeyvault/http/management/impl/LowkeyVaultManagementClientImplTest.java @@ -5,6 +5,7 @@ import com.azure.core.http.HttpRequest; import com.azure.core.http.HttpResponse; import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import com.fasterxml.jackson.databind.ObjectWriter; @@ -21,6 +22,8 @@ import org.mockito.*; import reactor.core.publisher.Mono; +import java.io.IOException; +import java.math.BigInteger; import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.Collections; @@ -35,6 +38,8 @@ class LowkeyVaultManagementClientImplTest { + public static final String SIMPLE_JSON = "{\"property\":42}"; + public static final String SIMPLE_JSON_PRETTY = "{\n\t\"property\": 42\n}"; private static final String HTTPS_LOCALHOST = "https://localhost"; private static final String JSON = "{}"; private static final int RECOVERABLE_DAYS = 90; @@ -474,5 +479,58 @@ void testSendAndProcessShouldThrowExceptionWhenResponseCodeIsNot2xx() throws Jso verify(objectReader, never()).forType(eq(VaultModel.class)); verify(objectReader, never()).readValue(anyString()); } + + @Test + void testUnpackBackupShouldThrowExceptionWhenCalledWithNull() { + //given + + //when + Assertions.assertThrows(IllegalArgumentException.class, () -> underTest.unpackBackup(null)); + + //then + exception + } + + @SuppressWarnings("ConstantConditions") + @Test + void testCompressBackupShouldThrowExceptionWhenCalledWithNull() { + //given + + //when + Assertions.assertThrows(IllegalArgumentException.class, () -> underTest.compressBackup(null)); + + //then + exception + } + + @Test + void testUnpackBackupShouldProduceFormattedJsonWhenCalledWithValidInput() throws IOException { + //given + final byte[] input = underTest.compressBackup(SIMPLE_JSON); + final JsonNode node = mock(JsonNode.class); + when(objectReader.readTree(eq(SIMPLE_JSON))).thenReturn(node); + when(node.toPrettyString()).thenReturn(SIMPLE_JSON_PRETTY); + + //when + final String actual = underTest.unpackBackup(input); + + //then + Assertions.assertEquals(SIMPLE_JSON_PRETTY, actual); + final InOrder inOrder = inOrder(objectReader, node); + inOrder.verify(objectReader).readTree(eq(SIMPLE_JSON)); + inOrder.verify(node).toPrettyString(); + verifyNoMoreInteractions(objectReader, node); + } + + @Test + void testCompressBackupShouldProduceGzipBytesWhenCalledWithValidInput() throws IOException { + //given + final byte[] out = new BigInteger("239366333208093937709170404274988390036218345476049221665072896269330010352532848640") + .toByteArray(); + + //when + final byte[] actual = underTest.compressBackup(SIMPLE_JSON); + + //then + Assertions.assertArrayEquals(out, actual); + } } } diff --git a/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/context/KeyTestContext.java b/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/context/KeyTestContext.java index a773f243..1d2e0305 100644 --- a/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/context/KeyTestContext.java +++ b/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/context/KeyTestContext.java @@ -5,18 +5,18 @@ import com.azure.security.keyvault.keys.cryptography.models.DecryptResult; import com.azure.security.keyvault.keys.cryptography.models.EncryptResult; import com.azure.security.keyvault.keys.models.*; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.nagyesta.lowkeyvault.http.ApacheHttpClientProvider; +import com.github.nagyesta.lowkeyvault.http.management.LowkeyVaultManagementClient; import javax.crypto.SecretKey; import java.security.KeyPair; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; import java.util.Optional; public class KeyTestContext extends CommonTestContext { - public static final OffsetDateTime NOW = OffsetDateTime.now(ZoneOffset.UTC); - + private final ObjectMapper objectMapper = new ObjectMapper(); + private LowkeyVaultManagementClient lowkeyVaultManagementClient; private CryptographyClient cryptographyClient; private CreateRsaKeyOptions createRsaKeyOptions; private CreateEcKeyOptions createEcKeyOptions; @@ -38,6 +38,13 @@ protected KeyClient providerToClient(final ApacheHttpClientProvider provider) { return provider.getKeyClient(); } + public synchronized LowkeyVaultManagementClient getLowkeyVaultManagementClient() { + if (lowkeyVaultManagementClient == null) { + lowkeyVaultManagementClient = getProvider().getLowkeyVaultManagementClient(objectMapper); + } + return lowkeyVaultManagementClient; + } + public CryptographyClient getCryptographyClient() { return cryptographyClient; } diff --git a/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/CommonAssertions.java b/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/CommonAssertions.java index 6e8fc657..f3b094dd 100644 --- a/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/CommonAssertions.java +++ b/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/CommonAssertions.java @@ -2,10 +2,12 @@ import org.testng.Assert; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.*; +import java.util.stream.Collectors; public class CommonAssertions { @@ -53,4 +55,13 @@ protected void assertByteArrayLength(final int byteArrayLength, final byte[] byt assertTrue("Byte array was " + bytes.length + " long, expected " + byteArrayLength + " (+/-1 tolerance)", byteArrayLength - 1 <= bytes.length && byteArrayLength + 1 >= bytes.length); } + + protected String readResourceContent(final String resource) throws IOException { + //noinspection LocalCanBeFinal + try (InputStream stream = getClass().getResourceAsStream(resource); + InputStreamReader reader = new InputStreamReader(Objects.requireNonNull(stream)); + BufferedReader bufferedReader = new BufferedReader(reader)) { + return bufferedReader.lines().collect(Collectors.joining(System.lineSeparator())); + } + } } diff --git a/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/KeysStepDefs.java b/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/KeysStepDefs.java index 42210bbc..b9d1a8c2 100644 --- a/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/KeysStepDefs.java +++ b/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/KeysStepDefs.java @@ -17,6 +17,9 @@ import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.spec.IvParameterSpec; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.nio.charset.StandardCharsets; import java.security.*; import java.util.Arrays; @@ -117,6 +120,9 @@ public void ecKeyImportedWithNameAndParameters(final String name, final KeyCurve context.setKeyPair(keyPair); final JsonWebKey key = JsonWebKey.fromEc(keyPair, new BouncyCastleProvider()) .setKeyOps(List.of(KeyOperation.SIGN, KeyOperation.ENCRYPT, KeyOperation.WRAP_KEY)); + if (hsm) { + key.setKeyType(KeyType.EC_HSM); + } final ImportKeyOptions options = new ImportKeyOptions(name, key) .setHardwareProtected(hsm); final KeyVaultKey ecKey = context.getClient().importKey(options); @@ -129,6 +135,9 @@ public void rsaKeyImportedWithNameAndParameters(final String name, final int siz context.setKeyPair(keyPair); final JsonWebKey key = JsonWebKey.fromRsa(keyPair) .setKeyOps(List.of(KeyOperation.SIGN, KeyOperation.ENCRYPT, KeyOperation.WRAP_KEY)); + if (hsm) { + key.setKeyType(KeyType.RSA_HSM); + } final ImportKeyOptions options = new ImportKeyOptions(name, key) .setHardwareProtected(hsm); final KeyVaultKey rsaKey = context.getClient().importKey(options); @@ -393,6 +402,17 @@ public void theKeyNamedNameIsBackedUp(final String name) { context.setBackupBytes(name, bytes); } + @And("the key named {name} is backed up to resource") + public void theKeyNamedNameIsBackedUpToResource(final String name) throws IOException { + final byte[] bytes = context.getClient().backupKey(name); + final String s = context.getLowkeyVaultManagementClient().unpackBackup(bytes); + final File file = new File("/home/esta/IdeaProjects/github/lowkey-vault/lowkey-vault-docker/src/test/resources" + + "/json/backups/" + name + ".json"); + file.createNewFile(); + new FileWriter(file).append(s).close(); + context.setBackupBytes(name, bytes); + } + @And("the key named {name} is restored") public void theKeyNamedNameIsRestored(final String name) { final byte[] bytes = context.getBackupBytes(name); @@ -400,6 +420,14 @@ public void theKeyNamedNameIsRestored(final String name) { context.addFetchedKey(name, key); } + @And("the key named {name} is restored from classpath resource") + public void theKeyIsRestoredFromClasspath(final String name) throws IOException { + final String content = readResourceContent("/json/backups/" + name + ".json"); + final byte[] bytes = context.getLowkeyVaultManagementClient().compressBackup(content); + final KeyVaultKey key = context.getClient().restoreKeyBackup(bytes); + context.addFetchedKey(key.getName(), key); + } + private byte[] hash(final byte[] text, final String algorithm) { try { final MessageDigest md = MessageDigest.getInstance("SHA-" + algorithm.substring(2, 5)); diff --git a/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/KeysStepDefsAssertions.java b/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/KeysStepDefsAssertions.java index 6356a282..076424fa 100644 --- a/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/KeysStepDefsAssertions.java +++ b/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/KeysStepDefsAssertions.java @@ -7,6 +7,7 @@ import io.cucumber.java.en.Then; import org.springframework.beans.factory.annotation.Autowired; +import java.io.IOException; import java.time.temporal.ChronoUnit; import java.util.Collections; import java.util.LinkedList; @@ -168,4 +169,12 @@ public void theKeyNamedNameMatchesThePreviousBackup(final String name) { final byte[] bytes = context.getClient().backupKey(name); assertEquals(context.getBackupBytes(name), bytes); } + + @And("the unpacked backup of {name} matches the content of the classpath resource") + public void theKeyNamedNameMatchesTheResourceContent(final String name) throws IOException { + final byte[] bytes = context.getClient().backupKey(name); + final String backup = context.getLowkeyVaultManagementClient().unpackBackup(bytes); + final String expected = readResourceContent("/json/backups/" + name + ".json"); + assertEquals(expected, backup); + } } diff --git a/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/ParameterTypeDefs.java b/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/ParameterTypeDefs.java index c50d2bf6..55904ce0 100644 --- a/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/ParameterTypeDefs.java +++ b/lowkey-vault-docker/src/test/java/com/github/nagyesta/lowkeyvault/steps/ParameterTypeDefs.java @@ -45,7 +45,7 @@ public int octKeySize(final String size) { return Integer.parseInt(size); } - @ParameterType("(2048|4096)") + @ParameterType("(2048|3072|4096)") public int rsaKeySize(final String size) { return Integer.parseInt(size); } diff --git a/lowkey-vault-docker/src/test/resources/com/github/nagyesta/lowkeyvault/keys/BackupAndRestoreKeys.feature b/lowkey-vault-docker/src/test/resources/com/github/nagyesta/lowkeyvault/keys/BackupAndRestoreKeys.feature index 5731585b..ec702d01 100644 --- a/lowkey-vault-docker/src/test/resources/com/github/nagyesta/lowkeyvault/keys/BackupAndRestoreKeys.feature +++ b/lowkey-vault-docker/src/test/resources/com/github/nagyesta/lowkeyvault/keys/BackupAndRestoreKeys.feature @@ -77,3 +77,46 @@ Feature: Key backup and restore | backupOct-4 | 128 | A128CBC | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do. | | backupOct-5 | 192 | A192CBC | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do. | | backupOct-6 | 256 | A256CBC | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do. | + + @Key @KeyImport @KeyEncrypt @KeyBackup @KeyRestore @RSA + Scenario Outline: RSA_BACKUP_02 An RSA key is restored from json, backed up, then the backup content is compared to the source + Given a vault is created with name keys-backup- + And a key client is created with the vault named keys-backup- + And the key named is restored from classpath resource + When the key named is backed up + And the unpacked backup of matches the content of the classpath resource + + Examples: + | keyName | + | jsonBackupRsa-2048 | + | jsonBackupRsa-3072 | + | jsonBackupRsa-4096 | + + @Key @KeyImport @KeyEncrypt @KeyBackup @KeyRestore @EC + Scenario Outline: EC_BACKUP_02 An EC key is restored from json, backed up, then the backup content is compared to the source + Given a vault is created with name keys-backup- + And a key client is created with the vault named keys-backup- + And the key named is restored from classpath resource + When the key named is backed up + And the unpacked backup of matches the content of the classpath resource + + Examples: + | keyName | + | jsonBackupEc-256 | + | jsonBackupEc-256k | + | jsonBackupEc-384 | + | jsonBackupEc-521 | + + @Key @KeyImport @KeyEncrypt @KeyBackup @KeyRestore @OCT + Scenario Outline: OCT_BACKUP_02 An OCT key is restored from json, backed up, then the backup content is compared to the source + Given a vault is created with name keys-backup- + And a key client is created with the vault named keys-backup- + And the key named is restored from classpath resource + When the key named is backed up + And the unpacked backup of matches the content of the classpath resource + + Examples: + | keyName | + | jsonBackupOct-128 | + | jsonBackupOct-192 | + | jsonBackupOct-256 | diff --git a/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-256.json b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-256.json new file mode 100644 index 00000000..9ae4fe1b --- /dev/null +++ b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-256.json @@ -0,0 +1,23 @@ +[ { + "vaultBaseUri" : "https://keys-backup-jsonBackupEc-256.localhost:8443", + "entityId" : "jsonBackupEc-256", + "entityVersion" : "f16a91376c13478996195a0c2cee39cb", + "attributes" : { + "enabled" : true, + "created" : 1649503879, + "updated" : 1649503879, + "recoveryLevel" : "Recoverable+Purgeable", + "recoverableDays" : 90 + }, + "tags" : { }, + "managed" : false, + "keyMaterial" : { + "crv" : "P-256", + "d" : "IvdJQWa59MJflXPF25Cc4UlOREHZVL5_6sD27nyz1J8", + "key_ops" : [ "sign", "encrypt", "wrapKey" ], + "kid" : "https://keys-backup-jsonBackupEc-256.localhost:8443/keys/jsonBackupEc-256/f16a91376c13478996195a0c2cee39cb", + "kty" : "EC", + "x" : "XBlNkVS33eZqrVgbpeoNerx5XKMixFxFrYl5FJKQ5vQ", + "y" : "KKoHw5q3QM1lehkqggvNViaX1KBM2ePvmXE2IQbWiLE" + } +} ] \ No newline at end of file diff --git a/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-256k.json b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-256k.json new file mode 100644 index 00000000..4fb5ad54 --- /dev/null +++ b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-256k.json @@ -0,0 +1,23 @@ +[ { + "vaultBaseUri" : "https://keys-backup-jsonBackupEc-256k.localhost:8443", + "entityId" : "jsonBackupEc-256k", + "entityVersion" : "5425a5872c1f4a9fa96db8f40e6c5d07", + "attributes" : { + "enabled" : true, + "created" : 1649503879, + "updated" : 1649503879, + "recoveryLevel" : "Recoverable+Purgeable", + "recoverableDays" : 90 + }, + "tags" : { }, + "managed" : false, + "keyMaterial" : { + "crv" : "P-256K", + "d" : "AONvayGgRSTtrfA6lkCRC-qYccs_pQh35ZSXssCulkrJ", + "key_ops" : [ "sign", "encrypt", "wrapKey" ], + "kid" : "https://keys-backup-jsonBackupEc-256k.localhost:8443/keys/jsonBackupEc-256k/5425a5872c1f4a9fa96db8f40e6c5d07", + "kty" : "EC", + "x" : "AOSHhd4mwdHNED-SdhTnMasUYuEwLPWpLb8rNx-NV9OH", + "y" : "DJivtzkKcvFCNe9ZmzCzflbG_CSQrbuDBauJDneZ6Xc" + } +} ] \ No newline at end of file diff --git a/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-384.json b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-384.json new file mode 100644 index 00000000..b788ec1c --- /dev/null +++ b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-384.json @@ -0,0 +1,23 @@ +[ { + "vaultBaseUri" : "https://keys-backup-jsonBackupEc-384.localhost:8443", + "entityId" : "jsonBackupEc-384", + "entityVersion" : "7f4c0a2ef5454e07a533e597434984a8", + "attributes" : { + "enabled" : true, + "created" : 1649503879, + "updated" : 1649503879, + "recoveryLevel" : "Recoverable+Purgeable", + "recoverableDays" : 90 + }, + "tags" : { }, + "managed" : false, + "keyMaterial" : { + "crv" : "P-384", + "d" : "bd2taaXwxvA_DRUZ1wMT28l8TnaMDz1mn2Z2x_pJT_nkZ11BNS1FFxJvjYHIvoU4", + "key_ops" : [ "sign", "encrypt", "wrapKey" ], + "kid" : "https://keys-backup-jsonBackupEc-384.localhost:8443/keys/jsonBackupEc-384/7f4c0a2ef5454e07a533e597434984a8", + "kty" : "EC", + "x" : "KzD2vTm-aSjXN_RFlY7P78R6hpfdJcSHTC9WM7QXmf0VJro3cXdFOZk6vrx5WDjE", + "y" : "AKYy8hXwjc0O8mVBXOolUvHklqEV2POLIN6c3EpZIJ-Sz2H_Vce0EoAF320bZhxrfw" + } +} ] \ No newline at end of file diff --git a/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-521.json b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-521.json new file mode 100644 index 00000000..a6918152 --- /dev/null +++ b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupEc-521.json @@ -0,0 +1,23 @@ +[ { + "vaultBaseUri" : "https://keys-backup-jsonBackupEc-521.localhost:8443", + "entityId" : "jsonBackupEc-521", + "entityVersion" : "9301e31d18a540e08c68ad5230e60e21", + "attributes" : { + "enabled" : true, + "created" : 1649503879, + "updated" : 1649503879, + "recoveryLevel" : "Recoverable+Purgeable", + "recoverableDays" : 90 + }, + "tags" : { }, + "managed" : false, + "keyMaterial" : { + "crv" : "P-521", + "d" : "AWNmGqYqot0Zq_6uqnqv2lkA40ke1uTJhehp692dS_r2C7oPmJ0qcPgc31jOOFzc-v69chbMawkR-wyKXFf2O4mh", + "key_ops" : [ "sign", "encrypt", "wrapKey" ], + "kid" : "https://keys-backup-jsonBackupEc-521.localhost:8443/keys/jsonBackupEc-521/9301e31d18a540e08c68ad5230e60e21", + "kty" : "EC", + "x" : "AbDYVOxj0e-tUTgqybst45IXon0axFo_sXlHyJQgYvFDxMNrxa5d4rV7X5H487zh3p_aR_dnVEnbWz9od42mlldE", + "y" : "ANk3zxFnwHSgsJr2AZvCHe06Zv7LOQdifHIVaZqx72NOf87DQQoEEMXNp3lTMYANkAqlerz80kjGpoBAe1ZyEtsH" + } +} ] \ No newline at end of file diff --git a/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupOct-128.json b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupOct-128.json new file mode 100644 index 00000000..79d47b78 --- /dev/null +++ b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupOct-128.json @@ -0,0 +1,20 @@ +[ { + "vaultBaseUri" : "https://keys-backup-jsonBackupOct-128.localhost:8443", + "entityId" : "jsonBackupOct-128", + "entityVersion" : "730490a0df9b4ac78ed675902077a18f", + "attributes" : { + "enabled" : true, + "created" : 1649503106, + "updated" : 1649503106, + "recoveryLevel" : "Recoverable+Purgeable", + "recoverableDays" : 90 + }, + "tags" : { }, + "managed" : false, + "keyMaterial" : { + "k" : "sx32Vta2Zx1BsdQBY2l5iQ", + "key_ops" : [ "sign", "encrypt", "wrapKey" ], + "kid" : "https://keys-backup-jsonBackupOct-128.localhost:8443/keys/jsonBackupOct-128/730490a0df9b4ac78ed675902077a18f", + "kty" : "oct-HSM" + } +} ] diff --git a/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupOct-192.json b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupOct-192.json new file mode 100644 index 00000000..09d9b593 --- /dev/null +++ b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupOct-192.json @@ -0,0 +1,20 @@ +[ { + "vaultBaseUri" : "https://keys-backup-jsonBackupOct-192.localhost:8443", + "entityId" : "jsonBackupOct-192", + "entityVersion" : "55ccab8f94b244ab97d82899340c22dd", + "attributes" : { + "enabled" : true, + "created" : 1649503106, + "updated" : 1649503106, + "recoveryLevel" : "Recoverable+Purgeable", + "recoverableDays" : 90 + }, + "tags" : { }, + "managed" : false, + "keyMaterial" : { + "k" : "fp2J-nnMUBZVxCDFdKDxjDJX0F_BIM8P", + "key_ops" : [ "sign", "encrypt", "wrapKey" ], + "kid" : "https://keys-backup-jsonBackupOct-192.localhost:8443/keys/jsonBackupOct-192/55ccab8f94b244ab97d82899340c22dd", + "kty" : "oct-HSM" + } +} ] diff --git a/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupOct-256.json b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupOct-256.json new file mode 100644 index 00000000..1f1f1465 --- /dev/null +++ b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupOct-256.json @@ -0,0 +1,20 @@ +[ { + "vaultBaseUri" : "https://keys-backup-jsonBackupOct-256.localhost:8443", + "entityId" : "jsonBackupOct-256", + "entityVersion" : "19c6d13acb844fda8ccb14751252433a", + "attributes" : { + "enabled" : true, + "created" : 1649503106, + "updated" : 1649503106, + "recoveryLevel" : "Recoverable+Purgeable", + "recoverableDays" : 90 + }, + "tags" : { }, + "managed" : false, + "keyMaterial" : { + "k" : "nmgrv95gVLVdVQ2xe-RpUf-Eog7y0lT22W3EoBU4-cc", + "key_ops" : [ "sign", "encrypt", "wrapKey" ], + "kid" : "https://keys-backup-jsonBackupOct-256.localhost:8443/keys/jsonBackupOct-256/19c6d13acb844fda8ccb14751252433a", + "kty" : "oct-HSM" + } +} ] diff --git a/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupRsa-2048.json b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupRsa-2048.json new file mode 100644 index 00000000..32e5bb20 --- /dev/null +++ b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupRsa-2048.json @@ -0,0 +1,27 @@ +[ { + "vaultBaseUri" : "https://keys-backup-jsonBackupRsa-2048.localhost:8443", + "entityId" : "jsonBackupRsa-2048", + "entityVersion" : "2d93f37afada4679b00b528f7238ad5c", + "attributes" : { + "enabled" : true, + "created" : 1649504957, + "updated" : 1649504957, + "recoveryLevel" : "Recoverable+Purgeable", + "recoverableDays" : 90 + }, + "tags" : { }, + "managed" : false, + "keyMaterial" : { + "d" : "BOSCOBcA_oaZAMPp3APYWbQvyPuw0uFwblDxFSN8YGsSaMqNZMc4b01hC7oMRJzTC7k5dFkCcvikKJU3xWiqNY-FP9HEPJkHezEOQ9rk4nKuJuex157gf1SUxqzDttjQxty027P0ZVL-EmB6OdET2CKVpEyTo7RVZ9UBvQnb1S7-ZBU7UTBotWA7MRsfItvTX_EHX9atPJegpSWmJaJ05-_-dXkRnffrk43bLJ5cJEF4G6X7c4rUFjxSTJ3OwTjmpZPAJT1q85H3-NXrhXiabkFicR3cIj4OpA4egUpRwVze0VAbNOlIsZYIUocLuBelKYLLmr5hTnP_UKSKwznayQ", + "dp" : "AN9pfqyKw-uT9FWr8GqsyhqJYR9KLgTtX6uqxJk_Y-4NZEMooCeq2olaVpFic0tfaOMJnDufYsUBL_i1TxoD9w3s0YjVwBiURFKs-0Ghs2RGxk22WGbKrnS4Zh8k2RKkNvFPnRciXva1nfMjeWEahb6O8ReA7AZNECKAqJtE5UTB", + "dq" : "B7sIKKG4bo4Gvm4xj7KBnlP4X9UQH8FLnisGVe9HqDJH4Zu7d-dj5yHT-HaX07MU5p0r2H26owT829SxZGZB2qR_njnuyt8KnmAdEJPttNkW6L25csAoEzqdexi08wmWH0fAEMVDgeobAg1YtByts-VmajO0TWxYyO1oiJFc6ok", + "e" : "AQAB", + "key_ops" : [ "sign", "encrypt", "wrapKey" ], + "kid" : "https://keys-backup-jsonBackupRsa-2048.localhost:8443/keys/jsonBackupRsa-2048/2d93f37afada4679b00b528f7238ad5c", + "kty" : "RSA-HSM", + "n" : "AMfXpr8tkLe86czuJnDBbzcNFNk5paAm0hcI6zD-P1OYvinL2zJG3-8O0GQNuHeExZykhpfOqo6nOv1tbcqesUwkgcT385z2Cmf0G0TfK7EcvDRO8APxqMIvuQpglzFOXAJ4aqVD56IWFMzzkkaR73DKmDF-6cmWtrZu0dEv7LN5cZAk2wd421k5JTbcHoo5kAZBv_CJNt_M0n5VMK5jACV_d53mmaumTHffu-BLOyfBlr0cQMr63aBYh8q5KlcL7U5QJC01umOl4Wwl7yrbD4jZo5f3kWwYTDfeRQlz40h68XUssPc9lG7Gsj9hYxalyCwP9ix5dcs4x-OsYXLX-nM", + "p" : "AOqsdAb_YNN9OdgFRuVNUmMlG2DpgQfCs8kHUi0_s4IGLjgu4yX1LUhVNnBMLCxTEGO7U-N9e3jHRDexQLHbXzt2IkrN-pwh3MZVEry6yxQILxbMp4aPqZpWTs9ufSiX0iI68lb7uZhsiaMcpEYQX_N67Vlj1Z6-rCGM1K_-86op", + "q" : "ANoA3nnRaVah2bdmqdjK1Hh20wj4gTEQrKnt_XZDlxMo_HZ77saX_hMjJpYX008w-ZPV-LFNc_clcHK7ZedJZB6pcmuumPvLuvqSqifD4wEwcQAR3a8aTs2gBeqmjyxXXtQk8KK8LNpIzclm98n0vmk1kc0fHobmr_KVFyFBYAs7", + "qi" : "AOfgFCIEztUVLY7nA5-vMDPRYsf8oKSVeeXDqueXogic75BzYL4mfWevgfkyatP0aa8y8E38annoMN-E1J-cu2gBneLQCd9rf0cIqRIooTwZ-RMLPEKtpBNcT3sBirfeviITpDqOirbke92XbMNGkAEPoC5JPiCYU1FASGDaJFaF" + } +} ] \ No newline at end of file diff --git a/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupRsa-3072.json b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupRsa-3072.json new file mode 100644 index 00000000..987b4c79 --- /dev/null +++ b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupRsa-3072.json @@ -0,0 +1,27 @@ +[ { + "vaultBaseUri" : "https://keys-backup-jsonBackupRsa-3072.localhost:8443", + "entityId" : "jsonBackupRsa-3072", + "entityVersion" : "5ae349c717644397a14df7ece5eda28f", + "attributes" : { + "enabled" : true, + "created" : 1649506106, + "updated" : 1649506106, + "recoveryLevel" : "Recoverable+Purgeable", + "recoverableDays" : 90 + }, + "tags" : { }, + "managed" : false, + "keyMaterial" : { + "d" : "FwpaGDisPKDVoOzuCws9yGvvK2nu2LGFp1PefmoZ5mabkS2T-IpqdL-UUfpdZllIxWaFWmuN_c21nJXZhA1UL9g1qywUi5D3lKePDB00jVTIfdZSDrrXr_KTZwLQsYZ_iIeyiG1wPX4hWzx-rKFJTEXLEKUc3yWdlIJyFf9olfBy5PG_83Y6DC56RNFSIvqQUg9AhN-6KauP-0SrdBU2csSBkj97viPvhua2mrW7knwC1TajMQVhwn8DidcV1G13nib1ChBjia70Z3b4n_lisK3330BWfuKZAJyEfcUpIPZjFCF3YfAFcKJGA1hBqG5Up4IA02yekMHGtga_TnPPn9Z7RZ-eA6WlaFKgFvY0IKZYVNwkJ88coQxUmmMvgETy-Xz-yQBPLAaQmVW4dhBi9VUGCDHbgKC9n9XK6DNKz6ejhklctehpePrjweTEG4v0sJsSd1TiQBPL60dme3A8jwlLFdSxSjamn8ysDMdVe6Ck5Qtztm2GSRSdC6cb0d3B", + "dp" : "NgJjxYCpARiZJCwWrjgBLfajs55DykK1Vy6GtSuVhDtit-7vWNstxSnJIErnfv3-MNjQ0hVOOGck-c9cDuvXNNh0Nx8OTBqCOG4EPX6GiZdUpB27gpSmxEUNsa308kEXV-qmIRptQOco0rGY8HrJ7S1ktWQID89V0jVUHBvw9T6Ktc833rtlffQUEdLex3ijerDnqWorAAkKinXH9TwjgKH4FldpQrOe3b4KpslHn7oUeEsYvepOSFaKKyifym5B", + "dq" : "b6-Ny82SZFzMFz4dADqRLapsic8r6YRgjh0txKWgL-3tnXzF-YTutxRIhSUf_ypcKN3KmRLNK9ZIjB1YtC56CgbTseBABUbw9EuSN-g9T6zMM0XA916N7JmQhDeWxEaGPzLvLB50ZWoFnyyws4mC_lB8E4hWo615zBJ_06A87be5wRK-e5fIuVe9Zknlnuu3DuuP6ZSPP7lYf0A8ms_Eg8RHHUx_1WTNsCnwdPDfY_O1Fsg4MVpXdeqho7s6UouZ", + "e" : "AQAB", + "key_ops" : [ "sign", "encrypt", "wrapKey" ], + "kid" : "https://keys-backup-jsonBackupRsa-3072.localhost:8443/keys/jsonBackupRsa-3072/5ae349c717644397a14df7ece5eda28f", + "kty" : "RSA-HSM", + "n" : "AI2OC6QgoA3x6CzwXr8GPdMUZSOJ3FdKxS598-xoSCbwJGB6a761d0ugcFnqX87RsQAxaEp3OS3xviSGa0ilc-NIeGkbtKjd96bAkgAKxHRB99fkyHAxA-y8QQzvPF7xgx-eKKs0uR_NGFyJDeqOZPzmfdLZydpq8Y_Rmc_uNPxGaHzbTCiumkkNd9OXs1r6U1OPJecnv6tHLYDh8OMLJ3WZNbJ5OqlpOGMShWgoCV1c5olqcBoHQRyMCH31x9fnxKqWJMFnF5B3yimD-8AaTkTo4EEmi5-mrqJ4IDGoUSh9p8hgafv7XNmkms0ZkEUrsXOLuLvvPeyza_Ka9tgJBUDmkrjUu9mTUyRcKaiBHyR5VLxUBmeNtvS_Df_Vqoi4G-6vMQvVgut1pp6bijBjYtKp5b7m8mxtJ6my1nShu-NxAw4JFMQMmh477cJxqzfrBzlfefvFnhtFS8K78t1CJNRuEmDNB4TNlgrzLlvJq9BUzflBD-XvT_9Vj1_oIcGw3Q", + "p" : "AMVKqqCIRq9jh5SoW5UxLTfNrsjZkK5J4RAxgwcf2AtQXL0dxOUU-FepkASfo3MoYkStP9aJPlZKMJ0iixkgUjL-Fr0cX2tFgkZoFmyDKTmLguGvCEt07NJD633cnzAZ728OMsP6cK_bYcE48TuRtNvnbVq_QPbm7JLJii_qf2HHPL-EdFlBoFTWWWErxYfRd9XwxAgwHvd0FiNrlHRvtUxuc8h1OnYwORhtXPlrx5D0WFSUlWHbgLOEAnp_EI2FQQ", + "q" : "ALetcnXW5mFbud_4hh_Vw6QHuRrw1l0MYtgeFvVld6pDzAMzoiVbAVLM0rgmk9vVrHta5b5uj2cT08QqU8EXDRHgnC_fOT-ay966AaQmu3RUACeVv0CcRJQB_FzQ4RLUtHoDj7No23jGjLH849NNc8YaTYAWD7ntQEoVorxhZIyxGI7Zaf_pajkgQPKe2rT88SbONK9UTV-iAQ6wr-_W4amWlhpCWvObCHkhWFL01kmJhVDcrHvslCq4hdDuCeD4nQ", + "qi" : "MLMFbdT1qRanqk8krWVwbhStSNOdznS75gS3PgmrCLmJ63OCkk6O0EczBHrByPQF5P5sha_ec7ZCIFHaYGakTFrk-4vQJTFtFhx5IripRFUQ2NFhLzhDh_P2Tlg_TBjlaA1AF99iuKPoon2s114a5vq_C14Yzx0aTZgn4UzPUTAi5GATnyGknlR0A9bErtxSdLbHkgOTzYfQBMJvtzgbN8JSsT23cuE-bmitsGjokTFhMvyvmH0ZcaFY4RzTKXeQ" + } +} ] \ No newline at end of file diff --git a/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupRsa-4096.json b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupRsa-4096.json new file mode 100644 index 00000000..46d4b750 --- /dev/null +++ b/lowkey-vault-docker/src/test/resources/json/backups/jsonBackupRsa-4096.json @@ -0,0 +1,27 @@ +[ { + "vaultBaseUri" : "https://keys-backup-jsonBackupRsa-4096.localhost:8443", + "entityId" : "jsonBackupRsa-4096", + "entityVersion" : "6f009cc18cf146cf960a96254e8d3f39", + "attributes" : { + "enabled" : true, + "created" : 1649504966, + "updated" : 1649504966, + "recoveryLevel" : "Recoverable+Purgeable", + "recoverableDays" : 90 + }, + "tags" : { }, + "managed" : false, + "keyMaterial" : { + "d" : "Hrwbq60uhw31jEz1xm3xuBKcrsun5kzstkxTwkH4QgFvIDszuC1uWN9K46AT10Qr725AyTPTWMwdAXjw01wnuU9gmqcBSjM0kVus2z-WUW_b3qaoTNTmfZ4FkaAzcdslDkeoAu8uRlhbmcuela6pTYSF2vsrIpq-OPCB8PQ4kRU33mmCHk_Ikwx-sjrHqBZqrQubMGCat4n4mgLniHikqv91GK8k0XUDuvwngB6aIMFQ14LoudI12ED7AcP9ia1XwSjSWMRFUzrvJgt2R-jk5iSmZ0y-7WjwR8UBCyHEKEa_ZNP0gtyykSgY2jCwXuC0uRaeSv4AjZOTQuywaV3-aSDjzMx76xxCd2APs3dxkmD07-bRImC1Gcrz21Im7wzskYZTx8TIi6_2PmK6oLZJcewmFLdaveEPSX5KxfSYFNINI5Y9ybsYHA3EBr_vhXYywnvpVOUkRBHcckgxplf7Ehw-P1PFmk1UVsCvhbm2jASbbbG80-nwXocT0X6AimQfKhxgbOJ7I-v71pJD3v3R8UAnkhl8Y3SFwGjbgl_ow6E4OFuuxRZ2LwxFgYJCOnwEE5Xh8Sul9mJB41WN7XmusPqA83kdtJscBne8BmnwmdGaFWoxgxV6k5LNIdIZQox3DBaxgB8BTl5C_NX46TzpnRtpXUQvAK4v564Vc4discU", + "dp" : "XsWQH0UXj7rUjaaeFYWNP6fclxC5opmLrD4YWYBev3PBvS-cO5EhPL1WQtRicTtTPvabOxlXw9L24jZ6lwmpOkQuWMqnpds_Lpj79KAQTLRrQZ3lRMYsQ20z-ILmzCHaiFxkRK-mxYtVXuQ0-k6C4LDJTMxEWlan3iavG0FNoL44VEZGfw-d7vrUMCCZzOTOgIwi4pT_GLuhy2c7XE-Fs_Fia-MAbMbyTNQb1FcNYytcl3-H5e7pdR40rXV4ISr3ZfgU6lE--kQuK83Sgwkn9QCrwchY7ssK_fxGjv5YWBS9FhNE_u2fxGjo1qzoWRY-PepekuP7IBe-PvUnTMvcNQ", + "dq" : "Xh3PxcEoe17LVHtyf2qsfbE-PsDLz_petl-94WCVRHD9yOdM8uPIl20cX0paBKNFq9gCpQEag7iO8cJcuuHhdb1i9uBw2wPaSYvUYMWfdWvEmLCMUYNJn428mW6iAiGbvb6uzXTtcJBVC2OxoBEnEeNFlxtcSAuhAtD3sFi15td6gh8g_-Sh7EzBaxwIDS0pVKLs72V60b9OOggl-jcNL_cmaaNq7iAV2FgzOkZM-lkEfrwb_ovu0XdMT4aDaxLgrHHXpYlR6rKg3BBIZdxihR3Ned_6Mv_tJvaEBiu6aTiBMPsSrLZXN5VkO7-nWfP1unvktpuwnwqxyYcqcHdI4Q", + "e" : "AQAB", + "key_ops" : [ "sign", "encrypt", "wrapKey" ], + "kid" : "https://keys-backup-jsonBackupRsa-4096.localhost:8443/keys/jsonBackupRsa-4096/6f009cc18cf146cf960a96254e8d3f39", + "kty" : "RSA-HSM", + "n" : "AKNbPrSp6qQr5wIuHOh7U5i9Mdi0mSLYNfa9vaM2CuY32eqaB1uCcfdgYWP_SHRZDOUgzB2zoTc-30gX4ccHrFHoBMaYvckN9RIEAu0AhToqxm2xr77_9G0CNwgPoohlC2WB69pSYtX17fYfQQVfOPE0K8vo6mSWSgIcsKC9Nenib0DbQLMWPl04f0h_rleYKqyt8ecPpVEOkS9bb0d5p7GbaZCekPLdZ6GS_cYZJbiBqwpNjJoR6QbRCE9JyEo4UHDJ3_TX1rc50X5mAhV4lt_x-f-2YmRhExA7JU0IHQaHDABxeAIZ61bZT6MFNmA14316uAr33MeanjvlXrRyZDQ0QYfeXpDrg7qXJHCwP1kuZmQDWgzX5gUPi_9VqUD1FbxfBDWxjeHvmMVfJqIxRAd5Pk2PtJerIyER3YnmPdFK_Vo_31z84X21NFWTm4M93hudv01rr_cFwRAi3SZZ5ymPMjWbTjVjIyXmLMkgn51g8EwKdxOkv-GtE7NacdorbmcrGlL6CXg6MzbMtIXriqOrjGMTZwKRJXCyE56GblZCxbQpbd5Vm2exG_O_pDmobd6D5dJQBLBAPHhcgbqiVmOy9fcpLeVVEAyVoRnOSGLNKXREDHOxWTZPj-IG9AFl1VAaoW1XwpkwaMOP0Xy-kfKDoJsGaqE0BIY8kiXYHmHz", + "p" : "ANxECyf5q69UokIVyU-5uFNsvxPuNlIQSiJn8Bcs3nY6E_H-q1Mw56sCxNz2VW07eDQ8vOyYVF6WjHnGfCMeV-F44PpctxpfXySWqAGPy9KmSMsCXlVVlbi6SeEonJR1yuRM4j_8U8npCg-qelSbw6NJIziu5tbmp32LcQK1i3wj43q2bv1ZnYnNg936-EKpOH_skQds3kwtMsb6KQgIlqogMjwTy1d-kPdJx3ZSMhkZp3RfEPQ9zU4XcHH5jOgUH5orRuPI9XI4U_WT4ETQLsGr8EMAXqDNDHJ1ArwwzQSj025hrYym9nxiPg7VDJCXkjjpG6o_fwwjEJomcP4V-r8", + "q" : "AL3brFARAay4YLokvlYWqWNEnfmQACHWYliew86QygP1LMW6tB5j8ZblfZuRwXUq4m2K_QN_JSr0G1BidFj_6HvMgMIvl5J51Rz7okw6wPw-PCyLu66tUWfBr_9VANNVhtWoORUluE4mf24yiJJFhlv96mV_7qDPmDnilKfP40A3O4VnF8IDq6lf3SN4feXRJofhwPrJbQ0AsXbgy8Jza0i3vrK6oWQhEERx0BwwuRYsfwVc8MP8kzzhaKKJMgCNzbCXUzTFXqcWmIsSgWdbqUVIMx8vHzpDtGhrwbES2meolZo55fadgGS1hLSSx0ciOjxHGe240sKAGeEONwekKc0", + "qi" : "Izh5IJH37JMCWCMkws4wkx_I2p5YFawshvDQ791kVGKudOALGW9ljggOs6HNlPh09YieCUIfJ9-FRQs4XVaAWcaiCNwCY4tyis0-Z1UNLMrsLlYUFfMSmoGQ_aFj3xkAcFvoj2NKpoYbJA83XvAgCi7bm3r5cPq5DdU3F6yngIx1OjQ5OAikidYK1Sj5_Ue4zZLvSRt6-1BdpePwTBkp9RV7uqIn4jg4LQgC1SkkSZSu5mmSdL3msefrLSkRCxsv3qk92P4OsZpxvFm4Oi_A7uKOQ9d23c6iD5wjyCkl1OTuiPEcdjXJ5y0djNccebk0iZDZrsyLuO9qGAIZMAGCvw" + } +} ] \ No newline at end of file