Date: Wed, 21 Feb 2024 16:07:48 +1030
Subject: [PATCH 0080/1846] Add support for Camellia AEAD cipher
---
.../openpgp/operator/bc/BcAEADUtil.java | 9 +++++----
.../operator/bc/BcPGPDataEncryptorBuilder.java | 9 +++++----
.../openpgp/operator/jcajce/JceAEADUtil.java | 17 +++++++++--------
.../jcajce/JcePGPDataEncryptorBuilder.java | 7 ++++---
4 files changed, 23 insertions(+), 19 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
index 316b841bee..66b6c9d45a 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
@@ -110,6 +110,7 @@ static byte[][] deriveMessageKeyAndIv(int aeadAlgo, int cipherAlgo, byte[] sessi
public static AEADBlockCipher createAEADCipher(int encAlgorithm, int aeadAlgorithm)
throws PGPException
{
+ boolean enableCamellia = Boolean.parseBoolean(System.getProperty("enableCamelliaKeyWrapping"));
if (encAlgorithm == SymmetricKeyAlgorithmTags.AES_128
|| encAlgorithm == SymmetricKeyAlgorithmTags.AES_192
|| encAlgorithm == SymmetricKeyAlgorithmTags.AES_256)
@@ -126,9 +127,9 @@ public static AEADBlockCipher createAEADCipher(int encAlgorithm, int aeadAlgorit
throw new PGPException("unrecognised AEAD algorithm: " + aeadAlgorithm);
}
}
- else if (encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_128 ||
- encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_192 ||
- encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_256)
+ else if (enableCamellia && (encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_128
+ || encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_192
+ || encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_256))
{
switch (aeadAlgorithm)
{
@@ -143,7 +144,7 @@ else if (encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_128 ||
}
}
// Block Cipher must work on 16 byte blocks
- throw new PGPException("AEAD only supported for AES based algorithms");
+ throw new PGPException("AEAD only supported for AES" + (enableCamellia ? " and Camellia" : "") + " based algorithms");
}
/**
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPDataEncryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPDataEncryptorBuilder.java
index 6f00f1e311..bb77dfbd47 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPDataEncryptorBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPDataEncryptorBuilder.java
@@ -78,7 +78,7 @@ public BcPGPDataEncryptorBuilder setUseV6AEAD()
/**
* Sets whether the resulting encrypted data will be protected using an AEAD mode.
- *
+ *
* The chunkSize is used as a power of two, result in blocks (1 << chunkSize) containing data
* with an extra 16 bytes for the tag. The minimum chunkSize is 6.
*
@@ -89,14 +89,15 @@ public BcPGPDataEncryptorBuilder setUseV6AEAD()
@Override
public BcPGPDataEncryptorBuilder setWithAEAD(int aeadAlgorithm, int chunkSize)
{
+ boolean enableCamellia = Boolean.parseBoolean(System.getProperty("enableCamelliaKeyWrapping"));
if (encAlgorithm != SymmetricKeyAlgorithmTags.AES_128
&& encAlgorithm != SymmetricKeyAlgorithmTags.AES_192
&& encAlgorithm != SymmetricKeyAlgorithmTags.AES_256
- && encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_128
+ && (enableCamellia && (encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_128
&& encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_192
- && encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_256)
+ && encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_256)))
{
- throw new IllegalStateException("AEAD algorithms can only be used with AES and Camellia");
+ throw new IllegalStateException("AEAD algorithms can only be used with AES" + (enableCamellia ? " and Camellia" : ""));
}
if (chunkSize < 6)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
index 3a66e14efd..50c8bb2c98 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
@@ -109,9 +109,9 @@ static byte[][] deriveMessageKeyAndIv(int aeadAlgo, int cipherAlgo, byte[] sessi
byte[] messageKeyAndIv = new byte[keyLen + ivLen - 8];
hkdfGen.generateBytes(messageKeyAndIv, 0, messageKeyAndIv.length);
- return new byte[][] { Arrays.copyOfRange(messageKeyAndIv, 0, keyLen), Arrays.copyOfRange(messageKeyAndIv, keyLen, keyLen + ivLen) };
+ return new byte[][]{Arrays.copyOfRange(messageKeyAndIv, 0, keyLen), Arrays.copyOfRange(messageKeyAndIv, keyLen, keyLen + ivLen)};
}
-
+
/**
* Create a {@link PGPDataDecryptor} for decrypting AEAD encrypted OpenPGP v5 data packets.
*
@@ -237,15 +237,16 @@ public PGPDigestCalculator getIntegrityCalculator()
Cipher createAEADCipher(int encAlgorithm, int aeadAlgorithm)
throws PGPException
{
+ boolean enableCamellia = Boolean.parseBoolean(System.getProperty("enableCamelliaKeyWrapping"));
if (encAlgorithm != SymmetricKeyAlgorithmTags.AES_128
&& encAlgorithm != SymmetricKeyAlgorithmTags.AES_192
&& encAlgorithm != SymmetricKeyAlgorithmTags.AES_256
- && encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_128
+ && (enableCamellia && (encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_128
&& encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_192
- && encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_256)
+ && encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_256)))
{
// Block Cipher must work on 16 byte blocks
- throw new PGPException("AEAD only supported for AES and Camellia based algorithms");
+ throw new PGPException("AEAD only supported for AES" + (enableCamellia ? " and Camellia" : "") + " based algorithms");
}
String mode;
@@ -420,7 +421,7 @@ private byte[] readBlock()
byte[] decData;
try
{
- JceAEADCipherUtil.setUpAeadCipher(c, secretKey, Cipher.DECRYPT_MODE, getNonce(iv, chunkIndex), 128, adata);
+ JceAEADCipherUtil.setUpAeadCipher(c, secretKey, Cipher.DECRYPT_MODE, getNonce(iv, chunkIndex), 128, adata);
decData = c.doFinal(buf, 0, dataLen + aeadTagLength);
}
@@ -494,7 +495,7 @@ static class PGPAeadOutputStream
/**
* OutputStream for AEAD encryption.
*
- * @param isV5AEAD isV5AEAD of AEAD (OpenPGP v5 or v6)
+ * @param isV5AEAD isV5AEAD of AEAD (OpenPGP v5 or v6)
* @param out underlying OutputStream
* @param c AEAD cipher
* @param secretKey secret key
@@ -615,7 +616,7 @@ private void writeBlock()
try
{
- JceAEADCipherUtil.setUpAeadCipher(c, secretKey, Cipher.ENCRYPT_MODE, getNonce(iv, chunkIndex), 128, adata);
+ JceAEADCipherUtil.setUpAeadCipher(c, secretKey, Cipher.ENCRYPT_MODE, getNonce(iv, chunkIndex), 128, adata);
out.write(c.doFinal(data, 0, dataOff));
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java
index 7b695aec63..de7c1d0d9e 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java
@@ -78,14 +78,15 @@ public JcePGPDataEncryptorBuilder setWithIntegrityPacket(boolean withIntegrityPa
@Override
public JcePGPDataEncryptorBuilder setWithAEAD(int aeadAlgorithm, int chunkSize)
{
+ boolean enableCamellia = Boolean.parseBoolean(System.getProperty("enableCamelliaKeyWrapping"));
if (encAlgorithm != SymmetricKeyAlgorithmTags.AES_128
&& encAlgorithm != SymmetricKeyAlgorithmTags.AES_192
&& encAlgorithm != SymmetricKeyAlgorithmTags.AES_256
- && encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_128
+ && (enableCamellia && (encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_128
&& encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_192
- && encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_256)
+ && encAlgorithm != SymmetricKeyAlgorithmTags.CAMELLIA_256)))
{
- throw new IllegalStateException("AEAD algorithms can only be used with AES and Camellia");
+ throw new IllegalStateException("AEAD algorithms can only be used with AES" + (enableCamellia ? " and Camellia" : ""));
}
if (chunkSize < 6)
From 6d272bd4daaa73276065c894d2058342af1131a1 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 21 Feb 2024 16:29:09 +1030
Subject: [PATCH 0081/1846] Fix test failure in BcpgGeneralTest.
---
.../org/bouncycastle/openpgp/test/BcpgGeneralTest.java | 10 +---------
1 file changed, 1 insertion(+), 9 deletions(-)
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java
index 66d667374b..8ee0027eb7 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java
@@ -2,7 +2,6 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.OutputStream;
import java.security.SecureRandom;
import java.security.Security;
import java.util.Date;
@@ -10,7 +9,6 @@
import org.bouncycastle.bcpg.AEADAlgorithmTags;
import org.bouncycastle.bcpg.ArmoredInputStream;
-import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.BCPGOutputStream;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
@@ -26,21 +24,15 @@
import org.bouncycastle.crypto.generators.X25519KeyPairGenerator;
import org.bouncycastle.crypto.params.X25519KeyGenerationParameters;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openpgp.PGPEncryptedDataGenerator;
import org.bouncycastle.openpgp.PGPEncryptedDataList;
import org.bouncycastle.openpgp.PGPKdfParameters;
-import org.bouncycastle.openpgp.PGPLiteralData;
-import org.bouncycastle.openpgp.PGPLiteralDataGenerator;
import org.bouncycastle.openpgp.PGPObjectFactory;
import org.bouncycastle.openpgp.PGPPBEEncryptedData;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.bc.BcPGPObjectFactory;
-import org.bouncycastle.openpgp.operator.bc.BcPBEKeyEncryptionMethodGenerator;
-import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Strings;
-import org.bouncycastle.util.io.Streams;
import org.bouncycastle.util.test.SimpleTest;
public class BcpgGeneralTest
@@ -87,7 +79,7 @@ public void testPreferredAEADCiphersuites()
ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray());
SignatureSubpacketInputStream subpacketIn = new SignatureSubpacketInputStream(bIn);
- isEquals(subpacketIn.available(), 0);
+ isEquals(subpacketIn.available(), 8);
SignatureSubpacket subpacket = subpacketIn.readPacket();
assert subpacket != null;
assert subpacket instanceof PreferredAEADCiphersuites;
From 3ec1fb6735397d865f0f585a5203cdb31b5a5eee Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 21 Feb 2024 17:06:06 +1030
Subject: [PATCH 0082/1846] Refactor around Camellia in AEAD situations.
---
.../openpgp/operator/bc/BcAEADUtil.java | 93 +++++++++----------
.../openpgp/operator/jcajce/JceAEADUtil.java | 45 ++++-----
2 files changed, 64 insertions(+), 74 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
index 66b6c9d45a..8abf80b15d 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
@@ -10,6 +10,7 @@
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.SymmetricKeyUtils;
+import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.engines.AESEngine;
@@ -115,38 +116,39 @@ public static AEADBlockCipher createAEADCipher(int encAlgorithm, int aeadAlgorit
|| encAlgorithm == SymmetricKeyAlgorithmTags.AES_192
|| encAlgorithm == SymmetricKeyAlgorithmTags.AES_256)
{
- switch (aeadAlgorithm)
- {
- case AEADAlgorithmTags.EAX:
- return new EAXBlockCipher(AESEngine.newInstance());
- case AEADAlgorithmTags.OCB:
- return new OCBBlockCipher(AESEngine.newInstance(), AESEngine.newInstance());
- case AEADAlgorithmTags.GCM:
- return GCMBlockCipher.newInstance(AESEngine.newInstance());
- default:
- throw new PGPException("unrecognised AEAD algorithm: " + aeadAlgorithm);
- }
+ return createAEADCipher(aeadAlgorithm, AESEngine::newInstance);
}
else if (enableCamellia && (encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_128
|| encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_192
|| encAlgorithm == SymmetricKeyAlgorithmTags.CAMELLIA_256))
{
- switch (aeadAlgorithm)
- {
- case AEADAlgorithmTags.EAX:
- return new EAXBlockCipher(new CamelliaEngine());
- case AEADAlgorithmTags.OCB:
- return new OCBBlockCipher(new CamelliaEngine(), new CamelliaEngine());
- case AEADAlgorithmTags.GCM:
- return GCMBlockCipher.newInstance(new CamelliaEngine());
- default:
- throw new PGPException("unrecognised AEAD algorithm: " + aeadAlgorithm);
- }
+ return createAEADCipher(aeadAlgorithm, CamelliaEngine::new);
}
// Block Cipher must work on 16 byte blocks
throw new PGPException("AEAD only supported for AES" + (enableCamellia ? " and Camellia" : "") + " based algorithms");
}
+ private interface Engine
+ {
+ BlockCipher newInstance();
+ }
+
+ private static AEADBlockCipher createAEADCipher(int aeadAlgorithm, Engine engine)
+ throws PGPException
+ {
+ switch (aeadAlgorithm)
+ {
+ case AEADAlgorithmTags.EAX:
+ return new EAXBlockCipher(engine.newInstance());
+ case AEADAlgorithmTags.OCB:
+ return new OCBBlockCipher(engine.newInstance(), engine.newInstance());
+ case AEADAlgorithmTags.GCM:
+ return GCMBlockCipher.newInstance(engine.newInstance());
+ default:
+ throw new PGPException("unrecognised AEAD algorithm: " + aeadAlgorithm);
+ }
+ }
+
/**
* Create a decryptor for OpenPGP v5 AED (AEAD Encrypted Data) packets.
* This is type of packet is used by GnuPG.
@@ -426,18 +428,7 @@ private byte[] readBlock()
if (dataLen != chunkLength) // it's our last block
{
- if (isV5StyleAEAD)
- {
- adata = new byte[13];
- System.arraycopy(aaData, 0, adata, 0, aaData.length);
- xorChunkId(adata, chunkIndex);
- }
- else
- {
- adata = new byte[aaData.length + 8];
- System.arraycopy(aaData, 0, adata, 0, aaData.length);
- System.arraycopy(Pack.longToBigEndian(totalBytes), 0, adata, aaData.length, 8);
- }
+ adata = getAdata(isV5StyleAEAD, aaData, chunkIndex, totalBytes);
try
{
@@ -465,6 +456,24 @@ private byte[] readBlock()
return decData;
}
+
+ private static byte[] getAdata(boolean isV5StyleAEAD, byte[] aaData, long chunkIndex, long totalBytes)
+ {
+ byte[] adata;
+ if (isV5StyleAEAD)
+ {
+ adata = new byte[13];
+ System.arraycopy(aaData, 0, adata, 0, aaData.length);
+ xorChunkId(adata, chunkIndex);
+ }
+ else
+ {
+ adata = new byte[aaData.length + 8];
+ System.arraycopy(aaData, 0, adata, 0, aaData.length);
+ System.arraycopy(Pack.longToBigEndian(totalBytes), 0, adata, aaData.length, 8);
+ }
+ return adata;
+ }
}
protected static class PGPAeadOutputStream
@@ -625,22 +634,8 @@ private void finish()
{
writeBlock();
}
-
-
- byte[] adata;
boolean v5StyleAEAD = isV5StyleAEAD;
- if (v5StyleAEAD)
- {
- adata = new byte[13];
- System.arraycopy(aaData, 0, adata, 0, aaData.length);
- xorChunkId(adata, chunkIndex);
- }
- else
- {
- adata = new byte[aaData.length + 8];
- System.arraycopy(aaData, 0, adata, 0, aaData.length);
- System.arraycopy(Pack.longToBigEndian(totalBytes), 0, adata, aaData.length, 8);
- }
+ byte[] adata = PGPAeadInputStream.getAdata(v5StyleAEAD, aaData, chunkIndex, totalBytes);
try
{
c.init(true, new AEADParameters(secretKey, 128, getNonce(iv, chunkIndex))); // always full tag.
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
index 50c8bb2c98..e3f7bb90c8 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
@@ -437,18 +437,7 @@ private byte[] readBlock()
if (dataLen != chunkLength) // it's our last block
{
- if (v5StyleAEAD)
- {
- adata = new byte[13];
- System.arraycopy(aaData, 0, adata, 0, aaData.length);
- xorChunkId(adata, chunkIndex);
- }
- else
- {
- adata = new byte[aaData.length + 8];
- System.arraycopy(aaData, 0, adata, 0, aaData.length);
- System.arraycopy(Pack.longToBigEndian(totalBytes), 0, adata, aaData.length, 8);
- }
+ adata = PGPAeadOutputStream.getAdata(v5StyleAEAD, aaData, chunkIndex, totalBytes);
try
{
if (v5StyleAEAD)
@@ -638,19 +627,7 @@ private void finish()
writeBlock();
}
- byte[] adata;
- if (isV5AEAD)
- {
- adata = new byte[13];
- System.arraycopy(aaData, 0, adata, 0, aaData.length);
- xorChunkId(adata, chunkIndex);
- }
- else
- {
- adata = new byte[aaData.length + 8];
- System.arraycopy(aaData, 0, adata, 0, aaData.length);
- System.arraycopy(Pack.longToBigEndian(totalBytes), 0, adata, aaData.length, 8);
- }
+ byte[] adata = getAdata(isV5AEAD, aaData, chunkIndex, totalBytes);
try
{
@@ -671,5 +648,23 @@ private void finish()
}
out.close();
}
+
+ private static byte[] getAdata(boolean isV5AEAD, byte[] aaData, long chunkIndex, long totalBytes)
+ {
+ byte[] adata;
+ if (isV5AEAD)
+ {
+ adata = new byte[13];
+ System.arraycopy(aaData, 0, adata, 0, aaData.length);
+ xorChunkId(adata, chunkIndex);
+ }
+ else
+ {
+ adata = new byte[aaData.length + 8];
+ System.arraycopy(aaData, 0, adata, 0, aaData.length);
+ System.arraycopy(Pack.longToBigEndian(totalBytes), 0, adata, aaData.length, 8);
+ }
+ return adata;
+ }
}
}
From 5c8caa723a5647da7966412d3a048e7bf0147b8b Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 21 Feb 2024 18:51:07 +0700
Subject: [PATCH 0083/1846] Cleanup obsolete TODO
---
.../bc/BcDefaultTlsCredentialedDecryptor.java | 64 +++++++------------
.../JceDefaultTlsCredentialedDecryptor.java | 58 ++++++-----------
2 files changed, 41 insertions(+), 81 deletions(-)
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
index 2175bdf18e..3d8c375bcc 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
@@ -13,7 +13,6 @@
import org.bouncycastle.tls.TlsCredentialedDecryptor;
import org.bouncycastle.tls.crypto.TlsCryptoParameters;
import org.bouncycastle.tls.crypto.TlsSecret;
-import org.bouncycastle.tls.crypto.impl.TlsImplUtils;
import org.bouncycastle.util.Arrays;
/**
@@ -76,11 +75,11 @@ public TlsSecret decrypt(TlsCryptoParameters cryptoParams, byte[] ciphertext) th
}
/*
- * TODO[tls-ops] Probably need to make RSA encryption/decryption into TlsCrypto functions so
- * that users can implement "generic" encryption credentials externally
+ * TODO[tls-ops] Probably need to make RSA encryption/decryption into TlsCrypto functions so that users
+ * can implement "generic" encryption credentials externally
*/
- protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams, RSAKeyParameters rsaServerPrivateKey,
- byte[] encryptedPreMasterSecret)
+ protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
+ RSAKeyParameters rsaServerPrivateKey, byte[] encryptedPreMasterSecret)
{
SecureRandom secureRandom = crypto.getSecureRandom();
@@ -89,12 +88,8 @@ protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
*/
ProtocolVersion expectedVersion = cryptoParams.getRSAPreMasterSecretVersion();
- // TODO Provide as configuration option?
- boolean versionNumberCheckDisabled = false;
-
/*
- * Generate 48 random bytes we can use as a Pre-Master-Secret, if the
- * PKCS1 padding check should fail.
+ * Generate 48 random bytes we can use as a Pre-Master-Secret, if the PKCS1 padding check should fail.
*/
byte[] fallback = new byte[48];
secureRandom.nextBytes(fallback);
@@ -110,46 +105,31 @@ protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
catch (Exception e)
{
/*
- * This should never happen since the decryption should never throw an exception
- * and return a random value instead.
+ * This should never happen since the decryption should never throw an exception and return a
+ * random value instead.
*
- * In any case, a TLS server MUST NOT generate an alert if processing an
- * RSA-encrypted premaster secret message fails, or the version number is not as
- * expected. Instead, it MUST continue the handshake with a randomly generated
- * premaster secret.
+ * In any case, a TLS server MUST NOT generate an alert if processing an RSA-encrypted premaster
+ * secret message fails, or the version number is not as expected. Instead, it MUST continue the
+ * handshake with a randomly generated premaster secret.
*/
}
/*
- * If ClientHello.legacy_version is TLS 1.1 or higher, server implementations MUST check the
- * version number [..].
+ * Compare the version number in the decrypted Pre-Master-Secret with the legacy_version field from
+ * the ClientHello. If they don't match, continue the handshake with the randomly generated 'fallback'
+ * value.
+ *
+ * NOTE: The comparison and replacement must be constant-time.
*/
- if (versionNumberCheckDisabled && !TlsImplUtils.isTLSv11(expectedVersion))
- {
- /*
- * If the version number is TLS 1.0 or earlier, server implementations SHOULD check the
- * version number, but MAY have a configuration option to disable the check.
- */
- }
- else
- {
- /*
- * Compare the version number in the decrypted Pre-Master-Secret with the legacy_version
- * field from the ClientHello. If they don't match, continue the handshake with the
- * randomly generated 'fallback' value.
- *
- * NOTE: The comparison and replacement must be constant-time.
- */
- int mask = (expectedVersion.getMajorVersion() ^ (M[0] & 0xFF))
- | (expectedVersion.getMinorVersion() ^ (M[1] & 0xFF));
+ int mask = (expectedVersion.getMajorVersion() ^ (M[0] & 0xFF))
+ | (expectedVersion.getMinorVersion() ^ (M[1] & 0xFF));
- // 'mask' will be all 1s if the versions matched, or else all 0s.
- mask = (mask - 1) >> 31;
+ // 'mask' will be all 1s if the versions matched, or else all 0s.
+ mask = (mask - 1) >> 31;
- for (int i = 0; i < 48; i++)
- {
- M[i] = (byte)((M[i] & mask) | (fallback[i] & ~mask));
- }
+ for (int i = 0; i < 48; i++)
+ {
+ M[i] = (byte)((M[i] & mask) | (fallback[i] & ~mask));
}
return crypto.createSecret(M);
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java
index 21345c464a..3cecb3b788 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java
@@ -12,7 +12,6 @@
import org.bouncycastle.tls.TlsCredentialedDecryptor;
import org.bouncycastle.tls.crypto.TlsCryptoParameters;
import org.bouncycastle.tls.crypto.TlsSecret;
-import org.bouncycastle.tls.crypto.impl.TlsImplUtils;
import org.bouncycastle.util.Arrays;
/**
@@ -70,11 +69,11 @@ public TlsSecret decrypt(TlsCryptoParameters cryptoParams, byte[] ciphertext) th
}
/*
- * TODO[tls-ops] Probably need to make RSA encryption/decryption into TlsCrypto functions so
- * that users can implement "generic" encryption credentials externally
+ * TODO[tls-ops] Probably need to make RSA encryption/decryption into TlsCrypto functions so that users
+ * can implement "generic" encryption credentials externally
*/
protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams, PrivateKey rsaServerPrivateKey,
- byte[] encryptedPreMasterSecret)
+ byte[] encryptedPreMasterSecret)
{
SecureRandom secureRandom = crypto.getSecureRandom();
@@ -83,12 +82,8 @@ protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
*/
ProtocolVersion expectedVersion = cryptoParams.getRSAPreMasterSecretVersion();
- // TODO Provide as configuration option?
- boolean versionNumberCheckDisabled = false;
-
/*
- * Generate 48 random bytes we can use as a Pre-Master-Secret, if the
- * PKCS1 padding check should fail.
+ * Generate 48 random bytes we can use as a Pre-Master-Secret, if the PKCS1 padding check should fail.
*/
byte[] fallback = new byte[48];
secureRandom.nextBytes(fallback);
@@ -107,43 +102,28 @@ protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
catch (Exception e)
{
/*
- * A TLS server MUST NOT generate an alert if processing an
- * RSA-encrypted premaster secret message fails, or the version number is not as
- * expected. Instead, it MUST continue the handshake with a randomly generated
- * premaster secret.
+ * A TLS server MUST NOT generate an alert if processing an RSA-encrypted premaster secret message
+ * fails, or the version number is not as expected. Instead, it MUST continue the handshake with a
+ * randomly generated premaster secret.
*/
}
/*
- * If ClientHello.legacy_version is TLS 1.1 or higher, server implementations MUST check the
- * version number [..].
+ * Compare the version number in the decrypted Pre-Master-Secret with the legacy_version field from
+ * the ClientHello. If they don't match, continue the handshake with the randomly generated 'fallback'
+ * value.
+ *
+ * NOTE: The comparison and replacement must be constant-time.
*/
- if (versionNumberCheckDisabled && !TlsImplUtils.isTLSv11(expectedVersion))
- {
- /*
- * If the version number is TLS 1.0 or earlier, server implementations SHOULD check the
- * version number, but MAY have a configuration option to disable the check.
- */
- }
- else
- {
- /*
- * Compare the version number in the decrypted Pre-Master-Secret with the legacy_version
- * field from the ClientHello. If they don't match, continue the handshake with the
- * randomly generated 'fallback' value.
- *
- * NOTE: The comparison and replacement must be constant-time.
- */
- int mask = (expectedVersion.getMajorVersion() ^ (M[0] & 0xFF))
- | (expectedVersion.getMinorVersion() ^ (M[1] & 0xFF));
+ int mask = (expectedVersion.getMajorVersion() ^ (M[0] & 0xFF))
+ | (expectedVersion.getMinorVersion() ^ (M[1] & 0xFF));
- // 'mask' will be all 1s if the versions matched, or else all 0s.
- mask = (mask - 1) >> 31;
+ // 'mask' will be all 1s if the versions matched, or else all 0s.
+ mask = (mask - 1) >> 31;
- for (int i = 0; i < 48; i++)
- {
- M[i] = (byte)((M[i] & mask) | (fallback[i] & ~mask));
- }
+ for (int i = 0; i < 48; i++)
+ {
+ M[i] = (byte)((M[i] & mask) | (fallback[i] & ~mask));
}
return crypto.createSecret(M);
From db2bf0ee06feb232bd30a1cd78c2f5627c673fcc Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 22 Feb 2024 10:22:34 +1030
Subject: [PATCH 0084/1846] Add tests for CAMELLIA
---
.../bc/BcPublicKeyDataDecryptorFactory.java | 24 +++++++------------
.../openpgp/test/BcPGPPBETest.java | 2 +-
2 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index 6af601306d..864ea1a59a 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -2,6 +2,7 @@
import java.io.IOException;
import java.math.BigInteger;
+import java.util.Arrays;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
@@ -91,10 +92,7 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
}
bi = secKeyData[1]; // encoded MPI
- for (int i = 0; i != tmp.length; i++)
- {
- tmp[i] = 0;
- }
+ Arrays.fill(tmp, (byte)0);
if (bi.length - 2 > size) // leading Zero? Shouldn't happen but...
{
@@ -137,19 +135,11 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
if (ecPubKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
// skip the 0x40 header byte.
- if (pEnc.length != (1 + X25519PublicKeyParameters.KEY_SIZE) || 0x40 != pEnc[0])
- {
- throw new IllegalArgumentException("Invalid Curve25519 public key");
- }
- secret = getSecret(new X25519Agreement(), privKey, new X25519PublicKeyParameters(pEnc, 1));
+ secret = getSecret(new X25519Agreement(), pEnc.length != 1 + X25519PublicKeyParameters.KEY_SIZE || 0x40 != pEnc[0], privKey, new X25519PublicKeyParameters(pEnc, 1), "25519");
}
else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
{
- if (pEnc.length != (X448PublicKeyParameters.KEY_SIZE))
- {
- throw new IllegalArgumentException("Invalid Curve448 public key");
- }
- secret = getSecret(new X448Agreement(), privKey, new X448PublicKeyParameters(pEnc, 0));
+ secret = getSecret(new X448Agreement(), pEnc.length != X448PublicKeyParameters.KEY_SIZE, privKey, new X448PublicKeyParameters(pEnc, 0), "448");
}
else
{
@@ -188,8 +178,12 @@ else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
}
- private static byte[] getSecret(RawAgreement agreement, AsymmetricKeyParameter privKey, AsymmetricKeyParameter ephPub)
+ private static byte[] getSecret(RawAgreement agreement, boolean condition, AsymmetricKeyParameter privKey, AsymmetricKeyParameter ephPub, String curve)
{
+ if (condition)
+ {
+ throw new IllegalArgumentException("Invalid Curve" + curve + " public key");
+ }
agreement.init(privKey);
byte[] secret = new byte[agreement.getAgreementSize()];
agreement.calculateAgreement(ephPub, secret, 0);
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/BcPGPPBETest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/BcPGPPBETest.java
index 766126b1f2..9da5273c73 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/BcPGPPBETest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/BcPGPPBETest.java
@@ -439,7 +439,7 @@ public void performTest()
}
tryAlgorithm(PGPEncryptedData.AES_128, text);
- //tryAlgorithm(PGPEncryptedData.CAMELLIA_128, text);
+ tryAlgorithm(PGPEncryptedData.CAMELLIA_128, text);
}
private void tryAlgorithm(int algorithm, byte[] text)
From 85b34a6042dceff87dcda7d76f5b94279202e99e Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 22 Feb 2024 10:58:38 +1030
Subject: [PATCH 0085/1846] set default initial value for camellia
---
.../openpgp/operator/bc/BcAEADUtil.java | 13 ++++++++++
.../bc/BcPBEDataDecryptorFactory.java | 20 +++++++++-------
.../bc/BcPBEKeyEncryptionMethodGenerator.java | 4 +++-
.../openpgp/operator/bc/BcUtil.java | 7 +++---
.../openpgp/operator/jcajce/JceAEADUtil.java | 15 ++++++++++++
.../JcePBEDataDecryptorFactoryBuilder.java | 24 +++++++++----------
.../JcePBEKeyEncryptionMethodGenerator.java | 12 +++++-----
.../jcajce/JcePGPDataEncryptorBuilder.java | 2 +-
.../operator/jcajce/OperatorHelper.java | 2 +-
9 files changed, 66 insertions(+), 33 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
index 8abf80b15d..e636e375ab 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
@@ -34,6 +34,8 @@
public class BcAEADUtil
{
+ final static byte[] defaultIV = new byte[]{-90, -90, -90, -90, -90, -90, -90, -90};
+
/**
* Generate a nonce by xor-ing the given iv with the chunk index.
*
@@ -258,6 +260,17 @@ public PGPDigestCalculator getIntegrityCalculator()
};
}
+ static byte[] getDefaultIV(BlockCipher engine)
+ {
+ byte[] iv = new byte[engine.getBlockSize()];
+ if(engine instanceof CamelliaEngine)
+ {
+ // RFC3657 section 3.4.1 default initial value
+ System.arraycopy(defaultIV, 0, iv, 0,defaultIV.length);
+ }
+ return iv;
+ }
+
protected static class PGPAeadInputStream
extends InputStream
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEDataDecryptorFactory.java
index c48bdda65b..7fe6c8bc45 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEDataDecryptorFactory.java
@@ -9,6 +9,7 @@
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.engines.CamelliaEngine;
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
import org.bouncycastle.crypto.modes.AEADBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
@@ -29,8 +30,8 @@ public class BcPBEDataDecryptorFactory
/**
* Base constructor.
*
- * @param pass the passphrase to use as the primary source of key material.
- * @param calculatorProvider a digest calculator provider to provide calculators to support the key generation calculation required.
+ * @param pass the passphrase to use as the primary source of key material.
+ * @param calculatorProvider a digest calculator provider to provide calculators to support the key generation calculation required.
*/
public BcPBEDataDecryptorFactory(char[] pass, BcPGPDigestCalculatorProvider calculatorProvider)
{
@@ -41,9 +42,9 @@ public BcPBEDataDecryptorFactory(char[] pass, BcPGPDigestCalculatorProvider calc
* Recover the session key from a version 4 SKESK packet used in OpenPGP v4.
*
* @param keyAlgorithm the {@link SymmetricKeyAlgorithmTags encryption algorithm} used to
- * encrypt the session data.
- * @param key the key bytes for the encryption algorithm.
- * @param secKeyData the encrypted session data to decrypt.
+ * encrypt the session data.
+ * @param key the key bytes for the encryption algorithm.
+ * @param secKeyData the encrypted session data to decrypt.
* @return session key
* @throws PGPException
*/
@@ -56,7 +57,8 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[] key, byte[] secKeyData
if (secKeyData != null && secKeyData.length > 0)
{
BlockCipher engine = BcImplProvider.createBlockCipher(keyAlgorithm);
- BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(false, engine, key, new byte[engine.getBlockSize()]);
+ byte[] iv = BcAEADUtil.getDefaultIV(engine);
+ BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(false, engine, key, iv);
byte[] out = new byte[secKeyData.length];
@@ -84,7 +86,7 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[] key, byte[] secKeyData
@Override
public byte[] recoverAEADEncryptedSessionData(SymmetricKeyEncSessionPacket keyData, byte[] ikm)
- throws PGPException
+ throws PGPException
{
if (keyData.getVersion() < SymmetricKeyEncSessionPacket.VERSION_5)
{
@@ -111,7 +113,7 @@ public byte[] recoverAEADEncryptedSessionData(SymmetricKeyEncSessionPacket keyDa
// sessionData := AEAD(secretKey).decrypt(encSessionKey || authTag)
AEADParameters parameters = new AEADParameters(secretKey,
- aeadMacLen, aeadIv, keyData.getAAData());
+ aeadMacLen, aeadIv, keyData.getAAData());
aead.init(false, parameters);
int sessionKeyLen = aead.getOutputSize(encSessionKey.length + authTag.length);
byte[] sessionData = new byte[sessionKeyLen];
@@ -151,7 +153,7 @@ public PGPDataDecryptor createDataDecryptor(AEADEncDataPacket aeadEncDataPacket,
// OpenPGP v6
@Override
public PGPDataDecryptor createDataDecryptor(SymmetricEncIntegrityPacket seipd, PGPSessionKey sessionKey)
- throws PGPException
+ throws PGPException
{
return BcAEADUtil.createOpenPgpV6DataDecryptor(seipd, sessionKey);
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEKeyEncryptionMethodGenerator.java
index 950b072f52..c33536c797 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEKeyEncryptionMethodGenerator.java
@@ -6,6 +6,7 @@
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.engines.CamelliaEngine;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.operator.PBEKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
@@ -88,7 +89,8 @@ protected byte[] encryptSessionInfo(int encAlgorithm, byte[] key, byte[] session
try
{
BlockCipher engine = BcImplProvider.createBlockCipher(encAlgorithm);
- BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(true, engine, key, new byte[engine.getBlockSize()]);
+ byte[] iv = BcAEADUtil.getDefaultIV(engine);
+ BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(true, engine, key, iv);
byte[] out = new byte[sessionInfo.length];
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java
index 4a03d8c37e..6c40b09e06 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java
@@ -43,7 +43,7 @@ static BufferedBlockCipher createStreamCipher(boolean forEncryption, BlockCipher
if (withIntegrityPacket)
{
- c.init(forEncryption, new ParametersWithIV(keyParameter, new byte[engine.getBlockSize()]));
+ c.init(forEncryption, new ParametersWithIV(keyParameter, BcAEADUtil.getDefaultIV(engine)));
}
else
{
@@ -59,10 +59,11 @@ static BufferedBlockCipher createStreamCipher(boolean forEncryption, BlockCipher
* Data (SEIPD) packets.
* For AEAD packets, see {@link BcAEADUtil#createOpenPgpV5DataDecryptor(AEADEncDataPacket, PGPSessionKey)} and
* {@link BcAEADUtil#createOpenPgpV6DataDecryptor(SymmetricEncIntegrityPacket, PGPSessionKey)}.
+ *
* @param withIntegrityPacket if true, the data is contained in a SEIPD v1 packet, if false it is contained in a
* SED packet.
- * @param engine decryption engine
- * @param key decryption key
+ * @param engine decryption engine
+ * @param key decryption key
* @return decryptor
*/
public static PGPDataDecryptor createDataDecryptor(boolean withIntegrityPacket, BlockCipher engine, byte[] key)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
index e3f7bb90c8..7162a45267 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
@@ -4,6 +4,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
+import java.util.Locale;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
@@ -30,6 +31,8 @@
class JceAEADUtil
{
+ final static byte[] defaultIV = new byte[]{-90, -90, -90, -90, -90, -90, -90, -90};
+
private final OperatorHelper helper;
public JceAEADUtil(OperatorHelper helper)
@@ -271,6 +274,18 @@ Cipher createAEADCipher(int encAlgorithm, int aeadAlgorithm)
return helper.createCipher(cName);
}
+ static byte[] getDefaultIV(Cipher c)
+ {
+ byte[] iv = new byte[c.getBlockSize()];
+ String algorithm = c.getAlgorithm().toLowerCase(Locale.getDefault());
+ if (algorithm.contains("camellia"))
+ {
+ // RFC3657 section 3.4.1 default initial value
+ System.arraycopy(defaultIV, 0, iv, 0, defaultIV.length);
+ }
+ return iv;
+ }
+
static class PGPAeadInputStream
extends InputStream
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEDataDecryptorFactoryBuilder.java
index 7665f90eec..264aef000d 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEDataDecryptorFactoryBuilder.java
@@ -47,7 +47,7 @@ public JcePBEDataDecryptorFactoryBuilder()
/**
* Base constructor.
*
- * @param calculatorProvider a digest calculator provider to provide calculators to support the key generation calculation required.
+ * @param calculatorProvider a digest calculator provider to provide calculators to support the key generation calculation required.
*/
public JcePBEDataDecryptorFactoryBuilder(PGPDigestCalculatorProvider calculatorProvider)
{
@@ -57,8 +57,8 @@ public JcePBEDataDecryptorFactoryBuilder(PGPDigestCalculatorProvider calculatorP
/**
* Set the provider object to use for creating cryptographic primitives in the resulting factory the builder produces.
*
- * @param provider provider object for cryptographic primitives.
- * @return the current builder.
+ * @param provider provider object for cryptographic primitives.
+ * @return the current builder.
*/
public JcePBEDataDecryptorFactoryBuilder setProvider(Provider provider)
{
@@ -71,8 +71,8 @@ public JcePBEDataDecryptorFactoryBuilder setProvider(Provider provider)
/**
* Set the provider name to use for creating cryptographic primitives in the resulting factory the builder produces.
*
- * @param providerName the name of the provider to reference for cryptographic primitives.
- * @return the current builder.
+ * @param providerName the name of the provider to reference for cryptographic primitives.
+ * @return the current builder.
*/
public JcePBEDataDecryptorFactoryBuilder setProvider(String providerName)
{
@@ -105,7 +105,7 @@ public PBEDataDecryptorFactory build(char[] passPhrase)
{
@Override
public byte[] recoverSessionData(int keyAlgorithm, byte[] key, byte[] secKeyData)
- throws PGPException
+ throws PGPException
{
try
{
@@ -113,8 +113,8 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[] key, byte[] secKeyData
{
String cipherName = PGPUtil.getSymmetricCipherName(keyAlgorithm);
Cipher keyCipher = helper.createCipher(cipherName + "/CFB/NoPadding");
-
- keyCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, cipherName), new IvParameterSpec(new byte[keyCipher.getBlockSize()]));
+ byte[] iv = JceAEADUtil.getDefaultIV(keyCipher);
+ keyCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, cipherName), new IvParameterSpec(iv));
return keyCipher.doFinal(secKeyData);
}
@@ -136,7 +136,7 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[] key, byte[] secKeyData
@Override
public byte[] recoverAEADEncryptedSessionData(SymmetricKeyEncSessionPacket keyData, byte[] ikm)
- throws PGPException
+ throws PGPException
{
if (keyData.getVersion() < SymmetricKeyEncSessionPacket.VERSION_5)
{
@@ -186,7 +186,7 @@ public byte[] recoverAEADEncryptedSessionData(SymmetricKeyEncSessionPacket keyDa
// OpenPGP v4
@Override
public PGPDataDecryptor createDataDecryptor(boolean withIntegrityPacket, int encAlgorithm, byte[] key)
- throws PGPException
+ throws PGPException
{
return helper.createDataDecryptor(withIntegrityPacket, encAlgorithm, key);
}
@@ -194,7 +194,7 @@ public PGPDataDecryptor createDataDecryptor(boolean withIntegrityPacket, int enc
// OpenPGP v5
@Override
public PGPDataDecryptor createDataDecryptor(AEADEncDataPacket aeadEncDataPacket, PGPSessionKey sessionKey)
- throws PGPException
+ throws PGPException
{
return aeadHelper.createOpenPgpV5DataDecryptor(aeadEncDataPacket, sessionKey);
}
@@ -202,7 +202,7 @@ public PGPDataDecryptor createDataDecryptor(AEADEncDataPacket aeadEncDataPacket,
// OpenPGP v6
@Override
public PGPDataDecryptor createDataDecryptor(SymmetricEncIntegrityPacket seipd, PGPSessionKey sessionKey)
- throws PGPException
+ throws PGPException
{
return aeadHelper.createOpenPgpV6DataDecryptor(seipd, sessionKey);
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java
index 935d9165bf..542d8c2584 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java
@@ -33,7 +33,7 @@ public class JcePBEKeyEncryptionMethodGenerator
* Create a PBE encryption method generator using the provided digest and the default S2K count
* for key generation.
*
- * @param passPhrase the passphrase to use as the primary source of key material.
+ * @param passPhrase the passphrase to use as the primary source of key material.
* @param s2kDigestCalculator the digest calculator to use for key calculation.
*/
public JcePBEKeyEncryptionMethodGenerator(char[] passPhrase, PGPDigestCalculator s2kDigestCalculator)
@@ -56,9 +56,9 @@ public JcePBEKeyEncryptionMethodGenerator(char[] passPhrase)
* Create a PBE encryption method generator using the provided calculator and S2K count for key
* generation.
*
- * @param passPhrase the passphrase to use as the primary source of key material.
+ * @param passPhrase the passphrase to use as the primary source of key material.
* @param s2kDigestCalculator the digest calculator to use for key calculation.
- * @param s2kCount the single byte {@link S2K} count to use.
+ * @param s2kCount the single byte {@link S2K} count to use.
*/
public JcePBEKeyEncryptionMethodGenerator(char[] passPhrase, PGPDigestCalculator s2kDigestCalculator, int s2kCount)
{
@@ -70,7 +70,7 @@ public JcePBEKeyEncryptionMethodGenerator(char[] passPhrase, PGPDigestCalculator
* count other than the default for key generation.
*
* @param passPhrase the passphrase to use as the primary source of key material.
- * @param s2kCount the single byte {@link S2K} count to use.
+ * @param s2kCount the single byte {@link S2K} count to use.
*/
public JcePBEKeyEncryptionMethodGenerator(char[] passPhrase, int s2kCount)
{
@@ -118,8 +118,8 @@ protected byte[] encryptSessionInfo(int encAlgorithm, byte[] key, byte[] session
String cName = PGPUtil.getSymmetricCipherName(encAlgorithm);
Cipher c = helper.createCipher(cName + "/CFB/NoPadding");
SecretKey sKey = new SecretKeySpec(key, PGPUtil.getSymmetricCipherName(encAlgorithm));
-
- c.init(Cipher.ENCRYPT_MODE, sKey, new IvParameterSpec(new byte[c.getBlockSize()]));
+ byte[] iv = JceAEADUtil.getDefaultIV(c);
+ c.init(Cipher.ENCRYPT_MODE, sKey, new IvParameterSpec(iv));
return c.doFinal(sessionInfo, 0, sessionInfo.length);
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java
index de7c1d0d9e..1616a12518 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java
@@ -220,7 +220,7 @@ private class MyPGPDataEncryptor
{
if (withIntegrityPacket)
{
- byte[] iv = new byte[c.getBlockSize()];
+ byte[] iv = JceAEADUtil.getDefaultIV(c);
c.init(Cipher.ENCRYPT_MODE, JcaJcePGPUtil.makeSymmetricKey(encAlgorithm, keyBytes), new IvParameterSpec(iv));
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
index 3f8a96b87a..5ee9c2f2c8 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
@@ -128,7 +128,7 @@ PGPDataDecryptor createDataDecryptor(boolean withIntegrityPacket, int encAlgorit
if (withIntegrityPacket)
{
- byte[] iv = new byte[c.getBlockSize()];
+ byte[] iv = JceAEADUtil.getDefaultIV(c);
c.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
}
From 103afe3bd4816bbae0e2696cd1d259305ec0ddbf Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 22 Feb 2024 11:18:22 +1030
Subject: [PATCH 0086/1846] rollback the setting for default iv of camellia
---
.../openpgp/operator/bc/BcAEADUtil.java | 13 -------------
.../operator/bc/BcPBEDataDecryptorFactory.java | 3 +--
.../bc/BcPBEKeyEncryptionMethodGenerator.java | 3 +--
.../bouncycastle/openpgp/operator/bc/BcUtil.java | 2 +-
.../openpgp/operator/jcajce/JceAEADUtil.java | 15 ---------------
.../jcajce/JcePBEDataDecryptorFactoryBuilder.java | 3 +--
.../JcePBEKeyEncryptionMethodGenerator.java | 3 +--
.../jcajce/JcePGPDataEncryptorBuilder.java | 4 +---
.../openpgp/operator/jcajce/OperatorHelper.java | 4 +---
9 files changed, 7 insertions(+), 43 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
index e636e375ab..8abf80b15d 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcAEADUtil.java
@@ -34,8 +34,6 @@
public class BcAEADUtil
{
- final static byte[] defaultIV = new byte[]{-90, -90, -90, -90, -90, -90, -90, -90};
-
/**
* Generate a nonce by xor-ing the given iv with the chunk index.
*
@@ -260,17 +258,6 @@ public PGPDigestCalculator getIntegrityCalculator()
};
}
- static byte[] getDefaultIV(BlockCipher engine)
- {
- byte[] iv = new byte[engine.getBlockSize()];
- if(engine instanceof CamelliaEngine)
- {
- // RFC3657 section 3.4.1 default initial value
- System.arraycopy(defaultIV, 0, iv, 0,defaultIV.length);
- }
- return iv;
- }
-
protected static class PGPAeadInputStream
extends InputStream
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEDataDecryptorFactory.java
index 7fe6c8bc45..3dca31d018 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEDataDecryptorFactory.java
@@ -57,8 +57,7 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[] key, byte[] secKeyData
if (secKeyData != null && secKeyData.length > 0)
{
BlockCipher engine = BcImplProvider.createBlockCipher(keyAlgorithm);
- byte[] iv = BcAEADUtil.getDefaultIV(engine);
- BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(false, engine, key, iv);
+ BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(false, engine, key, new byte[engine.getBlockSize()]);
byte[] out = new byte[secKeyData.length];
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEKeyEncryptionMethodGenerator.java
index c33536c797..a18d262413 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPBEKeyEncryptionMethodGenerator.java
@@ -89,8 +89,7 @@ protected byte[] encryptSessionInfo(int encAlgorithm, byte[] key, byte[] session
try
{
BlockCipher engine = BcImplProvider.createBlockCipher(encAlgorithm);
- byte[] iv = BcAEADUtil.getDefaultIV(engine);
- BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(true, engine, key, iv);
+ BufferedBlockCipher cipher = BcUtil.createSymmetricKeyWrapper(true, engine, key, new byte[engine.getBlockSize()]);
byte[] out = new byte[sessionInfo.length];
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java
index 6c40b09e06..4804f3d828 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java
@@ -43,7 +43,7 @@ static BufferedBlockCipher createStreamCipher(boolean forEncryption, BlockCipher
if (withIntegrityPacket)
{
- c.init(forEncryption, new ParametersWithIV(keyParameter, BcAEADUtil.getDefaultIV(engine)));
+ c.init(forEncryption, new ParametersWithIV(keyParameter, new byte[engine.getBlockSize()]));
}
else
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
index 7162a45267..77758b9101 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
@@ -31,8 +31,6 @@
class JceAEADUtil
{
- final static byte[] defaultIV = new byte[]{-90, -90, -90, -90, -90, -90, -90, -90};
-
private final OperatorHelper helper;
public JceAEADUtil(OperatorHelper helper)
@@ -274,19 +272,6 @@ Cipher createAEADCipher(int encAlgorithm, int aeadAlgorithm)
return helper.createCipher(cName);
}
- static byte[] getDefaultIV(Cipher c)
- {
- byte[] iv = new byte[c.getBlockSize()];
- String algorithm = c.getAlgorithm().toLowerCase(Locale.getDefault());
- if (algorithm.contains("camellia"))
- {
- // RFC3657 section 3.4.1 default initial value
- System.arraycopy(defaultIV, 0, iv, 0, defaultIV.length);
- }
- return iv;
- }
-
-
static class PGPAeadInputStream
extends InputStream
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEDataDecryptorFactoryBuilder.java
index 264aef000d..8687678369 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEDataDecryptorFactoryBuilder.java
@@ -113,8 +113,7 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[] key, byte[] secKeyData
{
String cipherName = PGPUtil.getSymmetricCipherName(keyAlgorithm);
Cipher keyCipher = helper.createCipher(cipherName + "/CFB/NoPadding");
- byte[] iv = JceAEADUtil.getDefaultIV(keyCipher);
- keyCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, cipherName), new IvParameterSpec(iv));
+ keyCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, cipherName), new IvParameterSpec(new byte[keyCipher.getBlockSize()]));
return keyCipher.doFinal(secKeyData);
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java
index 542d8c2584..2ff933d2ba 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePBEKeyEncryptionMethodGenerator.java
@@ -118,8 +118,7 @@ protected byte[] encryptSessionInfo(int encAlgorithm, byte[] key, byte[] session
String cName = PGPUtil.getSymmetricCipherName(encAlgorithm);
Cipher c = helper.createCipher(cName + "/CFB/NoPadding");
SecretKey sKey = new SecretKeySpec(key, PGPUtil.getSymmetricCipherName(encAlgorithm));
- byte[] iv = JceAEADUtil.getDefaultIV(c);
- c.init(Cipher.ENCRYPT_MODE, sKey, new IvParameterSpec(iv));
+ c.init(Cipher.ENCRYPT_MODE, sKey, new IvParameterSpec(new byte[c.getBlockSize()]));
return c.doFinal(sessionInfo, 0, sessionInfo.length);
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java
index 1616a12518..2092927105 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePGPDataEncryptorBuilder.java
@@ -220,9 +220,7 @@ private class MyPGPDataEncryptor
{
if (withIntegrityPacket)
{
- byte[] iv = JceAEADUtil.getDefaultIV(c);
-
- c.init(Cipher.ENCRYPT_MODE, JcaJcePGPUtil.makeSymmetricKey(encAlgorithm, keyBytes), new IvParameterSpec(iv));
+ c.init(Cipher.ENCRYPT_MODE, JcaJcePGPUtil.makeSymmetricKey(encAlgorithm, keyBytes), new IvParameterSpec(new byte[c.getBlockSize()]));
}
else
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
index 5ee9c2f2c8..91ba8d54ab 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
@@ -128,9 +128,7 @@ PGPDataDecryptor createDataDecryptor(boolean withIntegrityPacket, int encAlgorit
if (withIntegrityPacket)
{
- byte[] iv = JceAEADUtil.getDefaultIV(c);
-
- c.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
+ c.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(new byte[c.getBlockSize()]));
}
else
{
From fd2b83505dfd24c0378943a0a5478c255dcf239b Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 22 Feb 2024 11:19:19 +1030
Subject: [PATCH 0087/1846] rollback the setting for default iv of camellia
---
.../org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
index 77758b9101..0b7a1ccfea 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JceAEADUtil.java
@@ -4,7 +4,6 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.security.GeneralSecurityException;
-import java.util.Locale;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
From ea2b9b9f1ad8958744701e045fdbc63938e87dcb Mon Sep 17 00:00:00 2001
From: gefeili
Date: Thu, 22 Feb 2024 17:01:42 +1030
Subject: [PATCH 0088/1846] Correct words in IllegalArgumentException. TODO:
Derive Ed25519 and Ed448 from EdDsa
---
.../operator/PublicKeyKeyEncryptionMethodGenerator.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
index 75e2b292de..90843616d8 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
@@ -46,9 +46,10 @@ protected PublicKeyKeyEncryptionMethodGenerator(
case PGPPublicKey.DSA:
throw new IllegalArgumentException("Can't use DSA for encryption.");
case PGPPublicKey.ECDSA:
+ throw new IllegalArgumentException("Can't use ECDSA for encryption.");
case PublicKeyAlgorithmTags.Ed448:
case PublicKeyAlgorithmTags.Ed25519:
- throw new IllegalArgumentException("Can't use ECDSA for encryption.");
+ throw new IllegalArgumentException("Can't use EdDSA for encryption.");
default:
throw new IllegalArgumentException("unknown asymmetric algorithm: " + pubKey.getAlgorithm());
}
From eafd9a23f924fef52d698559794f24e060c95e3d Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 23 Feb 2024 10:59:12 +1030
Subject: [PATCH 0089/1846] Ed448PublicBCPGKey works now.
---
.../bouncycastle/bcpg/Ed448PublicBCPGKey.java | 5 +-
.../bouncycastle/bcpg/OctetArrayBCPGKey.java | 51 +++++++++
.../bouncycastle/bcpg/PublicKeyPacket.java | 4 +-
.../operator/bc/BcPGPKeyConverter.java | 12 +-
.../jcajce/JcaPGPContentSignerBuilder.java | 11 +-
.../JcaPGPContentVerifierBuilderProvider.java | 14 +--
.../operator/jcajce/JcaPGPKeyConverter.java | 19 ++-
.../openpgp/test/BcpgGeneralTest.java | 2 +-
.../openpgp/test/OperatorBcTest.java | 108 ++++++++++++++++--
9 files changed, 188 insertions(+), 38 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/Ed448PublicBCPGKey.java b/pg/src/main/java/org/bouncycastle/bcpg/Ed448PublicBCPGKey.java
index 2ec27a14d2..f66a00a4de 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/Ed448PublicBCPGKey.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/Ed448PublicBCPGKey.java
@@ -3,13 +3,14 @@
import java.io.IOException;
public class Ed448PublicBCPGKey
- extends OctetArrayBCPGKey
+ extends OctetArrayBCPGKey
{
public static final int LENGTH = 57;
public Ed448PublicBCPGKey(BCPGInputStream in)
- throws IOException
+ throws IOException
{
+ //super(in);
super(LENGTH, in);
}
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java b/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java
index f4875edea5..d9bbf8e81a 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java
@@ -1,7 +1,10 @@
package org.bouncycastle.bcpg;
import java.io.IOException;
+import java.math.BigInteger;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.util.Arrays;
/**
@@ -12,6 +15,48 @@ public abstract class OctetArrayBCPGKey
implements BCPGKey
{
private final byte[] key;
+ ASN1ObjectIdentifier oid;
+ BigInteger point;
+
+ //TODO remove this method
+ OctetArrayBCPGKey(BCPGInputStream in)
+ throws IOException
+ {
+ this.oid = ASN1ObjectIdentifier.getInstance(ASN1Primitive.fromByteArray(readBytesOfEncodedLength(in)));
+ this.point = new MPInteger(in).getValue();
+ key = point.toByteArray();
+ }
+
+ public BigInteger getEncodedPoint()
+ {
+ return point;
+ }
+
+ protected static byte[] readBytesOfEncodedLength(
+ BCPGInputStream in)
+ throws IOException
+ {
+ int length = in.read();
+ if (length < 0)
+ {
+ throw new IOException("unexpected end-of-stream");
+ }
+ if (length == 0 || length == 0xFF)
+ {
+ throw new IOException("future extensions not yet implemented");
+ }
+ if (length > 127)
+ {
+ throw new IOException("unsupported OID");
+ }
+
+ byte[] buffer = new byte[length + 2];
+ in.readFully(buffer, 2, buffer.length - 2);
+ buffer[0] = (byte)0x06;
+ buffer[1] = (byte)length;
+
+ return buffer;
+ }
OctetArrayBCPGKey(int length, BCPGInputStream in)
throws IOException
@@ -59,6 +104,12 @@ public void encode(BCPGOutputStream out)
throws IOException
{
out.write(key);
+// //TODO
+// byte[] oid = this.oid.getEncoded();
+// out.write(oid, 1, oid.length - 1);
+//
+// MPInteger point = new MPInteger(this.point);
+// out.writeObject(point);
}
public byte[] getKey()
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java
index 91d62f0d39..b898b412f0 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java
@@ -74,9 +74,11 @@ public class PublicKeyPacket
break;
case EDDSA_LEGACY:
case Ed25519:
- case Ed448:
key = new EdDSAPublicBCPGKey(in);
break;
+ case Ed448:
+ key = new Ed448PublicBCPGKey(in);
+ break;
default:
throw new IOException("unknown PGP public key algorithm encountered: " + algorithm);
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
index c21014058c..a9d0190c51 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
@@ -20,6 +20,7 @@
import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
import org.bouncycastle.bcpg.ECPublicBCPGKey;
import org.bouncycastle.bcpg.ECSecretBCPGKey;
+import org.bouncycastle.bcpg.Ed448PublicBCPGKey;
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
import org.bouncycastle.bcpg.EdSecretBCPGKey;
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
@@ -30,6 +31,7 @@
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.bcpg.RSASecretBCPGKey;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.bcpg.X448PublicBCPGKey;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
@@ -157,7 +159,9 @@ else if (EdECObjectIdentifiers.id_X448.equals(ecdhPub.getCurveOID()))
}
case PublicKeyAlgorithmTags.Ed448:
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed448, Ed448.SECRET_KEY_SIZE, privPk);
+ return PrivateKeyFactory.createKey((new PrivateKeyInfo(
+ new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448),
+ new DEROctetString(BigIntegers.asUnsignedByteArray(Ed448.SECRET_KEY_SIZE, ((EdSecretBCPGKey)privPk).getX())))));
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
@@ -265,9 +269,9 @@ else if (eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
}
case PublicKeyAlgorithmTags.Ed448:
{
- EdDSAPublicBCPGKey eddsaK = (EdDSAPublicBCPGKey)publicPk.getKey();
+ Ed448PublicBCPGKey eddsaK = (Ed448PublicBCPGKey)publicPk.getKey();
- byte[] pEnc = BigIntegers.asUnsignedByteArray(eddsaK.getEncodedPoint());
+ byte[] pEnc = eddsaK.getKey().clone();
return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed448, pEnc, 0);
}
@@ -476,7 +480,7 @@ else if (pubKey instanceof Ed448PublicKeyParameters)
{
byte[] pointEnc = new byte[Ed448PublicKeyParameters.KEY_SIZE];
((Ed448PublicKeyParameters)pubKey).encode(pointEnc, 0);
- return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, pointEnc));
+ return new Ed448PublicBCPGKey(pointEnc);
}
else if (pubKey instanceof X25519PublicKeyParameters)
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPContentSignerBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPContentSignerBuilder.java
index b353482651..de028e85cc 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPContentSignerBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPContentSignerBuilder.java
@@ -95,15 +95,7 @@ public PGPContentSigner build(final int signatureType, final long keyID, final P
final PGPDigestCalculator digestCalculator = digestCalculatorProviderBuilder.build().get(hashAlgorithm);
final PGPDigestCalculator edDigestCalculator = digestCalculatorProviderBuilder.build().get(hashAlgorithm);
final Signature signature;
- if (privateKey.getAlgorithm().equalsIgnoreCase("ed448") && keyAlgorithm == PublicKeyAlgorithmTags.EDDSA_LEGACY)
- {
- signature = helper.createSignature(PublicKeyAlgorithmTags.Ed448, hashAlgorithm);
- }
- else
- {
- signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
- }
-
+ signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
try
{
@@ -124,6 +116,7 @@ public PGPContentSigner build(final int signatureType, final long keyID, final P
return new PGPContentSigner()
{
private final boolean isEdDsa = keyAlgorithm == PublicKeyAlgorithmTags.EDDSA_LEGACY || keyAlgorithm == PublicKeyAlgorithmTags.Ed448 || keyAlgorithm == PublicKeyAlgorithmTags.Ed25519;
+
public int getType()
{
return signatureType;
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPContentVerifierBuilderProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPContentVerifierBuilderProvider.java
index cc3b48a5b5..de459a43ac 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPContentVerifierBuilderProvider.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPContentVerifierBuilderProvider.java
@@ -73,17 +73,8 @@ public JcaPGPContentVerifierBuilder(int keyAlgorithm, int hashAlgorithm)
public PGPContentVerifier build(final PGPPublicKey publicKey)
throws PGPException
{
- final Signature signature;
- if (keyAlgorithm == PublicKeyAlgorithmTags.EDDSA_LEGACY &&
- publicKey.getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey
- && ((EdDSAPublicBCPGKey)publicKey.getPublicKeyPacket().getKey()).getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
- {
- signature = helper.createSignature(PublicKeyAlgorithmTags.Ed448, hashAlgorithm);
- }
- else
- {
- signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
- }
+ final Signature signature = helper.createSignature(keyAlgorithm, hashAlgorithm);
+
final PGPDigestCalculator digestCalculator = digestCalculatorProviderBuilder.build().get(hashAlgorithm);
final PublicKey jcaKey = keyConverter.getPublicKey(publicKey);
@@ -99,6 +90,7 @@ public PGPContentVerifier build(final PGPPublicKey publicKey)
return new PGPContentVerifier()
{
private final boolean isEdDsa = keyAlgorithm == PublicKeyAlgorithmTags.EDDSA_LEGACY || keyAlgorithm == PublicKeyAlgorithmTags.Ed448 || keyAlgorithm == PublicKeyAlgorithmTags.Ed25519;
+
public int getHashAlgorithm()
{
return hashAlgorithm;
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
index d65d3c831f..447248f805 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
@@ -57,6 +57,7 @@
import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
import org.bouncycastle.bcpg.ECPublicBCPGKey;
import org.bouncycastle.bcpg.ECSecretBCPGKey;
+import org.bouncycastle.bcpg.Ed448PublicBCPGKey;
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
import org.bouncycastle.bcpg.EdSecretBCPGKey;
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
@@ -329,7 +330,16 @@ else if (EdECObjectIdentifiers.id_X448.equals(ecdhK.getCurveOID()))
}
case PublicKeyAlgorithmTags.Ed448:
{
- return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed448, ((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint());
+ BCPGKey key = publicPk.getKey();
+ if (key instanceof Ed448PublicBCPGKey)
+ {
+ return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed448, new BigInteger(1,((Ed448PublicBCPGKey)publicPk.getKey()).getEncoded()));
+ }
+ else
+ {
+ return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed448, ((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint());
+ }
+
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
@@ -529,7 +539,12 @@ else if (pubKey.getAlgorithm().regionMatches(true, 0, "X2", 0, 2))
}
else if (pubKey.getAlgorithm().regionMatches(true, 0, "ED4", 0, 3))
{
- return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, getPointEnc(pubKey, Ed448.PUBLIC_KEY_SIZE)));
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+ byte[] pointEnc = new byte[Ed448.PUBLIC_KEY_SIZE];
+
+ System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
+ return new Ed448PublicBCPGKey(pointEnc);
+ //return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, getPointEnc(pubKey, Ed448.PUBLIC_KEY_SIZE)));
}
else if (pubKey.getAlgorithm().regionMatches(true, 0, "X4", 0, 2))
{
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java
index 8ee0027eb7..b425a7f09a 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java
@@ -170,7 +170,7 @@ public void testS2K()
{
S2K s2k = new S2K(HashAlgorithmTags.SHA1);
SymmetricKeyEncSessionPacket packet = SymmetricKeyEncSessionPacket.createV4Packet(SymmetricKeyAlgorithmTags.AES_256, s2k, null);
-
+//PGPObjectFactory
packet = new SymmetricKeyEncSessionPacket(new BCPGInputStream(new ByteArrayInputStream(packet.getEncoded())));
isEquals(s2k.getHashAlgorithm(), packet.getS2K().getHashAlgorithm());
isEquals(s2k.getType(), packet.getS2K().getType());
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index 04772ae6ae..5b455242ee 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -164,27 +164,28 @@ public void testBcPGPDataEncryptorBuilder()
public void testBcPGPKeyPair()
throws Exception
{
+ testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, "Ed448");
testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, PublicKeyAlgorithmTags.X448, "X448");
testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, PublicKeyAlgorithmTags.X25519, "X25519");
testCreateKeyPair(PublicKeyAlgorithmTags.X448, PublicKeyAlgorithmTags.ECDH, "X448");
testCreateKeyPair(PublicKeyAlgorithmTags.X25519, PublicKeyAlgorithmTags.ECDH, "X25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed448, "Ed448");
+ //testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed448, "Ed448");
testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed25519, "Ed25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed448");
+ //testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed448");
testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519");
testCreateKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, "RSA");
testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL");
testCreateKeyPair(PublicKeyAlgorithmTags.DSA, "DSA");
testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "X25519");
testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "X448");
- testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed448");
+// testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed448");
testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519");
testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA");
testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL");
testCreateKeyPair(PublicKeyAlgorithmTags.X25519, "X25519");
testCreateKeyPair(PublicKeyAlgorithmTags.X448, "X448");
testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, "Ed25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, "Ed448");
+
}
private void testCreateKeyPair(int algorithm, String name)
@@ -243,6 +244,8 @@ public void testKeyRings()
throws Exception
{
System.setProperty("enableCamelliaKeyWrapping", "True");
+ keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("ED25519", PublicKeyAlgorithmTags.Ed25519, "X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("ED25519", PublicKeyAlgorithmTags.Ed25519, "X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
@@ -251,13 +254,102 @@ public void testKeyRings()
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_128);
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_192);
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_256);
- keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("Ed448", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X448", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+
+ //keyringTest("Ed448", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X448", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("Ed448", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X448", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_192);
- keyringTest("Ed448", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X448", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_256);
+ keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_192);
+ keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_256);
+
+ }
+
+ private void keyringCompreTest(String ed_str, int ed_num, String x_str, int x_num, int hashAlgorithm, int symmetricWrapAlgorithm)
+ throws Exception
+ {
+
+ String identity = "eric@bouncycastle.org";
+ char[] passPhrase = "Hello, world!".toCharArray();
+
+ KeyPairGenerator edKp = KeyPairGenerator.getInstance("EdDSA", "BC");
+
+ edKp.initialize(new ECNamedCurveGenParameterSpec(ed_str));
+
+ PGPKeyPair dsaKeyPair = new JcaPGPKeyPair(ed_num, edKp.generateKeyPair(), new Date());
+
+ KeyPairGenerator dhKp = KeyPairGenerator.getInstance("XDH", "BC");
+
+ dhKp.initialize(new ECNamedCurveGenParameterSpec(x_str));
+
+ PGPKeyPair dhKeyPair = new JcaPGPKeyPair(x_num, new PGPKdfParameters(hashAlgorithm, symmetricWrapAlgorithm), dhKp.generateKeyPair(), new Date());
+
+ encryptDecryptTest(dhKeyPair.getPublicKey(), dhKeyPair.getPrivateKey());
+ encryptDecryptBcTest(dhKeyPair.getPublicKey(), dhKeyPair.getPrivateKey());
+
+ PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1);
+
+ PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(
+ PGPSignature.POSITIVE_CERTIFICATION, dsaKeyPair,
+ identity, sha1Calc, null, null,
+ new JcaPGPContentSignerBuilder(dsaKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA256).setProvider("BC"),
+ new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc).setProvider("BC").build(passPhrase));
+
+ keyRingGen.addSubKey(dhKeyPair);
+
+ ByteArrayOutputStream secretOut = new ByteArrayOutputStream();
+ PGPSecretKeyRing secRing = keyRingGen.generateSecretKeyRing();
+
+// PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing();
+//
+ secRing.encode(secretOut);
+//
+ secretOut.close();
+ secRing = new PGPSecretKeyRing(secretOut.toByteArray(), new JcaKeyFingerprintCalculator());
+
+ Iterator pIt = secRing.getPublicKeys();
+ pIt.next();
+
+ PGPPublicKey sKey = (PGPPublicKey)pIt.next();
+ PGPPublicKey vKey = secRing.getPublicKey();
+
+ Iterator sIt = sKey.getSignatures();
+ int count = 0;
+ while (sIt.hasNext())
+ {
+ PGPSignature sig = (PGPSignature)sIt.next();
+
+ if (sig.getKeyID() == vKey.getKeyID()
+ && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING)
+ {
+ count++;
+ sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), vKey);
+
+ if (!sig.verifyCertification(vKey, sKey))
+ {
+ fail("failed to verify sub-key signature.");
+ }
+ }
+ }
+
+ isTrue(count == 1);
+
+ secRing = new PGPSecretKeyRing(secretOut.toByteArray(), new JcaKeyFingerprintCalculator());
+ PGPPublicKey pubKey = null;
+ PGPPrivateKey privKey = null;
+
+ for (Iterator it = secRing.getPublicKeys(); it.hasNext(); )
+ {
+ pubKey = (PGPPublicKey)it.next();
+ if (pubKey.isEncryptionKey())
+ {
+ privKey = secRing.getSecretKey(pubKey.getKeyID()).extractPrivateKey(
+ new JcePBESecretKeyDecryptorBuilder().setProvider(new BouncyCastleProvider()).build(passPhrase));
+ break;
+ }
+ }
+
+ encryptDecryptTest(pubKey, privKey);
+ encryptDecryptBcTest(pubKey, privKey);
}
private void keyringTest(String ed_str, int ed_num, String x_str, int x_num, int hashAlgorithm, int symmetricWrapAlgorithm)
From f753f1bba9f3c525574f3049633310ade9ea65cb Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 23 Feb 2024 11:59:10 +1030
Subject: [PATCH 0090/1846] Ed25519 and Ed448 works now.
---
.../bouncycastle/bcpg/OctetArrayBCPGKey.java | 48 ------------
.../bouncycastle/bcpg/PublicKeyPacket.java | 4 +-
.../bouncycastle/openpgp/PGPSecretKey.java | 6 +-
.../bouncycastle/openpgp/PGPSignature.java | 26 +++----
.../openpgp/operator/bc/BcImplProvider.java | 9 +--
.../operator/bc/BcPGPKeyConverter.java | 53 ++++++--------
.../operator/jcajce/JcaPGPKeyConverter.java | 73 ++++++++++++++-----
.../openpgp/test/OperatorBcTest.java | 7 +-
8 files changed, 98 insertions(+), 128 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java b/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java
index d9bbf8e81a..c5538ef6e1 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java
@@ -15,48 +15,6 @@ public abstract class OctetArrayBCPGKey
implements BCPGKey
{
private final byte[] key;
- ASN1ObjectIdentifier oid;
- BigInteger point;
-
- //TODO remove this method
- OctetArrayBCPGKey(BCPGInputStream in)
- throws IOException
- {
- this.oid = ASN1ObjectIdentifier.getInstance(ASN1Primitive.fromByteArray(readBytesOfEncodedLength(in)));
- this.point = new MPInteger(in).getValue();
- key = point.toByteArray();
- }
-
- public BigInteger getEncodedPoint()
- {
- return point;
- }
-
- protected static byte[] readBytesOfEncodedLength(
- BCPGInputStream in)
- throws IOException
- {
- int length = in.read();
- if (length < 0)
- {
- throw new IOException("unexpected end-of-stream");
- }
- if (length == 0 || length == 0xFF)
- {
- throw new IOException("future extensions not yet implemented");
- }
- if (length > 127)
- {
- throw new IOException("unsupported OID");
- }
-
- byte[] buffer = new byte[length + 2];
- in.readFully(buffer, 2, buffer.length - 2);
- buffer[0] = (byte)0x06;
- buffer[1] = (byte)length;
-
- return buffer;
- }
OctetArrayBCPGKey(int length, BCPGInputStream in)
throws IOException
@@ -104,12 +62,6 @@ public void encode(BCPGOutputStream out)
throws IOException
{
out.write(key);
-// //TODO
-// byte[] oid = this.oid.getEncoded();
-// out.write(oid, 1, oid.length - 1);
-//
-// MPInteger point = new MPInteger(this.point);
-// out.writeObject(point);
}
public byte[] getKey()
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java
index b898b412f0..41fb14f975 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java
@@ -73,9 +73,11 @@ public class PublicKeyPacket
key = new ECDSAPublicBCPGKey(in);
break;
case EDDSA_LEGACY:
- case Ed25519:
key = new EdDSAPublicBCPGKey(in);
break;
+ case Ed25519:
+ key = new Ed25519PublicBCPGKey(in);
+ break;
case Ed448:
key = new Ed448PublicBCPGKey(in);
break;
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
index e3408572b4..aea3a0ac40 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
@@ -673,11 +673,11 @@ public PGPPrivateKey extractPrivateKey(
return new PGPPrivateKey(this.getKeyID(), pubPk, ecPriv);
case PGPPublicKey.EDDSA_LEGACY:
+ return new PGPPrivateKey(this.getKeyID(), pubPk, new EdSecretBCPGKey(in));
case PGPPublicKey.Ed25519:
+ return new PGPPrivateKey(this.getKeyID(), pubPk, new Ed25519SecretBCPGKey(in));
case PGPPublicKey.Ed448:
- EdSecretBCPGKey edPriv = new EdSecretBCPGKey(in);
-
- return new PGPPrivateKey(this.getKeyID(), pubPk, edPriv);
+ return new PGPPrivateKey(this.getKeyID(), pubPk, new Ed448SecretBCPGKey(in));
default:
throw new PGPException("unknown public key algorithm encountered");
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java
index 3da3f4ec70..32711f8b9a 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSignature.java
@@ -452,23 +452,21 @@ public byte[] getSignature()
signature = BigIntegers.asUnsignedByteArray(sigValues[0].getValue());
}
else if (getKeyAlgorithm() == PublicKeyAlgorithmTags.EDDSA_LEGACY ||
- getKeyAlgorithm() == PublicKeyAlgorithmTags.Ed25519 ||
- getKeyAlgorithm() == PublicKeyAlgorithmTags.Ed448)
+ getKeyAlgorithm() == PublicKeyAlgorithmTags.Ed25519)
{
byte[] a = BigIntegers.asUnsignedByteArray(sigValues[0].getValue());
byte[] b = BigIntegers.asUnsignedByteArray(sigValues[1].getValue());
- if (a.length == Ed448.PUBLIC_KEY_SIZE && b.length == Ed448.PUBLIC_KEY_SIZE && getKeyAlgorithm() != PublicKeyAlgorithmTags.Ed25519)
- {
- signature = new byte[Ed448.SIGNATURE_SIZE];
- System.arraycopy(a, 0, signature, Ed448.PUBLIC_KEY_SIZE - a.length, a.length);
- System.arraycopy(b, 0, signature, Ed448.SIGNATURE_SIZE - b.length, b.length);
- }
- else
- {
- signature = new byte[Ed25519.SIGNATURE_SIZE];
- System.arraycopy(a, 0, signature, Ed25519.PUBLIC_KEY_SIZE - a.length, a.length);
- System.arraycopy(b, 0, signature, Ed25519.SIGNATURE_SIZE - b.length, b.length);
- }
+ signature = new byte[Ed25519.SIGNATURE_SIZE];
+ System.arraycopy(a, 0, signature, Ed25519.PUBLIC_KEY_SIZE - a.length, a.length);
+ System.arraycopy(b, 0, signature, Ed25519.SIGNATURE_SIZE - b.length, b.length);
+ }
+ else if (getKeyAlgorithm() == PublicKeyAlgorithmTags.Ed448)
+ {
+ byte[] a = BigIntegers.asUnsignedByteArray(sigValues[0].getValue());
+ byte[] b = BigIntegers.asUnsignedByteArray(sigValues[1].getValue());
+ signature = new byte[Ed448.SIGNATURE_SIZE];
+ System.arraycopy(a, 0, signature, Ed448.PUBLIC_KEY_SIZE - a.length, a.length);
+ System.arraycopy(b, 0, signature, Ed448.SIGNATURE_SIZE - b.length, b.length);
}
else
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java
index 94b6d52805..915e692dbc 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcImplProvider.java
@@ -98,15 +98,10 @@ static Signer createSigner(int keyAlgorithm, int hashAlgorithm, CipherParameters
case PublicKeyAlgorithmTags.ECDSA:
return new DSADigestSigner(new ECDSASigner(), createDigest(hashAlgorithm));
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
- if (keyParam instanceof Ed25519PrivateKeyParameters || keyParam instanceof Ed25519PublicKeyParameters)
- {
- return new EdDsaSigner(new Ed25519Signer(), createDigest(hashAlgorithm));
- }
- return new EdDsaSigner(new Ed448Signer(new byte[0]), createDigest(hashAlgorithm));
- case PublicKeyAlgorithmTags.Ed448:
- return new EdDsaSigner(new Ed448Signer(new byte[0]), createDigest(hashAlgorithm));
case PublicKeyAlgorithmTags.Ed25519:
return new EdDsaSigner(new Ed25519Signer(), createDigest(hashAlgorithm));
+ case PublicKeyAlgorithmTags.Ed448:
+ return new EdDsaSigner(new Ed448Signer(new byte[0]), createDigest(hashAlgorithm));
default:
throw new PGPException("cannot recognise keyAlgorithm: " + keyAlgorithm);
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
index a9d0190c51..ee121de798 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
@@ -20,7 +20,10 @@
import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
import org.bouncycastle.bcpg.ECPublicBCPGKey;
import org.bouncycastle.bcpg.ECSecretBCPGKey;
+import org.bouncycastle.bcpg.Ed25519PublicBCPGKey;
+import org.bouncycastle.bcpg.Ed25519SecretBCPGKey;
import org.bouncycastle.bcpg.Ed448PublicBCPGKey;
+import org.bouncycastle.bcpg.Ed448SecretBCPGKey;
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
import org.bouncycastle.bcpg.EdSecretBCPGKey;
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
@@ -147,21 +150,19 @@ else if (EdECObjectIdentifiers.id_X448.equals(ecdhPub.getCurveOID()))
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
- if (((EdDSAPublicBCPGKey)pubPk.getKey()).getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
- {
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed448, Ed448.SECRET_KEY_SIZE, privPk);
- }
return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed25519, Ed25519.SECRET_KEY_SIZE, privPk);
}
case PublicKeyAlgorithmTags.Ed25519:
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed25519, Ed25519.SECRET_KEY_SIZE, privPk);
+ return PrivateKeyFactory.createKey((new PrivateKeyInfo(
+ new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519),
+ new DEROctetString(BigIntegers.asUnsignedByteArray(Ed25519.SECRET_KEY_SIZE, new BigInteger(1, privPk.getEncoded()))))));
}
case PublicKeyAlgorithmTags.Ed448:
{
return PrivateKeyFactory.createKey((new PrivateKeyInfo(
new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448),
- new DEROctetString(BigIntegers.asUnsignedByteArray(Ed448.SECRET_KEY_SIZE, ((EdSecretBCPGKey)privPk).getX())))));
+ new DEROctetString(BigIntegers.asUnsignedByteArray(Ed448.SECRET_KEY_SIZE, new BigInteger(1, privPk.getEncoded()))))));
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
@@ -246,33 +247,22 @@ else if (ecdhK.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
byte[] pEnc = BigIntegers.asUnsignedByteArray(eddsaK.getEncodedPoint());
- if (pEnc.length < 1)
+ if (pEnc.length < 1 || pEnc[0] != 0x40)
{
throw new IllegalArgumentException("Invalid EdDSA public key");
}
-
- if (pEnc[0] == 0x40 && !eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
- {
- return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed25519, pEnc, 1);
- }
- else if (eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
- {
- return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed448, pEnc, 0);
- }
-
- throw new IllegalArgumentException("Invalid EdDSA public key");
+ return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed25519, pEnc, 1);
}
case PublicKeyAlgorithmTags.Ed25519:
{
- byte[] pEnc = get25519EncodedPoint(((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint(), "Ed");
- return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed25519, pEnc, 1);
+ Ed25519PublicBCPGKey eddsaK = (Ed25519PublicBCPGKey)publicPk.getKey();
+ byte[] pEnc = eddsaK.getKey().clone();
+ return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed25519, pEnc, 0);
}
case PublicKeyAlgorithmTags.Ed448:
{
Ed448PublicBCPGKey eddsaK = (Ed448PublicBCPGKey)publicPk.getKey();
-
byte[] pEnc = eddsaK.getKey().clone();
-
return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed448, pEnc, 0);
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
@@ -377,22 +367,15 @@ else if (privKey instanceof X448PrivateKeyParameters)
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
- if (privKey instanceof Ed25519PrivateKeyParameters)
- {
- return getEdSecretBCPGKey(((Ed25519PrivateKeyParameters)privKey).getEncoded());
- }
- else
- {
- return getEdSecretBCPGKey(((Ed448PrivateKeyParameters)privKey).getEncoded());
- }
+ return getEdSecretBCPGKey(((Ed25519PrivateKeyParameters)privKey).getEncoded());
}
case PublicKeyAlgorithmTags.Ed25519:
{
- return getEdSecretBCPGKey(((Ed25519PrivateKeyParameters)privKey).getEncoded());
+ return new Ed25519SecretBCPGKey(((Ed25519PrivateKeyParameters)privKey).getEncoded());
}
case PublicKeyAlgorithmTags.Ed448:
{
- return getEdSecretBCPGKey(((Ed448PrivateKeyParameters)privKey).getEncoded());
+ return new Ed448SecretBCPGKey(((Ed448PrivateKeyParameters)privKey).getEncoded());
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
@@ -469,6 +452,12 @@ else if (algorithm == PGPPublicKey.ECDSA)
throw new PGPException("unknown EC algorithm");
}
}
+ else if (algorithm == PublicKeyAlgorithmTags.Ed25519)
+ {
+ byte[] pointEnc = new byte[Ed25519PublicKeyParameters.KEY_SIZE];
+ ((Ed25519PublicKeyParameters)pubKey).encode(pointEnc, 0);
+ return new Ed25519PublicBCPGKey(pointEnc);
+ }
else if (pubKey instanceof Ed25519PublicKeyParameters)
{
byte[] pointEnc = new byte[1 + Ed25519PublicKeyParameters.KEY_SIZE];
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
index 447248f805..57e877bc75 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
@@ -57,7 +57,10 @@
import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
import org.bouncycastle.bcpg.ECPublicBCPGKey;
import org.bouncycastle.bcpg.ECSecretBCPGKey;
+import org.bouncycastle.bcpg.Ed25519PublicBCPGKey;
+import org.bouncycastle.bcpg.Ed25519SecretBCPGKey;
import org.bouncycastle.bcpg.Ed448PublicBCPGKey;
+import org.bouncycastle.bcpg.Ed448SecretBCPGKey;
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
import org.bouncycastle.bcpg.EdSecretBCPGKey;
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
@@ -218,19 +221,21 @@ else if (EdECObjectIdentifiers.id_X448.equals(ecdhPub.getCurveOID()))
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
- if (((EdDSAPublicBCPGKey)pubPk.getKey()).getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
- {
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed448, Ed448.SECRET_KEY_SIZE, privPk);
- }
return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed25519, Ed25519.SECRET_KEY_SIZE, privPk);
}
case PublicKeyAlgorithmTags.Ed25519:
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed25519, Ed25519.SECRET_KEY_SIZE, privPk);
+ PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(
+ new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519),
+ new DEROctetString(BigIntegers.asUnsignedByteArray(Ed25519.SECRET_KEY_SIZE, new BigInteger(1, privPk.getEncoded())))).getEncoded());
+ return implGeneratePrivate("EdDSA", pkcs8Spec);
}
case PublicKeyAlgorithmTags.Ed448:
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed448, Ed448.SECRET_KEY_SIZE, privPk);
+ PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(
+ new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448),
+ new DEROctetString(BigIntegers.asUnsignedByteArray(Ed448.SECRET_KEY_SIZE, new BigInteger(1, privPk.getEncoded())))).getEncoded());
+ return implGeneratePrivate("EdDSA", pkcs8Spec);
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
@@ -314,26 +319,26 @@ else if (EdECObjectIdentifiers.id_X448.equals(ecdhK.getCurveOID()))
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
EdDSAPublicBCPGKey eddsaK = (EdDSAPublicBCPGKey)publicPk.getKey();
-
- if (EdECObjectIdentifiers.id_Ed448.equals(eddsaK.getCurveOID()))
+ return get25519PublicKey(eddsaK.getEncodedPoint(), EdECObjectIdentifiers.id_Ed25519, "EdDSA", "Ed");
+ }
+ case PublicKeyAlgorithmTags.Ed25519:
+ {
+ BCPGKey key = publicPk.getKey();
+ if (key instanceof Ed25519PublicBCPGKey)
{
- return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed448, eddsaK.getEncodedPoint());
+ return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed25519, new BigInteger(1, publicPk.getKey().getEncoded()));
}
else
{
- return get25519PublicKey(eddsaK.getEncodedPoint(), EdECObjectIdentifiers.id_Ed25519, "EdDSA", "Ed");
+ return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed25519, ((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint());
}
}
- case PublicKeyAlgorithmTags.Ed25519:
- {
- return get25519PublicKey(((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint(), EdECObjectIdentifiers.id_Ed25519, "EdDSA", "Ed");
- }
case PublicKeyAlgorithmTags.Ed448:
{
BCPGKey key = publicPk.getKey();
if (key instanceof Ed448PublicBCPGKey)
{
- return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed448, new BigInteger(1,((Ed448PublicBCPGKey)publicPk.getKey()).getEncoded()));
+ return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed448, new BigInteger(1, publicPk.getKey().getEncoded()));
}
else
{
@@ -425,8 +430,6 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey)
}
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
- case PublicKeyAlgorithmTags.Ed25519:
- case PublicKeyAlgorithmTags.Ed448:
{
PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
@@ -440,6 +443,31 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey)
throw new PGPException(e.getMessage(), e);
}
}
+ case PublicKeyAlgorithmTags.Ed25519:
+ {
+ PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
+ try
+ {
+ return new Ed25519SecretBCPGKey(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets());
+ }
+ catch (IOException e)
+ {
+ throw new PGPException(e.getMessage(), e);
+ }
+ }
+ case PublicKeyAlgorithmTags.Ed448:
+ {
+ PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
+
+ try
+ {
+ return new Ed448SecretBCPGKey(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets());
+ }
+ catch (IOException e)
+ {
+ throw new PGPException(e.getMessage(), e);
+ }
+ }
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
@@ -526,6 +554,14 @@ else if (algorithm == PGPPublicKey.ECDSA)
throw new PGPException("unknown EC algorithm");
}
}
+ else if (algorithm == PGPPublicKey.Ed25519)
+ {
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+ byte[] pointEnc = new byte[Ed25519.PUBLIC_KEY_SIZE];
+
+ System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
+ return new Ed25519PublicBCPGKey(pointEnc);
+ }
else if (pubKey.getAlgorithm().regionMatches(true, 0, "ED2", 0, 3))
{
return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, getPointEncUncompressed(pubKey, Ed25519.PUBLIC_KEY_SIZE)));
@@ -537,14 +573,13 @@ else if (pubKey.getAlgorithm().regionMatches(true, 0, "X2", 0, 2))
return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, getPointEncUncompressed(pubKey, X25519.SCALAR_SIZE)),
kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm());
}
- else if (pubKey.getAlgorithm().regionMatches(true, 0, "ED4", 0, 3))
+ else if (algorithm == PGPPublicKey.Ed448)
{
SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
byte[] pointEnc = new byte[Ed448.PUBLIC_KEY_SIZE];
System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
return new Ed448PublicBCPGKey(pointEnc);
- //return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, getPointEnc(pubKey, Ed448.PUBLIC_KEY_SIZE)));
}
else if (pubKey.getAlgorithm().regionMatches(true, 0, "X4", 0, 2))
{
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index 5b455242ee..c5ee678c32 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -164,13 +164,13 @@ public void testBcPGPDataEncryptorBuilder()
public void testBcPGPKeyPair()
throws Exception
{
+ testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed25519, "Ed25519");
testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, "Ed448");
testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, PublicKeyAlgorithmTags.X448, "X448");
testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, PublicKeyAlgorithmTags.X25519, "X25519");
testCreateKeyPair(PublicKeyAlgorithmTags.X448, PublicKeyAlgorithmTags.ECDH, "X448");
testCreateKeyPair(PublicKeyAlgorithmTags.X25519, PublicKeyAlgorithmTags.ECDH, "X25519");
//testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed448, "Ed448");
- testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed25519, "Ed25519");
//testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed448");
testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519");
testCreateKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, "RSA");
@@ -213,7 +213,7 @@ private void testCreateKeyPair(int algorithm1, int algorithm2, String name)
PrivateKey privKey = jcaPGPKeyConverter.getPrivateKey(jcaPgpPair.getPrivateKey());
PublicKey pubKey = jcaPGPKeyConverter.getPublicKey(jcaPgpPair.getPublicKey());
- if (!Arrays.equals(jcaPgpPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(),
+ if (algorithm1 == algorithm2 &&!Arrays.equals(jcaPgpPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(),
bcKeyPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded()))
{
throw new PGPException("JcaPGPKeyPair and BcPGPKeyPair private keys are not equal.");
@@ -244,10 +244,9 @@ public void testKeyRings()
throws Exception
{
System.setProperty("enableCamelliaKeyWrapping", "True");
+ keyringTest("ED25519", PublicKeyAlgorithmTags.Ed25519, "X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
-
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("ED25519", PublicKeyAlgorithmTags.Ed25519, "X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("ED25519", PublicKeyAlgorithmTags.Ed25519, "X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_192);
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_256);
From e570bd03a74440582dded6eabdfcc65f7e819059 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 23 Feb 2024 16:36:25 +1030
Subject: [PATCH 0091/1846] Pass all tests for Ed25519, Ed448, X25519 and X448.
---
.../bouncycastle/bcpg/PublicKeyPacket.java | 6 +-
.../bouncycastle/openpgp/PGPSecretKey.java | 7 +-
.../openpgp/operator/RFC6637Utils.java | 38 ++++--
.../operator/bc/BcPGPKeyConverter.java | 81 +++++++------
.../bc/BcPublicKeyDataDecryptorFactory.java | 73 +++++++----
...PublicKeyKeyEncryptionMethodGenerator.java | 101 +++++++++++-----
.../operator/jcajce/JcaPGPKeyConverter.java | 89 +++++++++++---
...ePublicKeyDataDecryptorFactoryBuilder.java | 61 +++++++---
...PublicKeyKeyEncryptionMethodGenerator.java | 46 ++++---
.../openpgp/test/BcImplProviderTest.java | 17 +--
.../openpgp/test/OperatorBcTest.java | 113 ++----------------
11 files changed, 360 insertions(+), 272 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java
index 41fb14f975..0026365b9a 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/PublicKeyPacket.java
@@ -65,9 +65,13 @@ public class PublicKeyPacket
key = new ElGamalPublicBCPGKey(in);
break;
case ECDH:
+ key = new ECDHPublicBCPGKey(in);
+ break;
case X25519:
+ key = new X25519PublicBCPGKey(in);
+ break;
case X448:
- key = new ECDHPublicBCPGKey(in);
+ key = new X448PublicBCPGKey(in);
break;
case ECDSA:
key = new ECDSAPublicBCPGKey(in);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
index aea3a0ac40..fdc654c02e 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
@@ -667,11 +667,12 @@ public PGPPrivateKey extractPrivateKey(
return new PGPPrivateKey(this.getKeyID(), pubPk, elPriv);
case PGPPublicKey.ECDH:
case PGPPublicKey.ECDSA:
- case PGPPublicKey.X25519:
- case PGPPublicKey.X448:
ECSecretBCPGKey ecPriv = new ECSecretBCPGKey(in);
-
return new PGPPrivateKey(this.getKeyID(), pubPk, ecPriv);
+ case PGPPublicKey.X25519:
+ return new PGPPrivateKey(this.getKeyID(), pubPk, new X25519SecretBCPGKey(in));
+ case PGPPublicKey.X448:
+ return new PGPPrivateKey(this.getKeyID(), pubPk, new X448SecretBCPGKey(in));
case PGPPublicKey.EDDSA_LEGACY:
return new PGPPrivateKey(this.getKeyID(), pubPk, new EdSecretBCPGKey(in));
case PGPPublicKey.Ed25519:
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
index 0fc222becf..a769b8d488 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
@@ -11,6 +11,8 @@
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.bcpg.X25519PublicBCPGKey;
+import org.bouncycastle.bcpg.X448PublicBCPGKey;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.util.encoders.Hex;
@@ -27,24 +29,23 @@ private RFC6637Utils()
public static String getXDHAlgorithm(PublicKeyPacket pubKeyData)
{
- ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
- String curve;
- if (ecKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
+ if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
{
- curve = "X448";
+ return "X25519withSHA256CKDF";
}
- else
+ else if (pubKeyData.getKey() instanceof X448PublicBCPGKey)
{
- curve = "X25519";
+ return "X448withSHA512CKDF";
}
+ ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
switch (ecKey.getHashAlgorithm())
{
case HashAlgorithmTags.SHA256:
- return curve + "withSHA256CKDF";
+ return "X25519withSHA256CKDF";
case HashAlgorithmTags.SHA384:
- return curve + "withSHA384CKDF";
+ return "X25519withSHA384CKDF";
case HashAlgorithmTags.SHA512:
- return curve + "withSHA512CKDF";
+ return "X25519withSHA512CKDF";
default:
throw new IllegalArgumentException("Unknown hash algorithm specified: " + ecKey.getHashAlgorithm());
}
@@ -116,4 +117,23 @@ public static byte[] createUserKeyingMaterial(PublicKeyPacket pubKeyData, KeyFin
return pOut.toByteArray();
}
+
+ public static byte[] createUserKeyingMaterial(PublicKeyPacket pubKeyData, KeyFingerPrintCalculator fingerPrintCalculator,
+ ASN1ObjectIdentifier cuiveOID, int hashAlgorithm, int symmetricKeyAlgorithm)
+ throws IOException, PGPException
+ {
+ ByteArrayOutputStream pOut = new ByteArrayOutputStream();
+ byte[] encOid = cuiveOID.getEncoded();
+
+ pOut.write(encOid, 1, encOid.length - 1);
+ pOut.write(pubKeyData.getAlgorithm());
+ pOut.write(0x03);
+ pOut.write(0x01);
+ pOut.write(hashAlgorithm);
+ pOut.write(symmetricKeyAlgorithm);
+ pOut.write(ANONYMOUS_SENDER);
+ pOut.write(fingerPrintCalculator.calculateFingerprint(pubKeyData));
+
+ return pOut.toByteArray();
+ }
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
index ee121de798..3b3af70579 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
@@ -34,7 +34,10 @@
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.bcpg.RSASecretBCPGKey;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.bcpg.X25519PublicBCPGKey;
+import org.bouncycastle.bcpg.X25519SecretBCPGKey;
import org.bouncycastle.bcpg.X448PublicBCPGKey;
+import org.bouncycastle.bcpg.X448SecretBCPGKey;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
@@ -128,10 +131,6 @@ public AsymmetricKeyParameter getPrivateKey(PGPPrivateKey privKey)
{
return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_X25519, privPk);
}
- else if (EdECObjectIdentifiers.id_X448.equals(ecdhPub.getCurveOID()))
- {
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_X448, privPk);
- }
else
{
return implGetPrivateKeyEC(ecdhPub, (ECSecretBCPGKey)privPk);
@@ -139,17 +138,25 @@ else if (EdECObjectIdentifiers.id_X448.equals(ecdhPub.getCurveOID()))
}
case PublicKeyAlgorithmTags.X25519:
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_X25519, privPk);
+ return PrivateKeyFactory.createKey((new PrivateKeyInfo(
+ new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519),
+ new DEROctetString(Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(new BigInteger(privPk.getEncoded())))))));
}
case PublicKeyAlgorithmTags.X448:
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_X448, privPk);
+ return PrivateKeyFactory.createKey((new PrivateKeyInfo(
+ new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448),
+ new DEROctetString(Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(new BigInteger(privPk.getEncoded())))))));
}
case PublicKeyAlgorithmTags.ECDSA:
return implGetPrivateKeyEC((ECDSAPublicBCPGKey)pubPk.getKey(), (ECSecretBCPGKey)privPk);
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
+ if (((EdDSAPublicBCPGKey)pubPk.getKey()).getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
+ {
+ return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed448, Ed448.SECRET_KEY_SIZE, privPk);
+ }
return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed25519, Ed25519.SECRET_KEY_SIZE, privPk);
}
case PublicKeyAlgorithmTags.Ed25519:
@@ -221,10 +228,6 @@ public AsymmetricKeyParameter getPublicKey(PGPPublicKey publicKey)
{
return getX25519PublicKey(ecdhK);
}
- else if (ecdhK.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
- {
- return getX448PublicKey(ecdhK);
- }
else
{
return implGetPublicKeyEC(ecdhK);
@@ -232,11 +235,15 @@ else if (ecdhK.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
}
case PublicKeyAlgorithmTags.X25519:
{
- return getX25519PublicKey((ECDHPublicBCPGKey)publicPk.getKey());
+ X25519PublicBCPGKey eddsaK = (X25519PublicBCPGKey)publicPk.getKey();
+ byte[] pEnc = eddsaK.getKey().clone();
+ return implGetPublicKeyX509(EdECObjectIdentifiers.id_X25519, pEnc, 0);
}
case PublicKeyAlgorithmTags.X448:
{
- return getX448PublicKey((ECDHPublicBCPGKey)publicPk.getKey());
+ X448PublicBCPGKey eddsaK = (X448PublicBCPGKey)publicPk.getKey();
+ byte[] pEnc = eddsaK.getKey().clone();
+ return implGetPublicKeyX509(EdECObjectIdentifiers.id_X448, pEnc, 0);
}
case PublicKeyAlgorithmTags.ECDSA:
return implGetPublicKeyEC((ECDSAPublicBCPGKey)publicPk.getKey());
@@ -247,11 +254,21 @@ else if (ecdhK.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
byte[] pEnc = BigIntegers.asUnsignedByteArray(eddsaK.getEncodedPoint());
- if (pEnc.length < 1 || pEnc[0] != 0x40)
+ if (pEnc.length < 1)
{
throw new IllegalArgumentException("Invalid EdDSA public key");
}
- return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed25519, pEnc, 1);
+
+ if (pEnc[0] == 0x40 && !eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
+ {
+ return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed25519, pEnc, 1);
+ }
+ else if (eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
+ {
+ return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed448, pEnc, 0);
+ }
+
+ throw new IllegalArgumentException("Invalid EdDSA public key");
}
case PublicKeyAlgorithmTags.Ed25519:
{
@@ -292,12 +309,6 @@ else if (ecdhK.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
}
}
- private AsymmetricKeyParameter getX448PublicKey(ECDHPublicBCPGKey ecdhK)
- throws IOException
- {
- return implGetPublicKeyX509(EdECObjectIdentifiers.id_X448, BigIntegers.asUnsignedByteArray(ecdhK.getEncodedPoint()), 0);
- }
-
private byte[] get25519EncodedPoint(BigInteger x, String title)
{
byte[] pEnc = BigIntegers.asUnsignedByteArray(x);
@@ -333,32 +344,26 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pubKey, AsymmetricKeyParameter pr
DSAPrivateKeyParameters dsK = (DSAPrivateKeyParameters)privKey;
return new DSASecretBCPGKey(dsK.getX());
}
-
case PublicKeyAlgorithmTags.ECDH:
{
- if (privKey instanceof ECPrivateKeyParameters)
- {
- ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey;
- return new ECSecretBCPGKey(ecK.getD());
- }
- else if (privKey instanceof X25519PrivateKeyParameters)
+ if (privKey instanceof X25519PrivateKeyParameters)
{
return getECSecretBCPGKey(((X25519PrivateKeyParameters)privKey).getEncoded());
}
- else if (privKey instanceof X448PrivateKeyParameters)
+ else
{
- return getECSecretBCPGKey(((X448PrivateKeyParameters)privKey).getEncoded());
+ ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey;
+ return new ECSecretBCPGKey(ecK.getD());
}
}
case PublicKeyAlgorithmTags.X25519:
{
- return getECSecretBCPGKey(((X25519PrivateKeyParameters)privKey).getEncoded());
+ return new X25519SecretBCPGKey(Arrays.reverseInPlace(((X25519PrivateKeyParameters)privKey).getEncoded()));
}
case PublicKeyAlgorithmTags.X448:
{
- return getECSecretBCPGKey(((X448PrivateKeyParameters)privKey).getEncoded());
+ return new X448SecretBCPGKey(Arrays.reverseInPlace(((X448PrivateKeyParameters)privKey).getEncoded()));
}
-
case PublicKeyAlgorithmTags.ECDSA:
{
ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey;
@@ -471,6 +476,12 @@ else if (pubKey instanceof Ed448PublicKeyParameters)
((Ed448PublicKeyParameters)pubKey).encode(pointEnc, 0);
return new Ed448PublicBCPGKey(pointEnc);
}
+ else if (algorithm == PublicKeyAlgorithmTags.X25519)
+ {
+ byte[] pointEnc = new byte[X25519PublicKeyParameters.KEY_SIZE];
+ ((X25519PublicKeyParameters)pubKey).encode(pointEnc, 0);
+ return new X25519PublicBCPGKey(pointEnc);
+ }
else if (pubKey instanceof X25519PublicKeyParameters)
{
byte[] pointEnc = new byte[1 + X25519PublicKeyParameters.KEY_SIZE];
@@ -486,11 +497,7 @@ else if (pubKey instanceof X448PublicKeyParameters)
{
byte[] pointEnc = new byte[X448PublicKeyParameters.KEY_SIZE];
((X448PublicKeyParameters)pubKey).encode(pointEnc, 0);
-
- PGPKdfParameters kdfParams = implGetKdfParameters(algorithmParameters);
-
- return new ECDHPublicBCPGKey(EdECObjectIdentifiers.id_X448, new BigInteger(1, pointEnc),
- kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm());
+ return new X448PublicBCPGKey(pointEnc);
}
else
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index 864ea1a59a..e327cfcc7f 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -8,8 +8,12 @@
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.bcpg.AEADEncDataPacket;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.bcpg.X25519PublicBCPGKey;
+import org.bouncycastle.bcpg.X25519SecretBCPGKey;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedAsymmetricBlockCipher;
@@ -109,7 +113,7 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
}
else
{
- ECDHPublicBCPGKey ecPubKey = (ECDHPublicBCPGKey)pgpPrivKey.getPublicKeyPacket().getKey();
+
byte[] enc = secKeyData[0];
int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
@@ -131,40 +135,61 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);
byte[] secret;
- // XDH
- if (ecPubKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
+ RFC6637KDFCalculator rfc6637KDFCalculator;
+ byte[] userKeyingMaterial;
+ int symmetricKeyAlgorithm, hashAlgorithm;
+ if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
{
- // skip the 0x40 header byte.
- secret = getSecret(new X25519Agreement(), pEnc.length != 1 + X25519PublicKeyParameters.KEY_SIZE || 0x40 != pEnc[0], privKey, new X25519PublicKeyParameters(pEnc, 1), "25519");
+ ECDHPublicBCPGKey ecPubKey = (ECDHPublicBCPGKey)pgpPrivKey.getPublicKeyPacket().getKey();
+ // XDH
+ if (ecPubKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
+ {
+ // skip the 0x40 header byte.
+ secret = getSecret(new X25519Agreement(), pEnc.length != 1 + X25519PublicKeyParameters.KEY_SIZE || 0x40 != pEnc[0], privKey, new X25519PublicKeyParameters(pEnc, 1), "25519");
+ }
+ else
+ {
+ ECDomainParameters ecParameters = ((ECPrivateKeyParameters)privKey).getParameters();
+
+ ECPublicKeyParameters ephPub = new ECPublicKeyParameters(ecParameters.getCurve().decodePoint(pEnc),
+ ecParameters);
+
+ ECDHBasicAgreement agreement = new ECDHBasicAgreement();
+ agreement.init(privKey);
+ BigInteger S = agreement.calculateAgreement(ephPub);
+ secret = BigIntegers.asUnsignedByteArray(agreement.getFieldSize(), S);
+ }
+
+ userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(),
+ new BcKeyFingerprintCalculator());
+ symmetricKeyAlgorithm = ecPubKey.getSymmetricKeyAlgorithm();
+ hashAlgorithm = ecPubKey.getHashAlgorithm();
}
- else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
+ else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
- secret = getSecret(new X448Agreement(), pEnc.length != X448PublicKeyParameters.KEY_SIZE, privKey, new X448PublicKeyParameters(pEnc, 0), "448");
+ secret = getSecret(new X25519Agreement(), pEnc.length != X25519PublicKeyParameters.KEY_SIZE, privKey, new X25519PublicKeyParameters(pEnc, 0), "25519");
+ symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128;
+ hashAlgorithm = HashAlgorithmTags.SHA256;
+ userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(),
+ new BcKeyFingerprintCalculator(), CryptlibObjectIdentifiers.curvey25519, hashAlgorithm, symmetricKeyAlgorithm);
}
else
{
- ECDomainParameters ecParameters = ((ECPrivateKeyParameters)privKey).getParameters();
-
- ECPublicKeyParameters ephPub = new ECPublicKeyParameters(ecParameters.getCurve().decodePoint(pEnc),
- ecParameters);
-
- ECDHBasicAgreement agreement = new ECDHBasicAgreement();
- agreement.init(privKey);
- BigInteger S = agreement.calculateAgreement(ephPub);
- secret = BigIntegers.asUnsignedByteArray(agreement.getFieldSize(), S);
+ //PublicKeyAlgorithmTags.X448
+ secret = getSecret(new X448Agreement(), pEnc.length != X448PublicKeyParameters.KEY_SIZE, privKey, new X448PublicKeyParameters(pEnc, 0), "448");
+ symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_256;
+ hashAlgorithm = HashAlgorithmTags.SHA512;
+ userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(),
+ new BcKeyFingerprintCalculator(), EdECObjectIdentifiers.id_X448, hashAlgorithm, symmetricKeyAlgorithm);
}
-
- RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(
- new BcPGPDigestCalculatorProvider().get(ecPubKey.getHashAlgorithm()),
- ecPubKey.getSymmetricKeyAlgorithm());
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(),
- new BcKeyFingerprintCalculator());
-
+ rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm),
+ symmetricKeyAlgorithm);
KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
- Wrapper c = BcImplProvider.createWrapper(ecPubKey.getSymmetricKeyAlgorithm());
+ Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
c.init(false, key);
return PGPPad.unpadSessionData(c.unwrap(keyEnc, 0, keyEnc.length));
+
}
}
catch (IOException e)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index d17815be95..4fd82d3263 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -7,8 +7,11 @@
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
+import org.bouncycastle.bcpg.Ed25519PublicBCPGKey;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.InvalidCipherTextException;
@@ -76,8 +79,7 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
try
{
AsymmetricKeyParameter cryptoPublicKey = keyConverter.getPublicKey(pubKey);
- if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.ECDH || pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519
- || pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
+ if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.ECDH)
{
PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
ECDHPublicBCPGKey ecPubKey = (ECDHPublicBCPGKey)pubKeyPacket.getKey();
@@ -102,27 +104,27 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
ephPubEncoding[0] = X_HDR;
((X25519PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 1);
- return encryptSessionInfo(ecPubKey, sessionInfo, secret, userKeyingMaterial, ephPubEncoding);
- }
- else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
- {
- X448KeyPairGenerator gen = new X448KeyPairGenerator();
- gen.init(new X448KeyGenerationParameters(random));
-
- AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
-
- X448Agreement agreement = new X448Agreement();
- agreement.init(ephKp.getPrivate());
-
- byte[] secret = new byte[agreement.getAgreementSize()];
- agreement.calculateAgreement(cryptoPublicKey, secret, 0);
-
- byte[] ephPubEncoding = new byte[X448PublicKeyParameters.KEY_SIZE];
-
- ((X448PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 0);
-
- return encryptSessionInfo(ecPubKey, sessionInfo, secret, userKeyingMaterial, ephPubEncoding);
+ return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm());
}
+// else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
+// {
+// X448KeyPairGenerator gen = new X448KeyPairGenerator();
+// gen.init(new X448KeyGenerationParameters(random));
+//
+// AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
+//
+// X448Agreement agreement = new X448Agreement();
+// agreement.init(ephKp.getPrivate());
+//
+// byte[] secret = new byte[agreement.getAgreementSize()];
+// agreement.calculateAgreement(cryptoPublicKey, secret, 0);
+//
+// byte[] ephPubEncoding = new byte[X448PublicKeyParameters.KEY_SIZE];
+//
+// ((X448PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 0);
+//
+// return encryptSessionInfo(ecPubKey, sessionInfo, secret, userKeyingMaterial, ephPubEncoding);
+// }
else
{
ECDomainParameters ecParams = ((ECPublicKeyParameters)cryptoPublicKey).getParameters();
@@ -139,9 +141,54 @@ else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
byte[] ephPubEncoding = ((ECPublicKeyParameters)ephKp.getPublic()).getQ().getEncoded(false);
- return encryptSessionInfo(ecPubKey, sessionInfo, secret, userKeyingMaterial, ephPubEncoding);
+ return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm());
}
}
+ else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
+ {
+ PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
+
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator(),
+ CryptlibObjectIdentifiers.curvey25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+
+ X25519KeyPairGenerator gen = new X25519KeyPairGenerator();
+ gen.init(new X25519KeyGenerationParameters(random));
+
+ AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
+
+ X25519Agreement agreement = new X25519Agreement();
+ agreement.init(ephKp.getPrivate());
+
+ byte[] secret = new byte[agreement.getAgreementSize()];
+ agreement.calculateAgreement(cryptoPublicKey, secret, 0);
+
+ byte[] ephPubEncoding = new byte[ X25519PublicKeyParameters.KEY_SIZE];
+ ((X25519PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 0);
+
+ return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ }
+ else if ( pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
+ {
+ PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator(),
+ EdECObjectIdentifiers.id_X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+ X448KeyPairGenerator gen = new X448KeyPairGenerator();
+ gen.init(new X448KeyGenerationParameters(random));
+
+ AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
+
+ X448Agreement agreement = new X448Agreement();
+ agreement.init(ephKp.getPrivate());
+
+ byte[] secret = new byte[agreement.getAgreementSize()];
+ agreement.calculateAgreement(cryptoPublicKey, secret, 0);
+
+ byte[] ephPubEncoding = new byte[X448PublicKeyParameters.KEY_SIZE];
+
+ ((X448PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 0);
+
+ return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+ }
else
{
AsymmetricBlockCipher c = BcImplProvider.createPublicKeyCipher(pubKey.getAlgorithm());
@@ -161,17 +208,17 @@ else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
}
}
- private byte[] encryptSessionInfo(ECDHPublicBCPGKey ecPubKey, byte[] sessionInfo, byte[] secret,
- byte[] userKeyingMaterial, byte[] ephPubEncoding)
+ private byte[] encryptSessionInfo(byte[] sessionInfo, byte[] secret,
+ byte[] userKeyingMaterial, byte[] ephPubEncoding, int hashAlgorithm, int symmetricKeyAlgorithm)
throws IOException, PGPException
{
RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(
- new BcPGPDigestCalculatorProvider().get(ecPubKey.getHashAlgorithm()), ecPubKey.getSymmetricKeyAlgorithm());
+ new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
- Wrapper c = BcImplProvider.createWrapper(ecPubKey.getSymmetricKeyAlgorithm());
+ Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
c.init(true, new ParametersWithRandom(key, random));
byte[] C = c.wrap(paddedSessionData, 0, paddedSessionData.length);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
index 57e877bc75..bbebe6ea54 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
@@ -71,6 +71,10 @@
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.bcpg.RSASecretBCPGKey;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.bcpg.X25519PublicBCPGKey;
+import org.bouncycastle.bcpg.X25519SecretBCPGKey;
+import org.bouncycastle.bcpg.X448PublicBCPGKey;
+import org.bouncycastle.bcpg.X448SecretBCPGKey;
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
@@ -199,10 +203,6 @@ public PrivateKey getPrivateKey(PGPPrivateKey privKey)
{
return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_X25519, privPk);
}
- else if (EdECObjectIdentifiers.id_X448.equals(ecdhPub.getCurveOID()))
- {
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_X448, privPk);
- }
else
{
return implGetPrivateKeyEC("ECDH", ecdhPub, ecdhK);
@@ -210,11 +210,17 @@ else if (EdECObjectIdentifiers.id_X448.equals(ecdhPub.getCurveOID()))
}
case PublicKeyAlgorithmTags.X25519:
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_X25519, privPk);
+ PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(
+ new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519),
+ new DEROctetString(Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(new BigInteger(1, privPk.getEncoded()))))).getEncoded());
+ return implGeneratePrivate("XDH", pkcs8Spec);
}
case PublicKeyAlgorithmTags.X448:
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_X448, privPk);
+ PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(
+ new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448),
+ new DEROctetString(Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(new BigInteger(1, privPk.getEncoded()))))).getEncoded());
+ return implGeneratePrivate("XDH", pkcs8Spec);
}
case PublicKeyAlgorithmTags.ECDSA:
return implGetPrivateKeyEC("ECDSA", (ECDSAPublicBCPGKey)pubPk.getKey(), (ECSecretBCPGKey)privPk);
@@ -296,10 +302,6 @@ public PublicKey getPublicKey(PGPPublicKey publicKey)
{
return get25519PublicKey(ecdhK.getEncodedPoint(), EdECObjectIdentifiers.id_X25519, "XDH", "Curve");
}
- else if (EdECObjectIdentifiers.id_X448.equals(ecdhK.getCurveOID()))
- {
- return implGetPublicKeyX509("XDH", EdECObjectIdentifiers.id_X448, ecdhK.getEncodedPoint());
- }
else
{
return implGetPublicKeyEC("ECDH", ecdhK);
@@ -307,11 +309,19 @@ else if (EdECObjectIdentifiers.id_X448.equals(ecdhK.getCurveOID()))
}
case PublicKeyAlgorithmTags.X25519:
{
- return get25519PublicKey(((ECDHPublicBCPGKey)publicPk.getKey()).getEncodedPoint(), EdECObjectIdentifiers.id_X25519, "XDH", "Curve");
+ byte[] pEnc = publicPk.getKey().getEncoded();
+ X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519),
+ Arrays.copyOfRange(pEnc, 0, pEnc.length)).getEncoded());
+ return implGeneratePublic("XDH", x509Spec);
}
case PublicKeyAlgorithmTags.X448:
{
- return implGetPublicKeyX509("XDH", EdECObjectIdentifiers.id_X448, ((ECDHPublicBCPGKey)publicPk.getKey()).getEncodedPoint());
+ byte[] pEnc = publicPk.getKey().getEncoded();
+ X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448),
+ Arrays.copyOfRange(pEnc, 0, pEnc.length)).getEncoded());
+ return implGeneratePublic("XDH", x509Spec);
}
case PublicKeyAlgorithmTags.ECDSA:
return implGetPublicKeyEC("ECDSA", (ECDSAPublicBCPGKey)publicPk.getKey());
@@ -414,13 +424,46 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey)
}
else
{
- return getEcSecretBCPGKey(privKey);
+ PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
+
+ try
+ {
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return new ECSecretBCPGKey(new BigInteger(1,
+ Arrays.reverse(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets())));
+ }
+ catch (IOException e)
+ {
+ throw new PGPException(e.getMessage(), e);
+ }
}
}
case PublicKeyAlgorithmTags.X25519:
+ {
+ PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
+ try
+ {
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return new X25519SecretBCPGKey(Arrays.reverse(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets()));
+ }
+ catch (IOException e)
+ {
+ throw new PGPException(e.getMessage(), e);
+ }
+ }
case PublicKeyAlgorithmTags.X448:
{
- return getEcSecretBCPGKey(privKey);
+ PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
+
+ try
+ {
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return new X448SecretBCPGKey(Arrays.reverse(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets()));
+ }
+ catch (IOException e)
+ {
+ throw new PGPException(e.getMessage(), e);
+ }
}
case PublicKeyAlgorithmTags.ECDSA:
@@ -566,6 +609,14 @@ else if (pubKey.getAlgorithm().regionMatches(true, 0, "ED2", 0, 3))
{
return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, getPointEncUncompressed(pubKey, Ed25519.PUBLIC_KEY_SIZE)));
}
+ else if (algorithm == PGPPublicKey.X25519)
+ {
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+ byte[] pointEnc = new byte[X25519.SCALAR_SIZE];
+
+ System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
+ return new X25519PublicBCPGKey(pointEnc);
+ }
else if (pubKey.getAlgorithm().regionMatches(true, 0, "X2", 0, 2))
{
PGPKdfParameters kdfParams = implGetKdfParameters(algorithmParameters);
@@ -581,11 +632,13 @@ else if (algorithm == PGPPublicKey.Ed448)
System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
return new Ed448PublicBCPGKey(pointEnc);
}
- else if (pubKey.getAlgorithm().regionMatches(true, 0, "X4", 0, 2))
+ else if (algorithm == PGPPublicKey.X448)
{
- PGPKdfParameters kdfParams = implGetKdfParameters(algorithmParameters);
- return new ECDHPublicBCPGKey(EdECObjectIdentifiers.id_X448, new BigInteger(1, getPointEnc(pubKey, X448.SCALAR_SIZE)),
- kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm());
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+ byte[] pointEnc = new byte[X448.SCALAR_SIZE];
+
+ System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
+ return new X448PublicBCPGKey(pointEnc);
}
else
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
index 9bbe5eda1d..0cf563b0c4 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
@@ -27,9 +27,12 @@
import org.bouncycastle.asn1.x9.X9ECParametersHolder;
import org.bouncycastle.bcpg.AEADEncDataPacket;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.bcpg.X25519PublicBCPGKey;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
import org.bouncycastle.crypto.params.X448PublicKeyParameters;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
@@ -218,7 +221,7 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
throws PGPException
{
PublicKeyPacket pubKeyData = privKey.getPublicKeyPacket();
- ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
+
byte[] enc = secKeyData[0];
@@ -244,32 +247,52 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
{
KeyAgreement agreement;
PublicKey publicKey;
+ int symmetricKeyAlgorithm, hashALgorithm;
+ ASN1ObjectIdentifier curveID;
+ if (pubKeyData.getKey() instanceof ECDHPublicBCPGKey)
+ {
+ ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
+ symmetricKeyAlgorithm = ecKey.getSymmetricKeyAlgorithm();
+ hashALgorithm = ecKey.getHashAlgorithm();
+ curveID = ecKey.getCurveOID();
+ // XDH
+ if (curveID.equals(CryptlibObjectIdentifiers.curvey25519))
+ {
+ agreement = helper.createKeyAgreement(RFC6637Utils.getXDHAlgorithm(pubKeyData));
+ publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X25519, 1,
+ pEnc.length != (1 + X25519PublicKeyParameters.KEY_SIZE) || 0x40 != pEnc[0], "25519");
+ }
+ else
+ {
+ X9ECParametersHolder x9Params = ECNamedCurveTable.getByOIDLazy(ecKey.getCurveOID());
+ ECPoint publicPoint = x9Params.getCurve().decodePoint(pEnc);
+
+ agreement = helper.createKeyAgreement(RFC6637Utils.getAgreementAlgorithm(pubKeyData));
- // XDH
- if (ecKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
+ publicKey = converter.getPublicKey(new PGPPublicKey(new PublicKeyPacket(PublicKeyAlgorithmTags.ECDH, new Date(),
+ new ECDHPublicBCPGKey(ecKey.getCurveOID(), publicPoint, ecKey.getHashAlgorithm(), ecKey.getSymmetricKeyAlgorithm())), fingerprintCalculator));
+ }
+ }
+ else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
{
agreement = helper.createKeyAgreement(RFC6637Utils.getXDHAlgorithm(pubKeyData));
- publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X25519, 1,
- pEnc.length != (1 + X25519PublicKeyParameters.KEY_SIZE) || 0x40 != pEnc[0], "25519");
+ publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X25519, 0,
+ pEnc.length != (X25519PublicKeyParameters.KEY_SIZE), "25519");
+ hashALgorithm = HashAlgorithmTags.SHA256;
+ symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128;
+ curveID = CryptlibObjectIdentifiers.curvey25519;
}
- else if (ecKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
+ else
{
agreement = helper.createKeyAgreement(RFC6637Utils.getXDHAlgorithm(pubKeyData));
publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X448, 0,
pEnc.length != X448PublicKeyParameters.KEY_SIZE, "448");
- }
- else
- {
- X9ECParametersHolder x9Params = ECNamedCurveTable.getByOIDLazy(ecKey.getCurveOID());
- ECPoint publicPoint = x9Params.getCurve().decodePoint(pEnc);
-
- agreement = helper.createKeyAgreement(RFC6637Utils.getAgreementAlgorithm(pubKeyData));
-
- publicKey = converter.getPublicKey(new PGPPublicKey(new PublicKeyPacket(PublicKeyAlgorithmTags.ECDH, new Date(),
- new ECDHPublicBCPGKey(ecKey.getCurveOID(), publicPoint, ecKey.getHashAlgorithm(), ecKey.getSymmetricKeyAlgorithm())), fingerprintCalculator));
+ hashALgorithm = HashAlgorithmTags.SHA512;
+ symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_256;
+ curveID = EdECObjectIdentifiers.id_X448;
}
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyData, fingerprintCalculator);
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyData, fingerprintCalculator, curveID, hashALgorithm, symmetricKeyAlgorithm);
PrivateKey privateKey = converter.getPrivateKey(privKey);
@@ -277,9 +300,9 @@ else if (ecKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
agreement.doPhase(publicKey, true);
- Key key = agreement.generateSecret(RFC6637Utils.getKeyEncryptionOID(ecKey.getSymmetricKeyAlgorithm()).getId());
+ Key key = agreement.generateSecret(RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId());
- Cipher c = helper.createKeyWrapper(ecKey.getSymmetricKeyAlgorithm());
+ Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
c.init(Cipher.UNWRAP_MODE, key);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index 1ae1f1756f..8168a4e896 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -20,11 +20,15 @@
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
+import org.bouncycastle.bcpg.Ed25519PublicBCPGKey;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
@@ -94,8 +98,7 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
{
PublicKey cryptoPublicKey = keyConverter.getPublicKey(pubKey);
- if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.ECDH || pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448
- || pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
+ if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.ECDH)
{
PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyPacket.getKey();
@@ -107,18 +110,13 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
if (ecKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
return getEncryptSessionInfo("X25519", RFC6637Utils.getXDHAlgorithm(pubKeyPacket), ukmSpec, cryptoPublicKey, keyEncryptionOID,
- ecKey, sessionInfo, (kpGen) -> kpGen.initialize(255, random),
+ ecKey.getSymmetricKeyAlgorithm(), sessionInfo, (kpGen) -> kpGen.initialize(255, random),
(ephPubEncoding) -> Arrays.prepend(ephPubEncoding, X_HDR));
}
- else if (ecKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
- {
- return getEncryptSessionInfo("X448", RFC6637Utils.getXDHAlgorithm(pubKeyPacket), ukmSpec, cryptoPublicKey, keyEncryptionOID,
- ecKey, sessionInfo, (kpGen) -> kpGen.initialize(448, random), (ephPubEncoding) -> ephPubEncoding);
- }
else
{
return getEncryptSessionInfo("EC", RFC6637Utils.getAgreementAlgorithm(pubKeyPacket), ukmSpec, cryptoPublicKey, keyEncryptionOID,
- ecKey, sessionInfo, (kpGen) ->
+ ecKey.getSymmetricKeyAlgorithm(), sessionInfo, (kpGen) ->
{
AlgorithmParameters ecAlgParams = helper.createAlgorithmParameters("EC");
ecAlgParams.init(new X962Parameters(ecKey.getCurveOID()).getEncoded());
@@ -133,6 +131,26 @@ else if (ecKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
});
}
}
+ else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
+ {
+ PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
+ UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
+ new JcaKeyFingerprintCalculator(), CryptlibObjectIdentifiers.curvey25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128));
+ String keyEncryptionOID = NISTObjectIdentifiers.id_aes128_wrap.getId();
+ return getEncryptSessionInfo("X25519", RFC6637Utils.getXDHAlgorithm(pubKeyPacket), ukmSpec, cryptoPublicKey, keyEncryptionOID,
+ SymmetricKeyAlgorithmTags.AES_128, sessionInfo, (kpGen) -> kpGen.initialize(255, random),
+ (ephPubEncoding) -> ephPubEncoding);
+ }
+ else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
+ {
+ PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
+ UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
+ new JcaKeyFingerprintCalculator(), EdECObjectIdentifiers.id_X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256));
+ String keyEncryptionOID = NISTObjectIdentifiers.id_aes256_wrap.getId();
+ return getEncryptSessionInfo("X448", RFC6637Utils.getXDHAlgorithm(pubKeyPacket), ukmSpec, cryptoPublicKey, keyEncryptionOID,
+ SymmetricKeyAlgorithmTags.AES_256, sessionInfo, (kpGen) -> kpGen.initialize(448, random),
+ (ephPubEncoding) -> ephPubEncoding);
+ }
else
{
Cipher c = helper.createPublicKeyCipher(pubKey.getAlgorithm());
@@ -178,7 +196,7 @@ private interface EphPubEncoding
}
private byte[] getEncryptSessionInfo(String algorithmName, String algorithm, UserKeyingMaterialSpec ukmSpec,
- PublicKey cryptoPublicKey, String keyEncryptionOID, ECDHPublicBCPGKey ecKey, byte[] sessionInfo,
+ PublicKey cryptoPublicKey, String keyEncryptionOID, int symmetricKeyAlgorithm, byte[] sessionInfo,
KeyPairGeneratorOperation kpOperation, EphPubEncoding getEncoding)
throws GeneralSecurityException, IOException, PGPException
{
@@ -190,15 +208,9 @@ private byte[] getEncryptSessionInfo(String algorithmName, String algorithm, Use
agreement.doPhase(cryptoPublicKey, true);
Key secret = agreement.generateSecret(keyEncryptionOID);
byte[] ephPubEncoding = getEncoding.getEphPubEncoding(SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes());
- return encryptSessionInfo(ecKey, sessionInfo, secret, ephPubEncoding);
- }
-
- private byte[] encryptSessionInfo(ECDHPublicBCPGKey ecKey, byte[] sessionInfo, Key secret, byte[] ephPubEncoding)
- throws GeneralSecurityException, IOException, PGPException
- {
byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
- Cipher c = helper.createKeyWrapper(ecKey.getSymmetricKeyAlgorithm());
+ Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
c.init(Cipher.WRAP_MODE, secret, random);
byte[] C = c.wrap(new SecretKeySpec(paddedSessionData, PGPUtil.getSymmetricCipherName(sessionInfo[0])));
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/BcImplProviderTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/BcImplProviderTest.java
index be55fadf98..08576ff26f 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/BcImplProviderTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/BcImplProviderTest.java
@@ -23,6 +23,8 @@
import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.DSASecretBCPGKey;
import org.bouncycastle.bcpg.ECSecretBCPGKey;
+import org.bouncycastle.bcpg.Ed25519SecretBCPGKey;
+import org.bouncycastle.bcpg.Ed448SecretBCPGKey;
import org.bouncycastle.bcpg.EdSecretBCPGKey;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
@@ -145,14 +147,7 @@ public void testBcImplProvider()
testCreateSigner(PublicKeyAlgorithmTags.ECDSA, new DSADigestSigner(new ECDSASigner(), new SHA1Digest()), "ECDSA",
(pub, privKey) -> new ECSecretBCPGKey(((ECPrivateKey)privKey).getS()),
(kpGen) -> new ECGenParameterSpec("P-256"));
- testCreateSigner(PublicKeyAlgorithmTags.EDDSA_LEGACY, new EdDsaSigner(new Ed448Signer(new byte[0]), new SHA1Digest()), "EdDSA",
- (pub, privKey) ->
- {
- PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
- return new EdSecretBCPGKey(
- new BigInteger(1, ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets()));
- },
- (kpGen) -> kpGen.initialize(new ECNamedCurveGenParameterSpec("Ed448")));
+
testCreateSigner(PublicKeyAlgorithmTags.EDDSA_LEGACY, new EdDsaSigner(new Ed25519Signer(), new SHA1Digest()), "EdDSA",
(pub, privKey) ->
{
@@ -165,16 +160,14 @@ public void testBcImplProvider()
(pub, privKey) ->
{
PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
- return new EdSecretBCPGKey(
- new BigInteger(1, ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets()));
+ return new Ed448SecretBCPGKey(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets());
},
(kpGen) -> kpGen.initialize(new ECNamedCurveGenParameterSpec("Ed448")));
testCreateSigner(PublicKeyAlgorithmTags.Ed25519, new EdDsaSigner(new Ed25519Signer(), new SHA1Digest()), "EdDSA",
(pub, privKey) ->
{
PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
- return new EdSecretBCPGKey(
- new BigInteger(1, ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets()));
+ return new Ed25519SecretBCPGKey(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets());
},
(kpGen) -> kpGen.initialize(new ECNamedCurveGenParameterSpec("Ed25519")));
testException("cannot recognise keyAlgorithm:", "PGPException", ()->
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index c5ee678c32..de65703d6f 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -164,26 +164,21 @@ public void testBcPGPDataEncryptorBuilder()
public void testBcPGPKeyPair()
throws Exception
{
+ testCreateKeyPair(PublicKeyAlgorithmTags.X448, "X448");
+ testCreateKeyPair(PublicKeyAlgorithmTags.X25519, "X25519");
testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed25519, "Ed25519");
testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, "Ed448");
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, PublicKeyAlgorithmTags.X448, "X448");
testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, PublicKeyAlgorithmTags.X25519, "X25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.X448, PublicKeyAlgorithmTags.ECDH, "X448");
testCreateKeyPair(PublicKeyAlgorithmTags.X25519, PublicKeyAlgorithmTags.ECDH, "X25519");
- //testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed448, "Ed448");
- //testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed448");
testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519");
testCreateKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, "RSA");
testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL");
testCreateKeyPair(PublicKeyAlgorithmTags.DSA, "DSA");
testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "X25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "X448");
-// testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed448");
testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519");
testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA");
testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL");
- testCreateKeyPair(PublicKeyAlgorithmTags.X25519, "X25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.X448, "X448");
+
testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, "Ed25519");
}
@@ -244,111 +239,19 @@ public void testKeyRings()
throws Exception
{
System.setProperty("enableCamelliaKeyWrapping", "True");
- keyringTest("ED25519", PublicKeyAlgorithmTags.Ed25519, "X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("ED25519", PublicKeyAlgorithmTags.Ed25519, "X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("ED25519", PublicKeyAlgorithmTags.Ed25519, "X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_192);
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_256);
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_128);
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_192);
keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_256);
- //keyringTest("Ed448", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X448", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_192);
- keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_256);
-
- }
-
- private void keyringCompreTest(String ed_str, int ed_num, String x_str, int x_num, int hashAlgorithm, int symmetricWrapAlgorithm)
- throws Exception
- {
-
- String identity = "eric@bouncycastle.org";
- char[] passPhrase = "Hello, world!".toCharArray();
-
- KeyPairGenerator edKp = KeyPairGenerator.getInstance("EdDSA", "BC");
-
- edKp.initialize(new ECNamedCurveGenParameterSpec(ed_str));
-
- PGPKeyPair dsaKeyPair = new JcaPGPKeyPair(ed_num, edKp.generateKeyPair(), new Date());
-
- KeyPairGenerator dhKp = KeyPairGenerator.getInstance("XDH", "BC");
-
- dhKp.initialize(new ECNamedCurveGenParameterSpec(x_str));
-
- PGPKeyPair dhKeyPair = new JcaPGPKeyPair(x_num, new PGPKdfParameters(hashAlgorithm, symmetricWrapAlgorithm), dhKp.generateKeyPair(), new Date());
-
- encryptDecryptTest(dhKeyPair.getPublicKey(), dhKeyPair.getPrivateKey());
- encryptDecryptBcTest(dhKeyPair.getPublicKey(), dhKeyPair.getPrivateKey());
-
- PGPDigestCalculator sha1Calc = new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1);
-
- PGPKeyRingGenerator keyRingGen = new PGPKeyRingGenerator(
- PGPSignature.POSITIVE_CERTIFICATION, dsaKeyPair,
- identity, sha1Calc, null, null,
- new JcaPGPContentSignerBuilder(dsaKeyPair.getPublicKey().getAlgorithm(), HashAlgorithmTags.SHA256).setProvider("BC"),
- new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc).setProvider("BC").build(passPhrase));
-
- keyRingGen.addSubKey(dhKeyPair);
-
- ByteArrayOutputStream secretOut = new ByteArrayOutputStream();
-
- PGPSecretKeyRing secRing = keyRingGen.generateSecretKeyRing();
-
-// PGPPublicKeyRing pubRing = keyRingGen.generatePublicKeyRing();
-//
- secRing.encode(secretOut);
-//
- secretOut.close();
- secRing = new PGPSecretKeyRing(secretOut.toByteArray(), new JcaKeyFingerprintCalculator());
-
- Iterator pIt = secRing.getPublicKeys();
- pIt.next();
-
- PGPPublicKey sKey = (PGPPublicKey)pIt.next();
- PGPPublicKey vKey = secRing.getPublicKey();
-
- Iterator sIt = sKey.getSignatures();
- int count = 0;
- while (sIt.hasNext())
- {
- PGPSignature sig = (PGPSignature)sIt.next();
-
- if (sig.getKeyID() == vKey.getKeyID()
- && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING)
- {
- count++;
- sig.init(new JcaPGPContentVerifierBuilderProvider().setProvider("BC"), vKey);
- if (!sig.verifyCertification(vKey, sKey))
- {
- fail("failed to verify sub-key signature.");
- }
- }
- }
-
- isTrue(count == 1);
-
- secRing = new PGPSecretKeyRing(secretOut.toByteArray(), new JcaKeyFingerprintCalculator());
- PGPPublicKey pubKey = null;
- PGPPrivateKey privKey = null;
-
- for (Iterator it = secRing.getPublicKeys(); it.hasNext(); )
- {
- pubKey = (PGPPublicKey)it.next();
- if (pubKey.isEncryptionKey())
- {
- privKey = secRing.getSecretKey(pubKey.getKeyID()).extractPrivateKey(
- new JcePBESecretKeyDecryptorBuilder().setProvider(new BouncyCastleProvider()).build(passPhrase));
- break;
- }
- }
-
- encryptDecryptTest(pubKey, privKey);
- encryptDecryptBcTest(pubKey, privKey);
+ keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
}
private void keyringTest(String ed_str, int ed_num, String x_str, int x_num, int hashAlgorithm, int symmetricWrapAlgorithm)
From 13323ab57094f9d6aafcf2ef681ad5e372fde20a Mon Sep 17 00:00:00 2001
From: gefeili
Date: Fri, 23 Feb 2024 17:14:22 +1030
Subject: [PATCH 0092/1846] Add tests for curves
---
.../org/bouncycastle/openpgp/PGPUtil.java | 6 ++
...PublicKeyKeyEncryptionMethodGenerator.java | 19 ------
.../openpgp/test/BcImplProviderTest.java | 15 +++++
.../openpgp/test/OperatorBcTest.java | 58 ++++++++++++-------
4 files changed, 59 insertions(+), 39 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java
index 9986aa3b2e..0f3da60664 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java
@@ -17,7 +17,9 @@
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.bcpg.ArmoredInputStream;
import org.bouncycastle.bcpg.BCPGInputStream;
@@ -67,11 +69,15 @@ public class PGPUtil
{
{
put(CryptlibObjectIdentifiers.curvey25519, "Curve25519");
+ put(GNUObjectIdentifiers.Ed25519, "Ed25519Legacy");
put(EdECObjectIdentifiers.id_X25519, "Curve25519");
put(EdECObjectIdentifiers.id_Ed25519, "Ed25519");
put(SECObjectIdentifiers.secp256r1, "NIST P-256");
put(SECObjectIdentifiers.secp384r1, "NIST P-384");
put(SECObjectIdentifiers.secp521r1, "NIST P-521");
+ put(TeleTrusTObjectIdentifiers.brainpoolP256r1, "brainpoolP256r1");
+ put(TeleTrusTObjectIdentifiers.brainpoolP384r1, "brainpoolP384r1");
+ put(TeleTrusTObjectIdentifiers.brainpoolP512r1, "brainpoolP512r1");
}
};
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index 4fd82d3263..48c4b711b9 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -106,25 +106,6 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm());
}
-// else if (ecPubKey.getCurveOID().equals(EdECObjectIdentifiers.id_X448))
-// {
-// X448KeyPairGenerator gen = new X448KeyPairGenerator();
-// gen.init(new X448KeyGenerationParameters(random));
-//
-// AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
-//
-// X448Agreement agreement = new X448Agreement();
-// agreement.init(ephKp.getPrivate());
-//
-// byte[] secret = new byte[agreement.getAgreementSize()];
-// agreement.calculateAgreement(cryptoPublicKey, secret, 0);
-//
-// byte[] ephPubEncoding = new byte[X448PublicKeyParameters.KEY_SIZE];
-//
-// ((X448PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 0);
-//
-// return encryptSessionInfo(ecPubKey, sessionInfo, secret, userKeyingMaterial, ephPubEncoding);
-// }
else
{
ECDomainParameters ecParams = ((ECPublicKeyParameters)cryptoPublicKey).getParameters();
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/BcImplProviderTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/BcImplProviderTest.java
index 08576ff26f..600866d0a8 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/BcImplProviderTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/BcImplProviderTest.java
@@ -147,6 +147,21 @@ public void testBcImplProvider()
testCreateSigner(PublicKeyAlgorithmTags.ECDSA, new DSADigestSigner(new ECDSASigner(), new SHA1Digest()), "ECDSA",
(pub, privKey) -> new ECSecretBCPGKey(((ECPrivateKey)privKey).getS()),
(kpGen) -> new ECGenParameterSpec("P-256"));
+ testCreateSigner(PublicKeyAlgorithmTags.ECDSA, new DSADigestSigner(new ECDSASigner(), new SHA1Digest()), "ECDSA",
+ (pub, privKey) -> new ECSecretBCPGKey(((ECPrivateKey)privKey).getS()),
+ (kpGen) -> new ECGenParameterSpec("P-384"));
+ testCreateSigner(PublicKeyAlgorithmTags.ECDSA, new DSADigestSigner(new ECDSASigner(), new SHA1Digest()), "ECDSA",
+ (pub, privKey) -> new ECSecretBCPGKey(((ECPrivateKey)privKey).getS()),
+ (kpGen) -> new ECGenParameterSpec("P-521"));
+ testCreateSigner(PublicKeyAlgorithmTags.ECDSA, new DSADigestSigner(new ECDSASigner(), new SHA1Digest()), "ECDSA",
+ (pub, privKey) -> new ECSecretBCPGKey(((ECPrivateKey)privKey).getS()),
+ (kpGen) -> new ECGenParameterSpec("brainpoolP256r1"));
+ testCreateSigner(PublicKeyAlgorithmTags.ECDSA, new DSADigestSigner(new ECDSASigner(), new SHA1Digest()), "ECDSA",
+ (pub, privKey) -> new ECSecretBCPGKey(((ECPrivateKey)privKey).getS()),
+ (kpGen) -> new ECGenParameterSpec("brainpoolP384r1"));
+ testCreateSigner(PublicKeyAlgorithmTags.ECDSA, new DSADigestSigner(new ECDSASigner(), new SHA1Digest()), "ECDSA",
+ (pub, privKey) -> new ECSecretBCPGKey(((ECPrivateKey)privKey).getS()),
+ (kpGen) -> new ECGenParameterSpec("brainpoolP512r1"));
testCreateSigner(PublicKeyAlgorithmTags.EDDSA_LEGACY, new EdDsaSigner(new Ed25519Signer(), new SHA1Digest()), "EdDSA",
(pub, privKey) ->
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index de65703d6f..81eb1ef189 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -9,6 +9,7 @@
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
+import java.security.spec.ECGenParameterSpec;
import java.util.Arrays;
import java.util.Date;
import java.util.Iterator;
@@ -164,36 +165,53 @@ public void testBcPGPDataEncryptorBuilder()
public void testBcPGPKeyPair()
throws Exception
{
- testCreateKeyPair(PublicKeyAlgorithmTags.X448, "X448");
- testCreateKeyPair(PublicKeyAlgorithmTags.X25519, "X25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed25519, "Ed25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, "Ed448");
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, PublicKeyAlgorithmTags.X25519, "X25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.X25519, PublicKeyAlgorithmTags.ECDH, "X25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, "RSA");
- testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL");
- testCreateKeyPair(PublicKeyAlgorithmTags.DSA, "DSA");
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "X25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519");
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA");
- testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL");
-
- testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, "Ed25519");
+ testCreateKeyPair(PublicKeyAlgorithmTags.X448, "X448", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.X25519, "X25519", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed25519, "Ed25519", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, "Ed448", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, PublicKeyAlgorithmTags.X25519, "X25519", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("P-256")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("P-384")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("P-521")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP256r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP384r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP512r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.X25519, PublicKeyAlgorithmTags.ECDH, "X25519", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, "RSA", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.DSA, "DSA", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "X25519", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("P-256")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("P-384")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("P-521")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP256r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP384r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP512r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, "Ed25519", (gen)-> {});
}
- private void testCreateKeyPair(int algorithm, String name)
+ private void testCreateKeyPair(int algorithm, String name, KeyPairGeneratorOperation kpgen)
throws Exception
{
- testCreateKeyPair(algorithm, algorithm, name);
+ testCreateKeyPair(algorithm, algorithm, name, kpgen);
}
- private void testCreateKeyPair(int algorithm1, int algorithm2, String name)
+ private interface KeyPairGeneratorOperation
+ {
+ void initialize(KeyPairGenerator gen) throws Exception;
+ }
+
+ private void testCreateKeyPair(int algorithm1, int algorithm2, String name, KeyPairGeneratorOperation kpgen)
throws Exception
{
Date creationDate = new Date();
KeyPairGenerator gen = KeyPairGenerator.getInstance(name, "BC");
+ kpgen.initialize(gen);
KeyPair keyPair = gen.generateKeyPair();
BcPGPKeyConverter converter = new BcPGPKeyConverter();
@@ -208,7 +226,7 @@ private void testCreateKeyPair(int algorithm1, int algorithm2, String name)
PrivateKey privKey = jcaPGPKeyConverter.getPrivateKey(jcaPgpPair.getPrivateKey());
PublicKey pubKey = jcaPGPKeyConverter.getPublicKey(jcaPgpPair.getPublicKey());
- if (algorithm1 == algorithm2 &&!Arrays.equals(jcaPgpPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(),
+ if (algorithm1 == algorithm2 && !Arrays.equals(jcaPgpPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(),
bcKeyPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded()))
{
throw new PGPException("JcaPGPKeyPair and BcPGPKeyPair private keys are not equal.");
From e71cdcde1cb480be74085b64b3684a85af263474 Mon Sep 17 00:00:00 2001
From: royb
Date: Fri, 23 Feb 2024 18:17:40 -0500
Subject: [PATCH 0093/1846] Update SNTRUPrime KEMSpi for jdk21 (only tested
generic)
---
.../pqc/jcajce/provider/Util.java | 85 --------
.../ntruprime/SNTRUPrimeDecapsulatorSpi.java | 59 ++++--
.../ntruprime/SNTRUPrimeEncapsulatorSpi.java | 61 +++---
.../provider/ntruprime/SNTRUPrimeKEMSpi.java | 18 +-
.../provider/test/SNTRUPrimeKEMTest.java | 190 +++++++++---------
5 files changed, 179 insertions(+), 234 deletions(-)
delete mode 100644 prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/Util.java
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/Util.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/Util.java
deleted file mode 100644
index 08f37ba137..0000000000
--- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/Util.java
+++ /dev/null
@@ -1,85 +0,0 @@
-package org.bouncycastle.pqc.jcajce.provider;
-
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import org.bouncycastle.crypto.DerivationFunction;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.Xof;
-import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
-import org.bouncycastle.crypto.digests.SHAKEDigest;
-import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
-import org.bouncycastle.crypto.params.KDFParameters;
-import org.bouncycastle.jcajce.spec.KTSParameterSpec;
-
-import java.security.InvalidKeyException;
-
-public class Util
-{
- public static byte[] makeKeyBytes(KTSParameterSpec ktsSpec, byte[] secret)
- throws InvalidKeyException
- {
- AlgorithmIdentifier kdfAlgorithm = ktsSpec.getKdfAlgorithm();
- byte[] otherInfo = ktsSpec.getOtherInfo();
- byte[] keyBytes = new byte[(ktsSpec.getKeySize() + 7) / 8];
-
- if (X9ObjectIdentifiers.id_kdf_kdf2.equals(kdfAlgorithm.getAlgorithm()))
- {
- AlgorithmIdentifier digAlg = AlgorithmIdentifier.getInstance(kdfAlgorithm.getParameters());
- DerivationFunction kdf = new KDF2BytesGenerator(getDigest(digAlg.getAlgorithm()));
-
- kdf.init(new KDFParameters(secret, otherInfo));
-
- kdf.generateBytes(keyBytes, 0, keyBytes.length);
- }
- else if (X9ObjectIdentifiers.id_kdf_kdf3.equals(kdfAlgorithm.getAlgorithm()))
- {
- AlgorithmIdentifier digAlg = AlgorithmIdentifier.getInstance(kdfAlgorithm.getParameters());
- DerivationFunction kdf = new ConcatenationKDFGenerator(getDigest(digAlg.getAlgorithm()));
-
- kdf.init(new KDFParameters(secret, otherInfo));
-
- kdf.generateBytes(keyBytes, 0, keyBytes.length);
- }
- else if (NISTObjectIdentifiers.id_shake256.equals(kdfAlgorithm.getAlgorithm()))
- {
- Xof xof = new SHAKEDigest(256);
-
- xof.update(secret, 0, secret.length);
- xof.update(otherInfo, 0, otherInfo.length);
-
- xof.doFinal(keyBytes, 0, keyBytes.length);
- }
- else
- {
- throw new InvalidKeyException("Unrecognized KDF: " + kdfAlgorithm.getAlgorithm());
- }
-
- return keyBytes;
- }
-
- static Digest getDigest(ASN1ObjectIdentifier oid)
- {
- if (oid.equals(NISTObjectIdentifiers.id_sha256))
- {
- return new SHA256Digest();
- }
- if (oid.equals(NISTObjectIdentifiers.id_sha512))
- {
- return new SHA512Digest();
- }
- if (oid.equals(NISTObjectIdentifiers.id_shake128))
- {
- return new SHAKEDigest(128);
- }
- if (oid.equals(NISTObjectIdentifiers.id_shake256))
- {
- return new SHAKEDigest(256);
- }
-
- throw new IllegalArgumentException("unrecognized digest OID: " + oid);
- }
-}
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java
index b62793ca4b..e7d090191f 100644
--- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java
@@ -1,9 +1,7 @@
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.Wrapper;
-import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMExtractor;
import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
@@ -14,11 +12,8 @@
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
import java.util.Objects;
-import static org.bouncycastle.pqc.jcajce.provider.Util.makeKeyBytes;
-
class SNTRUPrimeDecapsulatorSpi
implements KEMSpi.DecapsulatorSpi
{
@@ -47,33 +42,59 @@ public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, Strin
throw new DecapsulateException("incorrect encapsulation size");
}
- KTSParameterSpec.Builder builder = new KTSParameterSpec.Builder(parameterSpec.getKeyAlgorithmName(), parameterSpec.getKeySize());
+ // if algorithm is Generic then use parameterSpec to wrap key
+ if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
+ algorithm.equals("Generic"))
+ {
+ algorithm = parameterSpec.getKeyAlgorithmName();
+ }
- if (!algorithm.equals("Generic"))
+ // check spec algorithm mismatch provided algorithm
+ if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
+ !parameterSpec.getKeyAlgorithmName().equals(algorithm))
{
- //TODO:
-// builder.withKdfAlgorithm(AlgorithmIdentifier.getInstance(algorithm));
+ throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm);
}
- KTSParameterSpec spec = builder.build();
- byte[] secret = kemExt.extractSecret(encapsulation);
+ // Only use KDF when ktsParameterSpec is provided
+ // Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
+ boolean wrapKey = !(parameterSpec.getKeyAlgorithmName().equals("Generic") && algorithm.equals("Generic"));
- byte[] kdfKey = Arrays.copyOfRange(secret, from, to);
+ byte[] secret = kemExt.extractSecret(encapsulation);
+ byte[] secretKey = Arrays.copyOfRange(secret, from, to);
- try
- {
- return new SecretKeySpec(makeKeyBytes(spec, kdfKey), algorithm);
- }
- catch (InvalidKeyException e)
+ if (wrapKey)
{
- throw new RuntimeException(e);
+ try
+ {
+ KTSParameterSpec spec = parameterSpec;
+ // Generate a new ktsParameterSpec if spec is generic but algorithm is not generic
+ if (parameterSpec.getKeyAlgorithmName().equals("Generic"))
+ {
+ spec = new KTSParameterSpec.Builder(algorithm, secretKey.length * 8).withNoKdf().build();
+ }
+
+ Wrapper kWrap = WrapUtil.getKeyUnwrapper(spec, secretKey);
+ secretKey = kWrap.unwrap(secretKey, 0, secretKey.length);
+
+ }
+ catch (InvalidCipherTextException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new RuntimeException(e);
+ }
+
}
+ return new SecretKeySpec(secretKey, algorithm);
}
@Override
public int engineSecretSize()
{
- return privateKey.getKeyParams().getParameters().getSessionKeySize() / 8;
+ return parameterSpec.getKeySize() / 8;
}
@Override
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java
index dbc1e50942..3cd14d57dc 100644
--- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java
@@ -1,10 +1,7 @@
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
-import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
-import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.SecretWithEncapsulation;
import org.bouncycastle.crypto.Wrapper;
-import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMGenerator;
import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
@@ -13,20 +10,15 @@
import javax.crypto.KEM;
import javax.crypto.KEMSpi;
import javax.crypto.spec.SecretKeySpec;
-import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
-import java.security.KeyPair;
import java.security.SecureRandom;
import java.util.Objects;
-import static org.bouncycastle.pqc.jcajce.provider.Util.makeKeyBytes;
-
class SNTRUPrimeEncapsulatorSpi
implements KEMSpi.EncapsulatorSpi
{
private final BCSNTRUPrimePublicKey publicKey;
private final KTSParameterSpec parameterSpec;
- private final SecureRandom random;
private final SNTRUPrimeKEMGenerator kemGen;
@@ -34,7 +26,6 @@ public SNTRUPrimeEncapsulatorSpi(BCSNTRUPrimePublicKey publicKey, KTSParameterSp
{
this.publicKey = publicKey;
this.parameterSpec = parameterSpec;
- this.random = random;
kemGen = new SNTRUPrimeKEMGenerator(random);
}
@@ -42,39 +33,63 @@ public SNTRUPrimeEncapsulatorSpi(BCSNTRUPrimePublicKey publicKey, KTSParameterSp
@Override
public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm)
{
- Objects.checkFromToIndex(from, to, engineEncapsulationSize());
+ Objects.checkFromToIndex(from, to, engineSecretSize());
Objects.requireNonNull(algorithm, "null algorithm");
- KTSParameterSpec.Builder builder = new KTSParameterSpec.Builder(parameterSpec.getKeyAlgorithmName(), parameterSpec.getKeySize());
+ // if algorithm is Generic then use parameterSpec to wrap key
+ if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
+ algorithm.equals("Generic"))
+ {
+ algorithm = parameterSpec.getKeyAlgorithmName();
+ }
- if (!algorithm.equals("Generic"))
+ // check spec algorithm mismatch provided algorithm
+ if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
+ !parameterSpec.getKeyAlgorithmName().equals(algorithm))
{
- //TODO:
-// builder.withKdfAlgorithm(AlgorithmIdentifier.getInstance(algorithm));
+ throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm);
}
- KTSParameterSpec spec = builder.build();
+
+ // Only use KDF when ktsParameterSpec is provided
+ // Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
+ boolean wrapKey = !(parameterSpec.getKeyAlgorithmName().equals("Generic") && algorithm.equals("Generic"));
SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams());
byte[] encapsulation = secEnc.getEncapsulation();
byte[] secret = secEnc.getSecret();
- byte[] kdfKey = Arrays.copyOfRange(secret, from, to);
+ byte[] secretKey = Arrays.copyOfRange(secret, from, to);
- try
+ if (wrapKey)
{
- return new KEM.Encapsulated(new SecretKeySpec(makeKeyBytes(spec, kdfKey), algorithm), encapsulation , null);
- }
- catch (InvalidKeyException e)
- {
- throw new RuntimeException(e);
+ try
+ {
+ KTSParameterSpec spec = parameterSpec;
+ // Generate a new ktsParameterSpec if spec is generic but algorithm is not generic
+ if (parameterSpec.getKeyAlgorithmName().equals("Generic"))
+ {
+ spec = new KTSParameterSpec.Builder(algorithm, secretKey.length * 8).withNoKdf().build();
+ }
+
+ Wrapper kWrap = WrapUtil.getKeyWrapper(spec, secret);
+ secretKey = kWrap.wrap(secretKey, 0, secretKey.length);
+// secretKey = Arrays.concatenate(encapsulation, kWrap.wrap(secretKey, 0, secretKey.length));
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new RuntimeException(e);
+ }
}
+
+ return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, parameterSpec.getOtherInfo());
+
}
@Override
public int engineSecretSize()
{
- return publicKey.getKeyParams().getParameters().getSessionKeySize() / 8;
+ return parameterSpec.getKeySize() / 8;
}
@Override
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java
index 93038d9dd7..64be2c116e 100644
--- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeKEMSpi.java
@@ -1,18 +1,8 @@
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
-import org.bouncycastle.crypto.CryptoServicesRegistrar;
-import org.bouncycastle.crypto.SecretWithEncapsulation;
-import org.bouncycastle.crypto.Wrapper;
-import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
-import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMGenerator;
-import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
-import org.bouncycastle.util.Arrays;
-import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KEMSpi;
-import javax.security.auth.DestroyFailedException;
-import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.PrivateKey;
@@ -33,8 +23,8 @@ public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParam
}
if (spec == null)
{
- // TODO: default should probably use shake.
- spec = new KTSParameterSpec.Builder("AES-KWP", 256).build();
+ // Do not wrap key, no KDF
+ spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build();
}
if (!(spec instanceof KTSParameterSpec))
{
@@ -56,8 +46,8 @@ public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmPar
}
if (spec == null)
{
- // TODO: default should probably use shake.
- spec = new KTSParameterSpec.Builder("AES-KWP", 256).build();
+ // Do not unwrap key, no KDF
+ spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build();
}
if (!(spec instanceof KTSParameterSpec))
{
diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
index c9f79de58a..72aee54033 100644
--- a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
+++ b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
@@ -45,7 +45,7 @@ public void testKEM()
// Sender side
KEM kemS = KEM.getInstance("SNTRUPrime"); //Should the name be "SNTRUPrime-KEM" ?
- KTSParameterSpec ktsSpec = new KTSParameterSpec.Builder("Camellia", 256).build();
+ KTSParameterSpec ktsSpec = null;
KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsSpec, null);
KEM.Encapsulated enc = e.encapsulate();
SecretKey secS = enc.key();
@@ -65,96 +65,100 @@ public void testKEM()
assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
}
- public void testBasicKEMAES()
- throws Exception
- {
- if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null)
- {
- Security.addProvider(new BouncyCastlePQCProvider());
- }
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
- kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
-
- performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
- performKEM(kpg.generateKeyPair(),0, 16, "AES", new KEMParameterSpec("AES"));
- performKEM(kpg.generateKeyPair(),0, 16, "AES-KWP", new KEMParameterSpec("AES"));
- performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES-KWP"));
-
- kpg.initialize(SNTRUPrimeParameterSpec.sntrup1013, new SecureRandom());
- performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
- performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES-KWP"));
- }
-
- public void testBasicKEMCamellia()
- throws Exception
- {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
- kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
-
- performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia", 256).build());
- performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia-KWP", 256).build());
- }
-
- public void testBasicKEMSEED()
- throws Exception
- {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
- kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
-
- performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("SEED", 128).build());
- }
-
- public void testBasicKEMARIA()
- throws Exception
- {
- KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
- kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
-
- performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA"));
- performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA-KWP"));
- }
-
- private void performKEM(KeyPair kp, int from, int to, String algorithm, KTSParameterSpec ktsParameterSpec)
- throws Exception
- {
- PublicKey pkR = kp.getPublic();
-
- // Sender side
- KEM kemS = KEM.getInstance("SNTRUPrime");
- KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
- KEM.Encapsulated enc = e.encapsulate(from, to, algorithm);
- SecretKey secS = enc.key();
- byte[] em = enc.encapsulation();
-
- // Receiver side
- KEM kemR = KEM.getInstance("SNTRUPrime");
- KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
- SecretKey secR = d.decapsulate(em, from, to, algorithm);
-
- // secS and secR will be identical
- assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
- assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
- }
-
- private void performKEM(KeyPair kp, KTSParameterSpec ktsParameterSpec)
- throws Exception
- {
- PublicKey pkR = kp.getPublic();
-
- // Sender side
- KEM kemS = KEM.getInstance("SNTRUPrime");
- KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
- KEM.Encapsulated enc = e.encapsulate();
- SecretKey secS = enc.key();
- byte[] em = enc.encapsulation();
-
- // Receiver side
- KEM kemR = KEM.getInstance("SNTRUPrime");
- KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
- SecretKey secR = d.decapsulate(em);
-
- // secS and secR will be identical
- assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
- assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
- }
+// public void testBasicKEMAES()
+// throws Exception
+// {
+// if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null)
+// {
+// Security.addProvider(new BouncyCastlePQCProvider());
+// }
+// KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
+// kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
+//
+// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
+// performKEM(kpg.generateKeyPair(),0, 16, "AES", new KEMParameterSpec("AES"));
+// performKEM(kpg.generateKeyPair(),0, 16, "AES-KWP", new KEMParameterSpec("AES"));
+// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES-KWP"));
+//
+// kpg.initialize(SNTRUPrimeParameterSpec.sntrup1013, new SecureRandom());
+// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
+// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES-KWP"));
+// }
+//
+// public void testBasicKEMCamellia()
+// throws Exception
+// {
+// KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
+// kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
+//
+// performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia", 256).build());
+// performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia-KWP", 256).build());
+// }
+//
+// public void testBasicKEMSEED()
+// throws Exception
+// {
+// KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
+// kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
+//
+// performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("SEED", 128).build());
+// }
+//
+// public void testBasicKEMARIA()
+// throws Exception
+// {
+// KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
+// kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
+//
+// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA"));
+// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA-KWP"));
+// }
+//
+// private void performKEM(KeyPair kp, int from, int to, String algorithm, KTSParameterSpec ktsParameterSpec)
+// throws Exception
+// {
+// PublicKey pkR = kp.getPublic();
+//
+// // Sender side
+// KEM kemS = KEM.getInstance("SNTRUPrime");
+// KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
+// KEM.Encapsulated enc = e.encapsulate(from, to, algorithm);
+// SecretKey secS = enc.key();
+// byte[] em = enc.encapsulation();
+//
+// // Receiver side
+// KEM kemR = KEM.getInstance("SNTRUPrime");
+// KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
+// SecretKey secR = d.decapsulate(em, from, to, algorithm);
+//
+// // secS and secR will be identical
+// assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
+// assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
+// }
+//
+// private void performKEM(KeyPair kp, KTSParameterSpec ktsParameterSpec)
+// throws Exception
+// {
+// PublicKey pkR = kp.getPublic();
+//
+// // Sender side
+// KEM kemS = KEM.getInstance("SNTRUPrime");
+// KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
+// KEM.Encapsulated enc = e.encapsulate();
+// SecretKey secS = enc.key();
+// byte[] em = enc.encapsulation();
+//
+// // Receiver side
+// KEM kemR = KEM.getInstance("SNTRUPrime");
+//// KTSParameterSpec RktsParameterSpec = new KTSParameterSpec.Builder(
+//// ktsParameterSpec.getKeyAlgorithmName(),
+//// enc.key().getEncoded().length
+//// ).withParameterSpec(ktsParameterSpec).build();
+// KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
+// SecretKey secR = d.decapsulate(em);
+//
+// // secS and secR will be identical
+// assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
+// assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
+// }
}
From bd6e70c7cad0a35fdcba055de13ef2e36f6a151b Mon Sep 17 00:00:00 2001
From: royb
Date: Fri, 23 Feb 2024 18:46:05 -0500
Subject: [PATCH 0094/1846] Fixed SNTRUPrime KEMSpi for jdk21, added more tests
---
.../pqc/jcajce/provider/Util.java | 85 ++++++++
.../ntruprime/SNTRUPrimeDecapsulatorSpi.java | 27 +--
.../ntruprime/SNTRUPrimeEncapsulatorSpi.java | 22 +-
.../provider/test/SNTRUPrimeKEMTest.java | 206 +++++++++---------
4 files changed, 204 insertions(+), 136 deletions(-)
create mode 100644 prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/Util.java
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/Util.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/Util.java
new file mode 100644
index 0000000000..08f37ba137
--- /dev/null
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/Util.java
@@ -0,0 +1,85 @@
+package org.bouncycastle.pqc.jcajce.provider;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.Xof;
+import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.digests.SHAKEDigest;
+import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
+import org.bouncycastle.crypto.params.KDFParameters;
+import org.bouncycastle.jcajce.spec.KTSParameterSpec;
+
+import java.security.InvalidKeyException;
+
+public class Util
+{
+ public static byte[] makeKeyBytes(KTSParameterSpec ktsSpec, byte[] secret)
+ throws InvalidKeyException
+ {
+ AlgorithmIdentifier kdfAlgorithm = ktsSpec.getKdfAlgorithm();
+ byte[] otherInfo = ktsSpec.getOtherInfo();
+ byte[] keyBytes = new byte[(ktsSpec.getKeySize() + 7) / 8];
+
+ if (X9ObjectIdentifiers.id_kdf_kdf2.equals(kdfAlgorithm.getAlgorithm()))
+ {
+ AlgorithmIdentifier digAlg = AlgorithmIdentifier.getInstance(kdfAlgorithm.getParameters());
+ DerivationFunction kdf = new KDF2BytesGenerator(getDigest(digAlg.getAlgorithm()));
+
+ kdf.init(new KDFParameters(secret, otherInfo));
+
+ kdf.generateBytes(keyBytes, 0, keyBytes.length);
+ }
+ else if (X9ObjectIdentifiers.id_kdf_kdf3.equals(kdfAlgorithm.getAlgorithm()))
+ {
+ AlgorithmIdentifier digAlg = AlgorithmIdentifier.getInstance(kdfAlgorithm.getParameters());
+ DerivationFunction kdf = new ConcatenationKDFGenerator(getDigest(digAlg.getAlgorithm()));
+
+ kdf.init(new KDFParameters(secret, otherInfo));
+
+ kdf.generateBytes(keyBytes, 0, keyBytes.length);
+ }
+ else if (NISTObjectIdentifiers.id_shake256.equals(kdfAlgorithm.getAlgorithm()))
+ {
+ Xof xof = new SHAKEDigest(256);
+
+ xof.update(secret, 0, secret.length);
+ xof.update(otherInfo, 0, otherInfo.length);
+
+ xof.doFinal(keyBytes, 0, keyBytes.length);
+ }
+ else
+ {
+ throw new InvalidKeyException("Unrecognized KDF: " + kdfAlgorithm.getAlgorithm());
+ }
+
+ return keyBytes;
+ }
+
+ static Digest getDigest(ASN1ObjectIdentifier oid)
+ {
+ if (oid.equals(NISTObjectIdentifiers.id_sha256))
+ {
+ return new SHA256Digest();
+ }
+ if (oid.equals(NISTObjectIdentifiers.id_sha512))
+ {
+ return new SHA512Digest();
+ }
+ if (oid.equals(NISTObjectIdentifiers.id_shake128))
+ {
+ return new SHAKEDigest(128);
+ }
+ if (oid.equals(NISTObjectIdentifiers.id_shake256))
+ {
+ return new SHAKEDigest(256);
+ }
+
+ throw new IllegalArgumentException("unrecognized digest OID: " + oid);
+ }
+}
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java
index e7d090191f..4a7c7b3139 100644
--- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java
@@ -1,10 +1,8 @@
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
-import org.bouncycastle.crypto.InvalidCipherTextException;
-import org.bouncycastle.crypto.Wrapper;
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMExtractor;
-import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
+import org.bouncycastle.pqc.jcajce.provider.Util;
import org.bouncycastle.util.Arrays;
import javax.crypto.DecapsulateException;
@@ -58,36 +56,23 @@ public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, Strin
// Only use KDF when ktsParameterSpec is provided
// Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
- boolean wrapKey = !(parameterSpec.getKeyAlgorithmName().equals("Generic") && algorithm.equals("Generic"));
+ boolean useKDF = parameterSpec.getKdfAlgorithm() != null;
byte[] secret = kemExt.extractSecret(encapsulation);
- byte[] secretKey = Arrays.copyOfRange(secret, from, to);
- if (wrapKey)
+ if (useKDF)
{
try
{
- KTSParameterSpec spec = parameterSpec;
- // Generate a new ktsParameterSpec if spec is generic but algorithm is not generic
- if (parameterSpec.getKeyAlgorithmName().equals("Generic"))
- {
- spec = new KTSParameterSpec.Builder(algorithm, secretKey.length * 8).withNoKdf().build();
- }
-
- Wrapper kWrap = WrapUtil.getKeyUnwrapper(spec, secretKey);
- secretKey = kWrap.unwrap(secretKey, 0, secretKey.length);
-
- }
- catch (InvalidCipherTextException e)
- {
- throw new RuntimeException(e);
+ secret = Util.makeKeyBytes(parameterSpec, secret);
}
catch (InvalidKeyException e)
{
throw new RuntimeException(e);
}
-
}
+ byte[] secretKey = Arrays.copyOfRange(secret, from, to);
+
return new SecretKeySpec(secretKey, algorithm);
}
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java
index 3cd14d57dc..e5b7fceced 100644
--- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java
@@ -1,10 +1,9 @@
package org.bouncycastle.pqc.jcajce.provider.ntruprime;
import org.bouncycastle.crypto.SecretWithEncapsulation;
-import org.bouncycastle.crypto.Wrapper;
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
import org.bouncycastle.pqc.crypto.ntruprime.SNTRUPrimeKEMGenerator;
-import org.bouncycastle.pqc.jcajce.provider.util.WrapUtil;
+import org.bouncycastle.pqc.jcajce.provider.Util;
import org.bouncycastle.util.Arrays;
import javax.crypto.KEM;
@@ -52,29 +51,20 @@ public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm)
// Only use KDF when ktsParameterSpec is provided
// Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
- boolean wrapKey = !(parameterSpec.getKeyAlgorithmName().equals("Generic") && algorithm.equals("Generic"));
+ boolean useKDF = parameterSpec.getKdfAlgorithm() != null;
SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams());
byte[] encapsulation = secEnc.getEncapsulation();
byte[] secret = secEnc.getSecret();
- byte[] secretKey = Arrays.copyOfRange(secret, from, to);
+ byte[] secretKey;
- if (wrapKey)
+ if (useKDF)
{
try
{
- KTSParameterSpec spec = parameterSpec;
- // Generate a new ktsParameterSpec if spec is generic but algorithm is not generic
- if (parameterSpec.getKeyAlgorithmName().equals("Generic"))
- {
- spec = new KTSParameterSpec.Builder(algorithm, secretKey.length * 8).withNoKdf().build();
- }
-
- Wrapper kWrap = WrapUtil.getKeyWrapper(spec, secret);
- secretKey = kWrap.wrap(secretKey, 0, secretKey.length);
-// secretKey = Arrays.concatenate(encapsulation, kWrap.wrap(secretKey, 0, secretKey.length));
+ secret = Util.makeKeyBytes(parameterSpec, secret);
}
catch (InvalidKeyException e)
{
@@ -82,6 +72,8 @@ public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm)
}
}
+ secretKey = Arrays.copyOfRange(secret, from, to);
+
return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, parameterSpec.getOtherInfo());
}
diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
index 72aee54033..33ed7d8485 100644
--- a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
+++ b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
@@ -7,13 +7,9 @@
import java.security.Security;
import javax.crypto.KEM;
-import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import junit.framework.TestCase;
-import org.bouncycastle.jcajce.SecretKeyWithEncapsulation;
-import org.bouncycastle.jcajce.spec.KEMExtractSpec;
-import org.bouncycastle.jcajce.spec.KEMGenerateSpec;
import org.bouncycastle.jcajce.spec.KEMParameterSpec;
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
@@ -65,100 +61,110 @@ public void testKEM()
assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
}
-// public void testBasicKEMAES()
-// throws Exception
-// {
-// if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null)
-// {
-// Security.addProvider(new BouncyCastlePQCProvider());
-// }
-// KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
-// kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
-//
-// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
-// performKEM(kpg.generateKeyPair(),0, 16, "AES", new KEMParameterSpec("AES"));
-// performKEM(kpg.generateKeyPair(),0, 16, "AES-KWP", new KEMParameterSpec("AES"));
-// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES-KWP"));
-//
-// kpg.initialize(SNTRUPrimeParameterSpec.sntrup1013, new SecureRandom());
-// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
-// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES-KWP"));
-// }
-//
-// public void testBasicKEMCamellia()
-// throws Exception
-// {
-// KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
-// kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
-//
-// performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia", 256).build());
-// performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia-KWP", 256).build());
-// }
-//
-// public void testBasicKEMSEED()
-// throws Exception
-// {
-// KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
-// kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
-//
-// performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("SEED", 128).build());
-// }
-//
-// public void testBasicKEMARIA()
-// throws Exception
-// {
-// KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
-// kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
-//
-// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA"));
-// performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA-KWP"));
-// }
-//
-// private void performKEM(KeyPair kp, int from, int to, String algorithm, KTSParameterSpec ktsParameterSpec)
-// throws Exception
-// {
-// PublicKey pkR = kp.getPublic();
-//
-// // Sender side
-// KEM kemS = KEM.getInstance("SNTRUPrime");
-// KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
-// KEM.Encapsulated enc = e.encapsulate(from, to, algorithm);
-// SecretKey secS = enc.key();
-// byte[] em = enc.encapsulation();
-//
-// // Receiver side
-// KEM kemR = KEM.getInstance("SNTRUPrime");
-// KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
-// SecretKey secR = d.decapsulate(em, from, to, algorithm);
-//
-// // secS and secR will be identical
-// assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
-// assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
-// }
-//
-// private void performKEM(KeyPair kp, KTSParameterSpec ktsParameterSpec)
-// throws Exception
-// {
-// PublicKey pkR = kp.getPublic();
-//
-// // Sender side
-// KEM kemS = KEM.getInstance("SNTRUPrime");
-// KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
-// KEM.Encapsulated enc = e.encapsulate();
-// SecretKey secS = enc.key();
-// byte[] em = enc.encapsulation();
-//
-// // Receiver side
-// KEM kemR = KEM.getInstance("SNTRUPrime");
-//// KTSParameterSpec RktsParameterSpec = new KTSParameterSpec.Builder(
-//// ktsParameterSpec.getKeyAlgorithmName(),
-//// enc.key().getEncoded().length
-//// ).withParameterSpec(ktsParameterSpec).build();
-// KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
-// SecretKey secR = d.decapsulate(em);
-//
-// // secS and secR will be identical
-// assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
-// assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
-// }
+ public void testBasicKEMAES()
+ throws Exception
+ {
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null)
+ {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
+ kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
+
+ performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
+ performKEM(kpg.generateKeyPair(),0, 16, "AES", new KEMParameterSpec("AES"));
+ performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES-KWP"));
+
+ try
+ {
+ performKEM(kpg.generateKeyPair(),0, 16, "AES-KWP", new KEMParameterSpec("AES"));
+ fail();
+ }
+ catch (Exception ex)
+ {
+ }
+
+ kpg.initialize(SNTRUPrimeParameterSpec.sntrup1013, new SecureRandom());
+ performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
+
+
+
+ }
+
+ public void testBasicKEMCamellia()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
+ kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
+
+ performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia", 256).build());
+ performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia-KWP", 256).build());
+ }
+
+ public void testBasicKEMSEED()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
+ kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
+
+ performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("SEED", 128).build());
+ }
+
+ public void testBasicKEMARIA()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("SNTRUPrime", "BCPQC");
+ kpg.initialize(SNTRUPrimeParameterSpec.sntrup653, new SecureRandom());
+
+ performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA"));
+ performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA-KWP"));
+ }
+
+ private void performKEM(KeyPair kp, int from, int to, String algorithm, KTSParameterSpec ktsParameterSpec)
+ throws Exception
+ {
+ PublicKey pkR = kp.getPublic();
+
+ // Sender side
+ KEM kemS = KEM.getInstance("SNTRUPrime");
+ KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
+ KEM.Encapsulated enc = e.encapsulate(from, to, algorithm);
+ SecretKey secS = enc.key();
+ byte[] em = enc.encapsulation();
+
+ // Receiver side
+ KEM kemR = KEM.getInstance("SNTRUPrime");
+ KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
+ SecretKey secR = d.decapsulate(em, from, to, algorithm);
+
+ // secS and secR will be identical
+ assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
+ assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
+ }
+
+ private void performKEM(KeyPair kp, KTSParameterSpec ktsParameterSpec)
+ throws Exception
+ {
+ PublicKey pkR = kp.getPublic();
+
+ // Sender side
+ KEM kemS = KEM.getInstance("SNTRUPrime");
+ KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
+ KEM.Encapsulated enc = e.encapsulate();
+ SecretKey secS = enc.key();
+ byte[] em = enc.encapsulation();
+
+ // Receiver side
+ KEM kemR = KEM.getInstance("SNTRUPrime");
+// KTSParameterSpec RktsParameterSpec = new KTSParameterSpec.Builder(
+// ktsParameterSpec.getKeyAlgorithmName(),
+// enc.key().getEncoded().length
+// ).withParameterSpec(ktsParameterSpec).build();
+ KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
+ SecretKey secR = d.decapsulate(em);
+
+ // secS and secR will be identical
+ assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
+ assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
+ }
}
From 766374ed2f04c053137d00da018fa4637df5d8ba Mon Sep 17 00:00:00 2001
From: mwcw
Date: Mon, 26 Feb 2024 09:29:13 +1100
Subject: [PATCH 0095/1846] source and javadoc generation
---
mls/build.gradle | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/mls/build.gradle b/mls/build.gradle
index bb58c7ea5b..23a4136c5f 100644
--- a/mls/build.gradle
+++ b/mls/build.gradle
@@ -121,3 +121,22 @@ extractIncludeTestProto {
createStartScripts('org.bouncycastle.mls.client.impl.MLSClient')
+task sourcesJar(type: Jar) {
+ archiveBaseName = jar.archiveBaseName
+ archiveClassifier = 'sources'
+ from sourceSets.main.allSource
+ duplicatesStrategy = DuplicatesStrategy.INCLUDE
+}
+
+
+task javadocJar(type: Jar, dependsOn: javadoc) {
+ archiveBaseName = jar.archiveBaseName
+ archiveClassifier = 'javadoc'
+ from javadoc.destinationDir
+}
+
+artifacts {
+ archives jar
+ archives javadocJar
+ archives sourcesJar
+}
\ No newline at end of file
From 4f64b6eb42dc2c5efeb2e7c7288f33acbf024265 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Mon, 26 Feb 2024 09:31:06 +1030
Subject: [PATCH 0096/1846] Try to correct the encryption procedures of X25519
and X448 encryption.
---
.../openpgp/operator/PGPKeyConverter.java | 111 +++++++
...PublicKeyKeyEncryptionMethodGenerator.java | 10 +
.../openpgp/operator/RFC6637Utils.java | 49 +--
.../operator/bc/BcPGPKeyConverter.java | 114 ++-----
.../bc/BcPublicKeyDataDecryptorFactory.java | 74 +++--
...PublicKeyKeyEncryptionMethodGenerator.java | 147 +++++----
.../operator/jcajce/JcaPGPKeyConverter.java | 291 ++++++------------
...ePublicKeyDataDecryptorFactoryBuilder.java | 73 +++--
...PublicKeyKeyEncryptionMethodGenerator.java | 60 ++--
.../openpgp/test/BcpgGeneralTest.java | 12 +-
.../openpgp/test/OperatorBcTest.java | 38 ++-
11 files changed, 504 insertions(+), 475 deletions(-)
create mode 100644 pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java
new file mode 100644
index 0000000000..73943631a6
--- /dev/null
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java
@@ -0,0 +1,111 @@
+package org.bouncycastle.openpgp.operator;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
+import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.openpgp.PGPAlgorithmParameters;
+import org.bouncycastle.openpgp.PGPKdfParameters;
+import org.bouncycastle.util.BigIntegers;
+
+public abstract class PGPKeyConverter
+{
+ /**
+ * Reference: RFC Draft-ietf-openpgp-crypto-refresh-13
+ *
+ * This class provides information about the recommended algorithms to use
+ * depending on the key version and curve type in OpenPGP keys.
+ *
+ *
+ * For OpenPGP keys using the specified curves, the following algorithms are recommended:
+ *
+ * Recommended Algorithms for OpenPGP Keys
+ *
+ * | Curve |
+ * Hash Algorithm |
+ * Symmetric Algorithm |
+ *
+ *
+ * | NIST P-256 |
+ * SHA2-256 |
+ * AES-128 |
+ *
+ *
+ * | NIST P-384 |
+ * SHA2-384 |
+ * AES-192 |
+ *
+ *
+ * | NIST P-521 |
+ * SHA2-512 |
+ * AES-256 |
+ *
+ *
+ * | brainpoolP256r1 |
+ * SHA2-256 |
+ * AES-128 |
+ *
+ *
+ * | brainpoolP384r1 |
+ * SHA2-384 |
+ * AES-192 |
+ *
+ *
+ * | brainpoolP512r1 |
+ * SHA2-512 |
+ * AES-256 |
+ *
+ *
+ * | Curve25519Legacy |
+ * SHA2-256 |
+ * AES-128 |
+ *
+ *
+ */
+ protected PGPKdfParameters implGetKdfParameters(ASN1ObjectIdentifier curveID, PGPAlgorithmParameters algorithmParameters)
+ {
+ if (null == algorithmParameters)
+ {
+ if (curveID.equals(SECObjectIdentifiers.secp256r1) || curveID.equals(TeleTrusTObjectIdentifiers.brainpoolP256r1)
+ || curveID.equals(CryptlibObjectIdentifiers.curvey25519) || curveID.equals(EdECObjectIdentifiers.id_X25519))
+ {
+ return new PGPKdfParameters(HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ }
+ else if (curveID.equals(SECObjectIdentifiers.secp384r1) || curveID.equals(TeleTrusTObjectIdentifiers.brainpoolP384r1))
+ {
+ return new PGPKdfParameters(HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_192);
+ }
+ else if (curveID.equals(SECObjectIdentifiers.secp521r1) || curveID.equals(TeleTrusTObjectIdentifiers.brainpoolP512r1))
+ {
+ return new PGPKdfParameters(HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+ }
+ else
+ {
+ throw new IllegalArgumentException("unknown curve");
+ }
+ }
+ return (PGPKdfParameters)algorithmParameters;
+ }
+
+ protected PrivateKeyInfo getPrivateKeyInfo(ASN1ObjectIdentifier algorithm, int keySize, byte[] key)
+ throws IOException
+ {
+ return (new PrivateKeyInfo(new AlgorithmIdentifier(algorithm),
+ new DEROctetString(BigIntegers.asUnsignedByteArray(keySize, new BigInteger(1, key)))));
+ }
+
+ protected PrivateKeyInfo getPrivateKeyInfo(ASN1ObjectIdentifier algorithm, byte[] key)
+ throws IOException
+ {
+ return (new PrivateKeyInfo(new AlgorithmIdentifier(algorithm), new DEROctetString(key)));
+ }
+}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
index 90843616d8..aeab14ed6b 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
@@ -49,6 +49,7 @@ protected PublicKeyKeyEncryptionMethodGenerator(
throw new IllegalArgumentException("Can't use ECDSA for encryption.");
case PublicKeyAlgorithmTags.Ed448:
case PublicKeyAlgorithmTags.Ed25519:
+ case PublicKeyAlgorithmTags.EDDSA_LEGACY:
throw new IllegalArgumentException("Can't use EdDSA for encryption.");
default:
throw new IllegalArgumentException("unknown asymmetric algorithm: " + pubKey.getAlgorithm());
@@ -184,4 +185,13 @@ protected static byte[] getSessionInfo(byte[] ephPubEncoding, byte[] c)
System.arraycopy(c, 0, rv, VB.length + 1, c.length);
return rv;
}
+
+ protected static byte[] getSessionInfo_25519or448(byte[] VB, byte[] c)
+ {
+ byte[] rv = new byte[VB.length + 1 + c.length];
+ System.arraycopy(VB, 0, rv, 0, VB.length);
+ rv[VB.length] = (byte)c.length;
+ System.arraycopy(c, 0, rv, VB.length + 1, c.length);
+ return rv;
+ }
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
index a769b8d488..41a4665d56 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
@@ -4,9 +4,11 @@
import java.io.IOException;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
+import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
@@ -103,28 +105,31 @@ public static byte[] createUserKeyingMaterial(PublicKeyPacket pubKeyData, KeyFin
throws IOException, PGPException
{
ByteArrayOutputStream pOut = new ByteArrayOutputStream();
- ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
- byte[] encOid = ecKey.getCurveOID().getEncoded();
-
- pOut.write(encOid, 1, encOid.length - 1);
- pOut.write(pubKeyData.getAlgorithm());
- pOut.write(0x03);
- pOut.write(0x01);
- pOut.write(ecKey.getHashAlgorithm());
- pOut.write(ecKey.getSymmetricKeyAlgorithm());
- pOut.write(ANONYMOUS_SENDER);
- pOut.write(fingerPrintCalculator.calculateFingerprint(pubKeyData));
-
- return pOut.toByteArray();
- }
-
- public static byte[] createUserKeyingMaterial(PublicKeyPacket pubKeyData, KeyFingerPrintCalculator fingerPrintCalculator,
- ASN1ObjectIdentifier cuiveOID, int hashAlgorithm, int symmetricKeyAlgorithm)
- throws IOException, PGPException
- {
- ByteArrayOutputStream pOut = new ByteArrayOutputStream();
- byte[] encOid = cuiveOID.getEncoded();
-
+ BCPGKey key = pubKeyData.getKey();
+ ASN1ObjectIdentifier curveID;
+ int hashAlgorithm, symmetricKeyAlgorithm;
+ if (key instanceof X25519PublicBCPGKey)
+ {
+ curveID = CryptlibObjectIdentifiers.curvey25519;
+ symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128;
+ hashAlgorithm = HashAlgorithmTags.SHA256;
+ }
+ else if (key instanceof X448PublicBCPGKey)
+ {
+ curveID = EdECObjectIdentifiers.id_X448;
+ symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_256;
+ hashAlgorithm = HashAlgorithmTags.SHA512;
+// pOut.write(key.getEncoded());
+// pOut.write(EdECObjectIdentifiers.id_X448.getEncoded());
+ }
+ else
+ {
+ ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
+ curveID = ecKey.getCurveOID();
+ hashAlgorithm = ecKey.getHashAlgorithm();
+ symmetricKeyAlgorithm = ecKey.getSymmetricKeyAlgorithm();
+ }
+ byte[] encOid = curveID.getEncoded();
pOut.write(encOid, 1, encOid.length - 1);
pOut.write(pubKeyData.getAlgorithm());
pOut.write(0x03);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
index 3b3af70579..197b3bbb97 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
@@ -5,11 +5,9 @@
import java.util.Date;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ECParameters;
@@ -28,12 +26,10 @@
import org.bouncycastle.bcpg.EdSecretBCPGKey;
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
-import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.bcpg.RSASecretBCPGKey;
-import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.X25519PublicBCPGKey;
import org.bouncycastle.bcpg.X25519SecretBCPGKey;
import org.bouncycastle.bcpg.X448PublicBCPGKey;
@@ -68,15 +64,13 @@
import org.bouncycastle.openpgp.PGPKdfParameters;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.operator.PGPKeyConverter;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
public class BcPGPKeyConverter
+ extends PGPKeyConverter
{
- // We default to these as they are specified as mandatory in RFC 6631.
- private static final PGPKdfParameters DEFAULT_KDF_PARAMETERS = new PGPKdfParameters(HashAlgorithmTags.SHA256,
- SymmetricKeyAlgorithmTags.AES_128);
-
public PGPPrivateKey getPGPPrivateKey(PGPPublicKey pubKey, AsymmetricKeyParameter privKey)
throws PGPException
{
@@ -129,7 +123,8 @@ public AsymmetricKeyParameter getPrivateKey(PGPPrivateKey privKey)
if (CryptlibObjectIdentifiers.curvey25519.equals(ecdhPub.getCurveOID()))
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_X25519, privPk);
+ return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519,
+ Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX()))));
}
else
{
@@ -138,19 +133,16 @@ public AsymmetricKeyParameter getPrivateKey(PGPPrivateKey privKey)
}
case PublicKeyAlgorithmTags.X25519:
{
- return PrivateKeyFactory.createKey((new PrivateKeyInfo(
- new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519),
- new DEROctetString(Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(new BigInteger(privPk.getEncoded())))))));
+ return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519, X25519SecretBCPGKey.LENGTH,
+ Arrays.reverseInPlace(privPk.getEncoded())));
}
case PublicKeyAlgorithmTags.X448:
{
- return PrivateKeyFactory.createKey((new PrivateKeyInfo(
- new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448),
- new DEROctetString(Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(new BigInteger(privPk.getEncoded())))))));
+ return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_X448, X448SecretBCPGKey.LENGTH,
+ Arrays.reverseInPlace(privPk.getEncoded())));
}
case PublicKeyAlgorithmTags.ECDSA:
return implGetPrivateKeyEC((ECDSAPublicBCPGKey)pubPk.getKey(), (ECSecretBCPGKey)privPk);
-
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
if (((EdDSAPublicBCPGKey)pubPk.getKey()).getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
@@ -161,17 +153,12 @@ public AsymmetricKeyParameter getPrivateKey(PGPPrivateKey privKey)
}
case PublicKeyAlgorithmTags.Ed25519:
{
- return PrivateKeyFactory.createKey((new PrivateKeyInfo(
- new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519),
- new DEROctetString(BigIntegers.asUnsignedByteArray(Ed25519.SECRET_KEY_SIZE, new BigInteger(1, privPk.getEncoded()))))));
+ return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519, Ed25519SecretBCPGKey.LENGTH, privPk.getEncoded()));
}
case PublicKeyAlgorithmTags.Ed448:
{
- return PrivateKeyFactory.createKey((new PrivateKeyInfo(
- new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448),
- new DEROctetString(BigIntegers.asUnsignedByteArray(Ed448.SECRET_KEY_SIZE, new BigInteger(1, privPk.getEncoded()))))));
+ return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed448, Ed448SecretBCPGKey.LENGTH, privPk.getEncoded()));
}
-
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
{
@@ -179,7 +166,6 @@ public AsymmetricKeyParameter getPrivateKey(PGPPrivateKey privKey)
ElGamalSecretBCPGKey elPriv = (ElGamalSecretBCPGKey)privPk;
return new ElGamalPrivateKeyParameters(elPriv.getX(), new ElGamalParameters(elPub.getP(), elPub.getG()));
}
-
case PublicKeyAlgorithmTags.RSA_ENCRYPT:
case PublicKeyAlgorithmTags.RSA_GENERAL:
case PublicKeyAlgorithmTags.RSA_SIGN:
@@ -190,7 +176,6 @@ public AsymmetricKeyParameter getPrivateKey(PGPPrivateKey privKey)
rsaPriv.getPrivateExponent(), rsaPriv.getPrimeP(), rsaPriv.getPrimeQ(), rsaPriv.getPrimeExponentP(),
rsaPriv.getPrimeExponentQ(), rsaPriv.getCrtCoefficient());
}
-
default:
throw new PGPException("unknown public key algorithm encountered");
}
@@ -219,14 +204,19 @@ public AsymmetricKeyParameter getPublicKey(PGPPublicKey publicKey)
DSAPublicBCPGKey dsaK = (DSAPublicBCPGKey)publicPk.getKey();
return new DSAPublicKeyParameters(dsaK.getY(), new DSAParameters(dsaK.getP(), dsaK.getQ(), dsaK.getG()));
}
-
case PublicKeyAlgorithmTags.ECDH:
{
ECDHPublicBCPGKey ecdhK = (ECDHPublicBCPGKey)publicPk.getKey();
if (ecdhK.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
- return getX25519PublicKey(ecdhK);
+ byte[] pEnc = BigIntegers.asUnsignedByteArray(ecdhK.getEncodedPoint());
+ // skip the 0x40 header byte.
+ if (pEnc.length < 1 || 0x40 != pEnc[0])
+ {
+ throw new IllegalArgumentException("Invalid Curve25519 public key");
+ }
+ return implGetPublicKeyX509(EdECObjectIdentifiers.id_X25519, pEnc, 1);
}
else
{
@@ -309,31 +299,6 @@ else if (eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
}
}
- private byte[] get25519EncodedPoint(BigInteger x, String title)
- {
- byte[] pEnc = BigIntegers.asUnsignedByteArray(x);
- // skip the 0x40 header byte.
- if (pEnc.length < 1 || 0x40 != pEnc[0])
- {
- throw new IllegalArgumentException("Invalid " + title + "25519 public key");
- }
- return pEnc;
- }
-
- private AsymmetricKeyParameter getX25519PublicKey(ECDHPublicBCPGKey ecdhK)
- throws IOException
- {
- byte[] pEnc = get25519EncodedPoint(ecdhK.getEncodedPoint(), "Curve");
- return implGetPublicKeyX509(EdECObjectIdentifiers.id_X25519, pEnc, 1);
- }
-
- private AsymmetricKeyParameter implGetPublicKeyX509(ASN1ObjectIdentifier algorithm, byte[] pEnc, int pEncOff)
- throws IOException
- {
- return PublicKeyFactory.createKey(new SubjectPublicKeyInfo(new AlgorithmIdentifier(algorithm),
- Arrays.copyOfRange(pEnc, pEncOff, pEnc.length)));
- }
-
private BCPGKey getPrivateBCPGKey(PGPPublicKey pubKey, AsymmetricKeyParameter privKey)
throws PGPException
{
@@ -348,7 +313,7 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pubKey, AsymmetricKeyParameter pr
{
if (privKey instanceof X25519PrivateKeyParameters)
{
- return getECSecretBCPGKey(((X25519PrivateKeyParameters)privKey).getEncoded());
+ return new ECSecretBCPGKey(new BigInteger(1, Arrays.reverseInPlace(((X25519PrivateKeyParameters)privKey).getEncoded())));
}
else
{
@@ -369,10 +334,9 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pubKey, AsymmetricKeyParameter pr
ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey;
return new ECSecretBCPGKey(ecK.getD());
}
-
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
- return getEdSecretBCPGKey(((Ed25519PrivateKeyParameters)privKey).getEncoded());
+ return new EdSecretBCPGKey(new BigInteger(1, ((Ed25519PrivateKeyParameters)privKey).getEncoded()));
}
case PublicKeyAlgorithmTags.Ed25519:
{
@@ -402,19 +366,7 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pubKey, AsymmetricKeyParameter pr
}
}
- private BCPGKey getEdSecretBCPGKey(byte[] x)
- {
- return new EdSecretBCPGKey(new BigInteger(1, x));
- }
-
- private BCPGKey getECSecretBCPGKey(byte[] x)
- {
- // 'reverse' because the native format for X25519/X448 private keys is little-endian
- return new ECSecretBCPGKey(new BigInteger(1, Arrays.reverseInPlace(x)));
- }
-
- private BCPGKey getPublicBCPGKey(int algorithm, PGPAlgorithmParameters algorithmParameters,
- AsymmetricKeyParameter pubKey)
+ private BCPGKey getPublicBCPGKey(int algorithm, PGPAlgorithmParameters algorithmParameters, AsymmetricKeyParameter pubKey)
throws PGPException
{
if (pubKey instanceof RSAKeyParameters)
@@ -443,7 +395,7 @@ else if (pubKey instanceof ECPublicKeyParameters)
if (algorithm == PGPPublicKey.ECDH)
{
- PGPKdfParameters kdfParams = implGetKdfParameters(algorithmParameters);
+ PGPKdfParameters kdfParams = implGetKdfParameters(parameters.getName(), algorithmParameters);
return new ECDHPublicBCPGKey(parameters.getName(), ecK.getQ(), kdfParams.getHashAlgorithm(),
kdfParams.getSymmetricWrapAlgorithm());
@@ -488,7 +440,7 @@ else if (pubKey instanceof X25519PublicKeyParameters)
pointEnc[0] = 0x40;
((X25519PublicKeyParameters)pubKey).encode(pointEnc, 1);
- PGPKdfParameters kdfParams = implGetKdfParameters(algorithmParameters);
+ PGPKdfParameters kdfParams = implGetKdfParameters(CryptlibObjectIdentifiers.curvey25519, algorithmParameters);
return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, pointEnc),
kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm());
@@ -505,9 +457,11 @@ else if (pubKey instanceof X448PublicKeyParameters)
}
}
- private PGPKdfParameters implGetKdfParameters(PGPAlgorithmParameters algorithmParameters)
+ private AsymmetricKeyParameter implGetPublicKeyX509(ASN1ObjectIdentifier algorithm, byte[] pEnc, int pEncOff)
+ throws IOException
{
- return null == algorithmParameters ? DEFAULT_KDF_PARAMETERS : (PGPKdfParameters)algorithmParameters;
+ return PublicKeyFactory.createKey(new SubjectPublicKeyInfo(new AlgorithmIdentifier(algorithm),
+ Arrays.copyOfRange(pEnc, pEncOff, pEnc.length)));
}
private ECNamedDomainParameters implGetParametersEC(ECPublicBCPGKey ecPub)
@@ -518,30 +472,20 @@ private ECNamedDomainParameters implGetParametersEC(ECPublicBCPGKey ecPub)
}
private AsymmetricKeyParameter implGetPrivateKeyEC(ECPublicBCPGKey ecPub, ECSecretBCPGKey ecPriv)
- throws IOException, PGPException
+ throws PGPException
{
ECNamedDomainParameters parameters = implGetParametersEC(ecPub);
return new ECPrivateKeyParameters(ecPriv.getX(), parameters);
}
- private AsymmetricKeyParameter implGetPrivateKeyPKCS8(ASN1ObjectIdentifier algorithm, BCPGKey privPk)
- throws IOException
- {
- return PrivateKeyFactory.createKey((new PrivateKeyInfo(
- new AlgorithmIdentifier(algorithm),
- new DEROctetString(Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX()))))));
- }
-
private AsymmetricKeyParameter implGetPrivateKeyPKCS8(ASN1ObjectIdentifier algorithm, int keySize, BCPGKey privPk)
throws IOException
{
- return PrivateKeyFactory.createKey((new PrivateKeyInfo(
- new AlgorithmIdentifier(algorithm),
- new DEROctetString(BigIntegers.asUnsignedByteArray(keySize, ((EdSecretBCPGKey)privPk).getX())))));
+ return PrivateKeyFactory.createKey(getPrivateKeyInfo(algorithm, BigIntegers.asUnsignedByteArray(keySize, ((EdSecretBCPGKey)privPk).getX())));
}
private AsymmetricKeyParameter implGetPublicKeyEC(ECPublicBCPGKey ecPub)
- throws IOException, PGPException
+ throws PGPException
{
ECNamedDomainParameters parameters = implGetParametersEC(ecPub);
ECPoint pubPoint = BcUtil.decodePoint(ecPub.getEncodedPoint(), parameters.getCurve());
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index e327cfcc7f..1c0e408236 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -5,7 +5,6 @@
import java.util.Arrays;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.bcpg.AEADEncDataPacket;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
import org.bouncycastle.bcpg.HashAlgorithmTags;
@@ -13,7 +12,7 @@
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.X25519PublicBCPGKey;
-import org.bouncycastle.bcpg.X25519SecretBCPGKey;
+import org.bouncycastle.bcpg.X448PublicBCPGKey;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedAsymmetricBlockCipher;
@@ -113,26 +112,55 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
}
else
{
-
byte[] enc = secKeyData[0];
-
- int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
- if ((2 + pLen + 1) > enc.length)
+ byte[] pEnc;
+ byte[] keyEnc;
+ if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
{
- throw new PGPException("encoded length out of range");
- }
+ int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
+ if ((2 + pLen + 1) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
- byte[] pEnc = new byte[pLen];
- System.arraycopy(enc, 2, pEnc, 0, pLen);
+ pEnc = new byte[pLen];
+ System.arraycopy(enc, 2, pEnc, 0, pLen);
- int keyLen = enc[pLen + 2] & 0xff;
- if ((2 + pLen + 1 + keyLen) > enc.length)
+ int keyLen = enc[pLen + 2] & 0xff;
+ if ((2 + pLen + 1 + keyLen) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
+
+ keyEnc = new byte[keyLen];
+ System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);
+ }
+ else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
- throw new PGPException("encoded length out of range");
+ int pLen = X25519PublicBCPGKey.LENGTH;
+ pEnc = new byte[pLen];
+ System.arraycopy(enc, 0, pEnc, 0, pLen);
+ int keyLen = enc[pLen] & 0xff;
+ if ((pLen + 1 + keyLen) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
+ keyEnc = new byte[keyLen];
+ System.arraycopy(enc, pLen + 1, keyEnc, 0, keyLen);
+ }
+ else
+ {
+ int pLen = X448PublicBCPGKey.LENGTH;
+ pEnc = new byte[pLen];
+ System.arraycopy(enc, 0, pEnc, 0, pLen);
+ int keyLen = enc[pLen] & 0xff;
+ if ((pLen + 1 + keyLen) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
+ keyEnc = new byte[keyLen];
+ System.arraycopy(enc, pLen + 1, keyEnc, 0, keyLen);
}
-
- byte[] keyEnc = new byte[keyLen];
- System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);
byte[] secret;
RFC6637KDFCalculator rfc6637KDFCalculator;
@@ -159,19 +187,14 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
BigInteger S = agreement.calculateAgreement(ephPub);
secret = BigIntegers.asUnsignedByteArray(agreement.getFieldSize(), S);
}
-
- userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(),
- new BcKeyFingerprintCalculator());
- symmetricKeyAlgorithm = ecPubKey.getSymmetricKeyAlgorithm();
hashAlgorithm = ecPubKey.getHashAlgorithm();
+ symmetricKeyAlgorithm = ecPubKey.getSymmetricKeyAlgorithm();
}
else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
secret = getSecret(new X25519Agreement(), pEnc.length != X25519PublicKeyParameters.KEY_SIZE, privKey, new X25519PublicKeyParameters(pEnc, 0), "25519");
symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128;
hashAlgorithm = HashAlgorithmTags.SHA256;
- userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(),
- new BcKeyFingerprintCalculator(), CryptlibObjectIdentifiers.curvey25519, hashAlgorithm, symmetricKeyAlgorithm);
}
else
{
@@ -179,17 +202,14 @@ else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
secret = getSecret(new X448Agreement(), pEnc.length != X448PublicKeyParameters.KEY_SIZE, privKey, new X448PublicKeyParameters(pEnc, 0), "448");
symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_256;
hashAlgorithm = HashAlgorithmTags.SHA512;
- userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(),
- new BcKeyFingerprintCalculator(), EdECObjectIdentifiers.id_X448, hashAlgorithm, symmetricKeyAlgorithm);
}
- rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm),
- symmetricKeyAlgorithm);
+ userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(), new BcKeyFingerprintCalculator());
+ rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
c.init(false, key);
return PGPPad.unpadSessionData(c.unwrap(keyEnc, 0, keyEnc.length));
-
}
}
catch (IOException e)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index 48c4b711b9..b9ffab36fb 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -5,16 +5,16 @@
import java.security.SecureRandom;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
-import org.bouncycastle.bcpg.Ed25519PublicBCPGKey;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.RawAgreement;
import org.bouncycastle.crypto.Wrapper;
import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
import org.bouncycastle.crypto.agreement.X25519Agreement;
@@ -79,35 +79,27 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
try
{
AsymmetricKeyParameter cryptoPublicKey = keyConverter.getPublicKey(pubKey);
+ PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.ECDH)
{
- PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
ECDHPublicBCPGKey ecPubKey = (ECDHPublicBCPGKey)pubKeyPacket.getKey();
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
- new BcKeyFingerprintCalculator());
-
if (ecPubKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
- X25519KeyPairGenerator gen = new X25519KeyPairGenerator();
- gen.init(new X25519KeyGenerationParameters(random));
-
- AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
-
- X25519Agreement agreement = new X25519Agreement();
- agreement.init(ephKp.getPrivate());
-
- byte[] secret = new byte[agreement.getAgreementSize()];
- agreement.calculateAgreement(cryptoPublicKey, secret, 0);
-
- byte[] ephPubEncoding = new byte[1 + X25519PublicKeyParameters.KEY_SIZE];
- ephPubEncoding[0] = X_HDR;
- ((X25519PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 1);
-
- return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm());
+ return encryptSessionInfo(sessionInfo, pubKeyPacket, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm(),
+ new X25519KeyPairGenerator(), new X25519Agreement(), cryptoPublicKey,
+ (gen) -> gen.init(new X25519KeyGenerationParameters(random)),
+ (publicKey) ->
+ {
+ byte[] ephPubEncoding = new byte[1 + X25519PublicKeyParameters.KEY_SIZE];
+ ephPubEncoding[0] = X_HDR;
+ ((X25519PublicKeyParameters)publicKey).encode(ephPubEncoding, 1);
+ return ephPubEncoding;
+ });
}
else
{
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator());
ECDomainParameters ecParams = ((ECPublicKeyParameters)cryptoPublicKey).getParameters();
ECKeyPairGenerator gen = new ECKeyPairGenerator();
@@ -127,48 +119,27 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
{
- PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
-
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator(),
- CryptlibObjectIdentifiers.curvey25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
-
- X25519KeyPairGenerator gen = new X25519KeyPairGenerator();
- gen.init(new X25519KeyGenerationParameters(random));
-
- AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
-
- X25519Agreement agreement = new X25519Agreement();
- agreement.init(ephKp.getPrivate());
-
- byte[] secret = new byte[agreement.getAgreementSize()];
- agreement.calculateAgreement(cryptoPublicKey, secret, 0);
-
- byte[] ephPubEncoding = new byte[ X25519PublicKeyParameters.KEY_SIZE];
- ((X25519PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 0);
-
- return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ return encryptSessionInfo_25519_448(sessionInfo, pubKeyPacket, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128,
+ new X25519KeyPairGenerator(), new X25519Agreement(), cryptoPublicKey,
+ (gen) -> gen.init(new X25519KeyGenerationParameters(random)),
+ (publicKey) ->
+ {
+ byte[] ephPubEncoding = new byte[X25519PublicKeyParameters.KEY_SIZE];
+ ((X25519PublicKeyParameters)publicKey).encode(ephPubEncoding, 0);
+ return ephPubEncoding;
+ });
}
- else if ( pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
+ else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
{
- PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator(),
- EdECObjectIdentifiers.id_X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
- X448KeyPairGenerator gen = new X448KeyPairGenerator();
- gen.init(new X448KeyGenerationParameters(random));
-
- AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
-
- X448Agreement agreement = new X448Agreement();
- agreement.init(ephKp.getPrivate());
-
- byte[] secret = new byte[agreement.getAgreementSize()];
- agreement.calculateAgreement(cryptoPublicKey, secret, 0);
-
- byte[] ephPubEncoding = new byte[X448PublicKeyParameters.KEY_SIZE];
-
- ((X448PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 0);
-
- return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+ return encryptSessionInfo_25519_448(sessionInfo, pubKeyPacket, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256,
+ new X448KeyPairGenerator(), new X448Agreement(), cryptoPublicKey,
+ (gen) -> gen.init(new X448KeyGenerationParameters(random)),
+ (publicKey) ->
+ {
+ byte[] ephPubEncoding = new byte[X448PublicKeyParameters.KEY_SIZE];
+ ((X448PublicKeyParameters)publicKey).encode(ephPubEncoding, 0);
+ return ephPubEncoding;
+ });
}
else
{
@@ -189,6 +160,58 @@ else if ( pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
}
}
+ @FunctionalInterface
+ private interface KeyPairGeneratorOperation
+ {
+ void initialize(AsymmetricCipherKeyPairGenerator gen);
+ }
+
+ @FunctionalInterface
+ private interface ephPubEncodingOperation
+ {
+ byte[] getEphPubEncoding(AsymmetricKeyParameter publicKey);
+ }
+
+ private byte[] encryptSessionInfo(byte[] sessionInfo, PublicKeyPacket pubKeyPacket, int hashAlgorithm, int symmetricKeyAlgorithm,
+ AsymmetricCipherKeyPairGenerator gen, RawAgreement agreement, AsymmetricKeyParameter cryptoPublicKey,
+ KeyPairGeneratorOperation kpg, ephPubEncodingOperation ephPubEncodingOperation)
+ throws PGPException, IOException
+ {
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator());
+ kpg.initialize(gen);
+ AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
+ agreement.init(ephKp.getPrivate());
+ byte[] secret = new byte[agreement.getAgreementSize()];
+ agreement.calculateAgreement(cryptoPublicKey, secret, 0);
+ byte[] ephPubEncoding = ephPubEncodingOperation.getEphPubEncoding(ephKp.getPublic());
+ return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, hashAlgorithm, symmetricKeyAlgorithm);
+ }
+
+ private byte[] encryptSessionInfo_25519_448(byte[] sessionInfo, PublicKeyPacket pubKeyPacket, int hashAlgorithm, int symmetricKeyAlgorithm,
+ AsymmetricCipherKeyPairGenerator gen, RawAgreement agreement, AsymmetricKeyParameter cryptoPublicKey,
+ KeyPairGeneratorOperation kpg, ephPubEncodingOperation ephPubEncodingOperation)
+ throws PGPException, IOException
+ {
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator());
+ kpg.initialize(gen);
+ AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
+ agreement.init(ephKp.getPrivate());
+ byte[] secret = new byte[agreement.getAgreementSize()];
+ agreement.calculateAgreement(cryptoPublicKey, secret, 0);
+ byte[] ephPubEncoding = ephPubEncodingOperation.getEphPubEncoding(ephKp.getPublic());
+ RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(
+ new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
+ KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
+
+ byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
+
+ Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
+ c.init(true, new ParametersWithRandom(key, random));
+ byte[] C = c.wrap(paddedSessionData, 0, paddedSessionData.length);
+
+ return getSessionInfo_25519or448(ephPubEncoding, C);
+ }
+
private byte[] encryptSessionInfo(byte[] sessionInfo, byte[] secret,
byte[] userKeyingMaterial, byte[] ephPubEncoding, int hashAlgorithm, int symmetricKeyAlgorithm)
throws IOException, PGPException
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
index bbebe6ea54..0e789636a3 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
@@ -65,12 +65,10 @@
import org.bouncycastle.bcpg.EdSecretBCPGKey;
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
-import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
import org.bouncycastle.bcpg.RSASecretBCPGKey;
-import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.X25519PublicBCPGKey;
import org.bouncycastle.bcpg.X25519SecretBCPGKey;
import org.bouncycastle.bcpg.X448PublicBCPGKey;
@@ -79,25 +77,22 @@
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
import org.bouncycastle.math.ec.ECPoint;
+
import org.bouncycastle.math.ec.rfc7748.X25519;
-import org.bouncycastle.math.ec.rfc7748.X448;
import org.bouncycastle.math.ec.rfc8032.Ed25519;
-import org.bouncycastle.math.ec.rfc8032.Ed448;
import org.bouncycastle.openpgp.PGPAlgorithmParameters;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKdfParameters;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
+import org.bouncycastle.openpgp.operator.PGPKeyConverter;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
public class JcaPGPKeyConverter
+ extends PGPKeyConverter
{
- // We default to these as they are specified as mandatory in RFC 6631.
- private static final PGPKdfParameters DEFAULT_KDF_PARAMETERS = new PGPKdfParameters(HashAlgorithmTags.SHA256,
- SymmetricKeyAlgorithmTags.AES_128);
-
private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
private KeyFingerPrintCalculator fingerPrintCalculator = new JcaKeyFingerprintCalculator();
@@ -201,7 +196,9 @@ public PrivateKey getPrivateKey(PGPPrivateKey privKey)
if (CryptlibObjectIdentifiers.curvey25519.equals(ecdhPub.getCurveOID()))
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_X25519, privPk);
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return implGeneratePrivate("XDH", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519,
+ Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX()))));
}
else
{
@@ -210,38 +207,31 @@ public PrivateKey getPrivateKey(PGPPrivateKey privKey)
}
case PublicKeyAlgorithmTags.X25519:
{
- PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(
- new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519),
- new DEROctetString(Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(new BigInteger(1, privPk.getEncoded()))))).getEncoded());
- return implGeneratePrivate("XDH", pkcs8Spec);
+ return implGeneratePrivate("XDH", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519,
+ X25519SecretBCPGKey.LENGTH, Arrays.reverseInPlace(privPk.getEncoded())));
}
case PublicKeyAlgorithmTags.X448:
{
- PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(
- new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448),
- new DEROctetString(Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(new BigInteger(1, privPk.getEncoded()))))).getEncoded());
- return implGeneratePrivate("XDH", pkcs8Spec);
+ return implGeneratePrivate("XDH", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_X448,
+ X448SecretBCPGKey.LENGTH, Arrays.reverseInPlace(privPk.getEncoded())));
}
case PublicKeyAlgorithmTags.ECDSA:
return implGetPrivateKeyEC("ECDSA", (ECDSAPublicBCPGKey)pubPk.getKey(), (ECSecretBCPGKey)privPk);
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
- return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed25519, Ed25519.SECRET_KEY_SIZE, privPk);
+ return implGeneratePrivate("EdDSA", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519,
+ BigIntegers.asUnsignedByteArray(Ed25519.SECRET_KEY_SIZE, ((EdSecretBCPGKey)privPk).getX())));
}
case PublicKeyAlgorithmTags.Ed25519:
{
- PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(
- new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519),
- new DEROctetString(BigIntegers.asUnsignedByteArray(Ed25519.SECRET_KEY_SIZE, new BigInteger(1, privPk.getEncoded())))).getEncoded());
- return implGeneratePrivate("EdDSA", pkcs8Spec);
+ return implGeneratePrivate("EdDSA", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519,
+ Ed25519SecretBCPGKey.LENGTH, privPk.getEncoded()));
}
case PublicKeyAlgorithmTags.Ed448:
{
- PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(
- new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448),
- new DEROctetString(BigIntegers.asUnsignedByteArray(Ed448.SECRET_KEY_SIZE, new BigInteger(1, privPk.getEncoded())))).getEncoded());
- return implGeneratePrivate("EdDSA", pkcs8Spec);
+ return implGeneratePrivate("EdDSA", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed448,
+ Ed448SecretBCPGKey.LENGTH, privPk.getEncoded()));
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
@@ -309,54 +299,38 @@ public PublicKey getPublicKey(PGPPublicKey publicKey)
}
case PublicKeyAlgorithmTags.X25519:
{
- byte[] pEnc = publicPk.getKey().getEncoded();
- X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(new SubjectPublicKeyInfo(
- new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519),
- Arrays.copyOfRange(pEnc, 0, pEnc.length)).getEncoded());
- return implGeneratePublic("XDH", x509Spec);
+ return implGetPublicKeyX509(publicPk.getKey().getEncoded(), 0, EdECObjectIdentifiers.id_X25519, "XDH");
}
case PublicKeyAlgorithmTags.X448:
{
- byte[] pEnc = publicPk.getKey().getEncoded();
- X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(new SubjectPublicKeyInfo(
- new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448),
- Arrays.copyOfRange(pEnc, 0, pEnc.length)).getEncoded());
- return implGeneratePublic("XDH", x509Spec);
+ return implGetPublicKeyX509(publicPk.getKey().getEncoded(), 0, EdECObjectIdentifiers.id_X448, "XDH");
}
case PublicKeyAlgorithmTags.ECDSA:
return implGetPublicKeyEC("ECDSA", (ECDSAPublicBCPGKey)publicPk.getKey());
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
- EdDSAPublicBCPGKey eddsaK = (EdDSAPublicBCPGKey)publicPk.getKey();
- return get25519PublicKey(eddsaK.getEncodedPoint(), EdECObjectIdentifiers.id_Ed25519, "EdDSA", "Ed");
+ return get25519PublicKey(((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint(), EdECObjectIdentifiers.id_Ed25519, "EdDSA", "Ed");
}
case PublicKeyAlgorithmTags.Ed25519:
{
BCPGKey key = publicPk.getKey();
if (key instanceof Ed25519PublicBCPGKey)
{
- return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed25519, new BigInteger(1, publicPk.getKey().getEncoded()));
+ return implGetPublicKeyX509(BigIntegers.asUnsignedByteArray(new BigInteger(1, publicPk.getKey().getEncoded())),
+ 0, EdECObjectIdentifiers.id_Ed25519, "EdDSA");
}
else
{
- return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed25519, ((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint());
+ return implGetPublicKeyX509(BigIntegers.asUnsignedByteArray(((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint()),
+ 0, EdECObjectIdentifiers.id_Ed25519, "EdDSA");
}
}
case PublicKeyAlgorithmTags.Ed448:
{
- BCPGKey key = publicPk.getKey();
- if (key instanceof Ed448PublicBCPGKey)
- {
- return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed448, new BigInteger(1, publicPk.getKey().getEncoded()));
- }
- else
- {
- return implGetPublicKeyX509("EdDSA", EdECObjectIdentifiers.id_Ed448, ((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint());
- }
-
+ return implGetPublicKeyX509(BigIntegers.asUnsignedByteArray(new BigInteger(1, publicPk.getKey().getEncoded())),
+ 0, EdECObjectIdentifiers.id_Ed448, "EdDSA");
}
-
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
{
@@ -388,12 +362,6 @@ public PublicKey getPublicKey(PGPPublicKey publicKey)
}
}
- private ECParameterSpec getECParameterSpec(ASN1ObjectIdentifier curveOid)
- throws NoSuchAlgorithmException, NoSuchProviderException, InvalidParameterSpecException
- {
- return getECParameterSpec(curveOid, JcaJcePGPUtil.getX9Parameters(curveOid));
- }
-
private ECParameterSpec getECParameterSpec(ASN1ObjectIdentifier curveOid, X9ECParameters x9Params)
throws InvalidParameterSpecException, NoSuchProviderException, NoSuchAlgorithmException
{
@@ -404,6 +372,22 @@ private ECParameterSpec getECParameterSpec(ASN1ObjectIdentifier curveOid, X9ECPa
return params.getParameterSpec(ECParameterSpec.class);
}
+ private BCPGKey getPrivateBCPGKey(PrivateKey privKey, BCPGKeyOperation operation)
+ throws PGPException
+ {
+ PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
+
+ try
+ {
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return operation.getBCPGKey(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets());
+ }
+ catch (IOException e)
+ {
+ throw new PGPException(e.getMessage(), e);
+ }
+ }
+
private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey)
throws PGPException
{
@@ -424,92 +408,35 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey)
}
else
{
- PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
-
- try
- {
- // 'reverse' because the native format for X25519 private keys is little-endian
- return new ECSecretBCPGKey(new BigInteger(1,
- Arrays.reverse(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets())));
- }
- catch (IOException e)
- {
- throw new PGPException(e.getMessage(), e);
- }
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new ECSecretBCPGKey(new BigInteger(1, Arrays.reverse(pInfoEncoded))));
}
}
case PublicKeyAlgorithmTags.X25519:
{
- PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
- try
- {
- // 'reverse' because the native format for X25519 private keys is little-endian
- return new X25519SecretBCPGKey(Arrays.reverse(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets()));
- }
- catch (IOException e)
- {
- throw new PGPException(e.getMessage(), e);
- }
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new X25519SecretBCPGKey(Arrays.reverse(pInfoEncoded)));
}
case PublicKeyAlgorithmTags.X448:
{
- PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
-
- try
- {
- // 'reverse' because the native format for X25519 private keys is little-endian
- return new X448SecretBCPGKey(Arrays.reverse(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets()));
- }
- catch (IOException e)
- {
- throw new PGPException(e.getMessage(), e);
- }
+ // 'reverse' because the native format for X448 private keys is little-endian
+ return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new X448SecretBCPGKey(Arrays.reverse(pInfoEncoded)));
}
-
case PublicKeyAlgorithmTags.ECDSA:
{
- ECPrivateKey ecK = (ECPrivateKey)privKey;
- return new ECSecretBCPGKey(ecK.getS());
+ return new ECSecretBCPGKey(((ECPrivateKey)privKey).getS());
}
-
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
- PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
-
- try
- {
- return new EdSecretBCPGKey(
- new BigInteger(1, ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets()));
- }
- catch (IOException e)
- {
- throw new PGPException(e.getMessage(), e);
- }
+ return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new EdSecretBCPGKey(new BigInteger(1, pInfoEncoded)));
}
case PublicKeyAlgorithmTags.Ed25519:
{
- PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
- try
- {
- return new Ed25519SecretBCPGKey(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets());
- }
- catch (IOException e)
- {
- throw new PGPException(e.getMessage(), e);
- }
+ return getPrivateBCPGKey(privKey, Ed25519SecretBCPGKey::new);
}
case PublicKeyAlgorithmTags.Ed448:
{
- PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
-
- try
- {
- return new Ed448SecretBCPGKey(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets());
- }
- catch (IOException e)
- {
- throw new PGPException(e.getMessage(), e);
- }
+ return getPrivateBCPGKey(privKey, Ed448SecretBCPGKey::new);
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
@@ -532,23 +459,6 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey)
}
}
- private static ECSecretBCPGKey getEcSecretBCPGKey(PrivateKey privKey)
- throws PGPException
- {
- PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
-
- try
- {
- // 'reverse' because the native format for X25519 private keys is little-endian
- return new ECSecretBCPGKey(new BigInteger(1,
- Arrays.reverse(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets())));
- }
- catch (IOException e)
- {
- throw new PGPException(e.getMessage(), e);
- }
- }
-
private BCPGKey getPublicBCPGKey(int algorithm, PGPAlgorithmParameters algorithmParameters, PublicKey pubKey)
throws PGPException
{
@@ -583,7 +493,7 @@ else if (pubKey instanceof ECPublicKey)
if (algorithm == PGPPublicKey.ECDH)
{
- PGPKdfParameters kdfParams = implGetKdfParameters(algorithmParameters);
+ PGPKdfParameters kdfParams = implGetKdfParameters(curveOid, algorithmParameters);
return new ECDHPublicBCPGKey(curveOid, derQ.getPoint(), kdfParams.getHashAlgorithm(),
kdfParams.getSymmetricWrapAlgorithm());
@@ -599,11 +509,7 @@ else if (algorithm == PGPPublicKey.ECDSA)
}
else if (algorithm == PGPPublicKey.Ed25519)
{
- SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
- byte[] pointEnc = new byte[Ed25519.PUBLIC_KEY_SIZE];
-
- System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
- return new Ed25519PublicBCPGKey(pointEnc);
+ return getPublicBCPGKey(pubKey, Ed25519PublicBCPGKey.LENGTH, Ed25519PublicBCPGKey::new);
}
else if (pubKey.getAlgorithm().regionMatches(true, 0, "ED2", 0, 3))
{
@@ -611,34 +517,22 @@ else if (pubKey.getAlgorithm().regionMatches(true, 0, "ED2", 0, 3))
}
else if (algorithm == PGPPublicKey.X25519)
{
- SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
- byte[] pointEnc = new byte[X25519.SCALAR_SIZE];
-
- System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
- return new X25519PublicBCPGKey(pointEnc);
+ return getPublicBCPGKey(pubKey, X25519PublicBCPGKey.LENGTH, X25519PublicBCPGKey::new);
}
else if (pubKey.getAlgorithm().regionMatches(true, 0, "X2", 0, 2))
{
- PGPKdfParameters kdfParams = implGetKdfParameters(algorithmParameters);
+ PGPKdfParameters kdfParams = implGetKdfParameters(CryptlibObjectIdentifiers.curvey25519, algorithmParameters);
return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, getPointEncUncompressed(pubKey, X25519.SCALAR_SIZE)),
kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm());
}
else if (algorithm == PGPPublicKey.Ed448)
{
- SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
- byte[] pointEnc = new byte[Ed448.PUBLIC_KEY_SIZE];
-
- System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
- return new Ed448PublicBCPGKey(pointEnc);
+ return getPublicBCPGKey(pubKey, Ed448PublicBCPGKey.LENGTH, Ed448PublicBCPGKey::new);
}
else if (algorithm == PGPPublicKey.X448)
{
- SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
- byte[] pointEnc = new byte[X448.SCALAR_SIZE];
-
- System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
- return new X448PublicBCPGKey(pointEnc);
+ return getPublicBCPGKey(pubKey, X448PublicBCPGKey.LENGTH, X448PublicBCPGKey::new);
}
else
{
@@ -646,13 +540,19 @@ else if (algorithm == PGPPublicKey.X448)
}
}
- private static byte[] getPointEnc(PublicKey pubKey, int publicKeySize)
+ @FunctionalInterface
+ private interface BCPGKeyOperation
+ {
+ BCPGKey getBCPGKey(byte[] key);
+ }
+
+ private BCPGKey getPublicBCPGKey(PublicKey pubKey, int keySize, BCPGKeyOperation operation)
{
SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
- byte[] pointEnc = new byte[publicKeySize];
+ byte[] pointEnc = new byte[keySize];
System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
- return pointEnc;
+ return operation.getBCPGKey(pointEnc);
}
private byte[] getPointEncUncompressed(PublicKey pubKey, int publicKeySize)
@@ -665,6 +565,21 @@ private byte[] getPointEncUncompressed(PublicKey pubKey, int publicKeySize)
return pointEnc;
}
+ @FunctionalInterface
+ private interface Operation
+ {
+ PrivateKeyInfo getPrivateKeyInfo()
+ throws IOException;
+ }
+
+ private PrivateKey implGeneratePrivate(String keyAlgorithm, Operation operation)
+ throws GeneralSecurityException, PGPException, IOException
+ {
+ PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(operation.getPrivateKeyInfo().getEncoded());
+ KeyFactory keyFactory = helper.createKeyFactory(keyAlgorithm);
+ return keyFactory.generatePrivate(pkcs8Spec);
+ }
+
private PrivateKey implGeneratePrivate(String keyAlgorithm, KeySpec keySpec)
throws GeneralSecurityException, PGPException
{
@@ -679,15 +594,18 @@ private PublicKey implGeneratePublic(String keyAlgorithm, KeySpec keySpec)
return keyFactory.generatePublic(keySpec);
}
- private PGPKdfParameters implGetKdfParameters(PGPAlgorithmParameters algorithmParameters)
+ private PublicKey implGetPublicKeyX509(byte[] pEnc, int pEncOff, ASN1ObjectIdentifier algorithm, String keyAlgorithm)
+ throws IOException, PGPException, GeneralSecurityException
{
- return null == algorithmParameters ? DEFAULT_KDF_PARAMETERS : (PGPKdfParameters)algorithmParameters;
+ return implGeneratePublic(keyAlgorithm, new X509EncodedKeySpec(new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(algorithm), Arrays.copyOfRange(pEnc, pEncOff, pEnc.length)).getEncoded()));
}
private PrivateKey implGetPrivateKeyEC(String keyAlgorithm, ECPublicBCPGKey ecPub, ECSecretBCPGKey ecPriv)
throws GeneralSecurityException, PGPException
{
- ECPrivateKeySpec ecPrivSpec = new ECPrivateKeySpec(ecPriv.getX(), getECParameterSpec(ecPub.getCurveOID()));
+ ASN1ObjectIdentifier curveOid = ecPub.getCurveOID();
+ ECPrivateKeySpec ecPrivSpec = new ECPrivateKeySpec(ecPriv.getX(), getECParameterSpec(curveOid, JcaJcePGPUtil.getX9Parameters(curveOid)));
return implGeneratePrivate(keyAlgorithm, ecPrivSpec);
}
@@ -705,16 +623,6 @@ private PublicKey implGetPublicKeyEC(String keyAlgorithm, ECPublicBCPGKey ecPub)
return implGeneratePublic(keyAlgorithm, ecPubSpec);
}
- private PublicKey implGetPublicKeyX509(String keyAlgorithm, ASN1ObjectIdentifier algorithm, BigInteger x)
- throws GeneralSecurityException, IOException, PGPException
- {
- byte[] pEnc = BigIntegers.asUnsignedByteArray(x);
- X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(new SubjectPublicKeyInfo(
- new AlgorithmIdentifier(algorithm),
- Arrays.copyOfRange(pEnc, 0, pEnc.length)).getEncoded());
- return implGeneratePublic(keyAlgorithm, x509Spec);
- }
-
private PublicKey get25519PublicKey(BigInteger x, ASN1ObjectIdentifier algorithm, String keyAlgorithm, String name)
throws PGPException, GeneralSecurityException, IOException
{
@@ -725,29 +633,6 @@ private PublicKey get25519PublicKey(BigInteger x, ASN1ObjectIdentifier algorithm
{
throw new IllegalArgumentException("Invalid " + name + "25519 public key");
}
-
- X509EncodedKeySpec x509Spec = new X509EncodedKeySpec(new SubjectPublicKeyInfo(
- new AlgorithmIdentifier(algorithm),
- Arrays.copyOfRange(pEnc, 1, pEnc.length)).getEncoded());
- return implGeneratePublic(keyAlgorithm, x509Spec);
- }
-
- private PrivateKey implGetPrivateKeyPKCS8(ASN1ObjectIdentifier algorithm, BCPGKey privPk)
- throws GeneralSecurityException, IOException, PGPException
- {
- // 'reverse' because the native format for X25519/X448 private keys is little-endian
- PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(
- new AlgorithmIdentifier(algorithm),
- new DEROctetString(Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX())))).getEncoded());
- return implGeneratePrivate("XDH", pkcs8Spec);
- }
-
- private PrivateKey implGetPrivateKeyPKCS8(ASN1ObjectIdentifier algorithm, int keySize, BCPGKey privPk)
- throws GeneralSecurityException, IOException, PGPException
- {
- PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(
- new AlgorithmIdentifier(algorithm),
- new DEROctetString(BigIntegers.asUnsignedByteArray(keySize, ((EdSecretBCPGKey)privPk).getX()))).getEncoded());
- return implGeneratePrivate("EdDSA", pkcs8Spec);
+ return implGetPublicKeyX509(pEnc, 1, algorithm, keyAlgorithm);
}
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
index 0cf563b0c4..0076ed7dc5 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
@@ -27,12 +27,12 @@
import org.bouncycastle.asn1.x9.X9ECParametersHolder;
import org.bouncycastle.bcpg.AEADEncDataPacket;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
-import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.X25519PublicBCPGKey;
+import org.bouncycastle.bcpg.X448PublicBCPGKey;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
import org.bouncycastle.crypto.params.X448PublicKeyParameters;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
@@ -224,36 +224,65 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
byte[] enc = secKeyData[0];
-
- int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
- if ((2 + pLen + 1) > enc.length)
+ int pLen;
+ byte[] pEnc;
+ byte[] keyEnc;
+ if (pubKeyData.getKey() instanceof ECDHPublicBCPGKey)
{
- throw new PGPException("encoded length out of range");
- }
+ pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
+ if ((2 + pLen + 1) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
- byte[] pEnc = new byte[pLen];
- System.arraycopy(enc, 2, pEnc, 0, pLen);
+ pEnc = new byte[pLen];
+ System.arraycopy(enc, 2, pEnc, 0, pLen);
+ int keyLen = enc[pLen + 2] & 0xff;
+ if ((2 + pLen + 1 + keyLen) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
- int keyLen = enc[pLen + 2] & 0xff;
- if ((2 + pLen + 1 + keyLen) > enc.length)
+ keyEnc = new byte[keyLen];
+ System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);
+ }
+ else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
{
- throw new PGPException("encoded length out of range");
+ pLen = X25519PublicBCPGKey.LENGTH;
+ pEnc = new byte[pLen];
+ System.arraycopy(enc, 0, pEnc, 0, pLen);
+ int keyLen = enc[pLen] & 0xff;
+ if ((pLen + 1 + keyLen) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
+ keyEnc = new byte[keyLen];
+ System.arraycopy(enc, pLen + 1, keyEnc, 0, keyLen);
+ }
+ else
+ {
+ pLen = X448PublicBCPGKey.LENGTH;
+ pEnc = new byte[pLen];
+ System.arraycopy(enc, 0, pEnc, 0, pLen);
+ int keyLen = enc[pLen] & 0xff;
+ if ((pLen + 1 + keyLen) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
+ keyEnc = new byte[keyLen];
+ System.arraycopy(enc, pLen + 1, keyEnc, 0, keyLen);
}
-
- byte[] keyEnc = new byte[keyLen];
- System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);
try
{
KeyAgreement agreement;
PublicKey publicKey;
- int symmetricKeyAlgorithm, hashALgorithm;
+ int symmetricKeyAlgorithm;
ASN1ObjectIdentifier curveID;
if (pubKeyData.getKey() instanceof ECDHPublicBCPGKey)
{
ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
symmetricKeyAlgorithm = ecKey.getSymmetricKeyAlgorithm();
- hashALgorithm = ecKey.getHashAlgorithm();
curveID = ecKey.getCurveOID();
// XDH
if (curveID.equals(CryptlibObjectIdentifiers.curvey25519))
@@ -276,23 +305,17 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
{
agreement = helper.createKeyAgreement(RFC6637Utils.getXDHAlgorithm(pubKeyData));
- publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X25519, 0,
- pEnc.length != (X25519PublicKeyParameters.KEY_SIZE), "25519");
- hashALgorithm = HashAlgorithmTags.SHA256;
+ publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X25519, 0, pEnc.length != (X25519PublicKeyParameters.KEY_SIZE), "25519");
symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128;
- curveID = CryptlibObjectIdentifiers.curvey25519;
}
else
{
agreement = helper.createKeyAgreement(RFC6637Utils.getXDHAlgorithm(pubKeyData));
- publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X448, 0,
- pEnc.length != X448PublicKeyParameters.KEY_SIZE, "448");
- hashALgorithm = HashAlgorithmTags.SHA512;
+ publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X448, 0, pEnc.length != X448PublicKeyParameters.KEY_SIZE, "448");
symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_256;
- curveID = EdECObjectIdentifiers.id_X448;
}
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyData, fingerprintCalculator, curveID, hashALgorithm, symmetricKeyAlgorithm);
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyData, fingerprintCalculator);
PrivateKey privateKey = converter.getPrivateKey(privKey);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index 8168a4e896..f5ea52c652 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -19,13 +19,10 @@
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
-import org.bouncycastle.bcpg.Ed25519PublicBCPGKey;
-import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
@@ -100,22 +97,19 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.ECDH)
{
- PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
- ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyPacket.getKey();
-
- UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(
- RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new JcaKeyFingerprintCalculator()));
+ ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKey.getPublicKeyPacket().getKey();
String keyEncryptionOID = RFC6637Utils.getKeyEncryptionOID(ecKey.getSymmetricKeyAlgorithm()).getId();
if (ecKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
- return getEncryptSessionInfo("X25519", RFC6637Utils.getXDHAlgorithm(pubKeyPacket), ukmSpec, cryptoPublicKey, keyEncryptionOID,
+ return getEncryptSessionInfo(pubKey, "X25519", cryptoPublicKey, keyEncryptionOID,
ecKey.getSymmetricKeyAlgorithm(), sessionInfo, (kpGen) -> kpGen.initialize(255, random),
- (ephPubEncoding) -> Arrays.prepend(ephPubEncoding, X_HDR));
+ (ephPubEncoding) -> Arrays.prepend(ephPubEncoding, X_HDR), RFC6637Utils::getXDHAlgorithm,
+ PublicKeyKeyEncryptionMethodGenerator::getSessionInfo);
}
else
{
- return getEncryptSessionInfo("EC", RFC6637Utils.getAgreementAlgorithm(pubKeyPacket), ukmSpec, cryptoPublicKey, keyEncryptionOID,
+ return getEncryptSessionInfo(pubKey, "EC", cryptoPublicKey, keyEncryptionOID,
ecKey.getSymmetricKeyAlgorithm(), sessionInfo, (kpGen) ->
{
AlgorithmParameters ecAlgParams = helper.createAlgorithmParameters("EC");
@@ -128,28 +122,20 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
ephPubEncoding = JcaJcePGPUtil.getX9Parameters(ecKey.getCurveOID()).getCurve().decodePoint(ephPubEncoding).getEncoded(false);
}
return ephPubEncoding;
- });
+ }, RFC6637Utils::getAgreementAlgorithm, PublicKeyKeyEncryptionMethodGenerator::getSessionInfo);
}
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
{
- PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
- UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
- new JcaKeyFingerprintCalculator(), CryptlibObjectIdentifiers.curvey25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128));
- String keyEncryptionOID = NISTObjectIdentifiers.id_aes128_wrap.getId();
- return getEncryptSessionInfo("X25519", RFC6637Utils.getXDHAlgorithm(pubKeyPacket), ukmSpec, cryptoPublicKey, keyEncryptionOID,
+ return getEncryptSessionInfo(pubKey, "X25519", cryptoPublicKey, NISTObjectIdentifiers.id_aes128_wrap.getId(),
SymmetricKeyAlgorithmTags.AES_128, sessionInfo, (kpGen) -> kpGen.initialize(255, random),
- (ephPubEncoding) -> ephPubEncoding);
+ (ephPubEncoding) -> ephPubEncoding, RFC6637Utils::getXDHAlgorithm, PublicKeyKeyEncryptionMethodGenerator::getSessionInfo_25519or448);
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
{
- PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
- UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
- new JcaKeyFingerprintCalculator(), EdECObjectIdentifiers.id_X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256));
- String keyEncryptionOID = NISTObjectIdentifiers.id_aes256_wrap.getId();
- return getEncryptSessionInfo("X448", RFC6637Utils.getXDHAlgorithm(pubKeyPacket), ukmSpec, cryptoPublicKey, keyEncryptionOID,
+ return getEncryptSessionInfo(pubKey, "X448", cryptoPublicKey, NISTObjectIdentifiers.id_aes256_wrap.getId(),
SymmetricKeyAlgorithmTags.AES_256, sessionInfo, (kpGen) -> kpGen.initialize(448, random),
- (ephPubEncoding) -> ephPubEncoding);
+ (ephPubEncoding) -> ephPubEncoding, RFC6637Utils::getXDHAlgorithm, PublicKeyKeyEncryptionMethodGenerator::getSessionInfo_25519or448);
}
else
{
@@ -195,15 +181,31 @@ private interface EphPubEncoding
byte[] getEphPubEncoding(byte[] publicKeyData);
}
- private byte[] getEncryptSessionInfo(String algorithmName, String algorithm, UserKeyingMaterialSpec ukmSpec,
- PublicKey cryptoPublicKey, String keyEncryptionOID, int symmetricKeyAlgorithm, byte[] sessionInfo,
- KeyPairGeneratorOperation kpOperation, EphPubEncoding getEncoding)
+ @FunctionalInterface
+ private interface CheckAlgorithmName
+ {
+ String getAlgorithmName(PublicKeyPacket pubKeyData);
+ }
+
+ @FunctionalInterface
+ private interface GetSessionInfo
+ {
+ byte[] getSessionInfo(byte[] ephPubEncoding, byte[] C)
+ throws IOException;
+ }
+
+ private byte[] getEncryptSessionInfo(PGPPublicKey pubKey, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
+ int symmetricKeyAlgorithm, byte[] sessionInfo, KeyPairGeneratorOperation kpOperation,
+ EphPubEncoding getEncoding, CheckAlgorithmName checkAlgorithmName, GetSessionInfo getSessionInfo)
throws GeneralSecurityException, IOException, PGPException
{
+ PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
+ UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
+ new JcaKeyFingerprintCalculator()));
KeyPairGenerator kpGen = helper.createKeyPairGenerator(algorithmName);
kpOperation.initialize(kpGen);
KeyPair ephKP = kpGen.generateKeyPair();
- KeyAgreement agreement = helper.createKeyAgreement(algorithm);
+ KeyAgreement agreement = helper.createKeyAgreement(checkAlgorithmName.getAlgorithmName(pubKeyPacket));
agreement.init(ephKP.getPrivate(), ukmSpec);
agreement.doPhase(cryptoPublicKey, true);
Key secret = agreement.generateSecret(keyEncryptionOID);
@@ -214,6 +216,6 @@ private byte[] getEncryptSessionInfo(String algorithmName, String algorithm, Use
c.init(Cipher.WRAP_MODE, secret, random);
byte[] C = c.wrap(new SecretKeySpec(paddedSessionData, PGPUtil.getSymmetricCipherName(sessionInfo[0])));
- return getSessionInfo(ephPubEncoding, C);
+ return getSessionInfo.getSessionInfo(ephPubEncoding, C);
}
}
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java
index b425a7f09a..75c68d9b4a 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/BcpgGeneralTest.java
@@ -103,15 +103,15 @@ public void testECDHPublicBCPGKey()
throws Exception
{
SecureRandom random = CryptoServicesRegistrar.getSecureRandom();
- System.setProperty("enableCamelliaKeyWrapping", "true");
+// System.setProperty("enableCamelliaKeyWrapping", "true");
final X25519KeyPairGenerator gen = new X25519KeyPairGenerator();
gen.init(new X25519KeyGenerationParameters(random));
- testException("Symmetric key algorithm must be AES-128 or stronger.", "IllegalStateException", () ->
- new BcPGPKeyPair(PGPPublicKey.ECDH, new PGPKdfParameters(8, SymmetricKeyAlgorithmTags.IDEA), gen.generateKeyPair(), new Date()));
- testException("Hash algorithm must be SHA-256 or stronger.", "IllegalStateException", () ->
- new BcPGPKeyPair(PGPPublicKey.ECDH, new PGPKdfParameters(HashAlgorithmTags.SHA1, 7), gen.generateKeyPair(), new Date()));
+// testException("Symmetric key algorithm must be AES-128 or stronger.", "IllegalStateException", () ->
+// new BcPGPKeyPair(PGPPublicKey.ECDH, new PGPKdfParameters(8, SymmetricKeyAlgorithmTags.IDEA), gen.generateKeyPair(), new Date()));
+// testException("Hash algorithm must be SHA-256 or stronger.", "IllegalStateException", () ->
+// new BcPGPKeyPair(PGPPublicKey.ECDH, new PGPKdfParameters(HashAlgorithmTags.SHA1, 7), gen.generateKeyPair(), new Date()));
- new BcPGPKeyPair(PGPPublicKey.ECDH, new PGPKdfParameters(8, SymmetricKeyAlgorithmTags.CAMELLIA_256), gen.generateKeyPair(), new Date());
+// new BcPGPKeyPair(PGPPublicKey.ECDH, new PGPKdfParameters(8, SymmetricKeyAlgorithmTags.CAMELLIA_256), gen.generateKeyPair(), new Date());
BcPGPKeyPair kp = new BcPGPKeyPair(PGPPublicKey.ECDH, gen.generateKeyPair(), new Date());
ECDHPublicBCPGKey publicBCPGKey = (ECDHPublicBCPGKey)kp.getPublicKey().getPublicKeyPacket().getKey();
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index 81eb1ef189..c3e2d66692 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -257,35 +257,41 @@ public void testKeyRings()
throws Exception
{
System.setProperty("enableCamelliaKeyWrapping", "True");
- keyringTest("ED25519", PublicKeyAlgorithmTags.Ed25519, "X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
-
- keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_192);
- keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_256);
- keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_128);
- keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_192);
- keyringTest("Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_256);
-
-
- keyringTest("Ed448", PublicKeyAlgorithmTags.Ed448, "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+ keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.Ed25519, "XDH","X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+
+ keyringTest("ECDSA","NIST P-256", PublicKeyAlgorithmTags.ECDSA, "ECDH","NIST P-256", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("ECDSA","NIST P-384", PublicKeyAlgorithmTags.ECDSA, "ECDH","NIST P-384", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_192);
+ keyringTest("ECDSA","NIST P-521", PublicKeyAlgorithmTags.ECDSA, "ECDH","NIST P-521", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+ keyringTest("ECDSA","brainpoolP256r1", PublicKeyAlgorithmTags.ECDSA, "ECDH","brainpoolP256r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("ECDSA","brainpoolP384r1", PublicKeyAlgorithmTags.ECDSA, "ECDH","brainpoolP384r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_192);
+ keyringTest("ECDSA","brainpoolP512r1", PublicKeyAlgorithmTags.ECDSA, "ECDH","brainpoolP512r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+
+ keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_192);
+ keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_256);
+ keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_128);
+ keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_192);
+ keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_256);
+
+ keyringTest("EdDSA","Ed448", PublicKeyAlgorithmTags.Ed448, "XDH","X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
}
- private void keyringTest(String ed_str, int ed_num, String x_str, int x_num, int hashAlgorithm, int symmetricWrapAlgorithm)
+ private void keyringTest(String algorithmName1, String ed_str, int ed_num, String algorithmName2, String x_str, int x_num, int hashAlgorithm, int symmetricWrapAlgorithm)
throws Exception
{
String identity = "eric@bouncycastle.org";
char[] passPhrase = "Hello, world!".toCharArray();
- KeyPairGenerator edKp = KeyPairGenerator.getInstance("EdDSA", "BC");
+ KeyPairGenerator edKp = KeyPairGenerator.getInstance(algorithmName1, "BC");
edKp.initialize(new ECNamedCurveGenParameterSpec(ed_str));
PGPKeyPair dsaKeyPair = new JcaPGPKeyPair(ed_num, edKp.generateKeyPair(), new Date());
- KeyPairGenerator dhKp = KeyPairGenerator.getInstance("XDH", "BC");
+ KeyPairGenerator dhKp = KeyPairGenerator.getInstance(algorithmName2, "BC");
dhKp.initialize(new ECNamedCurveGenParameterSpec(x_str));
From 3e0b21cf633a9d0ce572abe671f89da220711106 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Mon, 26 Feb 2024 13:27:37 +1030
Subject: [PATCH 0097/1846] Correct the PKESK format of X25519 and X448.
---
.../openpgp/PGPPublicKeyEncryptedData.java | 10 ++-
...PublicKeyKeyEncryptionMethodGenerator.java | 9 +--
.../bc/BcPublicKeyDataDecryptorFactory.java | 24 ++++---
...PublicKeyKeyEncryptionMethodGenerator.java | 8 ++-
...ePublicKeyDataDecryptorFactoryBuilder.java | 35 ++++++++---
...PublicKeyKeyEncryptionMethodGenerator.java | 62 ++++++++++++++-----
.../openpgp/test/OperatorBcTest.java | 6 +-
7 files changed, 110 insertions(+), 44 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java
index bad5fcc009..ddf5bfa68c 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java
@@ -5,6 +5,7 @@
import org.bouncycastle.bcpg.AEADEncDataPacket;
import org.bouncycastle.bcpg.BCPGInputStream;
import org.bouncycastle.bcpg.InputStreamPacket;
+import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyEncSessionPacket;
import org.bouncycastle.bcpg.SymmetricEncIntegrityPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
@@ -78,7 +79,7 @@ public int getSymmetricAlgorithm(
else if (keyData.getVersion() == PublicKeyEncSessionPacket.VERSION_6)
{
// PKESK v5 stores the cipher algorithm in the SEIPD v2 packet fields.
- return ((SymmetricEncIntegrityPacket) encData).getCipherAlgorithm();
+ return ((SymmetricEncIntegrityPacket)encData).getCipherAlgorithm();
}
else
{
@@ -98,11 +99,14 @@ public PGPSessionKey getSessionKey(
throws PGPException
{
byte[] sessionData = dataDecryptorFactory.recoverSessionData(keyData.getAlgorithm(), keyData.getEncSessionKey());
- if (!confirmCheckSum(sessionData))
+ if (!(keyData.getAlgorithm() == PublicKeyAlgorithmTags.X25519 || keyData.getAlgorithm() == PublicKeyAlgorithmTags.X448) && !confirmCheckSum(sessionData))
{
throw new PGPKeyValidationException("key checksum failed");
}
-
+ if (keyData.getAlgorithm() == PublicKeyAlgorithmTags.X25519 || keyData.getAlgorithm() == PublicKeyAlgorithmTags.X448)
+ {
+ return new PGPSessionKey(sessionData[0] & 0xff, Arrays.copyOfRange(sessionData, 1, sessionData.length));
+ }
return new PGPSessionKey(sessionData[0] & 0xff, Arrays.copyOfRange(sessionData, 1, sessionData.length - 2));
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
index aeab14ed6b..dbe80ae1d8 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
@@ -186,12 +186,13 @@ protected static byte[] getSessionInfo(byte[] ephPubEncoding, byte[] c)
return rv;
}
- protected static byte[] getSessionInfo_25519or448(byte[] VB, byte[] c)
+ protected static byte[] getSessionInfo_25519or448(byte[] VB, int sysmmetricKeyAlgorithm, byte[] c)
{
- byte[] rv = new byte[VB.length + 1 + c.length];
+ byte[] rv = new byte[VB.length + 2 + c.length];
System.arraycopy(VB, 0, rv, 0, VB.length);
- rv[VB.length] = (byte)c.length;
- System.arraycopy(c, 0, rv, VB.length + 1, c.length);
+ rv[VB.length] = (byte)(c.length + 1);
+ rv[VB.length + 1] = (byte)sysmmetricKeyAlgorithm;
+ System.arraycopy(c, 0, rv, VB.length + 2, c.length);
return rv;
}
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index 1c0e408236..c051295926 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -115,9 +115,10 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
byte[] enc = secKeyData[0];
byte[] pEnc;
byte[] keyEnc;
+ int pLen;
if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
{
- int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
+ pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
if ((2 + pLen + 1) > enc.length)
{
throw new PGPException("encoded length out of range");
@@ -137,7 +138,7 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
}
else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
- int pLen = X25519PublicBCPGKey.LENGTH;
+ pLen = X25519PublicBCPGKey.LENGTH;
pEnc = new byte[pLen];
System.arraycopy(enc, 0, pEnc, 0, pLen);
int keyLen = enc[pLen] & 0xff;
@@ -145,12 +146,12 @@ else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
throw new PGPException("encoded length out of range");
}
- keyEnc = new byte[keyLen];
- System.arraycopy(enc, pLen + 1, keyEnc, 0, keyLen);
+ keyEnc = new byte[keyLen - 1];
+ System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
}
else
{
- int pLen = X448PublicBCPGKey.LENGTH;
+ pLen = X448PublicBCPGKey.LENGTH;
pEnc = new byte[pLen];
System.arraycopy(enc, 0, pEnc, 0, pLen);
int keyLen = enc[pLen] & 0xff;
@@ -158,8 +159,8 @@ else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
throw new PGPException("encoded length out of range");
}
- keyEnc = new byte[keyLen];
- System.arraycopy(enc, pLen + 1, keyEnc, 0, keyLen);
+ keyEnc = new byte[keyLen - 1];
+ System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
}
byte[] secret;
@@ -189,6 +190,13 @@ else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
}
hashAlgorithm = ecPubKey.getHashAlgorithm();
symmetricKeyAlgorithm = ecPubKey.getSymmetricKeyAlgorithm();
+ userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(), new BcKeyFingerprintCalculator());
+ rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
+ KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
+
+ Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
+ c.init(false, key);
+ return PGPPad.unpadSessionData(c.unwrap(keyEnc, 0, keyEnc.length));
}
else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
@@ -209,7 +217,7 @@ else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
c.init(false, key);
- return PGPPad.unpadSessionData(c.unwrap(keyEnc, 0, keyEnc.length));
+ return org.bouncycastle.util.Arrays.concatenate(new byte[]{enc[pLen + 1]}, c.unwrap(keyEnc, 0, keyEnc.length));
}
}
catch (IOException e)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index b9ffab36fb..6994403bc2 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -202,14 +202,16 @@ private byte[] encryptSessionInfo_25519_448(byte[] sessionInfo, PublicKeyPacket
RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(
new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
-
- byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
+ //No checksum
+ byte[] paddedSessionData = new byte[sessionInfo.length - 3];
+ System.arraycopy(sessionInfo, 1, paddedSessionData, 0, paddedSessionData.length);
+ //byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo_withoutChecksum, sessionKeyObfuscation);
Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
c.init(true, new ParametersWithRandom(key, random));
byte[] C = c.wrap(paddedSessionData, 0, paddedSessionData.length);
- return getSessionInfo_25519or448(ephPubEncoding, C);
+ return getSessionInfo_25519or448(ephPubEncoding, sessionInfo[0], C);
}
private byte[] encryptSessionInfo(byte[] sessionInfo, byte[] secret,
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
index 0076ed7dc5..57f6ec853c 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
@@ -222,7 +222,7 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
{
PublicKeyPacket pubKeyData = privKey.getPublicKeyPacket();
-
+ int symmetricKeyAlgorithm = 0;
byte[] enc = secKeyData[0];
int pLen;
byte[] pEnc;
@@ -256,8 +256,9 @@ else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
{
throw new PGPException("encoded length out of range");
}
- keyEnc = new byte[keyLen];
- System.arraycopy(enc, pLen + 1, keyEnc, 0, keyLen);
+// symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
+ keyEnc = new byte[keyLen - 1];
+ System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
}
else
{
@@ -269,15 +270,16 @@ else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
{
throw new PGPException("encoded length out of range");
}
- keyEnc = new byte[keyLen];
- System.arraycopy(enc, pLen + 1, keyEnc, 0, keyLen);
+// symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
+ keyEnc = new byte[keyLen - 1];
+ System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
}
try
{
KeyAgreement agreement;
PublicKey publicKey;
- int symmetricKeyAlgorithm;
+
ASN1ObjectIdentifier curveID;
if (pubKeyData.getKey() instanceof ECDHPublicBCPGKey)
{
@@ -301,6 +303,23 @@ else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
publicKey = converter.getPublicKey(new PGPPublicKey(new PublicKeyPacket(PublicKeyAlgorithmTags.ECDH, new Date(),
new ECDHPublicBCPGKey(ecKey.getCurveOID(), publicPoint, ecKey.getHashAlgorithm(), ecKey.getSymmetricKeyAlgorithm())), fingerprintCalculator));
}
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyData, fingerprintCalculator);
+
+ PrivateKey privateKey = converter.getPrivateKey(privKey);
+
+ agreement.init(privateKey, new UserKeyingMaterialSpec(userKeyingMaterial));
+
+ agreement.doPhase(publicKey, true);
+
+ Key key = agreement.generateSecret(RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId());
+
+ Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
+
+ c.init(Cipher.UNWRAP_MODE, key);
+
+ Key paddedSessionKey = c.unwrap(keyEnc, "Session", Cipher.SECRET_KEY);
+
+ return PGPPad.unpadSessionData(paddedSessionKey.getEncoded());
}
else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
{
@@ -330,8 +349,8 @@ else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
c.init(Cipher.UNWRAP_MODE, key);
Key paddedSessionKey = c.unwrap(keyEnc, "Session", Cipher.SECRET_KEY);
-
- return PGPPad.unpadSessionData(paddedSessionKey.getEncoded());
+ symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
+ return Arrays.concatenate(new byte[]{(byte)symmetricKeyAlgorithm}, paddedSessionKey.getEncoded());
}
catch (InvalidKeyException e)
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index f5ea52c652..0b303d4e95 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -104,8 +104,7 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
{
return getEncryptSessionInfo(pubKey, "X25519", cryptoPublicKey, keyEncryptionOID,
ecKey.getSymmetricKeyAlgorithm(), sessionInfo, (kpGen) -> kpGen.initialize(255, random),
- (ephPubEncoding) -> Arrays.prepend(ephPubEncoding, X_HDR), RFC6637Utils::getXDHAlgorithm,
- PublicKeyKeyEncryptionMethodGenerator::getSessionInfo);
+ (ephPubEncoding) -> Arrays.prepend(ephPubEncoding, X_HDR), RFC6637Utils::getXDHAlgorithm);
}
else
{
@@ -122,20 +121,20 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
ephPubEncoding = JcaJcePGPUtil.getX9Parameters(ecKey.getCurveOID()).getCurve().decodePoint(ephPubEncoding).getEncoded(false);
}
return ephPubEncoding;
- }, RFC6637Utils::getAgreementAlgorithm, PublicKeyKeyEncryptionMethodGenerator::getSessionInfo);
+ }, RFC6637Utils::getAgreementAlgorithm);
}
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
{
- return getEncryptSessionInfo(pubKey, "X25519", cryptoPublicKey, NISTObjectIdentifiers.id_aes128_wrap.getId(),
- SymmetricKeyAlgorithmTags.AES_128, sessionInfo, (kpGen) -> kpGen.initialize(255, random),
- (ephPubEncoding) -> ephPubEncoding, RFC6637Utils::getXDHAlgorithm, PublicKeyKeyEncryptionMethodGenerator::getSessionInfo_25519or448);
+ return getEncryptSessionInfo_25519or448(pubKey, "X25519", cryptoPublicKey, NISTObjectIdentifiers.id_aes128_wrap.getId(),
+ SymmetricKeyAlgorithmTags.AES_128, sessionInfo, (kpGen) -> kpGen.initialize(255, random),
+ (ephPubEncoding) -> ephPubEncoding, RFC6637Utils::getXDHAlgorithm);
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
{
- return getEncryptSessionInfo(pubKey, "X448", cryptoPublicKey, NISTObjectIdentifiers.id_aes256_wrap.getId(),
+ return getEncryptSessionInfo_25519or448(pubKey, "X448", cryptoPublicKey, NISTObjectIdentifiers.id_aes256_wrap.getId(),
SymmetricKeyAlgorithmTags.AES_256, sessionInfo, (kpGen) -> kpGen.initialize(448, random),
- (ephPubEncoding) -> ephPubEncoding, RFC6637Utils::getXDHAlgorithm, PublicKeyKeyEncryptionMethodGenerator::getSessionInfo_25519or448);
+ (ephPubEncoding) -> ephPubEncoding, RFC6637Utils::getXDHAlgorithm);
}
else
{
@@ -187,16 +186,9 @@ private interface CheckAlgorithmName
String getAlgorithmName(PublicKeyPacket pubKeyData);
}
- @FunctionalInterface
- private interface GetSessionInfo
- {
- byte[] getSessionInfo(byte[] ephPubEncoding, byte[] C)
- throws IOException;
- }
-
private byte[] getEncryptSessionInfo(PGPPublicKey pubKey, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
int symmetricKeyAlgorithm, byte[] sessionInfo, KeyPairGeneratorOperation kpOperation,
- EphPubEncoding getEncoding, CheckAlgorithmName checkAlgorithmName, GetSessionInfo getSessionInfo)
+ EphPubEncoding getEncoding, CheckAlgorithmName checkAlgorithmName)
throws GeneralSecurityException, IOException, PGPException
{
PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
@@ -216,6 +208,42 @@ private byte[] getEncryptSessionInfo(PGPPublicKey pubKey, String algorithmName,
c.init(Cipher.WRAP_MODE, secret, random);
byte[] C = c.wrap(new SecretKeySpec(paddedSessionData, PGPUtil.getSymmetricCipherName(sessionInfo[0])));
- return getSessionInfo.getSessionInfo(ephPubEncoding, C);
+ return getSessionInfo(ephPubEncoding, C);
+ }
+
+ /**
+ * Note that unlike ECDH, no checksum or padding are appended to the
+ * session key before key wrapping. Finally, note that unlike the other
+ * public-key algorithms, in the case of a v3 PKESK packet, the
+ * symmetric algorithm ID is not encrypted. Instead, it is prepended to
+ * the encrypted session key in plaintext. In this case, the symmetric
+ * algorithm used MUST be AES-128, AES-192 or AES-256 (algorithm ID 7, 8
+ * or 9).
+ */
+ private byte[] getEncryptSessionInfo_25519or448(PGPPublicKey pubKey, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
+ int symmetricKeyAlgorithm, byte[] sessionInfo, KeyPairGeneratorOperation kpOperation,
+ EphPubEncoding getEncoding, CheckAlgorithmName checkAlgorithmName)
+ throws GeneralSecurityException, IOException, PGPException
+ {
+ PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
+ UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
+ new JcaKeyFingerprintCalculator()));
+ KeyPairGenerator kpGen = helper.createKeyPairGenerator(algorithmName);
+ kpOperation.initialize(kpGen);
+ KeyPair ephKP = kpGen.generateKeyPair();
+ KeyAgreement agreement = helper.createKeyAgreement(checkAlgorithmName.getAlgorithmName(pubKeyPacket));
+ agreement.init(ephKP.getPrivate(), ukmSpec);
+ agreement.doPhase(cryptoPublicKey, true);
+ Key secret = agreement.generateSecret(keyEncryptionOID);
+ byte[] ephPubEncoding = getEncoding.getEphPubEncoding(SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes());
+ //No checksum
+ byte[] paddedSessionData = new byte[sessionInfo.length - 3];
+ System.arraycopy(sessionInfo, 1, paddedSessionData, 0, paddedSessionData.length);
+
+ Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
+ c.init(Cipher.WRAP_MODE, secret, random);
+ byte[] C = c.wrap(new SecretKeySpec(paddedSessionData, PGPUtil.getSymmetricCipherName(sessionInfo[0])));
+
+ return getSessionInfo_25519or448(ephPubEncoding, sessionInfo[0], C);
}
}
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index c3e2d66692..7dccf31d98 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -259,6 +259,10 @@ public void testKeyRings()
System.setProperty("enableCamelliaKeyWrapping", "True");
keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.Ed25519, "XDH","X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+
+
+
keyringTest("ECDSA","NIST P-256", PublicKeyAlgorithmTags.ECDSA, "ECDH","NIST P-256", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("ECDSA","NIST P-384", PublicKeyAlgorithmTags.ECDSA, "ECDH","NIST P-384", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_192);
keyringTest("ECDSA","NIST P-521", PublicKeyAlgorithmTags.ECDSA, "ECDH","NIST P-521", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
@@ -266,7 +270,7 @@ public void testKeyRings()
keyringTest("ECDSA","brainpoolP384r1", PublicKeyAlgorithmTags.ECDSA, "ECDH","brainpoolP384r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_192);
keyringTest("ECDSA","brainpoolP512r1", PublicKeyAlgorithmTags.ECDSA, "ECDH","brainpoolP512r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
- keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+
keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_192);
From b8acab9c51afc95fc27f39e741c7434525a6a1f3 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Mon, 26 Feb 2024 15:56:06 +1030
Subject: [PATCH 0098/1846] Jcajce classes uses HKDF for X25519 and X448 now
---
...PublicKeyKeyEncryptionMethodGenerator.java | 99 +++++++++++++++++++
.../openpgp/operator/RFC6637Utils.java | 26 ++++-
...ePublicKeyDataDecryptorFactoryBuilder.java | 9 +-
...PublicKeyKeyEncryptionMethodGenerator.java | 29 +++---
.../openpgp/test/OperatorBcTest.java | 3 +-
.../jcajce/provider/asymmetric/EdEC.java | 3 +
.../asymmetric/edec/KeyAgreementSpi.java | 19 ++++
.../asymmetric/util/BaseAgreementSpi.java | 18 ++--
8 files changed, 175 insertions(+), 31 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
index dbe80ae1d8..a87d357fc9 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
@@ -1,11 +1,20 @@
package org.bouncycastle.openpgp.operator;
import org.bouncycastle.bcpg.ContainedPacket;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.MPInteger;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyEncSessionPacket;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
+import org.bouncycastle.crypto.hpke.HPKE;
+import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Properties;
import java.io.IOException;
@@ -195,4 +204,94 @@ protected static byte[] getSessionInfo_25519or448(byte[] VB, int sysmmetricKeyAl
System.arraycopy(c, 0, rv, VB.length + 2, c.length);
return rv;
}
+
+ protected byte[] getHKDF(int hashAlgorithm, byte[] pubKeyPacket, byte[] secret, byte[] ephPubEncoding)
+ {
+ HKDF hkdf = new HKDF(hashAlgorithm);
+ return hkdf.Extract(null, Arrays.concatenate(pubKeyPacket, secret, ephPubEncoding));
+ }
+
+ static class HKDF
+ {
+ private final HKDFBytesGenerator kdf;
+ private final int hashLength;
+
+ HKDF(int kdfId)
+ {
+ Digest hash;
+
+ switch (kdfId)
+ {
+ case HashAlgorithmTags.SHA256:
+ hash = new SHA256Digest();
+ break;
+ case HashAlgorithmTags.SHA384:
+ hash = new SHA384Digest();
+ break;
+ case HashAlgorithmTags.SHA512:
+ hash = new SHA512Digest();
+ break;
+ default:
+ throw new IllegalArgumentException("invalid kdf id");
+ }
+ kdf = new HKDFBytesGenerator(hash);
+ hashLength = hash.getDigestSize();
+ }
+
+ int getHashSize()
+ {
+ return hashLength;
+ }
+
+ /**
+ * HKDF-Extract algorithm implementation.
+ *
+ * This method extracts a pseudorandom key (PRK) using the HKDF-Extract function.
+ *
+ * @param salt optional salt value (a non-secret random value); if not provided,
+ * it is set to a byte array of HashLen zeros.
+ * @param ikm input keying material
+ * @return a pseudorandom key (of HashLen bytes) generated using HMAC-Hash(salt, IKM)
+ */
+ public byte[] Extract(byte[] salt, byte[] ikm)
+ {
+ if (salt == null)
+ {
+ salt = new byte[hashLength];
+ }
+
+ return kdf.extractPRK(salt, ikm);
+ }
+
+ /**
+ * HKDF-Expand algorithm implementation.
+ *
+ * This method expands a pseudorandom key (PRK) into output keying material (OKM)
+ * using the HKDF-Expand function.
+ *
+ * @param prk a pseudorandom key of at least HashLen bytes
+ * (usually, the output from the extract step)
+ * @param info optional context and application-specific information
+ * (can be a zero-length byte array)
+ * @param L length of output keying material in bytes
+ * (<= 65536*HashLen)
+ * @return output keying material (of L bytes) generated using HKDF-Expand
+ * @throws IllegalArgumentException if L is larger than 65536*HashLen
+ */
+ public byte[] Expand(byte[] prk, byte[] info, int L)
+ {
+ if (L > (1 << 16))
+ {
+ throw new IllegalArgumentException("Expand length cannot be larger than 2^16");
+ }
+
+ kdf.init(HKDFParameters.skipExtractParameters(prk, info));
+
+ byte[] rv = new byte[L];
+
+ kdf.generateBytes(rv, 0, rv.length);
+
+ return rv;
+ }
+ }
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
index 41a4665d56..801bb603db 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
@@ -15,7 +15,16 @@
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.X25519PublicBCPGKey;
import org.bouncycastle.bcpg.X448PublicBCPGKey;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
+import org.bouncycastle.crypto.hpke.HPKE;
+import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Pack;
import org.bouncycastle.util.encoders.Hex;
@@ -119,8 +128,6 @@ else if (key instanceof X448PublicBCPGKey)
curveID = EdECObjectIdentifiers.id_X448;
symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_256;
hashAlgorithm = HashAlgorithmTags.SHA512;
-// pOut.write(key.getEncoded());
-// pOut.write(EdECObjectIdentifiers.id_X448.getEncoded());
}
else
{
@@ -128,7 +135,20 @@ else if (key instanceof X448PublicBCPGKey)
curveID = ecKey.getCurveOID();
hashAlgorithm = ecKey.getHashAlgorithm();
symmetricKeyAlgorithm = ecKey.getSymmetricKeyAlgorithm();
+ byte[] encOid = curveID.getEncoded();
+ pOut.write(encOid, 1, encOid.length - 1);
+ pOut.write(pubKeyData.getAlgorithm());
+ pOut.write(0x03);
+ pOut.write(0x01);
+ pOut.write(hashAlgorithm);
+ pOut.write(symmetricKeyAlgorithm);
+ pOut.write(ANONYMOUS_SENDER);
+ pOut.write(fingerPrintCalculator.calculateFingerprint(pubKeyData));
+
+ return pOut.toByteArray();
}
+// HKDF hkdf = new HKDF(kdfId);
+
byte[] encOid = curveID.getEncoded();
pOut.write(encOid, 1, encOid.length - 1);
pOut.write(pubKeyData.getAlgorithm());
@@ -138,7 +158,7 @@ else if (key instanceof X448PublicBCPGKey)
pOut.write(symmetricKeyAlgorithm);
pOut.write(ANONYMOUS_SENDER);
pOut.write(fingerPrintCalculator.calculateFingerprint(pubKeyData));
-
return pOut.toByteArray();
}
+
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
index 57f6ec853c..8a1962bdb9 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
@@ -279,7 +279,6 @@ else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
{
KeyAgreement agreement;
PublicKey publicKey;
-
ASN1ObjectIdentifier curveID;
if (pubKeyData.getKey() instanceof ECDHPublicBCPGKey)
{
@@ -323,22 +322,20 @@ else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
}
else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
{
- agreement = helper.createKeyAgreement(RFC6637Utils.getXDHAlgorithm(pubKeyData));
+ agreement = helper.createKeyAgreement("X25519withSHA256HKDF");
publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X25519, 0, pEnc.length != (X25519PublicKeyParameters.KEY_SIZE), "25519");
symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128;
}
else
{
- agreement = helper.createKeyAgreement(RFC6637Utils.getXDHAlgorithm(pubKeyData));
+ agreement = helper.createKeyAgreement("X448withSHA512HKDF");
publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X448, 0, pEnc.length != X448PublicKeyParameters.KEY_SIZE, "448");
symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_256;
}
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyData, fingerprintCalculator);
-
PrivateKey privateKey = converter.getPrivateKey(privKey);
- agreement.init(privateKey, new UserKeyingMaterialSpec(userKeyingMaterial));
+ agreement.init(privateKey);
agreement.doPhase(publicKey, true);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index 0b303d4e95..c8760ae9a8 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -126,15 +126,15 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
{
- return getEncryptSessionInfo_25519or448(pubKey, "X25519", cryptoPublicKey, NISTObjectIdentifiers.id_aes128_wrap.getId(),
- SymmetricKeyAlgorithmTags.AES_128, sessionInfo, (kpGen) -> kpGen.initialize(255, random),
- (ephPubEncoding) -> ephPubEncoding, RFC6637Utils::getXDHAlgorithm);
+ return getEncryptSessionInfo_25519or448("X25519", cryptoPublicKey, NISTObjectIdentifiers.id_aes128_wrap.getId(),
+ SymmetricKeyAlgorithmTags.AES_128, sessionInfo, "X25519withSHA256HKDF", (kpGen) -> kpGen.initialize(255, random),
+ (ephPubEncoding) -> ephPubEncoding);
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
{
- return getEncryptSessionInfo_25519or448(pubKey, "X448", cryptoPublicKey, NISTObjectIdentifiers.id_aes256_wrap.getId(),
- SymmetricKeyAlgorithmTags.AES_256, sessionInfo, (kpGen) -> kpGen.initialize(448, random),
- (ephPubEncoding) -> ephPubEncoding, RFC6637Utils::getXDHAlgorithm);
+ return getEncryptSessionInfo_25519or448("X448", cryptoPublicKey, NISTObjectIdentifiers.id_aes256_wrap.getId(),
+ SymmetricKeyAlgorithmTags.AES_256, sessionInfo, "X448withSHA512HKDF", (kpGen) -> kpGen.initialize(448, random),
+ (ephPubEncoding) -> ephPubEncoding);
}
else
{
@@ -220,22 +220,21 @@ private byte[] getEncryptSessionInfo(PGPPublicKey pubKey, String algorithmName,
* algorithm used MUST be AES-128, AES-192 or AES-256 (algorithm ID 7, 8
* or 9).
*/
- private byte[] getEncryptSessionInfo_25519or448(PGPPublicKey pubKey, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
- int symmetricKeyAlgorithm, byte[] sessionInfo, KeyPairGeneratorOperation kpOperation,
- EphPubEncoding getEncoding, CheckAlgorithmName checkAlgorithmName)
+ private byte[] getEncryptSessionInfo_25519or448(String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
+ int symmetricKeyAlgorithm, byte[] sessionInfo, String agreementAlgorithmName,
+ KeyPairGeneratorOperation kpOperation, EphPubEncoding getEncoding)
throws GeneralSecurityException, IOException, PGPException
{
- PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
- UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
- new JcaKeyFingerprintCalculator()));
KeyPairGenerator kpGen = helper.createKeyPairGenerator(algorithmName);
kpOperation.initialize(kpGen);
KeyPair ephKP = kpGen.generateKeyPair();
- KeyAgreement agreement = helper.createKeyAgreement(checkAlgorithmName.getAlgorithmName(pubKeyPacket));
- agreement.init(ephKP.getPrivate(), ukmSpec);
+
+ byte[] ephPubEncoding = getEncoding.getEphPubEncoding(SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes());
+
+ KeyAgreement agreement = helper.createKeyAgreement(agreementAlgorithmName);
+ agreement.init(ephKP.getPrivate());
agreement.doPhase(cryptoPublicKey, true);
Key secret = agreement.generateSecret(keyEncryptionOID);
- byte[] ephPubEncoding = getEncoding.getEphPubEncoding(SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes());
//No checksum
byte[] paddedSessionData = new byte[sessionInfo.length - 3];
System.arraycopy(sessionInfo, 1, paddedSessionData, 0, paddedSessionData.length);
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index 7dccf31d98..326d5bd030 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -257,6 +257,7 @@ public void testKeyRings()
throws Exception
{
System.setProperty("enableCamelliaKeyWrapping", "True");
+ keyringTest("EdDSA","Ed448", PublicKeyAlgorithmTags.Ed448, "XDH","X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.Ed25519, "XDH","X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
@@ -279,7 +280,7 @@ public void testKeyRings()
keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_192);
keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_256);
- keyringTest("EdDSA","Ed448", PublicKeyAlgorithmTags.Ed448, "XDH","X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+
}
private void keyringTest(String algorithmName1, String ed_str, int ed_num, String algorithmName2, String x_str, int x_num, int hashAlgorithm, int symmetricWrapAlgorithm)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java
index 8e3b4aef18..aba481467f 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java
@@ -69,6 +69,9 @@ public void configure(ConfigurableProvider provider)
provider.addAlgorithm("KeyAgreement.X25519UWITHSHA256KDF", PREFIX + "KeyAgreementSpi$X25519UwithSHA256KDF");
provider.addAlgorithm("KeyAgreement.X448UWITHSHA512KDF", PREFIX + "KeyAgreementSpi$X448UwithSHA512KDF");
+ provider.addAlgorithm("KeyAgreement.X448withSHA512HKDF", PREFIX + "KeyAgreementSpi$X448withSHA512HKDF");
+ provider.addAlgorithm("KeyAgreement.X25519withSHA256HKDF", PREFIX + "KeyAgreementSpi$X25519withSHA256HKDF");
+
provider.addAlgorithm("KeyPairGenerator.XDH", PREFIX + "KeyPairGeneratorSpi$XDH");
provider.addAlgorithm("KeyPairGenerator.X448", PREFIX + "KeyPairGeneratorSpi$X448");
provider.addAlgorithm("KeyPairGenerator.X25519", PREFIX + "KeyPairGeneratorSpi$X25519");
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
index c697137521..9203c47106 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
@@ -14,6 +14,7 @@
import org.bouncycastle.crypto.agreement.X448Agreement;
import org.bouncycastle.crypto.agreement.XDHUnifiedAgreement;
import org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator;
+import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
@@ -315,4 +316,22 @@ public X448UwithSHA512KDF()
super("X448UwithSHA512KDF", new KDF2BytesGenerator(DigestFactory.createSHA512()));
}
}
+
+ public final static class X448withSHA512HKDF
+ extends KeyAgreementSpi
+ {
+ public X448withSHA512HKDF()
+ {
+ super("X448withSHA512HKDF", new HKDFBytesGenerator(DigestFactory.createSHA512()));
+ }
+ }
+
+ public final static class X25519withSHA256HKDF
+ extends KeyAgreementSpi
+ {
+ public X25519withSHA256HKDF()
+ {
+ super("X25519withSHA256HKDF", new HKDFBytesGenerator(DigestFactory.createSHA256()));
+ }
+ }
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
index 374db2026b..52ec8f2de7 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -27,7 +27,9 @@
import org.bouncycastle.crypto.DerivationFunction;
import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator;
+import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
import org.bouncycastle.crypto.params.DESParameters;
+import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.crypto.params.KDFParameters;
import org.bouncycastle.jcajce.spec.HybridValueParameterSpec;
import org.bouncycastle.util.Arrays;
@@ -149,7 +151,7 @@ public abstract class BaseAgreementSpi
protected final String kaAlgorithm;
protected final DerivationFunction kdf;
- protected byte[] ukmParameters;
+ protected byte[] ukmParameters;
private HybridValueParameterSpec hybridSpec;
public BaseAgreementSpi(String kaAlgorithm, DerivationFunction kdf)
@@ -223,8 +225,8 @@ protected static byte[] trimZeroes(byte[] secret)
}
protected void engineInit(
- Key key,
- SecureRandom random)
+ Key key,
+ SecureRandom random)
throws InvalidKeyException
{
try
@@ -276,8 +278,8 @@ protected byte[] engineGenerateSecret()
}
protected int engineGenerateSecret(
- byte[] sharedSecret,
- int offset)
+ byte[] sharedSecret,
+ int offset)
throws IllegalStateException, ShortBufferException
{
byte[] secret = engineGenerateSecret();
@@ -304,7 +306,7 @@ protected SecretKey engineGenerateSecret(
oidAlgorithm = ((ASN1ObjectIdentifier)oids.get(algKey)).getId();
}
- int keySize = getKeySize(oidAlgorithm);
+ int keySize = getKeySize(oidAlgorithm);
byte[] secret = getSharedSecretBytes(calcSecret(), oidAlgorithm, keySize);
@@ -348,6 +350,10 @@ private byte[] getSharedSecretBytes(byte[] secret, String oidAlgorithm, int keyS
kdf.init(params);
}
+ else if (kdf instanceof HKDFBytesGenerator)
+ {
+ kdf.init(HKDFParameters.skipExtractParameters(secret, null));
+ }
else
{
KDFParameters params = new KDFParameters(secret, ukmParameters);
From d37128e62b282f61df663430e5a97a55de97302d Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Mon, 26 Feb 2024 19:19:36 +0700
Subject: [PATCH 0099/1846] Factor out TlsRsaKeyExchange class into core
---
.../crypto/tls/TlsRsaKeyExchange.java | 66 +++++++++++++++++++
.../bc/BcDefaultTlsCredentialedDecryptor.java | 58 ++--------------
2 files changed, 70 insertions(+), 54 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java b/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
new file mode 100644
index 0000000000..5cf2ec91aa
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
@@ -0,0 +1,66 @@
+package org.bouncycastle.crypto.tls;
+
+import java.security.SecureRandom;
+
+import org.bouncycastle.crypto.encodings.PKCS1Encoding;
+import org.bouncycastle.crypto.engines.RSABlindedEngine;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Pack;
+
+public abstract class TlsRsaKeyExchange
+{
+ private TlsRsaKeyExchange()
+ {
+ }
+
+ public static byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret, RSAKeyParameters privateKey,
+ int protocolVersion, SecureRandom secureRandom)
+ {
+ /*
+ * Generate 48 random bytes we can use as a Pre-Master-Secret, if the PKCS1 padding check should fail.
+ */
+ byte[] fallback = new byte[48];
+ secureRandom.nextBytes(fallback);
+
+ byte[] M = Arrays.clone(fallback);
+ try
+ {
+ PKCS1Encoding encoding = new PKCS1Encoding(new RSABlindedEngine(), fallback);
+ encoding.init(false, new ParametersWithRandom(privateKey, secureRandom));
+
+ M = encoding.processBlock(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.length);
+ }
+ catch (Exception e)
+ {
+ /*
+ * This should never happen since the decryption should never throw an exception and return a
+ * random value instead.
+ *
+ * In any case, a TLS server MUST NOT generate an alert if processing an RSA-encrypted premaster
+ * secret message fails, or the version number is not as expected. Instead, it MUST continue the
+ * handshake with a randomly generated premaster secret.
+ */
+ }
+
+ /*
+ * Compare the version number in the decrypted Pre-Master-Secret with the legacy_version field from
+ * the ClientHello. If they don't match, continue the handshake with the randomly generated 'fallback'
+ * value.
+ *
+ * NOTE: The comparison and replacement must be constant-time.
+ */
+ int mask = (Pack.bigEndianToShort(M, 0) ^ protocolVersion) & 0xFFFF;
+
+ // 'mask' will be all 1s if the versions matched, or else all 0s.
+ mask = (mask - 1) >> 31;
+
+ for (int i = 0; i < 48; i++)
+ {
+ M[i] = (byte)((M[i] & mask) | (fallback[i] & ~mask));
+ }
+
+ return M;
+ }
+}
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
index 3d8c375bcc..7d8aa929e2 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
@@ -1,19 +1,15 @@
package org.bouncycastle.tls.crypto.impl.bc;
import java.io.IOException;
-import java.security.SecureRandom;
-import org.bouncycastle.crypto.encodings.PKCS1Encoding;
-import org.bouncycastle.crypto.engines.RSABlindedEngine;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.tls.TlsRsaKeyExchange;
import org.bouncycastle.tls.Certificate;
import org.bouncycastle.tls.ProtocolVersion;
import org.bouncycastle.tls.TlsCredentialedDecryptor;
import org.bouncycastle.tls.crypto.TlsCryptoParameters;
import org.bouncycastle.tls.crypto.TlsSecret;
-import org.bouncycastle.util.Arrays;
/**
* Credentialed class decrypting RSA encrypted secrets sent from a peer for our end of the TLS connection using the BC light-weight API.
@@ -26,7 +22,7 @@ public class BcDefaultTlsCredentialedDecryptor
protected AsymmetricKeyParameter privateKey;
public BcDefaultTlsCredentialedDecryptor(BcTlsCrypto crypto, Certificate certificate,
- AsymmetricKeyParameter privateKey)
+ AsymmetricKeyParameter privateKey)
{
if (crypto == null)
{
@@ -81,56 +77,10 @@ public TlsSecret decrypt(TlsCryptoParameters cryptoParams, byte[] ciphertext) th
protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
RSAKeyParameters rsaServerPrivateKey, byte[] encryptedPreMasterSecret)
{
- SecureRandom secureRandom = crypto.getSecureRandom();
-
- /*
- * RFC 5246 7.4.7.1.
- */
ProtocolVersion expectedVersion = cryptoParams.getRSAPreMasterSecretVersion();
- /*
- * Generate 48 random bytes we can use as a Pre-Master-Secret, if the PKCS1 padding check should fail.
- */
- byte[] fallback = new byte[48];
- secureRandom.nextBytes(fallback);
-
- byte[] M = Arrays.clone(fallback);
- try
- {
- PKCS1Encoding encoding = new PKCS1Encoding(new RSABlindedEngine(), fallback);
- encoding.init(false, new ParametersWithRandom(rsaServerPrivateKey, secureRandom));
-
- M = encoding.processBlock(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.length);
- }
- catch (Exception e)
- {
- /*
- * This should never happen since the decryption should never throw an exception and return a
- * random value instead.
- *
- * In any case, a TLS server MUST NOT generate an alert if processing an RSA-encrypted premaster
- * secret message fails, or the version number is not as expected. Instead, it MUST continue the
- * handshake with a randomly generated premaster secret.
- */
- }
-
- /*
- * Compare the version number in the decrypted Pre-Master-Secret with the legacy_version field from
- * the ClientHello. If they don't match, continue the handshake with the randomly generated 'fallback'
- * value.
- *
- * NOTE: The comparison and replacement must be constant-time.
- */
- int mask = (expectedVersion.getMajorVersion() ^ (M[0] & 0xFF))
- | (expectedVersion.getMinorVersion() ^ (M[1] & 0xFF));
-
- // 'mask' will be all 1s if the versions matched, or else all 0s.
- mask = (mask - 1) >> 31;
-
- for (int i = 0; i < 48; i++)
- {
- M[i] = (byte)((M[i] & mask) | (fallback[i] & ~mask));
- }
+ byte[] M = TlsRsaKeyExchange.decryptPreMasterSecret(encryptedPreMasterSecret, rsaServerPrivateKey,
+ expectedVersion.getFullVersion(), crypto.getSecureRandom());
return crypto.createSecret(M);
}
From ce4ff4ec76cb63fed7081d24758a8fa5838246c3 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 27 Feb 2024 08:33:18 +1030
Subject: [PATCH 0100/1846] HKDF for X25519 and X448
---
.../bc/BcPublicKeyDataDecryptorFactory.java | 244 +++++++++---------
...PublicKeyKeyEncryptionMethodGenerator.java | 148 +++++------
.../operator/bc/RFC6637KDFCalculator.java | 28 ++
...ePublicKeyDataDecryptorFactoryBuilder.java | 205 ++++++---------
...PublicKeyKeyEncryptionMethodGenerator.java | 40 ++-
.../openpgp/test/OperatorBcTest.java | 3 +-
.../asymmetric/util/BaseAgreementSpi.java | 14 +-
7 files changed, 321 insertions(+), 361 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index c051295926..10617caa18 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -2,7 +2,6 @@
import java.io.IOException;
import java.math.BigInteger;
-import java.util.Arrays;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.bcpg.AEADEncDataPacket;
@@ -37,6 +36,7 @@
import org.bouncycastle.openpgp.operator.PGPPad;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.RFC6637Utils;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
/**
@@ -62,7 +62,78 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
{
AsymmetricKeyParameter privKey = KEY_CONVERTER.getPrivateKey(pgpPrivKey);
- if (keyAlgorithm != PublicKeyAlgorithmTags.ECDH && keyAlgorithm != PublicKeyAlgorithmTags.X448 && keyAlgorithm != PublicKeyAlgorithmTags.X25519)
+ if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
+ {
+ return getSessionData(secKeyData, privKey, X25519PublicBCPGKey.LENGTH, HashAlgorithmTags.SHA256,
+ SymmetricKeyAlgorithmTags.AES_128, new X25519Agreement(),
+ X25519PublicKeyParameters::new);
+ }
+ else if (keyAlgorithm == PublicKeyAlgorithmTags.X448)
+ {
+ return getSessionData(secKeyData, privKey, X448PublicBCPGKey.LENGTH, HashAlgorithmTags.SHA512,
+ SymmetricKeyAlgorithmTags.AES_256, new X448Agreement(),
+ X448PublicKeyParameters::new);
+ }
+ else if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
+ {
+ byte[] enc = secKeyData[0];
+ byte[] pEnc;
+ byte[] keyEnc;
+ int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
+ if ((2 + pLen + 1) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
+
+ pEnc = new byte[pLen];
+ System.arraycopy(enc, 2, pEnc, 0, pLen);
+
+ int keyLen = enc[pLen + 2] & 0xff;
+ if ((2 + pLen + 1 + keyLen) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
+
+ keyEnc = new byte[keyLen];
+ System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);
+
+ byte[] secret;
+ RFC6637KDFCalculator rfc6637KDFCalculator;
+ byte[] userKeyingMaterial;
+ int symmetricKeyAlgorithm, hashAlgorithm;
+
+ ECDHPublicBCPGKey ecPubKey = (ECDHPublicBCPGKey)pgpPrivKey.getPublicKeyPacket().getKey();
+ // XDH
+ if (ecPubKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
+ {
+ if (pEnc.length != 1 + X25519PublicKeyParameters.KEY_SIZE || 0x40 != pEnc[0])
+ {
+ throw new IllegalArgumentException("Invalid Curve25519 public key");
+ }
+ // skip the 0x40 header byte.
+ secret = getSecret(new X25519Agreement(), privKey, new X25519PublicKeyParameters(pEnc, 1));
+ }
+ else
+ {
+ ECDomainParameters ecParameters = ((ECPrivateKeyParameters)privKey).getParameters();
+
+ ECPublicKeyParameters ephPub = new ECPublicKeyParameters(ecParameters.getCurve().decodePoint(pEnc),
+ ecParameters);
+
+ ECDHBasicAgreement agreement = new ECDHBasicAgreement();
+ agreement.init(privKey);
+ BigInteger S = agreement.calculateAgreement(ephPub);
+ secret = BigIntegers.asUnsignedByteArray(agreement.getFieldSize(), S);
+ }
+ hashAlgorithm = ecPubKey.getHashAlgorithm();
+ symmetricKeyAlgorithm = ecPubKey.getSymmetricKeyAlgorithm();
+ userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(), new BcKeyFingerprintCalculator());
+ rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
+ KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
+
+ return PGPPad.unpadSessionData(getUnwrap(keyEnc, symmetricKeyAlgorithm, key));
+ }
+ else
{
AsymmetricBlockCipher c = BcImplProvider.createPublicKeyCipher(keyAlgorithm);
@@ -110,115 +181,6 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
return c1.doFinal();
}
- else
- {
- byte[] enc = secKeyData[0];
- byte[] pEnc;
- byte[] keyEnc;
- int pLen;
- if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
- {
- pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
- if ((2 + pLen + 1) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
-
- pEnc = new byte[pLen];
- System.arraycopy(enc, 2, pEnc, 0, pLen);
-
- int keyLen = enc[pLen + 2] & 0xff;
- if ((2 + pLen + 1 + keyLen) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
-
- keyEnc = new byte[keyLen];
- System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);
- }
- else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
- {
- pLen = X25519PublicBCPGKey.LENGTH;
- pEnc = new byte[pLen];
- System.arraycopy(enc, 0, pEnc, 0, pLen);
- int keyLen = enc[pLen] & 0xff;
- if ((pLen + 1 + keyLen) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
- keyEnc = new byte[keyLen - 1];
- System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
- }
- else
- {
- pLen = X448PublicBCPGKey.LENGTH;
- pEnc = new byte[pLen];
- System.arraycopy(enc, 0, pEnc, 0, pLen);
- int keyLen = enc[pLen] & 0xff;
- if ((pLen + 1 + keyLen) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
- keyEnc = new byte[keyLen - 1];
- System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
- }
-
- byte[] secret;
- RFC6637KDFCalculator rfc6637KDFCalculator;
- byte[] userKeyingMaterial;
- int symmetricKeyAlgorithm, hashAlgorithm;
- if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
- {
- ECDHPublicBCPGKey ecPubKey = (ECDHPublicBCPGKey)pgpPrivKey.getPublicKeyPacket().getKey();
- // XDH
- if (ecPubKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
- {
- // skip the 0x40 header byte.
- secret = getSecret(new X25519Agreement(), pEnc.length != 1 + X25519PublicKeyParameters.KEY_SIZE || 0x40 != pEnc[0], privKey, new X25519PublicKeyParameters(pEnc, 1), "25519");
- }
- else
- {
- ECDomainParameters ecParameters = ((ECPrivateKeyParameters)privKey).getParameters();
-
- ECPublicKeyParameters ephPub = new ECPublicKeyParameters(ecParameters.getCurve().decodePoint(pEnc),
- ecParameters);
-
- ECDHBasicAgreement agreement = new ECDHBasicAgreement();
- agreement.init(privKey);
- BigInteger S = agreement.calculateAgreement(ephPub);
- secret = BigIntegers.asUnsignedByteArray(agreement.getFieldSize(), S);
- }
- hashAlgorithm = ecPubKey.getHashAlgorithm();
- symmetricKeyAlgorithm = ecPubKey.getSymmetricKeyAlgorithm();
- userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(), new BcKeyFingerprintCalculator());
- rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
- KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
-
- Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
- c.init(false, key);
- return PGPPad.unpadSessionData(c.unwrap(keyEnc, 0, keyEnc.length));
- }
- else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
- {
- secret = getSecret(new X25519Agreement(), pEnc.length != X25519PublicKeyParameters.KEY_SIZE, privKey, new X25519PublicKeyParameters(pEnc, 0), "25519");
- symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128;
- hashAlgorithm = HashAlgorithmTags.SHA256;
- }
- else
- {
- //PublicKeyAlgorithmTags.X448
- secret = getSecret(new X448Agreement(), pEnc.length != X448PublicKeyParameters.KEY_SIZE, privKey, new X448PublicKeyParameters(pEnc, 0), "448");
- symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_256;
- hashAlgorithm = HashAlgorithmTags.SHA512;
- }
- userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pgpPrivKey.getPublicKeyPacket(), new BcKeyFingerprintCalculator());
- rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
- KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
-
- Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
- c.init(false, key);
- return org.bouncycastle.util.Arrays.concatenate(new byte[]{enc[pLen + 1]}, c.unwrap(keyEnc, 0, keyEnc.length));
- }
}
catch (IOException e)
{
@@ -228,19 +190,6 @@ else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
throw new PGPException("exception decrypting session info: " + e.getMessage(), e);
}
-
- }
-
- private static byte[] getSecret(RawAgreement agreement, boolean condition, AsymmetricKeyParameter privKey, AsymmetricKeyParameter ephPub, String curve)
- {
- if (condition)
- {
- throw new IllegalArgumentException("Invalid Curve" + curve + " public key");
- }
- agreement.init(privKey);
- byte[] secret = new byte[agreement.getAgreementSize()];
- agreement.calculateAgreement(ephPub, secret, 0);
- return secret;
}
// OpenPGP v4
@@ -268,4 +217,51 @@ public PGPDataDecryptor createDataDecryptor(SymmetricEncIntegrityPacket seipd, P
{
return BcAEADUtil.createOpenPgpV6DataDecryptor(seipd, sessionKey);
}
+
+ @FunctionalInterface
+ private interface PublicKeyParametersOperation
+ {
+ AsymmetricKeyParameter getPublicKeyParameters(byte[] pEnc, int pEncOff);
+ }
+
+ private byte[] getSessionData(byte[][] secKeyData, AsymmetricKeyParameter privKey, int pLen, int hashAlgorithm,
+ int symmetricKeyAlgorithm, RawAgreement agreement, PublicKeyParametersOperation pkp
+ )
+ throws PGPException, InvalidCipherTextException
+ {
+ byte[] enc = secKeyData[0];
+ byte[] pEnc = new byte[pLen];
+ byte[] keyEnc;
+ System.arraycopy(enc, 0, pEnc, 0, pLen);
+ int keyLen = enc[pLen] & 0xff;
+ if ((pLen + 1 + keyLen) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
+ keyEnc = new byte[keyLen - 1];
+ System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
+ byte[] secret = getSecret(agreement, privKey, pkp.getPublicKeyParameters(pEnc, 0));
+
+ RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
+
+ KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(Arrays.concatenate(pgpPrivKey.getPublicKeyPacket().getKey().getEncoded(), pEnc, secret)));
+
+ return Arrays.concatenate(new byte[]{enc[pLen + 1]}, getUnwrap(keyEnc, symmetricKeyAlgorithm, key));
+ }
+
+ private static byte[] getSecret(RawAgreement agreement, AsymmetricKeyParameter privKey, AsymmetricKeyParameter ephPub)
+ {
+ agreement.init(privKey);
+ byte[] secret = new byte[agreement.getAgreementSize()];
+ agreement.calculateAgreement(ephPub, secret, 0);
+ return secret;
+ }
+
+ private static byte[] getUnwrap(byte[] keyEnc, int symmetricKeyAlgorithm, KeyParameter key)
+ throws PGPException, InvalidCipherTextException
+ {
+ Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
+ c.init(false, key);
+ return c.unwrap(keyEnc, 0, keyEnc.length);
+ }
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index 6994403bc2..1a22e34805 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -14,6 +14,7 @@
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.RawAgreement;
import org.bouncycastle.crypto.Wrapper;
import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
@@ -23,7 +24,6 @@
import org.bouncycastle.crypto.generators.X25519KeyPairGenerator;
import org.bouncycastle.crypto.generators.X448KeyPairGenerator;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
-import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.KeyParameter;
@@ -37,6 +37,7 @@
import org.bouncycastle.openpgp.operator.PGPPad;
import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.openpgp.operator.RFC6637Utils;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
/**
@@ -83,29 +84,22 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.ECDH)
{
ECDHPublicBCPGKey ecPubKey = (ECDHPublicBCPGKey)pubKeyPacket.getKey();
-
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator());
if (ecPubKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
- return encryptSessionInfo(sessionInfo, pubKeyPacket, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm(),
- new X25519KeyPairGenerator(), new X25519Agreement(), cryptoPublicKey,
- (gen) -> gen.init(new X25519KeyGenerationParameters(random)),
- (publicKey) ->
- {
- byte[] ephPubEncoding = new byte[1 + X25519PublicKeyParameters.KEY_SIZE];
- ephPubEncoding[0] = X_HDR;
- ((X25519PublicKeyParameters)publicKey).encode(ephPubEncoding, 1);
- return ephPubEncoding;
- });
+ AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(new X25519KeyPairGenerator(), new X25519KeyGenerationParameters(random));
+
+ byte[] secret = getSecret(new X25519Agreement(), cryptoPublicKey, ephKp);
+
+ byte[] ephPubEncoding = new byte[1 + X25519PublicKeyParameters.KEY_SIZE];
+ ephPubEncoding[0] = X_HDR;
+ ((X25519PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 1);
+ return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm());
}
else
{
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator());
- ECDomainParameters ecParams = ((ECPublicKeyParameters)cryptoPublicKey).getParameters();
-
- ECKeyPairGenerator gen = new ECKeyPairGenerator();
- gen.init(new ECKeyGenerationParameters(ecParams, random));
-
- AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
+ AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(new ECKeyPairGenerator(),
+ new ECKeyGenerationParameters(((ECPublicKeyParameters)cryptoPublicKey).getParameters(), random));
ECDHBasicAgreement agreement = new ECDHBasicAgreement();
agreement.init(ephKp.getPrivate());
@@ -119,27 +113,15 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
{
- return encryptSessionInfo_25519_448(sessionInfo, pubKeyPacket, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128,
- new X25519KeyPairGenerator(), new X25519Agreement(), cryptoPublicKey,
- (gen) -> gen.init(new X25519KeyGenerationParameters(random)),
- (publicKey) ->
- {
- byte[] ephPubEncoding = new byte[X25519PublicKeyParameters.KEY_SIZE];
- ((X25519PublicKeyParameters)publicKey).encode(ephPubEncoding, 0);
- return ephPubEncoding;
- });
+ return encryptSessionInfo(pubKeyPacket, sessionInfo, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128,
+ new X25519KeyPairGenerator(), new X25519KeyGenerationParameters(random), new X25519Agreement(), cryptoPublicKey, X25519PublicKeyParameters.KEY_SIZE,
+ (publicKey, ephPubEncoding) -> ((X25519PublicKeyParameters)publicKey).encode(ephPubEncoding, 0));
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
{
- return encryptSessionInfo_25519_448(sessionInfo, pubKeyPacket, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256,
- new X448KeyPairGenerator(), new X448Agreement(), cryptoPublicKey,
- (gen) -> gen.init(new X448KeyGenerationParameters(random)),
- (publicKey) ->
- {
- byte[] ephPubEncoding = new byte[X448PublicKeyParameters.KEY_SIZE];
- ((X448PublicKeyParameters)publicKey).encode(ephPubEncoding, 0);
- return ephPubEncoding;
- });
+ return encryptSessionInfo(pubKeyPacket, sessionInfo, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256,
+ new X448KeyPairGenerator(), new X448KeyGenerationParameters(random), new X448Agreement(), cryptoPublicKey, X448PublicKeyParameters.KEY_SIZE,
+ (publicKey, ephPubEncoding) -> ((X448PublicKeyParameters)publicKey).encode(ephPubEncoding, 0));
}
else
{
@@ -160,74 +142,68 @@ else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
}
}
- @FunctionalInterface
- private interface KeyPairGeneratorOperation
- {
- void initialize(AsymmetricCipherKeyPairGenerator gen);
- }
-
@FunctionalInterface
private interface ephPubEncodingOperation
{
- byte[] getEphPubEncoding(AsymmetricKeyParameter publicKey);
+ void getEphPubEncoding(AsymmetricKeyParameter publicKey, byte[] ephPubEncoding);
}
- private byte[] encryptSessionInfo(byte[] sessionInfo, PublicKeyPacket pubKeyPacket, int hashAlgorithm, int symmetricKeyAlgorithm,
- AsymmetricCipherKeyPairGenerator gen, RawAgreement agreement, AsymmetricKeyParameter cryptoPublicKey,
- KeyPairGeneratorOperation kpg, ephPubEncodingOperation ephPubEncodingOperation)
- throws PGPException, IOException
- {
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator());
- kpg.initialize(gen);
- AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
- agreement.init(ephKp.getPrivate());
- byte[] secret = new byte[agreement.getAgreementSize()];
- agreement.calculateAgreement(cryptoPublicKey, secret, 0);
- byte[] ephPubEncoding = ephPubEncodingOperation.getEphPubEncoding(ephKp.getPublic());
- return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, hashAlgorithm, symmetricKeyAlgorithm);
- }
-
- private byte[] encryptSessionInfo_25519_448(byte[] sessionInfo, PublicKeyPacket pubKeyPacket, int hashAlgorithm, int symmetricKeyAlgorithm,
- AsymmetricCipherKeyPairGenerator gen, RawAgreement agreement, AsymmetricKeyParameter cryptoPublicKey,
- KeyPairGeneratorOperation kpg, ephPubEncodingOperation ephPubEncodingOperation)
- throws PGPException, IOException
+ private byte[] encryptSessionInfo(byte[] sessionInfo, byte[] secret,
+ byte[] userKeyingMaterial, byte[] ephPubEncoding, int hashAlgorithm, int symmetricKeyAlgorithm)
+ throws IOException, PGPException
{
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator());
- kpg.initialize(gen);
- AsymmetricCipherKeyPair ephKp = gen.generateKeyPair();
- agreement.init(ephKp.getPrivate());
- byte[] secret = new byte[agreement.getAgreementSize()];
- agreement.calculateAgreement(cryptoPublicKey, secret, 0);
- byte[] ephPubEncoding = ephPubEncodingOperation.getEphPubEncoding(ephKp.getPublic());
RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(
new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
- //No checksum
- byte[] paddedSessionData = new byte[sessionInfo.length - 3];
- System.arraycopy(sessionInfo, 1, paddedSessionData, 0, paddedSessionData.length);
- //byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo_withoutChecksum, sessionKeyObfuscation);
- Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
- c.init(true, new ParametersWithRandom(key, random));
- byte[] C = c.wrap(paddedSessionData, 0, paddedSessionData.length);
+ byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
- return getSessionInfo_25519or448(ephPubEncoding, sessionInfo[0], C);
+ byte[] C = getWrapper(symmetricKeyAlgorithm, key, paddedSessionData);
+
+ return getSessionInfo(ephPubEncoding, C);
}
- private byte[] encryptSessionInfo(byte[] sessionInfo, byte[] secret,
- byte[] userKeyingMaterial, byte[] ephPubEncoding, int hashAlgorithm, int symmetricKeyAlgorithm)
- throws IOException, PGPException
+ private byte[] encryptSessionInfo(PublicKeyPacket pubKeyPacket, byte[] sessionInfo, int hashAlgorithm, int symmetricKeyAlgorithm,
+ AsymmetricCipherKeyPairGenerator gen, KeyGenerationParameters parameters, RawAgreement agreement, AsymmetricKeyParameter cryptoPublicKey,
+ int keySize, ephPubEncodingOperation ephPubEncodingOperation)
+ throws PGPException, IOException
{
+ AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(gen, parameters);
+ byte[] secret = getSecret(agreement, cryptoPublicKey, ephKp);
+ byte[] ephPubEncoding = new byte[keySize];
+ ephPubEncodingOperation.getEphPubEncoding(ephKp.getPublic(), ephPubEncoding);
RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(
new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
- KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
+ KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(Arrays.concatenate(pubKeyPacket.getKey().getEncoded(), ephPubEncoding, secret)));
+ //No checksum and padding
+ byte[] sessionData = new byte[sessionInfo.length - 3];
+ System.arraycopy(sessionInfo, 1, sessionData, 0, sessionData.length);
- byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
+ byte[] C = getWrapper(symmetricKeyAlgorithm, key, sessionData);
+ return getSessionInfo_25519or448(ephPubEncoding, sessionInfo[0], C);
+ }
+
+ private byte[] getWrapper(int symmetricKeyAlgorithm, KeyParameter key, byte[] sessionData)
+ throws PGPException
+ {
Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
c.init(true, new ParametersWithRandom(key, random));
- byte[] C = c.wrap(paddedSessionData, 0, paddedSessionData.length);
+ byte[] C = c.wrap(sessionData, 0, sessionData.length);
+ return C;
+ }
- return getSessionInfo(ephPubEncoding, C);
+ private AsymmetricCipherKeyPair getAsymmetricCipherKeyPair(AsymmetricCipherKeyPairGenerator gen, KeyGenerationParameters parameters)
+ {
+ gen.init(parameters);
+ return gen.generateKeyPair();
+ }
+
+ private static byte[] getSecret(RawAgreement agreement, AsymmetricKeyParameter cryptoPublicKey, AsymmetricCipherKeyPair ephKp)
+ {
+ agreement.init(ephKp.getPrivate());
+ byte[] secret = new byte[agreement.getAgreementSize()];
+ agreement.calculateAgreement(cryptoPublicKey, secret, 0);
+ return secret;
}
-}
+}
\ No newline at end of file
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
index 84dcc64f5f..7cf260fd28 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
@@ -46,6 +46,20 @@ public byte[] createKey(byte[] secret, byte[] userKeyingMaterial)
}
}
+ public byte[] createKey(byte[] secret)
+ throws PGPException
+ {
+ try
+ {
+ // RFC 7748
+ return HKDF(digCalc, secret, getKeyLen(keyAlgorithm));
+ }
+ catch (IOException e)
+ {
+ throw new PGPException("Exception performing KDF: " + e.getMessage(), e);
+ }
+ }
+
// RFC 6637 - Section 7
// Implements KDF( X, oBits, Param );
// Input: point X = (x,y)
@@ -80,6 +94,20 @@ private static byte[] KDF(PGPDigestCalculator digCalc, byte[] ZB, int keyLen, by
return key;
}
+ private static byte[] HKDF(PGPDigestCalculator digCalc, byte[] ZB, int keyLen)
+ throws IOException
+ {
+ OutputStream dOut = digCalc.getOutputStream();
+ dOut.write(ZB);
+ byte[] digest = digCalc.getDigest();
+
+ byte[] key = new byte[keyLen];
+
+ System.arraycopy(digest, 0, key, 0, key.length);
+
+ return key;
+ }
+
private static int getKeyLen(int algID)
throws PGPException
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
index 8a1962bdb9..89e39aec2b 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
@@ -34,7 +34,6 @@
import org.bouncycastle.bcpg.X25519PublicBCPGKey;
import org.bouncycastle.bcpg.X448PublicBCPGKey;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
-import org.bouncycastle.crypto.params.X448PublicKeyParameters;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
@@ -181,10 +180,20 @@ public PublicKeyDataDecryptorFactory build(final PGPPrivateKey privKey)
public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
throws PGPException
{
- if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH || keyAlgorithm == PublicKeyAlgorithmTags.X25519 || keyAlgorithm == PublicKeyAlgorithmTags.X448)
+ if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
{
return decryptSessionData(keyConverter, privKey, secKeyData);
}
+ else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
+ {
+ return decryptSessionData(keyConverter, privKey, secKeyData[0], X25519PublicBCPGKey.LENGTH, "X25519withSHA256HKDF",
+ SymmetricKeyAlgorithmTags.AES_128, EdECObjectIdentifiers.id_X25519);
+ }
+ else if (keyAlgorithm == PublicKeyAlgorithmTags.X448)
+ {
+ return decryptSessionData(keyConverter, privKey, secKeyData[0], X448PublicBCPGKey.LENGTH, "X448withSHA512HKDF",
+ SymmetricKeyAlgorithmTags.AES_256, EdECObjectIdentifiers.id_X448);
+ }
PrivateKey jcePrivKey = keyConverter.getPrivateKey(privKey);
int expectedPayLoadSize = getExpectedPayloadSize(jcePrivKey);
@@ -222,170 +231,112 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
{
PublicKeyPacket pubKeyData = privKey.getPublicKeyPacket();
- int symmetricKeyAlgorithm = 0;
byte[] enc = secKeyData[0];
int pLen;
byte[] pEnc;
byte[] keyEnc;
- if (pubKeyData.getKey() instanceof ECDHPublicBCPGKey)
- {
- pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
- if ((2 + pLen + 1) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
- pEnc = new byte[pLen];
- System.arraycopy(enc, 2, pEnc, 0, pLen);
- int keyLen = enc[pLen + 2] & 0xff;
- if ((2 + pLen + 1 + keyLen) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
-
- keyEnc = new byte[keyLen];
- System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);
- }
- else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
+ pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
+ if ((2 + pLen + 1) > enc.length)
{
- pLen = X25519PublicBCPGKey.LENGTH;
- pEnc = new byte[pLen];
- System.arraycopy(enc, 0, pEnc, 0, pLen);
- int keyLen = enc[pLen] & 0xff;
- if ((pLen + 1 + keyLen) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
-// symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
- keyEnc = new byte[keyLen - 1];
- System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
+ throw new PGPException("encoded length out of range");
}
- else
+
+ pEnc = new byte[pLen];
+ System.arraycopy(enc, 2, pEnc, 0, pLen);
+ int keyLen = enc[pLen + 2] & 0xff;
+ if ((2 + pLen + 1 + keyLen) > enc.length)
{
- pLen = X448PublicBCPGKey.LENGTH;
- pEnc = new byte[pLen];
- System.arraycopy(enc, 0, pEnc, 0, pLen);
- int keyLen = enc[pLen] & 0xff;
- if ((pLen + 1 + keyLen) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
-// symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
- keyEnc = new byte[keyLen - 1];
- System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
+ throw new PGPException("encoded length out of range");
}
+ keyEnc = new byte[keyLen];
+ System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);
+
try
{
KeyAgreement agreement;
PublicKey publicKey;
- ASN1ObjectIdentifier curveID;
- if (pubKeyData.getKey() instanceof ECDHPublicBCPGKey)
+
+ ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
+ // XDH
+ if (ecKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
- ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
- symmetricKeyAlgorithm = ecKey.getSymmetricKeyAlgorithm();
- curveID = ecKey.getCurveOID();
- // XDH
- if (curveID.equals(CryptlibObjectIdentifiers.curvey25519))
- {
- agreement = helper.createKeyAgreement(RFC6637Utils.getXDHAlgorithm(pubKeyData));
- publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X25519, 1,
- pEnc.length != (1 + X25519PublicKeyParameters.KEY_SIZE) || 0x40 != pEnc[0], "25519");
- }
- else
+ agreement = helper.createKeyAgreement(RFC6637Utils.getXDHAlgorithm(pubKeyData));
+ if (pEnc.length != (1 + X25519PublicKeyParameters.KEY_SIZE) || 0x40 != pEnc[0])
{
- X9ECParametersHolder x9Params = ECNamedCurveTable.getByOIDLazy(ecKey.getCurveOID());
- ECPoint publicPoint = x9Params.getCurve().decodePoint(pEnc);
-
- agreement = helper.createKeyAgreement(RFC6637Utils.getAgreementAlgorithm(pubKeyData));
-
- publicKey = converter.getPublicKey(new PGPPublicKey(new PublicKeyPacket(PublicKeyAlgorithmTags.ECDH, new Date(),
- new ECDHPublicBCPGKey(ecKey.getCurveOID(), publicPoint, ecKey.getHashAlgorithm(), ecKey.getSymmetricKeyAlgorithm())), fingerprintCalculator));
+ throw new IllegalArgumentException("Invalid Curve25519 public key");
}
- byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyData, fingerprintCalculator);
-
- PrivateKey privateKey = converter.getPrivateKey(privKey);
-
- agreement.init(privateKey, new UserKeyingMaterialSpec(userKeyingMaterial));
-
- agreement.doPhase(publicKey, true);
-
- Key key = agreement.generateSecret(RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId());
-
- Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
-
- c.init(Cipher.UNWRAP_MODE, key);
-
- Key paddedSessionKey = c.unwrap(keyEnc, "Session", Cipher.SECRET_KEY);
-
- return PGPPad.unpadSessionData(paddedSessionKey.getEncoded());
- }
- else if (pubKeyData.getKey() instanceof X25519PublicBCPGKey)
- {
- agreement = helper.createKeyAgreement("X25519withSHA256HKDF");
- publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X25519, 0, pEnc.length != (X25519PublicKeyParameters.KEY_SIZE), "25519");
- symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128;
+ publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X25519, 1);
}
else
{
- agreement = helper.createKeyAgreement("X448withSHA512HKDF");
- publicKey = getPublicKey(pEnc, EdECObjectIdentifiers.id_X448, 0, pEnc.length != X448PublicKeyParameters.KEY_SIZE, "448");
- symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_256;
- }
-
- PrivateKey privateKey = converter.getPrivateKey(privKey);
-
- agreement.init(privateKey);
+ X9ECParametersHolder x9Params = ECNamedCurveTable.getByOIDLazy(ecKey.getCurveOID());
+ ECPoint publicPoint = x9Params.getCurve().decodePoint(pEnc);
- agreement.doPhase(publicKey, true);
+ agreement = helper.createKeyAgreement(RFC6637Utils.getAgreementAlgorithm(pubKeyData));
- Key key = agreement.generateSecret(RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId());
-
- Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
+ publicKey = converter.getPublicKey(new PGPPublicKey(new PublicKeyPacket(PublicKeyAlgorithmTags.ECDH, new Date(),
+ new ECDHPublicBCPGKey(ecKey.getCurveOID(), publicPoint, ecKey.getHashAlgorithm(), ecKey.getSymmetricKeyAlgorithm())), fingerprintCalculator));
+ }
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyData, fingerprintCalculator);
- c.init(Cipher.UNWRAP_MODE, key);
+ Key paddedSessionKey = getSessionKey(converter, privKey, agreement, userKeyingMaterial, publicKey, ecKey.getSymmetricKeyAlgorithm(), keyEnc);
- Key paddedSessionKey = c.unwrap(keyEnc, "Session", Cipher.SECRET_KEY);
- symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
- return Arrays.concatenate(new byte[]{(byte)symmetricKeyAlgorithm}, paddedSessionKey.getEncoded());
- }
- catch (InvalidKeyException e)
- {
- throw new PGPException("error setting asymmetric cipher", e);
+ return PGPPad.unpadSessionData(paddedSessionKey.getEncoded());
}
- catch (NoSuchAlgorithmException e)
+ catch (GeneralSecurityException | IOException e)
{
throw new PGPException("error setting asymmetric cipher", e);
}
- catch (InvalidAlgorithmParameterException e)
- {
- throw new PGPException("error setting asymmetric cipher", e);
- }
- catch (GeneralSecurityException e)
+ }
+
+ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey privKey, byte[] enc, int pLen, String agreementAlgorithm,
+ int symmetricKeyAlgorithm, ASN1ObjectIdentifier algprithmIdentifier)
+ throws PGPException
+ {
+ try
{
- throw new PGPException("error setting asymmetric cipher", e);
+ byte[] pEnc = new byte[pLen];
+ System.arraycopy(enc, 0, pEnc, 0, pLen);
+ int keyLen = enc[pLen] & 0xff;
+ if ((pLen + 1 + keyLen) > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
+ byte[] keyEnc = new byte[keyLen - 1];
+ System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
+ KeyAgreement agreement = helper.createKeyAgreement(agreementAlgorithm);
+ PublicKey publicKey = getPublicKey(pEnc, algprithmIdentifier, 0);
+ Key paddedSessionKey = getSessionKey(converter, privKey, agreement, Arrays.concatenate(privKey.getPublicKeyPacket().getKey().getEncoded(), pEnc), publicKey, symmetricKeyAlgorithm, keyEnc);
+ symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
+ return Arrays.concatenate(new byte[]{(byte)symmetricKeyAlgorithm}, paddedSessionKey.getEncoded());
}
- catch (IOException e)
+ catch (GeneralSecurityException | IOException e)
{
throw new PGPException("error setting asymmetric cipher", e);
}
}
- private PublicKey getPublicKey(byte[] pEnc, ASN1ObjectIdentifier algprithmIdentifier, int pEncOff,
- boolean condition, String curve)
+ private Key getSessionKey(JcaPGPKeyConverter converter, PGPPrivateKey privKey, KeyAgreement agreement, byte[] privKey1, PublicKey publicKey, int symmetricKeyAlgorithm, byte[] keyEnc)
+ throws PGPException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException
+ {
+ PrivateKey privateKey = converter.getPrivateKey(privKey);
+ agreement.init(privateKey, new UserKeyingMaterialSpec(privKey1));
+ agreement.doPhase(publicKey, true);
+ Key key = agreement.generateSecret(RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId());
+ Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
+ c.init(Cipher.UNWRAP_MODE, key);
+ return c.unwrap(keyEnc, "Session", Cipher.SECRET_KEY);
+ }
+
+ private PublicKey getPublicKey(byte[] pEnc, ASN1ObjectIdentifier algprithmIdentifier, int pEncOff)
throws PGPException, GeneralSecurityException, IOException
{
KeyFactory keyFact = helper.createKeyFactory("XDH");
- if (condition)
- {
- throw new IllegalArgumentException("Invalid Curve" + curve + " public key");
- }
-
- return keyFact.generatePublic(
- new X509EncodedKeySpec(
- new SubjectPublicKeyInfo(new AlgorithmIdentifier(algprithmIdentifier),
- Arrays.copyOfRange(pEnc, pEncOff, pEnc.length)).getEncoded()));
+ return keyFact.generatePublic(new X509EncodedKeySpec(new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(algprithmIdentifier), Arrays.copyOfRange(pEnc, pEncOff, pEnc.length)).getEncoded()));
}
private void updateWithMPI(Cipher c, int expectedPayloadSize, byte[] encMPI)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index c8760ae9a8..aad7415048 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -99,17 +99,19 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
{
ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKey.getPublicKeyPacket().getKey();
String keyEncryptionOID = RFC6637Utils.getKeyEncryptionOID(ecKey.getSymmetricKeyAlgorithm()).getId();
-
+ PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
if (ecKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
- return getEncryptSessionInfo(pubKey, "X25519", cryptoPublicKey, keyEncryptionOID,
- ecKey.getSymmetricKeyAlgorithm(), sessionInfo, (kpGen) -> kpGen.initialize(255, random),
- (ephPubEncoding) -> Arrays.prepend(ephPubEncoding, X_HDR), RFC6637Utils::getXDHAlgorithm);
+ return getEncryptSessionInfo(pubKeyPacket, "X25519", cryptoPublicKey, keyEncryptionOID,
+ ecKey.getSymmetricKeyAlgorithm(), sessionInfo, RFC6637Utils.getXDHAlgorithm(pubKeyPacket),
+ (kpGen) -> kpGen.initialize(255, random),
+ (ephPubEncoding) -> Arrays.prepend(ephPubEncoding, X_HDR));
}
else
{
- return getEncryptSessionInfo(pubKey, "EC", cryptoPublicKey, keyEncryptionOID,
- ecKey.getSymmetricKeyAlgorithm(), sessionInfo, (kpGen) ->
+ return getEncryptSessionInfo(pubKeyPacket, "EC", cryptoPublicKey, keyEncryptionOID,
+ ecKey.getSymmetricKeyAlgorithm(), sessionInfo, RFC6637Utils.getAgreementAlgorithm(pubKeyPacket),
+ (kpGen) ->
{
AlgorithmParameters ecAlgParams = helper.createAlgorithmParameters("EC");
ecAlgParams.init(new X962Parameters(ecKey.getCurveOID()).getEncoded());
@@ -121,18 +123,18 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
ephPubEncoding = JcaJcePGPUtil.getX9Parameters(ecKey.getCurveOID()).getCurve().decodePoint(ephPubEncoding).getEncoded(false);
}
return ephPubEncoding;
- }, RFC6637Utils::getAgreementAlgorithm);
+ });
}
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
{
- return getEncryptSessionInfo_25519or448("X25519", cryptoPublicKey, NISTObjectIdentifiers.id_aes128_wrap.getId(),
+ return getEncryptSessionInfo_25519or448(pubKey.getPublicKeyPacket().getKey().getEncoded(), "X25519", cryptoPublicKey, NISTObjectIdentifiers.id_aes128_wrap.getId(),
SymmetricKeyAlgorithmTags.AES_128, sessionInfo, "X25519withSHA256HKDF", (kpGen) -> kpGen.initialize(255, random),
(ephPubEncoding) -> ephPubEncoding);
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
{
- return getEncryptSessionInfo_25519or448("X448", cryptoPublicKey, NISTObjectIdentifiers.id_aes256_wrap.getId(),
+ return getEncryptSessionInfo_25519or448(pubKey.getPublicKeyPacket().getKey().getEncoded(), "X448", cryptoPublicKey, NISTObjectIdentifiers.id_aes256_wrap.getId(),
SymmetricKeyAlgorithmTags.AES_256, sessionInfo, "X448withSHA512HKDF", (kpGen) -> kpGen.initialize(448, random),
(ephPubEncoding) -> ephPubEncoding);
}
@@ -180,24 +182,17 @@ private interface EphPubEncoding
byte[] getEphPubEncoding(byte[] publicKeyData);
}
- @FunctionalInterface
- private interface CheckAlgorithmName
- {
- String getAlgorithmName(PublicKeyPacket pubKeyData);
- }
-
- private byte[] getEncryptSessionInfo(PGPPublicKey pubKey, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
- int symmetricKeyAlgorithm, byte[] sessionInfo, KeyPairGeneratorOperation kpOperation,
- EphPubEncoding getEncoding, CheckAlgorithmName checkAlgorithmName)
+ private byte[] getEncryptSessionInfo(PublicKeyPacket pubKeyPacket, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
+ int symmetricKeyAlgorithm, byte[] sessionInfo, String agreementName, KeyPairGeneratorOperation kpOperation,
+ EphPubEncoding getEncoding)
throws GeneralSecurityException, IOException, PGPException
{
- PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
new JcaKeyFingerprintCalculator()));
KeyPairGenerator kpGen = helper.createKeyPairGenerator(algorithmName);
kpOperation.initialize(kpGen);
KeyPair ephKP = kpGen.generateKeyPair();
- KeyAgreement agreement = helper.createKeyAgreement(checkAlgorithmName.getAlgorithmName(pubKeyPacket));
+ KeyAgreement agreement = helper.createKeyAgreement(agreementName);
agreement.init(ephKP.getPrivate(), ukmSpec);
agreement.doPhase(cryptoPublicKey, true);
Key secret = agreement.generateSecret(keyEncryptionOID);
@@ -220,7 +215,7 @@ private byte[] getEncryptSessionInfo(PGPPublicKey pubKey, String algorithmName,
* algorithm used MUST be AES-128, AES-192 or AES-256 (algorithm ID 7, 8
* or 9).
*/
- private byte[] getEncryptSessionInfo_25519or448(String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
+ private byte[] getEncryptSessionInfo_25519or448(byte[] pubKey, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
int symmetricKeyAlgorithm, byte[] sessionInfo, String agreementAlgorithmName,
KeyPairGeneratorOperation kpOperation, EphPubEncoding getEncoding)
throws GeneralSecurityException, IOException, PGPException
@@ -232,8 +227,9 @@ private byte[] getEncryptSessionInfo_25519or448(String algorithmName, PublicKey
byte[] ephPubEncoding = getEncoding.getEphPubEncoding(SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes());
KeyAgreement agreement = helper.createKeyAgreement(agreementAlgorithmName);
- agreement.init(ephKP.getPrivate());
+ agreement.init(ephKP.getPrivate(), new UserKeyingMaterialSpec(Arrays.concatenate(pubKey, ephPubEncoding)));//, HKDFParameters.defaultParameters(Arrays.concatenate(cryptoPublicKey.getEncoded(), ephKP.getPublic().getEncoded())));
agreement.doPhase(cryptoPublicKey, true);
+
Key secret = agreement.generateSecret(keyEncryptionOID);
//No checksum
byte[] paddedSessionData = new byte[sessionInfo.length - 3];
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index 326d5bd030..fad8b245b0 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -257,10 +257,11 @@ public void testKeyRings()
throws Exception
{
System.setProperty("enableCamelliaKeyWrapping", "True");
+ keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+
keyringTest("EdDSA","Ed448", PublicKeyAlgorithmTags.Ed448, "XDH","X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.Ed25519, "XDH","X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
index 52ec8f2de7..bc274a07d1 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -25,6 +25,7 @@
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.DerivationFunction;
+import org.bouncycastle.crypto.agreement.X448Agreement;
import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator;
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
@@ -352,7 +353,18 @@ private byte[] getSharedSecretBytes(byte[] secret, String oidAlgorithm, int keyS
}
else if (kdf instanceof HKDFBytesGenerator)
{
- kdf.init(HKDFParameters.skipExtractParameters(secret, null));
+ byte[] info = null;
+ if (secret.length == 56)
+ {
+ //X448Agreement
+ info = "OpenPGP X448".getBytes();
+ }
+ else if (secret.length == 32)
+ {
+ //X25519Agreement
+ info = "OpenPGP X25519".getBytes();
+ }
+ kdf.init(HKDFParameters.skipExtractParameters(Arrays.concatenate(ukmParameters, secret), info));
}
else
{
From 58de5a84b465f3f7d7030ec000b70cf416a2492d Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 27 Feb 2024 11:37:02 +1030
Subject: [PATCH 0101/1846] Refactor codes around X25519 and X448
---
.../openpgp/PGPPublicKeyEncryptedData.java | 8 +-
.../bouncycastle/openpgp/PGPSecretKey.java | 3 +-
...PublicKeyKeyEncryptionMethodGenerator.java | 101 +-----------------
.../operator/bc/BcPGPKeyConverter.java | 26 ++---
...PublicKeyKeyEncryptionMethodGenerator.java | 11 +-
.../operator/jcajce/JcaPGPKeyConverter.java | 6 +-
...PublicKeyKeyEncryptionMethodGenerator.java | 63 ++++++-----
7 files changed, 55 insertions(+), 163 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java
index ddf5bfa68c..792bd3ef19 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPPublicKeyEncryptedData.java
@@ -99,14 +99,14 @@ public PGPSessionKey getSessionKey(
throws PGPException
{
byte[] sessionData = dataDecryptorFactory.recoverSessionData(keyData.getAlgorithm(), keyData.getEncSessionKey());
- if (!(keyData.getAlgorithm() == PublicKeyAlgorithmTags.X25519 || keyData.getAlgorithm() == PublicKeyAlgorithmTags.X448) && !confirmCheckSum(sessionData))
- {
- throw new PGPKeyValidationException("key checksum failed");
- }
if (keyData.getAlgorithm() == PublicKeyAlgorithmTags.X25519 || keyData.getAlgorithm() == PublicKeyAlgorithmTags.X448)
{
return new PGPSessionKey(sessionData[0] & 0xff, Arrays.copyOfRange(sessionData, 1, sessionData.length));
}
+ if (!confirmCheckSum(sessionData))
+ {
+ throw new PGPKeyValidationException("key checksum failed");
+ }
return new PGPSessionKey(sessionData[0] & 0xff, Arrays.copyOfRange(sessionData, 1, sessionData.length - 2));
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
index fdc654c02e..fecddf9702 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPSecretKey.java
@@ -404,8 +404,7 @@ public boolean isSigningKey()
return ((algorithm == PGPPublicKey.RSA_GENERAL) || (algorithm == PGPPublicKey.RSA_SIGN)
|| (algorithm == PGPPublicKey.DSA) || (algorithm == PGPPublicKey.ECDSA) || (algorithm == PGPPublicKey.EDDSA_LEGACY)
- || (algorithm == PGPPublicKey.ELGAMAL_GENERAL) || (algorithm == PGPPublicKey.Ed448) || (algorithm == PGPPublicKey.X448)
- || (algorithm == PGPPublicKey.Ed25519) || (algorithm == PGPPublicKey.X25519));
+ || (algorithm == PGPPublicKey.ELGAMAL_GENERAL) || (algorithm == PGPPublicKey.Ed448) || (algorithm == PGPPublicKey.Ed25519));
}
/**
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
index a87d357fc9..0d9b46ca6a 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PublicKeyKeyEncryptionMethodGenerator.java
@@ -1,20 +1,11 @@
package org.bouncycastle.openpgp.operator;
import org.bouncycastle.bcpg.ContainedPacket;
-import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.MPInteger;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyEncSessionPacket;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
-import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
-import org.bouncycastle.crypto.hpke.HPKE;
-import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
-import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Properties;
import java.io.IOException;
@@ -195,7 +186,7 @@ protected static byte[] getSessionInfo(byte[] ephPubEncoding, byte[] c)
return rv;
}
- protected static byte[] getSessionInfo_25519or448(byte[] VB, int sysmmetricKeyAlgorithm, byte[] c)
+ protected static byte[] getSessionInfo(byte[] VB, int sysmmetricKeyAlgorithm, byte[] c)
{
byte[] rv = new byte[VB.length + 2 + c.length];
System.arraycopy(VB, 0, rv, 0, VB.length);
@@ -204,94 +195,4 @@ protected static byte[] getSessionInfo_25519or448(byte[] VB, int sysmmetricKeyAl
System.arraycopy(c, 0, rv, VB.length + 2, c.length);
return rv;
}
-
- protected byte[] getHKDF(int hashAlgorithm, byte[] pubKeyPacket, byte[] secret, byte[] ephPubEncoding)
- {
- HKDF hkdf = new HKDF(hashAlgorithm);
- return hkdf.Extract(null, Arrays.concatenate(pubKeyPacket, secret, ephPubEncoding));
- }
-
- static class HKDF
- {
- private final HKDFBytesGenerator kdf;
- private final int hashLength;
-
- HKDF(int kdfId)
- {
- Digest hash;
-
- switch (kdfId)
- {
- case HashAlgorithmTags.SHA256:
- hash = new SHA256Digest();
- break;
- case HashAlgorithmTags.SHA384:
- hash = new SHA384Digest();
- break;
- case HashAlgorithmTags.SHA512:
- hash = new SHA512Digest();
- break;
- default:
- throw new IllegalArgumentException("invalid kdf id");
- }
- kdf = new HKDFBytesGenerator(hash);
- hashLength = hash.getDigestSize();
- }
-
- int getHashSize()
- {
- return hashLength;
- }
-
- /**
- * HKDF-Extract algorithm implementation.
- *
- * This method extracts a pseudorandom key (PRK) using the HKDF-Extract function.
- *
- * @param salt optional salt value (a non-secret random value); if not provided,
- * it is set to a byte array of HashLen zeros.
- * @param ikm input keying material
- * @return a pseudorandom key (of HashLen bytes) generated using HMAC-Hash(salt, IKM)
- */
- public byte[] Extract(byte[] salt, byte[] ikm)
- {
- if (salt == null)
- {
- salt = new byte[hashLength];
- }
-
- return kdf.extractPRK(salt, ikm);
- }
-
- /**
- * HKDF-Expand algorithm implementation.
- *
- * This method expands a pseudorandom key (PRK) into output keying material (OKM)
- * using the HKDF-Expand function.
- *
- * @param prk a pseudorandom key of at least HashLen bytes
- * (usually, the output from the extract step)
- * @param info optional context and application-specific information
- * (can be a zero-length byte array)
- * @param L length of output keying material in bytes
- * (<= 65536*HashLen)
- * @return output keying material (of L bytes) generated using HKDF-Expand
- * @throws IllegalArgumentException if L is larger than 65536*HashLen
- */
- public byte[] Expand(byte[] prk, byte[] info, int L)
- {
- if (L > (1 << 16))
- {
- throw new IllegalArgumentException("Expand length cannot be larger than 2^16");
- }
-
- kdf.init(HKDFParameters.skipExtractParameters(prk, info));
-
- byte[] rv = new byte[L];
-
- kdf.generateBytes(rv, 0, rv.length);
-
- return rv;
- }
- }
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
index 197b3bbb97..d82c1d81c2 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java
@@ -26,6 +26,7 @@
import org.bouncycastle.bcpg.EdSecretBCPGKey;
import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
+import org.bouncycastle.bcpg.OctetArrayBCPGKey;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.RSAPublicBCPGKey;
@@ -225,15 +226,11 @@ public AsymmetricKeyParameter getPublicKey(PGPPublicKey publicKey)
}
case PublicKeyAlgorithmTags.X25519:
{
- X25519PublicBCPGKey eddsaK = (X25519PublicBCPGKey)publicPk.getKey();
- byte[] pEnc = eddsaK.getKey().clone();
- return implGetPublicKeyX509(EdECObjectIdentifiers.id_X25519, pEnc, 0);
+ return implGetPublicKeyX509((X25519PublicBCPGKey)publicPk.getKey(), EdECObjectIdentifiers.id_X25519);
}
case PublicKeyAlgorithmTags.X448:
{
- X448PublicBCPGKey eddsaK = (X448PublicBCPGKey)publicPk.getKey();
- byte[] pEnc = eddsaK.getKey().clone();
- return implGetPublicKeyX509(EdECObjectIdentifiers.id_X448, pEnc, 0);
+ return implGetPublicKeyX509((X448PublicBCPGKey)publicPk.getKey(), EdECObjectIdentifiers.id_X448);
}
case PublicKeyAlgorithmTags.ECDSA:
return implGetPublicKeyEC((ECDSAPublicBCPGKey)publicPk.getKey());
@@ -262,15 +259,11 @@ else if (eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448))
}
case PublicKeyAlgorithmTags.Ed25519:
{
- Ed25519PublicBCPGKey eddsaK = (Ed25519PublicBCPGKey)publicPk.getKey();
- byte[] pEnc = eddsaK.getKey().clone();
- return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed25519, pEnc, 0);
+ return implGetPublicKeyX509((Ed25519PublicBCPGKey)publicPk.getKey(), EdECObjectIdentifiers.id_Ed25519);
}
case PublicKeyAlgorithmTags.Ed448:
{
- Ed448PublicBCPGKey eddsaK = (Ed448PublicBCPGKey)publicPk.getKey();
- byte[] pEnc = eddsaK.getKey().clone();
- return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed448, pEnc, 0);
+ return implGetPublicKeyX509((Ed448PublicBCPGKey)publicPk.getKey(), EdECObjectIdentifiers.id_Ed448);
}
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
@@ -352,7 +345,6 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pubKey, AsymmetricKeyParameter pr
ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters)privKey;
return new ElGamalSecretBCPGKey(esK.getX());
}
-
case PublicKeyAlgorithmTags.RSA_ENCRYPT:
case PublicKeyAlgorithmTags.RSA_GENERAL:
case PublicKeyAlgorithmTags.RSA_SIGN:
@@ -457,6 +449,14 @@ else if (pubKey instanceof X448PublicKeyParameters)
}
}
+ private AsymmetricKeyParameter implGetPublicKeyX509(OctetArrayBCPGKey eddsaK, ASN1ObjectIdentifier algorithm)
+ throws IOException
+ {
+ byte[] pEnc = eddsaK.getKey().clone();
+ return PublicKeyFactory.createKey(new SubjectPublicKeyInfo(new AlgorithmIdentifier(algorithm),
+ Arrays.copyOfRange(pEnc, 0, pEnc.length)));
+ }
+
private AsymmetricKeyParameter implGetPublicKeyX509(ASN1ObjectIdentifier algorithm, byte[] pEnc, int pEncOff)
throws IOException
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index 1a22e34805..a1aa277ca0 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -158,9 +158,7 @@ private byte[] encryptSessionInfo(byte[] sessionInfo, byte[] secret,
byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
- byte[] C = getWrapper(symmetricKeyAlgorithm, key, paddedSessionData);
-
- return getSessionInfo(ephPubEncoding, C);
+ return getSessionInfo(ephPubEncoding, getWrapper(symmetricKeyAlgorithm, key, paddedSessionData));
}
private byte[] encryptSessionInfo(PublicKeyPacket pubKeyPacket, byte[] sessionInfo, int hashAlgorithm, int symmetricKeyAlgorithm,
@@ -179,9 +177,7 @@ private byte[] encryptSessionInfo(PublicKeyPacket pubKeyPacket, byte[] sessionIn
byte[] sessionData = new byte[sessionInfo.length - 3];
System.arraycopy(sessionInfo, 1, sessionData, 0, sessionData.length);
- byte[] C = getWrapper(symmetricKeyAlgorithm, key, sessionData);
-
- return getSessionInfo_25519or448(ephPubEncoding, sessionInfo[0], C);
+ return getSessionInfo(ephPubEncoding, sessionInfo[0], getWrapper(symmetricKeyAlgorithm, key, sessionData));
}
private byte[] getWrapper(int symmetricKeyAlgorithm, KeyParameter key, byte[] sessionData)
@@ -189,8 +185,7 @@ private byte[] getWrapper(int symmetricKeyAlgorithm, KeyParameter key, byte[] se
{
Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
c.init(true, new ParametersWithRandom(key, random));
- byte[] C = c.wrap(sessionData, 0, sessionData.length);
- return C;
+ return c.wrap(sessionData, 0, sessionData.length);
}
private AsymmetricCipherKeyPair getAsymmetricCipherKeyPair(AsymmetricCipherKeyPairGenerator gen, KeyGenerationParameters parameters)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
index 0e789636a3..66e0179a34 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
@@ -216,8 +216,9 @@ public PrivateKey getPrivateKey(PGPPrivateKey privKey)
X448SecretBCPGKey.LENGTH, Arrays.reverseInPlace(privPk.getEncoded())));
}
case PublicKeyAlgorithmTags.ECDSA:
+ {
return implGetPrivateKeyEC("ECDSA", (ECDSAPublicBCPGKey)pubPk.getKey(), (ECSecretBCPGKey)privPk);
-
+ }
case PublicKeyAlgorithmTags.EDDSA_LEGACY:
{
return implGeneratePrivate("EdDSA", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519,
@@ -438,14 +439,12 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey)
{
return getPrivateBCPGKey(privKey, Ed448SecretBCPGKey::new);
}
-
case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
{
DHPrivateKey esK = (DHPrivateKey)privKey;
return new ElGamalSecretBCPGKey(esK.getX());
}
-
case PublicKeyAlgorithmTags.RSA_ENCRYPT:
case PublicKeyAlgorithmTags.RSA_GENERAL:
case PublicKeyAlgorithmTags.RSA_SIGN:
@@ -453,7 +452,6 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey)
RSAPrivateCrtKey rsK = (RSAPrivateCrtKey)privKey;
return new RSASecretBCPGKey(rsK.getPrivateExponent(), rsK.getPrimeP(), rsK.getPrimeQ());
}
-
default:
throw new PGPException("unknown key class");
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index aad7415048..5f55bab80d 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -128,15 +128,13 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
{
- return getEncryptSessionInfo_25519or448(pubKey.getPublicKeyPacket().getKey().getEncoded(), "X25519", cryptoPublicKey, NISTObjectIdentifiers.id_aes128_wrap.getId(),
- SymmetricKeyAlgorithmTags.AES_128, sessionInfo, "X25519withSHA256HKDF", (kpGen) -> kpGen.initialize(255, random),
- (ephPubEncoding) -> ephPubEncoding);
+ return getEncryptSessionInfo(pubKey, "X25519", cryptoPublicKey, NISTObjectIdentifiers.id_aes128_wrap.getId(),
+ SymmetricKeyAlgorithmTags.AES_128, sessionInfo, "X25519withSHA256HKDF", 255);
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
{
- return getEncryptSessionInfo_25519or448(pubKey.getPublicKeyPacket().getKey().getEncoded(), "X448", cryptoPublicKey, NISTObjectIdentifiers.id_aes256_wrap.getId(),
- SymmetricKeyAlgorithmTags.AES_256, sessionInfo, "X448withSHA512HKDF", (kpGen) -> kpGen.initialize(448, random),
- (ephPubEncoding) -> ephPubEncoding);
+ return getEncryptSessionInfo(pubKey, "X448", cryptoPublicKey, NISTObjectIdentifiers.id_aes256_wrap.getId(),
+ SymmetricKeyAlgorithmTags.AES_256, sessionInfo, "X448withSHA512HKDF", 448);
}
else
{
@@ -187,23 +185,16 @@ private byte[] getEncryptSessionInfo(PublicKeyPacket pubKeyPacket, String algori
EphPubEncoding getEncoding)
throws GeneralSecurityException, IOException, PGPException
{
- UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
- new JcaKeyFingerprintCalculator()));
KeyPairGenerator kpGen = helper.createKeyPairGenerator(algorithmName);
kpOperation.initialize(kpGen);
KeyPair ephKP = kpGen.generateKeyPair();
- KeyAgreement agreement = helper.createKeyAgreement(agreementName);
- agreement.init(ephKP.getPrivate(), ukmSpec);
- agreement.doPhase(cryptoPublicKey, true);
- Key secret = agreement.generateSecret(keyEncryptionOID);
+ UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
+ new JcaKeyFingerprintCalculator()));
+ Key secret = getSecret(cryptoPublicKey, keyEncryptionOID, agreementName, ukmSpec, ephKP);
byte[] ephPubEncoding = getEncoding.getEphPubEncoding(SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes());
byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
- Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
- c.init(Cipher.WRAP_MODE, secret, random);
- byte[] C = c.wrap(new SecretKeySpec(paddedSessionData, PGPUtil.getSymmetricCipherName(sessionInfo[0])));
-
- return getSessionInfo(ephPubEncoding, C);
+ return getSessionInfo(ephPubEncoding, getWrapper(symmetricKeyAlgorithm, sessionInfo, secret, paddedSessionData));
}
/**
@@ -215,30 +206,38 @@ private byte[] getEncryptSessionInfo(PublicKeyPacket pubKeyPacket, String algori
* algorithm used MUST be AES-128, AES-192 or AES-256 (algorithm ID 7, 8
* or 9).
*/
- private byte[] getEncryptSessionInfo_25519or448(byte[] pubKey, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
- int symmetricKeyAlgorithm, byte[] sessionInfo, String agreementAlgorithmName,
- KeyPairGeneratorOperation kpOperation, EphPubEncoding getEncoding)
+ private byte[] getEncryptSessionInfo(PGPPublicKey pgpPublicKey, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
+ int symmetricKeyAlgorithm, byte[] sessionInfo, String agreementAlgorithmName, int keySize)
throws GeneralSecurityException, IOException, PGPException
{
KeyPairGenerator kpGen = helper.createKeyPairGenerator(algorithmName);
- kpOperation.initialize(kpGen);
+ kpGen.initialize(keySize, random);
KeyPair ephKP = kpGen.generateKeyPair();
- byte[] ephPubEncoding = getEncoding.getEphPubEncoding(SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes());
+ byte[] ephPubEncoding = SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes();
+ UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(Arrays.concatenate(pgpPublicKey.getPublicKeyPacket().getKey().getEncoded(), ephPubEncoding));
+ Key secret = getSecret(cryptoPublicKey, keyEncryptionOID, agreementAlgorithmName, ukmSpec, ephKP);
+ //No checksum or padding
+ byte[] sessionData = new byte[sessionInfo.length - 3];
+ System.arraycopy(sessionInfo, 1, sessionData, 0, sessionData.length);
- KeyAgreement agreement = helper.createKeyAgreement(agreementAlgorithmName);
- agreement.init(ephKP.getPrivate(), new UserKeyingMaterialSpec(Arrays.concatenate(pubKey, ephPubEncoding)));//, HKDFParameters.defaultParameters(Arrays.concatenate(cryptoPublicKey.getEncoded(), ephKP.getPublic().getEncoded())));
- agreement.doPhase(cryptoPublicKey, true);
+ return getSessionInfo(ephPubEncoding, sessionInfo[0], getWrapper(symmetricKeyAlgorithm, sessionInfo, secret, sessionData));
+ }
- Key secret = agreement.generateSecret(keyEncryptionOID);
- //No checksum
- byte[] paddedSessionData = new byte[sessionInfo.length - 3];
- System.arraycopy(sessionInfo, 1, paddedSessionData, 0, paddedSessionData.length);
+ private Key getSecret(PublicKey cryptoPublicKey, String keyEncryptionOID, String agreementName, UserKeyingMaterialSpec ukmSpec, KeyPair ephKP)
+ throws GeneralSecurityException
+ {
+ KeyAgreement agreement = helper.createKeyAgreement(agreementName);
+ agreement.init(ephKP.getPrivate(), ukmSpec);
+ agreement.doPhase(cryptoPublicKey, true);
+ return agreement.generateSecret(keyEncryptionOID);
+ }
+ private byte[] getWrapper(int symmetricKeyAlgorithm, byte[] sessionInfo, Key secret, byte[] sessionData)
+ throws PGPException, InvalidKeyException, IllegalBlockSizeException
+ {
Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
c.init(Cipher.WRAP_MODE, secret, random);
- byte[] C = c.wrap(new SecretKeySpec(paddedSessionData, PGPUtil.getSymmetricCipherName(sessionInfo[0])));
-
- return getSessionInfo_25519or448(ephPubEncoding, sessionInfo[0], C);
+ return c.wrap(new SecretKeySpec(sessionData, PGPUtil.getSymmetricCipherName(sessionInfo[0])));
}
}
From 20f2634ba8688a9e55f71f7de9fd443599647166 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 27 Feb 2024 11:57:37 +1030
Subject: [PATCH 0102/1846] Refactor codes around X25519 and X448
---
.../bc/BcPublicKeyDataDecryptorFactory.java | 48 +++++++++----------
1 file changed, 22 insertions(+), 26 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index 10617caa18..f4bd164a27 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -64,15 +64,13 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
- return getSessionData(secKeyData, privKey, X25519PublicBCPGKey.LENGTH, HashAlgorithmTags.SHA256,
- SymmetricKeyAlgorithmTags.AES_128, new X25519Agreement(),
- X25519PublicKeyParameters::new);
+ return getSessionData(secKeyData[0], privKey, X25519PublicBCPGKey.LENGTH, HashAlgorithmTags.SHA256,
+ SymmetricKeyAlgorithmTags.AES_128, new X25519Agreement(), X25519PublicKeyParameters::new);
}
else if (keyAlgorithm == PublicKeyAlgorithmTags.X448)
{
- return getSessionData(secKeyData, privKey, X448PublicBCPGKey.LENGTH, HashAlgorithmTags.SHA512,
- SymmetricKeyAlgorithmTags.AES_256, new X448Agreement(),
- X448PublicKeyParameters::new);
+ return getSessionData(secKeyData[0], privKey, X448PublicBCPGKey.LENGTH, HashAlgorithmTags.SHA512,
+ SymmetricKeyAlgorithmTags.AES_256, new X448Agreement(), X448PublicKeyParameters::new);
}
else if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
{
@@ -80,19 +78,13 @@ else if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
byte[] pEnc;
byte[] keyEnc;
int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
- if ((2 + pLen + 1) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
+ assertOutOfRange(2 + pLen + 1, enc);
pEnc = new byte[pLen];
System.arraycopy(enc, 2, pEnc, 0, pLen);
int keyLen = enc[pLen + 2] & 0xff;
- if ((2 + pLen + 1 + keyLen) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
+ assertOutOfRange(2 + pLen + 1 + keyLen, enc);
keyEnc = new byte[keyLen];
System.arraycopy(enc, 2 + pLen + 1, keyEnc, 0, keyLen);
@@ -131,7 +123,7 @@ else if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
- return PGPPad.unpadSessionData(getUnwrap(keyEnc, symmetricKeyAlgorithm, key));
+ return PGPPad.unpadSessionData(unwrapSessionData(keyEnc, symmetricKeyAlgorithm, key));
}
else
{
@@ -224,20 +216,15 @@ private interface PublicKeyParametersOperation
AsymmetricKeyParameter getPublicKeyParameters(byte[] pEnc, int pEncOff);
}
- private byte[] getSessionData(byte[][] secKeyData, AsymmetricKeyParameter privKey, int pLen, int hashAlgorithm,
- int symmetricKeyAlgorithm, RawAgreement agreement, PublicKeyParametersOperation pkp
- )
+ private byte[] getSessionData(byte[] enc, AsymmetricKeyParameter privKey, int pLen, int hashAlgorithm,
+ int symmetricKeyAlgorithm, RawAgreement agreement, PublicKeyParametersOperation pkp)
throws PGPException, InvalidCipherTextException
{
- byte[] enc = secKeyData[0];
byte[] pEnc = new byte[pLen];
byte[] keyEnc;
System.arraycopy(enc, 0, pEnc, 0, pLen);
int keyLen = enc[pLen] & 0xff;
- if ((pLen + 1 + keyLen) > enc.length)
- {
- throw new PGPException("encoded length out of range");
- }
+ assertOutOfRange(pLen + 1 + keyLen, enc);
keyEnc = new byte[keyLen - 1];
System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
byte[] secret = getSecret(agreement, privKey, pkp.getPublicKeyParameters(pEnc, 0));
@@ -246,7 +233,7 @@ private byte[] getSessionData(byte[][] secKeyData, AsymmetricKeyParameter privKe
KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(Arrays.concatenate(pgpPrivKey.getPublicKeyPacket().getKey().getEncoded(), pEnc, secret)));
- return Arrays.concatenate(new byte[]{enc[pLen + 1]}, getUnwrap(keyEnc, symmetricKeyAlgorithm, key));
+ return Arrays.concatenate(new byte[]{enc[pLen + 1]}, unwrapSessionData(keyEnc, symmetricKeyAlgorithm, key));
}
private static byte[] getSecret(RawAgreement agreement, AsymmetricKeyParameter privKey, AsymmetricKeyParameter ephPub)
@@ -257,11 +244,20 @@ private static byte[] getSecret(RawAgreement agreement, AsymmetricKeyParameter p
return secret;
}
- private static byte[] getUnwrap(byte[] keyEnc, int symmetricKeyAlgorithm, KeyParameter key)
+ private static byte[] unwrapSessionData(byte[] keyEnc, int symmetricKeyAlgorithm, KeyParameter key)
throws PGPException, InvalidCipherTextException
{
Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
c.init(false, key);
return c.unwrap(keyEnc, 0, keyEnc.length);
}
-}
+
+ private static void assertOutOfRange(int pLen, byte[] enc)
+ throws PGPException
+ {
+ if (pLen > enc.length)
+ {
+ throw new PGPException("encoded length out of range");
+ }
+ }
+}
\ No newline at end of file
From ad0d6da0a76b18043b51e10d5a0a4bbdaf7687a6 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 27 Feb 2024 13:04:58 +1030
Subject: [PATCH 0103/1846] TODO task: unable to parse the test vector for
Ed25519 key as the decrypted message is not correct.
---
.../org/bouncycastle/gpg/SExprParser.java | 3 +-
.../openpgp/test/PGPGeneralTest.java | 42 ++++++++++++++++++-
2 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/gpg/SExprParser.java b/pg/src/main/java/org/bouncycastle/gpg/SExprParser.java
index c1779ec4d8..0c6dd50dc7 100644
--- a/pg/src/main/java/org/bouncycastle/gpg/SExprParser.java
+++ b/pg/src/main/java/org/bouncycastle/gpg/SExprParser.java
@@ -84,7 +84,8 @@ public SExprParser(PGPDigestCalculatorProvider digestProvider)
private static final Map elgLabels = new HashMap()
{{
- //put(ProtectionModeTags.OPENPGP_S2K3_OCB_AES, new String[]{"elg", "p", "q", "g", "y", "protected-at"});
+ //https://github.com/gpg/gnupg/blob/40227e42ea0f2f1cf9c9f506375446648df17e8d/agent/cvt-openpgp.c#L217
+ put(ProtectionModeTags.OPENPGP_S2K3_OCB_AES, new String[]{"elg", "p", "q", "g", "y", "protected-at"});
put(ProtectionModeTags.OPENPGP_S2K3_SHA1_AES_CBC, new String[]{"elg", "p", "q", "g", "y", "x", "protected-at"});
}};
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java
index 5946b6975d..f45efb79ed 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java
@@ -800,6 +800,28 @@ public class PGPGeneralTest
" B1EB657029F2A94F35D09CD1514A099203B46CDF1AEECA99AE6898B5489DE85DDA55A7\n" +
" 9D8FD94539ECCCB95D23A6#)(protected-at \"20211022T000110\")))\n").getBytes();
+ //https://github.com/bcgit/bc-java/issues/1590
+ byte[] curveed25519 = ( /* OpenSSH 6.7p1 generated key: */
+ "(protected-private-key" +
+ "(ecc" +
+ "(curve Ed25519)" +
+ "(flags eddsa)" +
+ "(q #40A3577AA7830C50EBC15B538E9505DB2F0D2FFCD57EA477DD83dcaea530f3c277#)" +
+ "(protected openpgp-s2k3-sha1-aes-cbc" +
+ "(\n" +
+ "(sha1 #FA8123F1A37CBC1F# \"3812352\")" +
+ "#7671C7387E2DD931CC62C35CBBE08A28#)" +
+ "#75e928f4698172b61dffe9ef2ada1d3473f690f3879c5386e2717e5b2fa46884" +
+ "b189ee409827aab0ff37f62996e040b5fa7e75fc4d8152c8734e2e648dff90c9" +
+ "e8c3e39ea7485618d05c34b1b74ff59676e9a3d932245cc101b5904777a09f86#)" +
+ "(protected-at \"20150928T050210\")" +
+ ")" +
+ "(comment \"eddsa w/o comment\")" +
+ ")" + /* Passphrase="abc" */
+ "MD5:f1:fa:c8:a6:40:bb:b9:a1:65:d7:62:65:ac:26:78:0e" +
+ "SHA256:yhwBfYnTOnSXcWf1EOPo+oIIpNJ6w/bG36udZ96MmsQ" +
+ "0" /* The fingerprint works in FIPS mode because ECC algorithm is enabled */
+ ).getBytes();
char[] dsaPass = "hello world".toCharArray();
byte[] dsaElgamalOpen = ("Created: 20211020T050343\n" +
@@ -975,6 +997,7 @@ public String getName()
public void performTest()
throws Exception
{
+ //testEd25519();
// Tests for OpenedPGPKeyData
testOpenedPGPKeyData();
testECNistCurves();
@@ -1855,7 +1878,7 @@ public void testParseSecretKeyFromSExpr()
PGPPublicKeyEncryptedData encP = (PGPPublicKeyEncryptedData)encList.get(0);
PGPPublicKey publicKey = new JcaPGPPublicKeyRing(testPubKey2).getPublicKey(encP.getKeyID());
JcaPGPDigestCalculatorProviderBuilder digBuild = new JcaPGPDigestCalculatorProviderBuilder();
- PGPSecretKey secretKey = PGPSecretKey.parseSecretKeyFromSExpr(new ByteArrayInputStream(sExprKeySub), new JcePBEProtectionRemoverFactory("test".toCharArray(),digBuild.build()).setProvider("BC"), publicKey);
+ PGPSecretKey secretKey = PGPSecretKey.parseSecretKeyFromSExpr(new ByteArrayInputStream(sExprKeySub), new JcePBEProtectionRemoverFactory("test".toCharArray(), digBuild.build()).setProvider("BC"), publicKey);
InputStream clear = encP.getDataStream(new JcePublicKeyDataDecryptorFactoryBuilder().setProvider("BC").setContentProvider("BC").build(secretKey.extractPrivateKey(null)));
PGPObjectFactory plainFact = new PGPObjectFactory(clear, new BcKeyFingerprintCalculator());
PGPCompressedData cData = (PGPCompressedData)plainFact.nextObject();
@@ -3199,4 +3222,21 @@ public void testOpenedPGPKeyData()
isTrue("unable to resolve parameters for ", e.getMessage().contains("unable to resolve parameters for "));
}
}
+
+ public void testEd25519()
+ throws Exception
+ {
+ //TODO: Invalid key?
+ byte[] data = curveed25519;
+ ByteArrayInputStream bin = new ByteArrayInputStream(data);
+// isTrue(PGPSecretKeyParser.isExtendedSExpression(bin));
+ JcaPGPDigestCalculatorProviderBuilder digBuild = new JcaPGPDigestCalculatorProviderBuilder();
+ OpenedPGPKeyData openedPGPKeyData = PGPSecretKeyParser.parse(bin, 10);
+ ExtendedPGPSecretKey secretKey = openedPGPKeyData.getKeyData(
+ null,
+ digBuild.build(),
+ new JcePBEProtectionRemoverFactory("foobar".toCharArray(), digBuild.build()),
+ new JcaKeyFingerprintCalculator(), 10);
+ PGPKeyPair pair = secretKey.extractKeyPair(null);
+ }
}
From 063551862febb4b77bb0efafbcfcc08e67d08b2a Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 27 Feb 2024 13:34:06 +1030
Subject: [PATCH 0104/1846] Remove some unused codes
---
.../bouncycastle/bcpg/Ed448PublicBCPGKey.java | 1 -
.../bouncycastle/bcpg/OctetArrayBCPGKey.java | 4 --
.../openpgp/operator/RFC6637Utils.java | 52 +++----------------
.../openpgp/test/PGPGeneralTest.java | 46 ----------------
4 files changed, 6 insertions(+), 97 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/Ed448PublicBCPGKey.java b/pg/src/main/java/org/bouncycastle/bcpg/Ed448PublicBCPGKey.java
index f66a00a4de..93b0021a34 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/Ed448PublicBCPGKey.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/Ed448PublicBCPGKey.java
@@ -10,7 +10,6 @@ public class Ed448PublicBCPGKey
public Ed448PublicBCPGKey(BCPGInputStream in)
throws IOException
{
- //super(in);
super(LENGTH, in);
}
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java b/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java
index c5538ef6e1..483d41729b 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/OctetArrayBCPGKey.java
@@ -1,10 +1,6 @@
package org.bouncycastle.bcpg;
import java.io.IOException;
-import java.math.BigInteger;
-
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.util.Arrays;
/**
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
index 801bb603db..17eff075ef 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
@@ -15,16 +15,7 @@
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.bcpg.X25519PublicBCPGKey;
import org.bouncycastle.bcpg.X448PublicBCPGKey;
-import org.bouncycastle.crypto.Digest;
-import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.digests.SHA384Digest;
-import org.bouncycastle.crypto.digests.SHA512Digest;
-import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
-import org.bouncycastle.crypto.hpke.HPKE;
-import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.openpgp.PGPException;
-import org.bouncycastle.util.Arrays;
-import org.bouncycastle.util.Pack;
import org.bouncycastle.util.encoders.Hex;
@@ -114,50 +105,19 @@ public static byte[] createUserKeyingMaterial(PublicKeyPacket pubKeyData, KeyFin
throws IOException, PGPException
{
ByteArrayOutputStream pOut = new ByteArrayOutputStream();
- BCPGKey key = pubKeyData.getKey();
- ASN1ObjectIdentifier curveID;
- int hashAlgorithm, symmetricKeyAlgorithm;
- if (key instanceof X25519PublicBCPGKey)
- {
- curveID = CryptlibObjectIdentifiers.curvey25519;
- symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_128;
- hashAlgorithm = HashAlgorithmTags.SHA256;
- }
- else if (key instanceof X448PublicBCPGKey)
- {
- curveID = EdECObjectIdentifiers.id_X448;
- symmetricKeyAlgorithm = SymmetricKeyAlgorithmTags.AES_256;
- hashAlgorithm = HashAlgorithmTags.SHA512;
- }
- else
- {
- ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
- curveID = ecKey.getCurveOID();
- hashAlgorithm = ecKey.getHashAlgorithm();
- symmetricKeyAlgorithm = ecKey.getSymmetricKeyAlgorithm();
- byte[] encOid = curveID.getEncoded();
- pOut.write(encOid, 1, encOid.length - 1);
- pOut.write(pubKeyData.getAlgorithm());
- pOut.write(0x03);
- pOut.write(0x01);
- pOut.write(hashAlgorithm);
- pOut.write(symmetricKeyAlgorithm);
- pOut.write(ANONYMOUS_SENDER);
- pOut.write(fingerPrintCalculator.calculateFingerprint(pubKeyData));
-
- return pOut.toByteArray();
- }
-// HKDF hkdf = new HKDF(kdfId);
- byte[] encOid = curveID.getEncoded();
+ ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
+ byte[] encOid = ecKey.getCurveOID().getEncoded();
+
pOut.write(encOid, 1, encOid.length - 1);
pOut.write(pubKeyData.getAlgorithm());
pOut.write(0x03);
pOut.write(0x01);
- pOut.write(hashAlgorithm);
- pOut.write(symmetricKeyAlgorithm);
+ pOut.write(ecKey.getHashAlgorithm());
+ pOut.write(ecKey.getSymmetricKeyAlgorithm());
pOut.write(ANONYMOUS_SENDER);
pOut.write(fingerPrintCalculator.calculateFingerprint(pubKeyData));
+
return pOut.toByteArray();
}
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java
index f45efb79ed..9018276abb 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/PGPGeneralTest.java
@@ -2521,52 +2521,6 @@ public void testDSAElgamalOpen()
isTrue("does not have protected block", e.getMessage().contains("does not have protected block"));
}
- try
- {
- key = ("Created: 20211022T053140\n" +
- "Key: (protected-private-key (elg (p #00CD7275234699FE0D25FDBEE69DA2AA80\n" +
- " AAAB15906FACFC8F4EB5A9BAE23D22E5649199C119FB72951BD0FA717F51CFD7B904FD\n" +
- " BB1F0D0660938199976DA4447F54E91E2CC4B21F4BB162644EA43A3F27F7CAFF7D6355\n" +
- " 16E8640558E222EF20B55E8AF2AFD33D571092CE5C090E57DA3452484BC04398E24613\n" +
- " D593113F1F5CE7CA3229F5DFAFC1EFC47B725505E46A0EB9CC45FACFBEA6ECC6CA694E\n" +
- " D3781E011C48C66BBB6C1BA35DD810EF24CF7B92D9E9BCB0B0E19053CFA073AD2D9957\n" +
- " 270B3C55D60824F93EECBF8AF393F07C05BEA38636DFC6B6152424FAF5C0287435C145\n" +
- " B021E235AA30E2B063695EE01D6C696EAA381517E50A440D8AA00164B423#)(q\n" +
- " #00A4F8D3DC79F1F8388B9FF3F3A484568A76337BF968F05C207F5AF8E84F4B83C1#)\n" +
- " (g #32EC716A63D63CB69E17A678B9BC70686EA24AF4F96F46683E09ACF7EDE9839ADB\n" +
- " 914E61A38D151B28B65533362100B1D9D2948FD8617136FF82C8B61DF5A400B3D2A3E3\n" +
- " 2CEAF2B7DAEBF30D24CA3E681AC551F01EC366EECCDF1481B092E3534728D73211D962\n" +
- " 09069E8FA34395C94828D77F0FEF8E6DEFEA3687ED6267EB028007B84840E383E8B14C\n" +
- " AB93109FA414458E56F5BDAF7AB37ECB3E3FA8EDAED60B7323D3329FB3EA4E460FFA63\n" +
- " B9EC9836530B16710A0EA3A750BF646A48DA65E4144A9A7964513BF998755612791DC5\n" +
- " F840FAE54D34C44A62C1BE884774870BC6D0505FE5EE3F4B222194740E4CC639785E56\n" +
- " B93E17DCACBFE63703DE201DB3#)(y #1B1DAAA76ACF531DBC172304E6523C16B3E701\n" +
- " 2B8B3F0D37AFD9B2C8F63A2155F2CAAE34ADF7A8B068AB266AEE5A5598DD9BE116FA96\n" +
- " F855AA7AD74F780407F74255DC035339C28E1833E93D872EE73DE350E3E0B8AB1E9709\n" +
- " B835E58E6A5491383612A52EB4A3616C29418C0BE108739CC3D59BCF3B0299B283FEA6\n" +
- " 7E21A1909C2E02CD1BFE200F0B6EEE0BB8E4252B8F78711AD05C7056CE673ED81BE265\n" +
- " 60C0768AEC8121D5EB21EE6A8338CC35E306931D1B3516767E345B9C25DF7454C36C61\n" +
- " 739B193BC4998A47A4E5A4956FF525F322DA67B9DC6CFA468ADEBC82EBEEB7F35C4982\n" +
- " A2D347ED4ECB8605387161F03175A9D73659A34D97910B26F8027F#)(protected\n" +
- " openpgp-s2k3-ocb-aes ((sha1 #4F333DA86C1E7E55#\n" +
- " \"43860992\")#D8BD10519B004263EC2E35D4#)#57553ACF88CB775B65AAE3FAEB2480\n" +
- " F40BA80AFEA74DD1B9E59847B440733B3A83B062EAD3FDBF67996BA240B8504800C276\n" +
- " AAF1DE797066443807DDCE#)(protected-at \"20211022T053148\")))\n").getBytes();
- bin = new ByteArrayInputStream(key);
-
- openedPGPKeyData = PGPSecretKeyParser.parse(bin, 10);
- secretKey2 = (ExtendedPGPSecretKey)openedPGPKeyData.getKeyData(
- null,
- digBuild.build(),
- new JcePBEProtectionRemoverFactory("foobar".toCharArray(), digBuild.build()),
- new JcaKeyFingerprintCalculator(), 10);
- fail("no decryption support for protected elgamal keys");
- }
- catch (IllegalStateException e)
- {
- isTrue("no decryption support for protected elgamal keys", e.getMessage().contains("no decryption support for protected elgamal keys"));
- }
-
try
{
key = ("Created: 20211022T053140\n" +
From d9659327ed382e2d498ecd992104fb3724c1cc4b Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 27 Feb 2024 14:58:27 +1030
Subject: [PATCH 0105/1846] Changes around HKDF of X25519 and X448.
---
.../openpgp/operator/RFC6637Utils.java | 3 ---
.../bc/BcPublicKeyDataDecryptorFactory.java | 10 +++++-----
.../BcPublicKeyKeyEncryptionMethodGenerator.java | 8 ++++----
.../operator/bc/RFC6637KDFCalculator.java | 7 ++++---
.../JcePublicKeyDataDecryptorFactoryBuilder.java | 16 +++++++++-------
...JcePublicKeyKeyEncryptionMethodGenerator.java | 3 ++-
.../openpgp/test/OperatorBcTest.java | 3 ++-
.../asymmetric/edec/KeyAgreementSpi.java | 2 ++
.../asymmetric/util/BaseAgreementSpi.java | 14 ++------------
9 files changed, 30 insertions(+), 36 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
index 17eff075ef..4132038a39 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/RFC6637Utils.java
@@ -4,11 +4,8 @@
import java.io.IOException;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
-import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index f4bd164a27..bfeadca77d 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -65,12 +65,12 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
return getSessionData(secKeyData[0], privKey, X25519PublicBCPGKey.LENGTH, HashAlgorithmTags.SHA256,
- SymmetricKeyAlgorithmTags.AES_128, new X25519Agreement(), X25519PublicKeyParameters::new);
+ SymmetricKeyAlgorithmTags.AES_128, new X25519Agreement(), "X25519", X25519PublicKeyParameters::new);
}
else if (keyAlgorithm == PublicKeyAlgorithmTags.X448)
{
return getSessionData(secKeyData[0], privKey, X448PublicBCPGKey.LENGTH, HashAlgorithmTags.SHA512,
- SymmetricKeyAlgorithmTags.AES_256, new X448Agreement(), X448PublicKeyParameters::new);
+ SymmetricKeyAlgorithmTags.AES_256, new X448Agreement(), "X448", X448PublicKeyParameters::new);
}
else if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
{
@@ -216,8 +216,8 @@ private interface PublicKeyParametersOperation
AsymmetricKeyParameter getPublicKeyParameters(byte[] pEnc, int pEncOff);
}
- private byte[] getSessionData(byte[] enc, AsymmetricKeyParameter privKey, int pLen, int hashAlgorithm,
- int symmetricKeyAlgorithm, RawAgreement agreement, PublicKeyParametersOperation pkp)
+ private byte[] getSessionData(byte[] enc, AsymmetricKeyParameter privKey, int pLen, int hashAlgorithm, int symmetricKeyAlgorithm,
+ RawAgreement agreement, String algorithmName, PublicKeyParametersOperation pkp)
throws PGPException, InvalidCipherTextException
{
byte[] pEnc = new byte[pLen];
@@ -231,7 +231,7 @@ private byte[] getSessionData(byte[] enc, AsymmetricKeyParameter privKey, int pL
RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
- KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(Arrays.concatenate(pgpPrivKey.getPublicKeyPacket().getKey().getEncoded(), pEnc, secret)));
+ KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(Arrays.concatenate(pgpPrivKey.getPublicKeyPacket().getKey().getEncoded(), pEnc, secret), algorithmName));
return Arrays.concatenate(new byte[]{enc[pLen + 1]}, unwrapSessionData(keyEnc, symmetricKeyAlgorithm, key));
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index a1aa277ca0..81e2cf50d5 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -113,13 +113,13 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
{
- return encryptSessionInfo(pubKeyPacket, sessionInfo, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128,
+ return encryptSessionInfo(pubKeyPacket, sessionInfo, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128, "X25519",
new X25519KeyPairGenerator(), new X25519KeyGenerationParameters(random), new X25519Agreement(), cryptoPublicKey, X25519PublicKeyParameters.KEY_SIZE,
(publicKey, ephPubEncoding) -> ((X25519PublicKeyParameters)publicKey).encode(ephPubEncoding, 0));
}
else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
{
- return encryptSessionInfo(pubKeyPacket, sessionInfo, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256,
+ return encryptSessionInfo(pubKeyPacket, sessionInfo, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256, "X448",
new X448KeyPairGenerator(), new X448KeyGenerationParameters(random), new X448Agreement(), cryptoPublicKey, X448PublicKeyParameters.KEY_SIZE,
(publicKey, ephPubEncoding) -> ((X448PublicKeyParameters)publicKey).encode(ephPubEncoding, 0));
}
@@ -161,7 +161,7 @@ private byte[] encryptSessionInfo(byte[] sessionInfo, byte[] secret,
return getSessionInfo(ephPubEncoding, getWrapper(symmetricKeyAlgorithm, key, paddedSessionData));
}
- private byte[] encryptSessionInfo(PublicKeyPacket pubKeyPacket, byte[] sessionInfo, int hashAlgorithm, int symmetricKeyAlgorithm,
+ private byte[] encryptSessionInfo(PublicKeyPacket pubKeyPacket, byte[] sessionInfo, int hashAlgorithm, int symmetricKeyAlgorithm, String algorithmName,
AsymmetricCipherKeyPairGenerator gen, KeyGenerationParameters parameters, RawAgreement agreement, AsymmetricKeyParameter cryptoPublicKey,
int keySize, ephPubEncodingOperation ephPubEncodingOperation)
throws PGPException, IOException
@@ -172,7 +172,7 @@ private byte[] encryptSessionInfo(PublicKeyPacket pubKeyPacket, byte[] sessionIn
ephPubEncodingOperation.getEphPubEncoding(ephKp.getPublic(), ephPubEncoding);
RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(
new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
- KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(Arrays.concatenate(pubKeyPacket.getKey().getEncoded(), ephPubEncoding, secret)));
+ KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(Arrays.concatenate(pubKeyPacket.getKey().getEncoded(), ephPubEncoding, secret), algorithmName));
//No checksum and padding
byte[] sessionData = new byte[sessionInfo.length - 3];
System.arraycopy(sessionInfo, 1, sessionData, 0, sessionData.length);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
index 7cf260fd28..fec445c916 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
@@ -46,13 +46,13 @@ public byte[] createKey(byte[] secret, byte[] userKeyingMaterial)
}
}
- public byte[] createKey(byte[] secret)
+ public byte[] createKey(byte[] secret, String info)
throws PGPException
{
try
{
// RFC 7748
- return HKDF(digCalc, secret, getKeyLen(keyAlgorithm));
+ return HKDF(digCalc, secret, getKeyLen(keyAlgorithm), "OpenPGP " + info);
}
catch (IOException e)
{
@@ -94,11 +94,12 @@ private static byte[] KDF(PGPDigestCalculator digCalc, byte[] ZB, int keyLen, by
return key;
}
- private static byte[] HKDF(PGPDigestCalculator digCalc, byte[] ZB, int keyLen)
+ private static byte[] HKDF(PGPDigestCalculator digCalc, byte[] ZB, int keyLen, String info)
throws IOException
{
OutputStream dOut = digCalc.getOutputStream();
dOut.write(ZB);
+ dOut.write(info.getBytes());
byte[] digest = digCalc.getDigest();
byte[] key = new byte[keyLen];
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
index 89e39aec2b..0ea05d3cc4 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
@@ -187,12 +187,12 @@ public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData)
else if (keyAlgorithm == PublicKeyAlgorithmTags.X25519)
{
return decryptSessionData(keyConverter, privKey, secKeyData[0], X25519PublicBCPGKey.LENGTH, "X25519withSHA256HKDF",
- SymmetricKeyAlgorithmTags.AES_128, EdECObjectIdentifiers.id_X25519);
+ SymmetricKeyAlgorithmTags.AES_128, EdECObjectIdentifiers.id_X25519, "X25519");
}
else if (keyAlgorithm == PublicKeyAlgorithmTags.X448)
{
return decryptSessionData(keyConverter, privKey, secKeyData[0], X448PublicBCPGKey.LENGTH, "X448withSHA512HKDF",
- SymmetricKeyAlgorithmTags.AES_256, EdECObjectIdentifiers.id_X448);
+ SymmetricKeyAlgorithmTags.AES_256, EdECObjectIdentifiers.id_X448, "X448");
}
PrivateKey jcePrivKey = keyConverter.getPrivateKey(privKey);
int expectedPayLoadSize = getExpectedPayloadSize(jcePrivKey);
@@ -281,7 +281,7 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
}
byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyData, fingerprintCalculator);
- Key paddedSessionKey = getSessionKey(converter, privKey, agreement, userKeyingMaterial, publicKey, ecKey.getSymmetricKeyAlgorithm(), keyEnc);
+ Key paddedSessionKey = getSessionKey(converter, privKey, agreement, publicKey, ecKey.getSymmetricKeyAlgorithm(), keyEnc, new UserKeyingMaterialSpec(userKeyingMaterial));
return PGPPad.unpadSessionData(paddedSessionKey.getEncoded());
}
@@ -292,7 +292,7 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
}
private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey privKey, byte[] enc, int pLen, String agreementAlgorithm,
- int symmetricKeyAlgorithm, ASN1ObjectIdentifier algprithmIdentifier)
+ int symmetricKeyAlgorithm, ASN1ObjectIdentifier algprithmIdentifier, String algorithmName)
throws PGPException
{
try
@@ -308,7 +308,8 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
KeyAgreement agreement = helper.createKeyAgreement(agreementAlgorithm);
PublicKey publicKey = getPublicKey(pEnc, algprithmIdentifier, 0);
- Key paddedSessionKey = getSessionKey(converter, privKey, agreement, Arrays.concatenate(privKey.getPublicKeyPacket().getKey().getEncoded(), pEnc), publicKey, symmetricKeyAlgorithm, keyEnc);
+ Key paddedSessionKey = getSessionKey(converter, privKey, agreement, publicKey, symmetricKeyAlgorithm, keyEnc,
+ new UserKeyingMaterialSpec(Arrays.concatenate(privKey.getPublicKeyPacket().getKey().getEncoded(), pEnc), ("OpenPGP " + algorithmName).getBytes()));
symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
return Arrays.concatenate(new byte[]{(byte)symmetricKeyAlgorithm}, paddedSessionKey.getEncoded());
}
@@ -318,11 +319,12 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
}
}
- private Key getSessionKey(JcaPGPKeyConverter converter, PGPPrivateKey privKey, KeyAgreement agreement, byte[] privKey1, PublicKey publicKey, int symmetricKeyAlgorithm, byte[] keyEnc)
+ private Key getSessionKey(JcaPGPKeyConverter converter, PGPPrivateKey privKey, KeyAgreement agreement,
+ PublicKey publicKey, int symmetricKeyAlgorithm, byte[] keyEnc, UserKeyingMaterialSpec ukms)
throws PGPException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException
{
PrivateKey privateKey = converter.getPrivateKey(privKey);
- agreement.init(privateKey, new UserKeyingMaterialSpec(privKey1));
+ agreement.init(privateKey, ukms);
agreement.doPhase(publicKey, true);
Key key = agreement.generateSecret(RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId());
Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index 5f55bab80d..063d2a92b5 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -215,7 +215,8 @@ private byte[] getEncryptSessionInfo(PGPPublicKey pgpPublicKey, String algorithm
KeyPair ephKP = kpGen.generateKeyPair();
byte[] ephPubEncoding = SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes();
- UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(Arrays.concatenate(pgpPublicKey.getPublicKeyPacket().getKey().getEncoded(), ephPubEncoding));
+ UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(Arrays.concatenate(pgpPublicKey.getPublicKeyPacket().getKey().getEncoded(), ephPubEncoding),
+ ("OpenPGP " + algorithmName).getBytes());
Key secret = getSecret(cryptoPublicKey, keyEncryptionOID, agreementAlgorithmName, ukmSpec, ephKP);
//No checksum or padding
byte[] sessionData = new byte[sessionInfo.length - 3];
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index fad8b245b0..e3aab66f04 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -257,9 +257,10 @@ public void testKeyRings()
throws Exception
{
System.setProperty("enableCamelliaKeyWrapping", "True");
+ keyringTest("EdDSA","Ed448", PublicKeyAlgorithmTags.Ed448, "XDH","X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("EdDSA","Ed448", PublicKeyAlgorithmTags.Ed448, "XDH","X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+
keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.Ed25519, "XDH","X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
index 9203c47106..ba094c28af 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
@@ -73,6 +73,7 @@ else if (priv instanceof X448PrivateKeyParameters)
}
ukmParameters = null;
+ ukmParametersSalt = null;
if (params instanceof DHUParameterSpec)
{
if (kaAlgorithm.indexOf('U') < 0)
@@ -99,6 +100,7 @@ else if (params != null)
throw new InvalidAlgorithmParameterException("no KDF specified for UserKeyingMaterialSpec");
}
this.ukmParameters = ((UserKeyingMaterialSpec)params).getUserKeyingMaterial();
+ ukmParametersSalt = ((UserKeyingMaterialSpec)params).getSalt();
}
else
{
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
index bc274a07d1..cd32613c57 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -153,6 +153,7 @@ public abstract class BaseAgreementSpi
protected final DerivationFunction kdf;
protected byte[] ukmParameters;
+ protected byte[] ukmParametersSalt;
private HybridValueParameterSpec hybridSpec;
public BaseAgreementSpi(String kaAlgorithm, DerivationFunction kdf)
@@ -353,18 +354,7 @@ private byte[] getSharedSecretBytes(byte[] secret, String oidAlgorithm, int keyS
}
else if (kdf instanceof HKDFBytesGenerator)
{
- byte[] info = null;
- if (secret.length == 56)
- {
- //X448Agreement
- info = "OpenPGP X448".getBytes();
- }
- else if (secret.length == 32)
- {
- //X25519Agreement
- info = "OpenPGP X25519".getBytes();
- }
- kdf.init(HKDFParameters.skipExtractParameters(Arrays.concatenate(ukmParameters, secret), info));
+ kdf.init(new HKDFParameters(Arrays.concatenate(ukmParameters, secret), null, ukmParametersSalt));
}
else
{
From 1b909fdfe52ed2f85f7ed0533ac98d3b958a0eb3 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 27 Feb 2024 16:19:35 +1030
Subject: [PATCH 0106/1846] Correct HKDF settings for X25519 and X448.
---
.../bc/BcPublicKeyDataDecryptorFactory.java | 6 +-
...PublicKeyKeyEncryptionMethodGenerator.java | 11 +-
.../operator/bc/RFC6637KDFCalculator.java | 34 +---
...ePublicKeyDataDecryptorFactoryBuilder.java | 4 +-
...PublicKeyKeyEncryptionMethodGenerator.java | 2 +-
.../openpgp/test/OperatorBcTest.java | 164 ++++++++++++------
6 files changed, 131 insertions(+), 90 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index bfeadca77d..4049810059 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -228,10 +228,8 @@ private byte[] getSessionData(byte[] enc, AsymmetricKeyParameter privKey, int pL
keyEnc = new byte[keyLen - 1];
System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
byte[] secret = getSecret(agreement, privKey, pkp.getPublicKeyParameters(pEnc, 0));
-
- RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
-
- KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(Arrays.concatenate(pgpPrivKey.getPublicKeyPacket().getKey().getEncoded(), pEnc, secret), algorithmName));
+ KeyParameter key = new KeyParameter(RFC6637KDFCalculator.createKey(hashAlgorithm, symmetricKeyAlgorithm,
+ Arrays.concatenate(pEnc, pgpPrivKey.getPublicKeyPacket().getKey().getEncoded(), secret), algorithmName));
return Arrays.concatenate(new byte[]{enc[pLen + 1]}, unwrapSessionData(keyEnc, symmetricKeyAlgorithm, key));
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index 81e2cf50d5..2568558fa6 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -132,11 +132,7 @@ else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
return c.processBlock(sessionInfo, 0, sessionInfo.length);
}
}
- catch (InvalidCipherTextException e)
- {
- throw new PGPException("exception encrypting session info: " + e.getMessage(), e);
- }
- catch (IOException e)
+ catch (InvalidCipherTextException | IOException e)
{
throw new PGPException("exception encrypting session info: " + e.getMessage(), e);
}
@@ -170,9 +166,8 @@ private byte[] encryptSessionInfo(PublicKeyPacket pubKeyPacket, byte[] sessionIn
byte[] secret = getSecret(agreement, cryptoPublicKey, ephKp);
byte[] ephPubEncoding = new byte[keySize];
ephPubEncodingOperation.getEphPubEncoding(ephKp.getPublic(), ephPubEncoding);
- RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(
- new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
- KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(Arrays.concatenate(pubKeyPacket.getKey().getEncoded(), ephPubEncoding, secret), algorithmName));
+ KeyParameter key = new KeyParameter(RFC6637KDFCalculator.createKey(hashAlgorithm, symmetricKeyAlgorithm,
+ Arrays.concatenate(ephPubEncoding, pubKeyPacket.getKey().getEncoded(), secret), algorithmName));
//No checksum and padding
byte[] sessionData = new byte[sessionInfo.length - 3];
System.arraycopy(sessionInfo, 1, sessionData, 0, sessionData.length);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
index fec445c916..016bb4fad2 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
@@ -4,6 +4,8 @@
import java.io.OutputStream;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
+import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
@@ -46,18 +48,15 @@ public byte[] createKey(byte[] secret, byte[] userKeyingMaterial)
}
}
- public byte[] createKey(byte[] secret, String info)
+ public static byte[] createKey(int algorithm, int keyAlgorithm, byte[] secret, String info)
throws PGPException
{
- try
- {
- // RFC 7748
- return HKDF(digCalc, secret, getKeyLen(keyAlgorithm), "OpenPGP " + info);
- }
- catch (IOException e)
- {
- throw new PGPException("Exception performing KDF: " + e.getMessage(), e);
- }
+ // RFC 7748
+ HKDFBytesGenerator hkdf = new HKDFBytesGenerator(BcImplProvider.createDigest(algorithm));
+ hkdf.init(new HKDFParameters(secret, null, info.getBytes()));
+ byte[] key = new byte[getKeyLen(keyAlgorithm)];
+ hkdf.generateBytes(key, 0, key.length);
+ return key;
}
// RFC 6637 - Section 7
@@ -94,21 +93,6 @@ private static byte[] KDF(PGPDigestCalculator digCalc, byte[] ZB, int keyLen, by
return key;
}
- private static byte[] HKDF(PGPDigestCalculator digCalc, byte[] ZB, int keyLen, String info)
- throws IOException
- {
- OutputStream dOut = digCalc.getOutputStream();
- dOut.write(ZB);
- dOut.write(info.getBytes());
- byte[] digest = digCalc.getDigest();
-
- byte[] key = new byte[keyLen];
-
- System.arraycopy(digest, 0, key, 0, key.length);
-
- return key;
- }
-
private static int getKeyLen(int algID)
throws PGPException
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
index 0ea05d3cc4..5a062bf3c9 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
@@ -308,8 +308,8 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
KeyAgreement agreement = helper.createKeyAgreement(agreementAlgorithm);
PublicKey publicKey = getPublicKey(pEnc, algprithmIdentifier, 0);
- Key paddedSessionKey = getSessionKey(converter, privKey, agreement, publicKey, symmetricKeyAlgorithm, keyEnc,
- new UserKeyingMaterialSpec(Arrays.concatenate(privKey.getPublicKeyPacket().getKey().getEncoded(), pEnc), ("OpenPGP " + algorithmName).getBytes()));
+ Key paddedSessionKey = getSessionKey(converter, privKey, agreement, publicKey, symmetricKeyAlgorithm, keyEnc,
+ new UserKeyingMaterialSpec(Arrays.concatenate(pEnc, privKey.getPublicKeyPacket().getKey().getEncoded()), ("OpenPGP " + algorithmName).getBytes()));
symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
return Arrays.concatenate(new byte[]{(byte)symmetricKeyAlgorithm}, paddedSessionKey.getEncoded());
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index 063d2a92b5..5a459822a4 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -215,7 +215,7 @@ private byte[] getEncryptSessionInfo(PGPPublicKey pgpPublicKey, String algorithm
KeyPair ephKP = kpGen.generateKeyPair();
byte[] ephPubEncoding = SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes();
- UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(Arrays.concatenate(pgpPublicKey.getPublicKeyPacket().getKey().getEncoded(), ephPubEncoding),
+ UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(Arrays.concatenate(ephPubEncoding, pgpPublicKey.getPublicKeyPacket().getKey().getEncoded()),
("OpenPGP " + algorithmName).getBytes());
Key secret = getSecret(cryptoPublicKey, keyEncryptionOID, agreementAlgorithmName, ukmSpec, ephKP);
//No checksum or padding
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index e3aab66f04..8d533ca67c 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -1,6 +1,7 @@
package org.bouncycastle.openpgp.test;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyPair;
@@ -10,7 +11,7 @@
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.ECGenParameterSpec;
-import java.util.Arrays;
+
import java.util.Date;
import java.util.Iterator;
@@ -21,8 +22,18 @@
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.bouncycastle.crypto.Wrapper;
+import org.bouncycastle.crypto.agreement.X25519Agreement;
import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.engines.RFC3394WrapEngine;
+import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.HKDFParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
+import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
+import org.bouncycastle.jcajce.provider.asymmetric.edec.KeyAgreementSpi;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
import org.bouncycastle.openpgp.PGPEncryptedData;
@@ -47,6 +58,7 @@
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder;
+import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider;
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyConverter;
import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair;
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory;
@@ -62,6 +74,8 @@
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
import org.bouncycastle.util.test.UncloseableOutputStream;
@@ -85,6 +99,7 @@ public String getName()
public void performTest()
throws Exception
{
+ testX25519HKDF();
testKeyRings();
testBcPGPKeyPair();
testBcPGPDataEncryptorBuilder();
@@ -165,33 +180,48 @@ public void testBcPGPDataEncryptorBuilder()
public void testBcPGPKeyPair()
throws Exception
{
- testCreateKeyPair(PublicKeyAlgorithmTags.X448, "X448", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.X25519, "X25519", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed25519, "Ed25519", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, "Ed448", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, PublicKeyAlgorithmTags.X25519, "X25519", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("P-256")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("P-384")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("P-521")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP256r1")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP384r1")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP512r1")));
- testCreateKeyPair(PublicKeyAlgorithmTags.X25519, PublicKeyAlgorithmTags.ECDH, "X25519", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, "RSA", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.DSA, "DSA", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "X25519", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("P-256")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("P-384")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("P-521")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP256r1")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP384r1")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen)-> gen.initialize(new ECGenParameterSpec("brainpoolP512r1")));
- testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL", (gen)-> {});
- testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, "Ed25519", (gen)-> {});
+ testCreateKeyPair(PublicKeyAlgorithmTags.X448, "X448", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.X25519, "X25519", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, PublicKeyAlgorithmTags.Ed25519, "Ed25519", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.Ed448, "Ed448", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, PublicKeyAlgorithmTags.X25519, "X25519", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen) -> gen.initialize(new ECGenParameterSpec("P-256")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen) -> gen.initialize(new ECGenParameterSpec("P-384")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen) -> gen.initialize(new ECGenParameterSpec("P-521")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen) -> gen.initialize(new ECGenParameterSpec("brainpoolP256r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen) -> gen.initialize(new ECGenParameterSpec("brainpoolP384r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "ECDH", (gen) -> gen.initialize(new ECGenParameterSpec("brainpoolP512r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.X25519, PublicKeyAlgorithmTags.ECDH, "X25519", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.RSA_GENERAL, "RSA", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.DSA, "DSA", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDH, "X25519", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, "Ed25519", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen) -> gen.initialize(new ECGenParameterSpec("P-256")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen) -> gen.initialize(new ECGenParameterSpec("P-384")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen) -> gen.initialize(new ECGenParameterSpec("P-521")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen) -> gen.initialize(new ECGenParameterSpec("brainpoolP256r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen) -> gen.initialize(new ECGenParameterSpec("brainpoolP384r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ECDSA, "ECDSA", (gen) -> gen.initialize(new ECGenParameterSpec("brainpoolP512r1")));
+ testCreateKeyPair(PublicKeyAlgorithmTags.ELGAMAL_GENERAL, "ELGAMAL", (gen) -> {
+ });
+ testCreateKeyPair(PublicKeyAlgorithmTags.Ed25519, "Ed25519", (gen) -> {
+ });
}
@@ -203,7 +233,8 @@ private void testCreateKeyPair(int algorithm, String name, KeyPairGeneratorOpera
private interface KeyPairGeneratorOperation
{
- void initialize(KeyPairGenerator gen) throws Exception;
+ void initialize(KeyPairGenerator gen)
+ throws Exception;
}
private void testCreateKeyPair(int algorithm1, int algorithm2, String name, KeyPairGeneratorOperation kpgen)
@@ -226,13 +257,13 @@ private void testCreateKeyPair(int algorithm1, int algorithm2, String name, KeyP
PrivateKey privKey = jcaPGPKeyConverter.getPrivateKey(jcaPgpPair.getPrivateKey());
PublicKey pubKey = jcaPGPKeyConverter.getPublicKey(jcaPgpPair.getPublicKey());
- if (algorithm1 == algorithm2 && !Arrays.equals(jcaPgpPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(),
+ if (algorithm1 == algorithm2 && !Arrays.areEqual(jcaPgpPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(),
bcKeyPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded()))
{
throw new PGPException("JcaPGPKeyPair and BcPGPKeyPair private keys are not equal.");
}
- if (algorithm1 == algorithm2 && !Arrays.equals(jcaPgpPair.getPublicKey().getPublicKeyPacket().getEncoded(),
+ if (algorithm1 == algorithm2 && !Arrays.areEqual(jcaPgpPair.getPublicKey().getPublicKeyPacket().getEncoded(),
bcKeyPair.getPublicKey().getPublicKeyPacket().getEncoded()))
{
throw new PGPException("JcaPGPKeyPair and BcPGPKeyPair public keys are not equal.");
@@ -247,7 +278,7 @@ private void testCreateKeyPair(int algorithm1, int algorithm2, String name, KeyP
// }
// }
- isTrue(Arrays.equals(pubKey.getEncoded(), keyPair.getPublic().getEncoded()));
+ isTrue(Arrays.areEqual(pubKey.getEncoded(), keyPair.getPublic().getEncoded()));
isTrue(privKey.toString().equals(keyPair.getPrivate().toString()));
// getEncoded() are Not equal as privKey.hasPublicKey is false but keyPair.getPrivate().hasPublicKey is true
//isTrue(Arrays.equals(privKey.getEncoded(), keyPair.getPrivate().getEncoded()));
@@ -257,30 +288,28 @@ public void testKeyRings()
throws Exception
{
System.setProperty("enableCamelliaKeyWrapping", "True");
- keyringTest("EdDSA","Ed448", PublicKeyAlgorithmTags.Ed448, "XDH","X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
- keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
-
+ keyringTest("EdDSA", "Ed448", PublicKeyAlgorithmTags.Ed448, "XDH", "X448", PublicKeyAlgorithmTags.X448, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+ keyringTest("EdDSA", "Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH", "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.Ed25519, "XDH","X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("EdDSA", "ED25519", PublicKeyAlgorithmTags.Ed25519, "XDH", "X25519", PublicKeyAlgorithmTags.X25519, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("ECDSA", "NIST P-256", PublicKeyAlgorithmTags.ECDSA, "ECDH", "NIST P-256", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("ECDSA", "NIST P-384", PublicKeyAlgorithmTags.ECDSA, "ECDH", "NIST P-384", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_192);
+ keyringTest("ECDSA", "NIST P-521", PublicKeyAlgorithmTags.ECDSA, "ECDH", "NIST P-521", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
+ keyringTest("ECDSA", "brainpoolP256r1", PublicKeyAlgorithmTags.ECDSA, "ECDH", "brainpoolP256r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("ECDSA", "brainpoolP384r1", PublicKeyAlgorithmTags.ECDSA, "ECDH", "brainpoolP384r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_192);
+ keyringTest("ECDSA", "brainpoolP512r1", PublicKeyAlgorithmTags.ECDSA, "ECDH", "brainpoolP512r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
- keyringTest("ECDSA","NIST P-256", PublicKeyAlgorithmTags.ECDSA, "ECDH","NIST P-256", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("ECDSA","NIST P-384", PublicKeyAlgorithmTags.ECDSA, "ECDH","NIST P-384", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_192);
- keyringTest("ECDSA","NIST P-521", PublicKeyAlgorithmTags.ECDSA, "ECDH","NIST P-521", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
- keyringTest("ECDSA","brainpoolP256r1", PublicKeyAlgorithmTags.ECDSA, "ECDH","brainpoolP256r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("ECDSA","brainpoolP384r1", PublicKeyAlgorithmTags.ECDSA, "ECDH","brainpoolP384r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_192);
- keyringTest("ECDSA","brainpoolP512r1", PublicKeyAlgorithmTags.ECDSA, "ECDH","brainpoolP512r1", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256);
-
- keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("EdDSA","ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
- keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_192);
- keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_256);
- keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_128);
- keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_192);
- keyringTest("EdDSA","Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH","X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_256);
+ keyringTest("EdDSA", "ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH", "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("EdDSA", "ED25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH", "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_128);
+ keyringTest("EdDSA", "Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH", "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_192);
+ keyringTest("EdDSA", "Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH", "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_256);
+ keyringTest("EdDSA", "Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH", "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_128);
+ keyringTest("EdDSA", "Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH", "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_192);
+ keyringTest("EdDSA", "Ed25519", PublicKeyAlgorithmTags.EDDSA_LEGACY, "XDH", "X25519", PublicKeyAlgorithmTags.ECDH, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.CAMELLIA_256);
}
@@ -485,4 +514,39 @@ private void encryptDecryptTest(PGPPublicKey pubKey, PGPPrivateKey secKey)
fail("wrong plain text in generated packet");
}
}
+
+ public void testX25519HKDF()
+ throws Exception
+ {
+ byte[] ephmeralKey = Hex.decode("87 cf 18 d5 f1 b5 3f 81 7c ce 5a 00 4c f3 93 cc\n" +
+ " 89 58 bd dc 06 5f 25 f8 4a f5 09 b1 7d d3 67 64");
+ byte[] ephmeralSecretKey = Hex.decode("af 1e 43 c0 d1 23 ef e8 93 a7 d4 d3 90 f3 a7 61\n" +
+ " e3 fa c3 3d fc 7f 3e da a8 30 c9 01 13 52 c7 79");
+ byte[] publicKey = Hex.decode("86 93 24 83 67 f9 e5 01 5d b9 22 f8 f4 80 95 dd\n" +
+ " a7 84 98 7f 2d 59 85 b1 2f ba d1 6c af 5e 44 35");
+ byte[] privKey = Hex.decode("4d 60 0a 4f 79 4d 44 77 5c 57 a2 6e 0f ee fe d5\n" +
+ " 58 e9 af ff d6 ad 0d 58 2d 57 fb 2b a2 dc ed b8" +
+ "67 e3 0e 69 cd c7 ba b2 a2 68 0d 78 ac a4 6a 2f\n" +
+ " 8b 6e 2a e4 4d 39 8b dc 6f 92 c5 ad 4a 49 25 14");
+ byte[] expectedHKDF = Hex.decode("f6 6d ad cf f6 45 92 23 9b 25 45 39 b6 4f f6 07\n");
+// byte[] expectedDecryptedSessionKey = Hex.decode("dd 70 8f 6f a1 ed 65 11 4d 68 d2 34 3e 7c 2f 1d");
+ X25519PrivateKeyParameters ephmeralprivateKeyParameters = new X25519PrivateKeyParameters(ephmeralSecretKey);
+ X25519PublicKeyParameters publicKeyParameters = new X25519PublicKeyParameters(publicKey);
+ X25519Agreement agreement = new X25519Agreement();
+ agreement.init(ephmeralprivateKeyParameters);
+ byte[] secret = new byte[agreement.getAgreementSize()];
+ agreement.calculateAgreement(publicKeyParameters, secret, 0);
+ byte[] output2 = new byte[16];
+ HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA256Digest());
+ hkdf.init(new HKDFParameters(Arrays.concatenate(ephmeralKey, publicKey, secret), null, "OpenPGP X25519".getBytes()));
+ hkdf.generateBytes(output2, 0, 16);
+ isTrue(Arrays.areEqual(output2, expectedHKDF));
+// Wrapper c = new RFC3394WrapEngine(AESEngine.newInstance());
+// c.init(false, new KeyParameter(output2));
+// byte[] keyEnc = new byte[32];
+// keyEnc = c.unwrap(keyEnc, 0, keyEnc.length);
+// System.out.println(Hex.toHexString(output2));
+ //hkdf.init(new HKDFParameters(Arrays.concatenate()));
+ }
+
}
From 1c811fdbbdd6b461324e388d8e52af81be01cc4b Mon Sep 17 00:00:00 2001
From: gefeili
Date: Tue, 27 Feb 2024 16:27:32 +1030
Subject: [PATCH 0107/1846] correct info of for HKDF in
BcPublicKeyDataDecryptorFactory and BcPublicKeyKeyEncryptionMethodGenerator
---
.../openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java | 2 +-
.../operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index 4049810059..74ac0ef365 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -229,7 +229,7 @@ private byte[] getSessionData(byte[] enc, AsymmetricKeyParameter privKey, int pL
System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
byte[] secret = getSecret(agreement, privKey, pkp.getPublicKeyParameters(pEnc, 0));
KeyParameter key = new KeyParameter(RFC6637KDFCalculator.createKey(hashAlgorithm, symmetricKeyAlgorithm,
- Arrays.concatenate(pEnc, pgpPrivKey.getPublicKeyPacket().getKey().getEncoded(), secret), algorithmName));
+ Arrays.concatenate(pEnc, pgpPrivKey.getPublicKeyPacket().getKey().getEncoded(), secret), "OpenPGP " + algorithmName));
return Arrays.concatenate(new byte[]{enc[pLen + 1]}, unwrapSessionData(keyEnc, symmetricKeyAlgorithm, key));
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index 2568558fa6..da7d66b21a 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -167,7 +167,7 @@ private byte[] encryptSessionInfo(PublicKeyPacket pubKeyPacket, byte[] sessionIn
byte[] ephPubEncoding = new byte[keySize];
ephPubEncodingOperation.getEphPubEncoding(ephKp.getPublic(), ephPubEncoding);
KeyParameter key = new KeyParameter(RFC6637KDFCalculator.createKey(hashAlgorithm, symmetricKeyAlgorithm,
- Arrays.concatenate(ephPubEncoding, pubKeyPacket.getKey().getEncoded(), secret), algorithmName));
+ Arrays.concatenate(ephPubEncoding, pubKeyPacket.getKey().getEncoded(), secret), "OpenPGP " + algorithmName));
//No checksum and padding
byte[] sessionData = new byte[sessionInfo.length - 3];
System.arraycopy(sessionInfo, 1, sessionData, 0, sessionData.length);
From 8767f0b2a5ae15d5e5ae1b868fa92e1753a4b317 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Tue, 27 Feb 2024 16:55:45 +0700
Subject: [PATCH 0108/1846] Inline RSA, PKCS1 code into TlsRsaKeyExchange
---
.../crypto/tls/TlsRsaKeyExchange.java | 224 ++++++++++++++++--
1 file changed, 199 insertions(+), 25 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java b/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
index 5cf2ec91aa..f5573a2cd3 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
@@ -1,16 +1,23 @@
package org.bouncycastle.crypto.tls;
+import java.math.BigInteger;
import java.security.SecureRandom;
-import org.bouncycastle.crypto.encodings.PKCS1Encoding;
-import org.bouncycastle.crypto.engines.RSABlindedEngine;
-import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.CryptoServicePurpose;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.bouncycastle.crypto.DataLengthException;
+import org.bouncycastle.crypto.constraints.ConstraintUtils;
+import org.bouncycastle.crypto.constraints.DefaultServiceProperties;
import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
import org.bouncycastle.util.Pack;
public abstract class TlsRsaKeyExchange
{
+ private static final BigInteger ONE = BigInteger.valueOf(1);
+
private TlsRsaKeyExchange()
{
}
@@ -18,25 +25,70 @@ private TlsRsaKeyExchange()
public static byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret, RSAKeyParameters privateKey,
int protocolVersion, SecureRandom secureRandom)
{
+ if (encryptedPreMasterSecret == null)
+ {
+ throw new NullPointerException("'encryptedPreMasterSecret' cannot be null");
+ }
+
+ if (!privateKey.isPrivate())
+ {
+ throw new IllegalArgumentException("'privateKey' must be an RSA private key");
+ }
+
+ BigInteger modulus = privateKey.getModulus();
+ int bitLength = modulus.bitLength();
+ if (bitLength < 512)
+ {
+ throw new IllegalArgumentException("'privateKey' must be at least 512 bits");
+ }
+
+ int bitsOfSecurity = ConstraintUtils.bitsOfSecurityFor(modulus);
+ CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties("RSA", bitsOfSecurity, privateKey,
+ CryptoServicePurpose.DECRYPTION));
+
+ if ((protocolVersion & 0xFFFF) != protocolVersion)
+ {
+ throw new IllegalArgumentException("'protocolVersion' must be a 16 bit value");
+ }
+
+ secureRandom = CryptoServicesRegistrar.getSecureRandom(secureRandom);
+
/*
- * Generate 48 random bytes we can use as a Pre-Master-Secret, if the PKCS1 padding check should fail.
+ * Generate 48 random bytes we can use as a Pre-Master-Secret if the decrypted value is invalid.
*/
- byte[] fallback = new byte[48];
- secureRandom.nextBytes(fallback);
+ byte[] result = new byte[48];
+ secureRandom.nextBytes(result);
- byte[] M = Arrays.clone(fallback);
try
{
- PKCS1Encoding encoding = new PKCS1Encoding(new RSABlindedEngine(), fallback);
- encoding.init(false, new ParametersWithRandom(privateKey, secureRandom));
+ int pkcs1Length = (bitLength - 1) / 8;
+ int plainTextOffset = pkcs1Length - 48;
+
+ BigInteger input = convertInput(modulus, encryptedPreMasterSecret);
+ BigInteger output = rsaBlinded(privateKey, input, secureRandom);
+ byte[] block = convertOutput(output);
+
+ byte[] encoding = block;
+ if (block.length != pkcs1Length)
+ {
+ encoding = new byte[pkcs1Length];
+ }
- M = encoding.processBlock(encryptedPreMasterSecret, 0, encryptedPreMasterSecret.length);
+ int badEncodingMask = checkPkcs1Encoding2(encoding, 48);
+ int badVersionMask = -((Pack.bigEndianToShort(encoding, plainTextOffset) ^ protocolVersion) & 0xFFFF) >> 31;
+ int fallbackMask = badEncodingMask | badVersionMask;
+
+ for (int i = 0; i < 48; ++i)
+ {
+ result[i] = (byte)((result[i] & fallbackMask) | (encoding[plainTextOffset + i] & ~fallbackMask));
+ }
+
+ Arrays.fill(block, (byte)0);
}
catch (Exception e)
{
/*
- * This should never happen since the decryption should never throw an exception and return a
- * random value instead.
+ * Decryption should never throw an exception; return a random value instead.
*
* In any case, a TLS server MUST NOT generate an alert if processing an RSA-encrypted premaster
* secret message fails, or the version number is not as expected. Instead, it MUST continue the
@@ -44,23 +96,145 @@ public static byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret, RSA
*/
}
- /*
- * Compare the version number in the decrypted Pre-Master-Secret with the legacy_version field from
- * the ClientHello. If they don't match, continue the handshake with the randomly generated 'fallback'
- * value.
- *
- * NOTE: The comparison and replacement must be constant-time.
- */
- int mask = (Pack.bigEndianToShort(M, 0) ^ protocolVersion) & 0xFFFF;
+ return result;
+ }
+
+ /**
+ * Check the argument is a valid encoding with type 2 of a plaintext with the given length. Returns 0 if
+ * valid, or -1 if invalid.
+ */
+ private static int checkPkcs1Encoding2(byte[] buf, int plaintextLength)
+ {
+ // The first byte should be 0x02
+ int badPadSign = -((buf[0] & 0xFF) ^ 0x02);
+
+ int lastPadPos = buf.length - 1 - plaintextLength;
+
+ // The header should be at least 10 bytes
+ badPadSign |= lastPadPos - 9;
+
+ // All pad bytes before the last one should be non-zero
+ for (int i = 1; i < lastPadPos; ++i)
+ {
+ badPadSign |= (buf[i] & 0xFF) - 1;
+ }
+
+ // Last pad byte should be zero
+ badPadSign |= -(buf[lastPadPos] & 0xFF);
+
+ return badPadSign >> 31;
+ }
+
+ public static BigInteger convertInput(BigInteger modulus, byte[] input)
+ {
+ int inputLimit = (modulus.bitLength() + 7) / 8;
- // 'mask' will be all 1s if the versions matched, or else all 0s.
- mask = (mask - 1) >> 31;
+ if (input.length <= inputLimit)
+ {
+ BigInteger result = new BigInteger(1, input);
+ if (result.compareTo(modulus) < 0)
+ {
+ return result;
+ }
+ }
+
+ throw new DataLengthException("input too large for RSA cipher.");
+ }
+
+ public static byte[] convertOutput(BigInteger result)
+ {
+ byte[] output = result.toByteArray();
+
+ byte[] rv;
+ if (output[0] == 0) // have ended up with an extra zero byte, copy down.
+ {
+ rv = new byte[output.length - 1];
+
+ System.arraycopy(output, 1, rv, 0, rv.length);
+ }
+ else // maintain decryption time
+ {
+ rv = new byte[output.length];
+
+ System.arraycopy(output, 0, rv, 0, rv.length);
+ }
+
+ Arrays.fill(output, (byte) 0);
+
+ return rv;
+ }
+
+ private static BigInteger rsa(RSAKeyParameters privateKey, BigInteger input)
+ {
+ if (privateKey instanceof RSAPrivateCrtKeyParameters)
+ {
+ //
+ // we have the extra factors, use the Chinese Remainder Theorem - the author
+ // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
+ // advice regarding the expression of this.
+ //
+ RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)privateKey;
+
+ BigInteger e = crtKey.getPublicExponent();
+ if (e != null) // can't apply fault-attack countermeasure without public exponent
+ {
+ BigInteger p = crtKey.getP();
+ BigInteger q = crtKey.getQ();
+ BigInteger dP = crtKey.getDP();
+ BigInteger dQ = crtKey.getDQ();
+ BigInteger qInv = crtKey.getQInv();
+
+ BigInteger mP, mQ, h, m;
+
+ // mP = ((input mod p) ^ dP)) mod p
+ mP = (input.remainder(p)).modPow(dP, p);
+
+ // mQ = ((input mod q) ^ dQ)) mod q
+ mQ = (input.remainder(q)).modPow(dQ, q);
+
+ // h = qInv * (mP - mQ) mod p
+ h = mP.subtract(mQ);
+ h = h.multiply(qInv);
+ h = h.mod(p); // mod (in Java) returns the positive residual
+
+ // m = h * q + mQ
+ m = h.multiply(q).add(mQ);
+
+ // defence against Arjen Lenstra’s CRT attack
+ BigInteger check = m.modPow(e, crtKey.getModulus());
+ if (!check.equals(input))
+ {
+ throw new IllegalStateException("RSA engine faulty decryption/signing detected");
+ }
- for (int i = 0; i < 48; i++)
+ return m;
+ }
+ }
+
+ return input.modPow(privateKey.getExponent(), privateKey.getModulus());
+ }
+
+ private static BigInteger rsaBlinded(RSAKeyParameters privateKey, BigInteger input, SecureRandom secureRandom)
+ {
+ if (privateKey instanceof RSAPrivateCrtKeyParameters)
{
- M[i] = (byte)((M[i] & mask) | (fallback[i] & ~mask));
+ RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)privateKey;
+
+ BigInteger e = crtKey.getPublicExponent();
+ if (e != null) // can't do blinding without a public exponent
+ {
+ BigInteger m = crtKey.getModulus();
+
+ BigInteger r = BigIntegers.createRandomInRange(ONE, m.subtract(ONE), secureRandom);
+ BigInteger blind = r.modPow(e, m);
+ BigInteger unblind = BigIntegers.modOddInverse(m, r);
+
+ BigInteger blindedInput = blind.multiply(input).mod(m);
+ BigInteger blindedResult = rsa(privateKey, blindedInput);
+ return unblind.multiply(blindedResult).mod(m);
+ }
}
- return M;
+ return rsa(privateKey, input);
}
}
From 28927072aef8e8a14e78a79435499fa4b1bbe9a6 Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 28 Feb 2024 12:23:30 +1030
Subject: [PATCH 0109/1846] Update the test case for X25519 with HKDF
---
.../openpgp/test/OperatorBcTest.java | 29 +++++++------------
1 file changed, 11 insertions(+), 18 deletions(-)
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index 8d533ca67c..200101d5d6 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -518,18 +518,12 @@ private void encryptDecryptTest(PGPPublicKey pubKey, PGPPrivateKey secKey)
public void testX25519HKDF()
throws Exception
{
- byte[] ephmeralKey = Hex.decode("87 cf 18 d5 f1 b5 3f 81 7c ce 5a 00 4c f3 93 cc\n" +
- " 89 58 bd dc 06 5f 25 f8 4a f5 09 b1 7d d3 67 64");
- byte[] ephmeralSecretKey = Hex.decode("af 1e 43 c0 d1 23 ef e8 93 a7 d4 d3 90 f3 a7 61\n" +
- " e3 fa c3 3d fc 7f 3e da a8 30 c9 01 13 52 c7 79");
- byte[] publicKey = Hex.decode("86 93 24 83 67 f9 e5 01 5d b9 22 f8 f4 80 95 dd\n" +
- " a7 84 98 7f 2d 59 85 b1 2f ba d1 6c af 5e 44 35");
- byte[] privKey = Hex.decode("4d 60 0a 4f 79 4d 44 77 5c 57 a2 6e 0f ee fe d5\n" +
- " 58 e9 af ff d6 ad 0d 58 2d 57 fb 2b a2 dc ed b8" +
- "67 e3 0e 69 cd c7 ba b2 a2 68 0d 78 ac a4 6a 2f\n" +
- " 8b 6e 2a e4 4d 39 8b dc 6f 92 c5 ad 4a 49 25 14");
- byte[] expectedHKDF = Hex.decode("f6 6d ad cf f6 45 92 23 9b 25 45 39 b6 4f f6 07\n");
-// byte[] expectedDecryptedSessionKey = Hex.decode("dd 70 8f 6f a1 ed 65 11 4d 68 d2 34 3e 7c 2f 1d");
+ byte[] ephmeralKey = Hex.decode("87cf18d5f1b53f817cce5a004cf393cc8958bddc065f25f84af509b17dd36764");
+ byte[] ephmeralSecretKey = Hex.decode("af1e43c0d123efe893a7d4d390f3a761e3fac33dfc7f3edaa830c9011352c779");
+ byte[] publicKey = Hex.decode("8693248367f9e5015db922f8f48095dda784987f2d5985b12fbad16caf5e4435");
+ byte[] expectedHKDF = Hex.decode("f66dadcff64592239b254539b64ff607");
+ byte[] keyEnc = Hex.decode("dea355437956617901e06957fbca8a6a47a5b5153e8d3ab7");
+ byte[] expectedDecryptedSessionKey = Hex.decode("dd708f6fa1ed65114d68d2343e7c2f1d");
X25519PrivateKeyParameters ephmeralprivateKeyParameters = new X25519PrivateKeyParameters(ephmeralSecretKey);
X25519PublicKeyParameters publicKeyParameters = new X25519PublicKeyParameters(publicKey);
X25519Agreement agreement = new X25519Agreement();
@@ -540,13 +534,12 @@ public void testX25519HKDF()
HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA256Digest());
hkdf.init(new HKDFParameters(Arrays.concatenate(ephmeralKey, publicKey, secret), null, "OpenPGP X25519".getBytes()));
hkdf.generateBytes(output2, 0, 16);
+
isTrue(Arrays.areEqual(output2, expectedHKDF));
-// Wrapper c = new RFC3394WrapEngine(AESEngine.newInstance());
-// c.init(false, new KeyParameter(output2));
-// byte[] keyEnc = new byte[32];
-// keyEnc = c.unwrap(keyEnc, 0, keyEnc.length);
-// System.out.println(Hex.toHexString(output2));
- //hkdf.init(new HKDFParameters(Arrays.concatenate()));
+ Wrapper c = new RFC3394WrapEngine(AESEngine.newInstance());
+ c.init(false, new KeyParameter(output2));
+ byte[] output = c.unwrap(keyEnc, 0, keyEnc.length);
+ isTrue(Arrays.areEqual(output, expectedDecryptedSessionKey));
}
}
From 30cecc634e77c97eae8b58b80e14ad530e99e7ba Mon Sep 17 00:00:00 2001
From: gefeili
Date: Wed, 28 Feb 2024 14:55:05 +1030
Subject: [PATCH 0110/1846] Use UserKeyingMaterialSpecWithPrepend for
transporting HKDFParameters setting.
---
.../bc/BcPublicKeyDataDecryptorFactory.java | 12 +---
...PublicKeyKeyEncryptionMethodGenerator.java | 12 +---
.../openpgp/operator/bc/BcUtil.java | 10 +++
.../operator/bc/RFC6637KDFCalculator.java | 24 ++++++-
.../operator/jcajce/JcaJcePGPUtil.java | 30 ++++++++-
...ePublicKeyDataDecryptorFactoryBuilder.java | 25 +++-----
...PublicKeyKeyEncryptionMethodGenerator.java | 18 ++----
.../openpgp/test/OperatorBcTest.java | 2 +
.../openpgp/test/OperatorJcajceTest.java | 64 ++++++++++++++++++-
.../asymmetric/edec/KeyAgreementSpi.java | 11 +++-
.../asymmetric/util/BaseAgreementSpi.java | 3 +-
.../UserKeyingMaterialSpecWithPrepend.java | 62 ++++++++++++++++++
12 files changed, 214 insertions(+), 59 deletions(-)
create mode 100644 prov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpecWithPrepend.java
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
index 74ac0ef365..cc5aa2524b 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyDataDecryptorFactory.java
@@ -103,7 +103,7 @@ else if (keyAlgorithm == PublicKeyAlgorithmTags.ECDH)
throw new IllegalArgumentException("Invalid Curve25519 public key");
}
// skip the 0x40 header byte.
- secret = getSecret(new X25519Agreement(), privKey, new X25519PublicKeyParameters(pEnc, 1));
+ secret = BcUtil.getSecret(new X25519Agreement(), privKey, new X25519PublicKeyParameters(pEnc, 1));
}
else
{
@@ -227,21 +227,13 @@ private byte[] getSessionData(byte[] enc, AsymmetricKeyParameter privKey, int pL
assertOutOfRange(pLen + 1 + keyLen, enc);
keyEnc = new byte[keyLen - 1];
System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
- byte[] secret = getSecret(agreement, privKey, pkp.getPublicKeyParameters(pEnc, 0));
+ byte[] secret = BcUtil.getSecret(agreement, privKey, pkp.getPublicKeyParameters(pEnc, 0));
KeyParameter key = new KeyParameter(RFC6637KDFCalculator.createKey(hashAlgorithm, symmetricKeyAlgorithm,
Arrays.concatenate(pEnc, pgpPrivKey.getPublicKeyPacket().getKey().getEncoded(), secret), "OpenPGP " + algorithmName));
return Arrays.concatenate(new byte[]{enc[pLen + 1]}, unwrapSessionData(keyEnc, symmetricKeyAlgorithm, key));
}
- private static byte[] getSecret(RawAgreement agreement, AsymmetricKeyParameter privKey, AsymmetricKeyParameter ephPub)
- {
- agreement.init(privKey);
- byte[] secret = new byte[agreement.getAgreementSize()];
- agreement.calculateAgreement(ephPub, secret, 0);
- return secret;
- }
-
private static byte[] unwrapSessionData(byte[] keyEnc, int symmetricKeyAlgorithm, KeyParameter key)
throws PGPException, InvalidCipherTextException
{
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
index da7d66b21a..42e93a57bf 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -89,7 +89,7 @@ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
{
AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(new X25519KeyPairGenerator(), new X25519KeyGenerationParameters(random));
- byte[] secret = getSecret(new X25519Agreement(), cryptoPublicKey, ephKp);
+ byte[] secret = BcUtil.getSecret(new X25519Agreement(), ephKp.getPrivate(), cryptoPublicKey);
byte[] ephPubEncoding = new byte[1 + X25519PublicKeyParameters.KEY_SIZE];
ephPubEncoding[0] = X_HDR;
@@ -163,7 +163,7 @@ private byte[] encryptSessionInfo(PublicKeyPacket pubKeyPacket, byte[] sessionIn
throws PGPException, IOException
{
AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(gen, parameters);
- byte[] secret = getSecret(agreement, cryptoPublicKey, ephKp);
+ byte[] secret = BcUtil.getSecret(agreement, ephKp.getPrivate(), cryptoPublicKey);
byte[] ephPubEncoding = new byte[keySize];
ephPubEncodingOperation.getEphPubEncoding(ephKp.getPublic(), ephPubEncoding);
KeyParameter key = new KeyParameter(RFC6637KDFCalculator.createKey(hashAlgorithm, symmetricKeyAlgorithm,
@@ -188,12 +188,4 @@ private AsymmetricCipherKeyPair getAsymmetricCipherKeyPair(AsymmetricCipherKeyPa
gen.init(parameters);
return gen.generateKeyPair();
}
-
- private static byte[] getSecret(RawAgreement agreement, AsymmetricKeyParameter cryptoPublicKey, AsymmetricCipherKeyPair ephKp)
- {
- agreement.init(ephKp.getPrivate());
- byte[] secret = new byte[agreement.getAgreementSize()];
- agreement.calculateAgreement(cryptoPublicKey, secret, 0);
- return secret;
- }
}
\ No newline at end of file
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java
index 4804f3d828..9a4af7103c 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcUtil.java
@@ -11,10 +11,12 @@
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.DefaultBufferedBlockCipher;
+import org.bouncycastle.crypto.RawAgreement;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
import org.bouncycastle.crypto.io.CipherInputStream;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
import org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import org.bouncycastle.math.ec.ECCurve;
@@ -115,4 +117,12 @@ static ECPoint decodePoint(
{
return curve.decodePoint(BigIntegers.asUnsignedByteArray(encodedPoint));
}
+
+ static byte[] getSecret(RawAgreement agreement, AsymmetricKeyParameter privKey, AsymmetricKeyParameter ephPub)
+ {
+ agreement.init(privKey);
+ byte[] secret = new byte[agreement.getAgreementSize()];
+ agreement.calculateAgreement(ephPub, secret, 0);
+ return secret;
+ }
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
index 016bb4fad2..8da21226e5 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/RFC6637KDFCalculator.java
@@ -9,6 +9,7 @@
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
+import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
/**
@@ -48,12 +49,29 @@ public byte[] createKey(byte[] secret, byte[] userKeyingMaterial)
}
}
- public static byte[] createKey(int algorithm, int keyAlgorithm, byte[] secret, String info)
+ /**
+ * Creates a session key for X25519 or X448 encryption based on the provided algorithm and key algorithm.
+ *
+ * The method follows the specifications outlined in the OpenPGP standards, specifically sections 5.1.6 and 5.1.7
+ * of draft-ietf-openpgp-crypto-refresh-13.
+ *
+ * @param algorithm The algorithm to use for key derivation, such as SHA256 or SHA512.
+ * @param keyAlgorithm The key algorithm identifier, representing AES-128 or AES-256.
+ * @param prepend The bytes to prepend before deriving the key, which should include:
+ * - 32/56 octets of the ephemeral X25519 or X448 public key
+ * - 32/56 octets of the recipient public key material
+ * - 32/56 octets of the shared secret
+ * @param info The info parameter used in the HKDF function. For X25519, use "OpenPGP X25519".
+ * For X448, use "OpenPGP X448".
+ * @return The derived key for encryption.
+ * @throws PGPException If an error occurs during key derivation.
+ * @see draft-ietf-openpgp-crypto-refresh-13
+ */
+ public static byte[] createKey(int algorithm, int keyAlgorithm, byte[] prepend, String info)
throws PGPException
{
- // RFC 7748
HKDFBytesGenerator hkdf = new HKDFBytesGenerator(BcImplProvider.createDigest(algorithm));
- hkdf.init(new HKDFParameters(secret, null, info.getBytes()));
+ hkdf.init(new HKDFParameters(prepend, null, Strings.toByteArray(info)));
byte[] key = new byte[getKeyLen(keyAlgorithm)];
hkdf.generateBytes(key, 0, key.length);
return key;
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaJcePGPUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaJcePGPUtil.java
index 223b7aa626..312d2ffd5d 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaJcePGPUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaJcePGPUtil.java
@@ -2,18 +2,27 @@
import java.io.IOException;
import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.PublicKey;
+import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x9.ECNamedCurveTable;
import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
+import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpecWithPrepend;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.BigIntegers;
+import org.bouncycastle.util.Strings;
/**
* Basic utility class
@@ -21,11 +30,11 @@
class JcaJcePGPUtil
{
public static SecretKey makeSymmetricKey(
- int algorithm,
- byte[] keyBytes)
+ int algorithm,
+ byte[] keyBytes)
throws PGPException
{
- String algName = org.bouncycastle.openpgp.PGPUtil.getSymmetricCipherName(algorithm);
+ String algName = org.bouncycastle.openpgp.PGPUtil.getSymmetricCipherName(algorithm);
if (algName == null)
{
@@ -54,4 +63,19 @@ static X9ECParameters getX9Parameters(ASN1ObjectIdentifier curveOID)
return x9Params;
}
+
+ static UserKeyingMaterialSpecWithPrepend getUserKeyingMaterialSpecWithPrepend(byte[] ephmeralPublicKey, PublicKeyPacket pkp, String algorithmName)
+ throws IOException
+ {
+ return new UserKeyingMaterialSpecWithPrepend(Arrays.concatenate(ephmeralPublicKey, pkp.getEncoded()), Strings.toByteArray("OpenPGP " + algorithmName));
+ }
+
+ static Key getSecret(OperatorHelper helper, PublicKey cryptoPublicKey, String keyEncryptionOID, String agreementName, UserKeyingMaterialSpec ukmSpec, Key privKey)
+ throws GeneralSecurityException
+ {
+ KeyAgreement agreement = helper.createKeyAgreement(agreementName);
+ agreement.init(privKey, ukmSpec);
+ agreement.doPhase(cryptoPublicKey, true);
+ return agreement.generateSecret(keyEncryptionOID);
+ }
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
index 5a062bf3c9..b3e1722c63 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
@@ -2,11 +2,9 @@
import java.io.IOException;
import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
@@ -15,7 +13,6 @@
import java.util.Date;
import javax.crypto.Cipher;
-import javax.crypto.KeyAgreement;
import javax.crypto.interfaces.DHKey;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
@@ -255,14 +252,13 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
try
{
- KeyAgreement agreement;
PublicKey publicKey;
-
+ String agreementName;
ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKeyData.getKey();
// XDH
if (ecKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
{
- agreement = helper.createKeyAgreement(RFC6637Utils.getXDHAlgorithm(pubKeyData));
+ agreementName = RFC6637Utils.getXDHAlgorithm(pubKeyData);
if (pEnc.length != (1 + X25519PublicKeyParameters.KEY_SIZE) || 0x40 != pEnc[0])
{
throw new IllegalArgumentException("Invalid Curve25519 public key");
@@ -274,14 +270,14 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
X9ECParametersHolder x9Params = ECNamedCurveTable.getByOIDLazy(ecKey.getCurveOID());
ECPoint publicPoint = x9Params.getCurve().decodePoint(pEnc);
- agreement = helper.createKeyAgreement(RFC6637Utils.getAgreementAlgorithm(pubKeyData));
+ agreementName = RFC6637Utils.getAgreementAlgorithm(pubKeyData);
publicKey = converter.getPublicKey(new PGPPublicKey(new PublicKeyPacket(PublicKeyAlgorithmTags.ECDH, new Date(),
new ECDHPublicBCPGKey(ecKey.getCurveOID(), publicPoint, ecKey.getHashAlgorithm(), ecKey.getSymmetricKeyAlgorithm())), fingerprintCalculator));
}
byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyData, fingerprintCalculator);
- Key paddedSessionKey = getSessionKey(converter, privKey, agreement, publicKey, ecKey.getSymmetricKeyAlgorithm(), keyEnc, new UserKeyingMaterialSpec(userKeyingMaterial));
+ Key paddedSessionKey = getSessionKey(converter, privKey, agreementName, publicKey, ecKey.getSymmetricKeyAlgorithm(), keyEnc, new UserKeyingMaterialSpec(userKeyingMaterial));
return PGPPad.unpadSessionData(paddedSessionKey.getEncoded());
}
@@ -306,10 +302,9 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
}
byte[] keyEnc = new byte[keyLen - 1];
System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
- KeyAgreement agreement = helper.createKeyAgreement(agreementAlgorithm);
PublicKey publicKey = getPublicKey(pEnc, algprithmIdentifier, 0);
- Key paddedSessionKey = getSessionKey(converter, privKey, agreement, publicKey, symmetricKeyAlgorithm, keyEnc,
- new UserKeyingMaterialSpec(Arrays.concatenate(pEnc, privKey.getPublicKeyPacket().getKey().getEncoded()), ("OpenPGP " + algorithmName).getBytes()));
+ Key paddedSessionKey = getSessionKey(converter, privKey, agreementAlgorithm, publicKey, symmetricKeyAlgorithm, keyEnc,
+ JcaJcePGPUtil.getUserKeyingMaterialSpecWithPrepend(pEnc, privKey.getPublicKeyPacket(), algorithmName));
symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
return Arrays.concatenate(new byte[]{(byte)symmetricKeyAlgorithm}, paddedSessionKey.getEncoded());
}
@@ -319,14 +314,12 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
}
}
- private Key getSessionKey(JcaPGPKeyConverter converter, PGPPrivateKey privKey, KeyAgreement agreement,
+ private Key getSessionKey(JcaPGPKeyConverter converter, PGPPrivateKey privKey, String agreementName,
PublicKey publicKey, int symmetricKeyAlgorithm, byte[] keyEnc, UserKeyingMaterialSpec ukms)
- throws PGPException, InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException
+ throws PGPException, GeneralSecurityException
{
PrivateKey privateKey = converter.getPrivateKey(privKey);
- agreement.init(privateKey, ukms);
- agreement.doPhase(publicKey, true);
- Key key = agreement.generateSecret(RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId());
+ Key key = JcaJcePGPUtil.getSecret(helper, publicKey, RFC6637Utils.getKeyEncryptionOID(symmetricKeyAlgorithm).getId(), agreementName, ukms, privateKey);
Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
c.init(Cipher.UNWRAP_MODE, key);
return c.unwrap(keyEnc, "Session", Cipher.SECRET_KEY);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index 5a459822a4..d1a4400138 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -15,7 +15,6 @@
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.KeyAgreement;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
@@ -27,6 +26,7 @@
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
+import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpecWithPrepend;
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
@@ -190,7 +190,7 @@ private byte[] getEncryptSessionInfo(PublicKeyPacket pubKeyPacket, String algori
KeyPair ephKP = kpGen.generateKeyPair();
UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
new JcaKeyFingerprintCalculator()));
- Key secret = getSecret(cryptoPublicKey, keyEncryptionOID, agreementName, ukmSpec, ephKP);
+ Key secret = JcaJcePGPUtil.getSecret(helper, cryptoPublicKey, keyEncryptionOID, agreementName, ukmSpec, ephKP.getPrivate());
byte[] ephPubEncoding = getEncoding.getEphPubEncoding(SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes());
byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
@@ -215,9 +215,8 @@ private byte[] getEncryptSessionInfo(PGPPublicKey pgpPublicKey, String algorithm
KeyPair ephKP = kpGen.generateKeyPair();
byte[] ephPubEncoding = SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes();
- UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(Arrays.concatenate(ephPubEncoding, pgpPublicKey.getPublicKeyPacket().getKey().getEncoded()),
- ("OpenPGP " + algorithmName).getBytes());
- Key secret = getSecret(cryptoPublicKey, keyEncryptionOID, agreementAlgorithmName, ukmSpec, ephKP);
+ UserKeyingMaterialSpecWithPrepend ukmSpec = JcaJcePGPUtil.getUserKeyingMaterialSpecWithPrepend(ephPubEncoding, pgpPublicKey.getPublicKeyPacket(), algorithmName);
+ Key secret = JcaJcePGPUtil.getSecret(helper, cryptoPublicKey, keyEncryptionOID, agreementAlgorithmName, ukmSpec, ephKP.getPrivate());
//No checksum or padding
byte[] sessionData = new byte[sessionInfo.length - 3];
System.arraycopy(sessionInfo, 1, sessionData, 0, sessionData.length);
@@ -225,15 +224,6 @@ private byte[] getEncryptSessionInfo(PGPPublicKey pgpPublicKey, String algorithm
return getSessionInfo(ephPubEncoding, sessionInfo[0], getWrapper(symmetricKeyAlgorithm, sessionInfo, secret, sessionData));
}
- private Key getSecret(PublicKey cryptoPublicKey, String keyEncryptionOID, String agreementName, UserKeyingMaterialSpec ukmSpec, KeyPair ephKP)
- throws GeneralSecurityException
- {
- KeyAgreement agreement = helper.createKeyAgreement(agreementName);
- agreement.init(ephKP.getPrivate(), ukmSpec);
- agreement.doPhase(cryptoPublicKey, true);
- return agreement.generateSecret(keyEncryptionOID);
- }
-
private byte[] getWrapper(int symmetricKeyAlgorithm, byte[] sessionInfo, Key secret, byte[] sessionData)
throws PGPException, InvalidKeyException, IllegalBlockSizeException
{
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index 200101d5d6..da4d1d1f40 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -542,4 +542,6 @@ public void testX25519HKDF()
isTrue(Arrays.areEqual(output, expectedDecryptedSessionKey));
}
+
+
}
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
index 58cad2936a..13ed0483b8 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
@@ -1,17 +1,40 @@
package org.bouncycastle.openpgp.test;
+import java.security.Key;
+import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
+import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.Security;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
+import javax.crypto.KeyAgreement;
+
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.bcpg.AEADAlgorithmTags;
import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.crypto.Wrapper;
+import org.bouncycastle.crypto.agreement.X25519Agreement;
import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.engines.AESEngine;
+import org.bouncycastle.crypto.engines.RFC3394WrapEngine;
+import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
+import org.bouncycastle.crypto.params.HKDFParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
+import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
+import org.bouncycastle.crypto.util.PrivateKeyFactory;
+import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
+import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
+import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
+import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpecWithPrepend;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPPublicKey;
@@ -26,6 +49,9 @@
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
+import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
public class OperatorJcajceTest
@@ -48,6 +74,7 @@ public String getName()
public void performTest()
throws Exception
{
+ testX25519HKDF();
testJcePBESecretKeyEncryptorBuilder();
testJcaPGPContentVerifierBuilderProvider();
testJcaPGPDigestCalculatorProviderBuilder();
@@ -97,7 +124,7 @@ public void testJcePGPDataEncryptorBuilder()
{
testException("null cipher specified", "IllegalArgumentException", () -> new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.NULL));
- testException("AEAD algorithms can only be used with AES", "IllegalStateException", () -> new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.IDEA).setWithAEAD(AEADAlgorithmTags.OCB, 6));
+ //testException("AEAD algorithms can only be used with AES", "IllegalStateException", () -> new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.IDEA).setWithAEAD(AEADAlgorithmTags.OCB, 6));
testException("minimum chunkSize is 6", "IllegalArgumentException", () -> new JcePGPDataEncryptorBuilder(SymmetricKeyAlgorithmTags.AES_256).setWithAEAD(AEADAlgorithmTags.OCB, 5));
@@ -133,4 +160,39 @@ public void testJcePBESecretKeyEncryptorBuilder()
testException("s2KCount value outside of range 0 to 255.", "IllegalArgumentException", () -> new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc, -1));
}
+ public void testX25519HKDF()
+ throws Exception
+ {
+ byte[] ephmeralKey = Hex.decode("87cf18d5f1b53f817cce5a004cf393cc8958bddc065f25f84af509b17dd36764");
+ byte[] ephmeralSecretKey = Hex.decode("af1e43c0d123efe893a7d4d390f3a761e3fac33dfc7f3edaa830c9011352c779");
+ byte[] publicKey = Hex.decode("8693248367f9e5015db922f8f48095dda784987f2d5985b12fbad16caf5e4435");
+ byte[] expectedHKDF = Hex.decode("f66dadcff64592239b254539b64ff607");
+ byte[] keyEnc = Hex.decode("dea355437956617901e06957fbca8a6a47a5b5153e8d3ab7");
+ byte[] expectedDecryptedSessionKey = Hex.decode("dd708f6fa1ed65114d68d2343e7c2f1d");
+ X25519PrivateKeyParameters ephmeralprivateKeyParameters = new X25519PrivateKeyParameters(ephmeralSecretKey);
+ X25519PublicKeyParameters publicKeyParameters = new X25519PublicKeyParameters(publicKey);
+ KeyFactory keyfact = KeyFactory.getInstance("X25519", "BC");
+ PrivateKey privKey = keyfact.generatePrivate(new PKCS8EncodedKeySpec(PrivateKeyInfoFactory.createPrivateKeyInfo(ephmeralprivateKeyParameters).getEncoded()));
+ PublicKey pubKey = keyfact.generatePublic(new X509EncodedKeySpec(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKeyParameters).getEncoded()));
+ KeyAgreement agreement = KeyAgreement.getInstance("X25519withSHA256HKDF", "BC");
+ agreement.init(privKey, new UserKeyingMaterialSpecWithPrepend(Arrays.concatenate(ephmeralKey, publicKey), Strings.toByteArray("OpenPGP X25519")));
+ agreement.doPhase(pubKey, true);
+ Key secretKey= agreement.generateSecret(NISTObjectIdentifiers.id_aes128_wrap.getId());
+
+// agreement.init(ephmeralprivateKeyParameters);
+// byte[] secret = new byte[agreement.getAgreementSize()];
+// agreement.calculateAgreement(publicKeyParameters, secret, 0);
+ byte[] output2 = secretKey.getEncoded();
+
+// HKDFBytesGenerator hkdf = new HKDFBytesGenerator(new SHA256Digest());
+// hkdf.init(new HKDFParameters(Arrays.concatenate(ephmeralKey, publicKey, secret), null, "OpenPGP X25519".getBytes()));
+// hkdf.generateBytes(output2, 0, 16);
+//
+ isTrue(Arrays.areEqual(output2, expectedHKDF));
+// Wrapper c = new RFC3394WrapEngine(AESEngine.newInstance());
+// c.init(false, new KeyParameter(output2));
+// byte[] output = c.unwrap(keyEnc, 0, keyEnc.length);
+ //isTrue(Arrays.areEqual(output, expectedDecryptedSessionKey));
+ }
+
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
index ba094c28af..65d2be360a 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
@@ -25,6 +25,7 @@
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi;
import org.bouncycastle.jcajce.spec.DHUParameterSpec;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
+import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpecWithPrepend;
import org.bouncycastle.util.Properties;
public class KeyAgreementSpi
@@ -100,7 +101,15 @@ else if (params != null)
throw new InvalidAlgorithmParameterException("no KDF specified for UserKeyingMaterialSpec");
}
this.ukmParameters = ((UserKeyingMaterialSpec)params).getUserKeyingMaterial();
- ukmParametersSalt = ((UserKeyingMaterialSpec)params).getSalt();
+ this.ukmParametersSalt = ((UserKeyingMaterialSpec)params).getSalt();
+ if (params instanceof UserKeyingMaterialSpecWithPrepend)
+ {
+ this.ukmParametersPrepend = ((UserKeyingMaterialSpecWithPrepend)params).getPrepend();
+ }
+ else
+ {
+ this.ukmParametersPrepend = null;
+ }
}
else
{
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
index cd32613c57..e6126fe97a 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -154,6 +154,7 @@ public abstract class BaseAgreementSpi
protected byte[] ukmParameters;
protected byte[] ukmParametersSalt;
+ protected byte[] ukmParametersPrepend;
private HybridValueParameterSpec hybridSpec;
public BaseAgreementSpi(String kaAlgorithm, DerivationFunction kdf)
@@ -354,7 +355,7 @@ private byte[] getSharedSecretBytes(byte[] secret, String oidAlgorithm, int keyS
}
else if (kdf instanceof HKDFBytesGenerator)
{
- kdf.init(new HKDFParameters(Arrays.concatenate(ukmParameters, secret), null, ukmParametersSalt));
+ kdf.init(new HKDFParameters(Arrays.concatenate(ukmParametersPrepend, secret), ukmParametersSalt, ukmParameters));
}
else
{
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpecWithPrepend.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpecWithPrepend.java
new file mode 100644
index 0000000000..375cbc0143
--- /dev/null
+++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpecWithPrepend.java
@@ -0,0 +1,62 @@
+package org.bouncycastle.jcajce.spec;
+
+import org.bouncycastle.util.Arrays;
+
+/**
+ * This class extends {@link UserKeyingMaterialSpec} to store additional information required
+ * for HKDF in OpenPGP encryption, as outlined in sections 5.1.6 and 5.1.7 of
+ * draft-ietf-openpgp-crypto-refresh-13.
+ *
+ * The class is designed to hold the concatenated byte arrays of the ephemeral public keys
+ * and the shared secret in the {@code prepend} field, and the user keying material (info parameter)
+ * in the {@code userKeyingMaterial} field.
+ */
+public class UserKeyingMaterialSpecWithPrepend
+ extends UserKeyingMaterialSpec
+{
+ private final byte[] prepend;
+
+ /**
+ * Constructs a new UserKeyingMaterialSpecWithPrepend object with the specified prepend bytes
+ * and user keying material.
+ *
+ * @param prepend The bytes to prepend before deriving the key, which should include:
+ * - 32/56 octets of the ephemeral X25519 or X448 public key
+ * - 32/56 octets of the recipient public key material
+ * - 32/56 octets of the shared secret
+ * @param userKeyingMaterial The user keying material (info parameter) used for key derivation.
+ */
+ public UserKeyingMaterialSpecWithPrepend(byte[] prepend, byte[] userKeyingMaterial)
+ {
+ super(userKeyingMaterial);
+ this.prepend = Arrays.clone(prepend);
+ }
+
+
+ /**
+ * Constructs a new UserKeyingMaterialSpecWithPrepend object with the specified prepend bytes,
+ * user keying material, and salt.
+ *
+ * @param prepend The bytes to prepend before deriving the key, which should include:
+ * - 32/56 octets of the ephemeral X25519 or X448 public key
+ * - 32/56 octets of the recipient public key material
+ * - 32/56 octets of the shared secret
+ * @param userKeyingMaterial The user keying material (info parameter) used for key derivation.
+ * @param salt The salt value used in key derivation (can be {@code null}).
+ */
+ public UserKeyingMaterialSpecWithPrepend(byte[] prepend, byte[] userKeyingMaterial, byte[] salt)
+ {
+ super(userKeyingMaterial, salt);
+ this.prepend = Arrays.clone(prepend);
+ }
+
+ /**
+ * Get the bytes that are prepended before deriving the key.
+ *
+ * @return The prepend bytes.
+ */
+ public byte[] getPrepend()
+ {
+ return Arrays.clone(prepend);
+ }
+}
From 5954ec819a721b79535b71e10725260bdfa7652e Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 28 Feb 2024 16:56:14 +1100
Subject: [PATCH 0111/1846] fixed OSGI export
---
jmail/build.gradle | 2 +-
mail/build.gradle | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/jmail/build.gradle b/jmail/build.gradle
index bdfd42566e..62333c7649 100644
--- a/jmail/build.gradle
+++ b/jmail/build.gradle
@@ -81,7 +81,7 @@ jar {
}
manifest.attributes('Multi-Release': 'true')
manifest.attributes('Bundle-RequiredExecutionEnvironment': 'JavaSE-1.8')
- manifest.attributes('Export-Package': 'org.bouncycastle.*')
+ manifest.attributes('Export-Package': 'org.bouncycastle.mail.*')
manifest.attributes('Import-Package': 'java.*;resolution:=optional;javax.*;resolution:=optional;org.bouncycastle.*;version="[2.73,4)"')
}
diff --git a/mail/build.gradle b/mail/build.gradle
index 2efe22a4db..96e8135121 100644
--- a/mail/build.gradle
+++ b/mail/build.gradle
@@ -61,7 +61,7 @@ jar {
}
manifest.attributes('Multi-Release': 'true')
manifest.attributes('Bundle-RequiredExecutionEnvironment': 'JavaSE-1.8')
- manifest.attributes('Export-Package': 'org.bouncycastle.*')
+ manifest.attributes('Export-Package': 'org.bouncycastle.mail.*')
manifest.attributes('Import-Package': 'java.*;resolution:=optional;javax.*;resolution:=optional;org.bouncycastle.*;version="[2.73,4)"')
}
From 303e58849503f9acf609209ca1fd06154e754e30 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 28 Feb 2024 17:15:16 +1100
Subject: [PATCH 0112/1846] fixed OSGI export
---
util/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/util/build.gradle b/util/build.gradle
index 43c4555db9..c2267c65c6 100644
--- a/util/build.gradle
+++ b/util/build.gradle
@@ -74,7 +74,7 @@ jar {
manifest.attributes('Multi-Release': 'true')
manifest.attributes('Bundle-RequiredExecutionEnvironment': 'JavaSE-1.8')
- manifest.attributes('Export-Package': 'org.bouncycastle.*')
+ manifest.attributes('Export-Package': 'org.bouncycastle.asn1.{bsi|cmc|cmp|cms|crmf|dvcs|eac|esf|ess|est|icao|isismtt|smime|tsp}.*;org.bouncycastle.oer.*')
manifest.attributes('Import-Package': 'java.*;resolution:=optional;javax.*;resolution:=optional')
}
From 0cadb15f38126612bed37d8bd0b711b2fffadb9e Mon Sep 17 00:00:00 2001
From: David Hook
Date: Thu, 29 Feb 2024 13:52:06 +1100
Subject: [PATCH 0113/1846] fixed international characters in HTML
---
CONTRIBUTORS.html | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/CONTRIBUTORS.html b/CONTRIBUTORS.html
index 5be72106c7..563910cc91 100644
--- a/CONTRIBUTORS.html
+++ b/CONTRIBUTORS.html
@@ -384,7 +384,7 @@
Tobias Wich<tobias.wich@ecsec.de> Provided patch for TLS to work around servers sending Supported Elliptic Curves extension unexpectedly.
Hauke Mehrtens<hauke@hauke-m.de> TLS patch to add ECDHE_ECDSA CCM ciphersuites from RFC 7251.
Daniel Zimmerman<dmz@galois.com> Further key quality improvements to RSAKeyPairGenerator.
-Jens Kapitza<j.kapitza@schwarze-allianz.de> Iterable support in OpenPGP API, code cleanup in OpenPGP API.
+Jens Kapitza<j.kapitza@schwarze-allianz.de> Iterable support in OpenPGP API, code cleanup in OpenPGP API.
Johan Eklund<johan@primekey.se> update to RFC 6960 for OCSPObjectIdentifiers.
nikosn<https://github.com/nikosn> Fix to encoding of EC private keys to ensure encoding matches order length.
Axel von dem Bruch <axel-vdb@riseup.net> Contributions to BCrypt/OpenBSDBCrypt, original version of Blake2bDigest.
@@ -488,7 +488,7 @@
vvvlado <https://github.com/vvvlado> Fix to support repeated headers in PGP armored data.
a--v--k <https://github.com/a--v--k> Clean up for some invalid mappings in the Java provider.
lipnitsk <https://github.com/lipnitsk> Fix for non-CRT RSA Private serialisation.
-Niccolò Fontana <https://github.com/NicFontana> Initial fix for high-latency DTLS HelloVerifyRequest handshakes.
+Niccolò Fontana <https://github.com/NicFontana> Initial fix for high-latency DTLS HelloVerifyRequest handshakes.
sudheernv <https://github.com/sudheernv> Patch for KMAC rightEncode() encoding.
Mathias Neuhaus <https://github.com/mneuhaus-cv> Patch for cSHAKE extra padding on block aligned N and S bug.
Yuri Schimke <https://github.com/yschimke> Patch for nested exception handling in BcKeyStoreSpi.
@@ -529,7 +529,7 @@
Amazon AWS Security Team - isolation and identification of performance bottlenecks in the BC PEM parsing support.
Phillip Schichtel <https://github.com/pschichtel> - initial code for specifying wrapping algorithm with PGP PBE encryption method, forcing of session key usage.
Alexander Dippel <https://github.com/adippel> - corrections to prevent NPEs on chunked encoding of EST responses.
-Johann N. Löfflmann <https://github.com/jonelo> - fix to "too small" buffer issue in Blake2sp.
+Johann N. Löfflmann <https://github.com/jonelo> - fix to "too small" buffer issue in Blake2sp.
Scott Xu <https://github.com/scott-xu> - message fix in OpenSSHPublicKeyUtil
Scott Arciszewski <https://github/scottarc> - correction to ant scripts to ensure UTF8 support.
GitHub Security team - identification of the X509LDAPCertStoreSpi wildcard bug (see CVE-2023-33201).
From 9ec817308328a80b2a2245ac090a7c1f46f921e8 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Thu, 29 Feb 2024 14:04:59 +1100
Subject: [PATCH 0114/1846] fixed OSGI export
---
tls/build.gradle | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tls/build.gradle b/tls/build.gradle
index 4b1b8424b4..f19dbc8858 100644
--- a/tls/build.gradle
+++ b/tls/build.gradle
@@ -147,7 +147,7 @@ jar {
}
manifest.attributes('Multi-Release': 'true')
manifest.attributes('Bundle-RequiredExecutionEnvironment': 'JavaSE-1.8')
- manifest.attributes('Export-Package': 'org.bouncycastle.*')
+ manifest.attributes('Export-Package': 'org.bouncycastle.{jsse|tls}.*')
manifest.attributes('Import-Package': 'java.*;resolution:=optional;javax.*;resolution:=optional')
}
@@ -264,4 +264,4 @@ task test21(type: Test) {
excludeTestsMatching "${excludeTests}"
}
}
-}
\ No newline at end of file
+}
From 85cb6673a5ec1bea1ffaeae0e18b2766dbd983c0 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Thu, 29 Feb 2024 14:07:43 +1100
Subject: [PATCH 0115/1846] fixed OSGI export
---
pkix/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pkix/build.gradle b/pkix/build.gradle
index f81804caff..c8e1213a43 100644
--- a/pkix/build.gradle
+++ b/pkix/build.gradle
@@ -75,7 +75,7 @@ jar {
}
manifest.attributes('Multi-Release': 'true')
manifest.attributes('Bundle-RequiredExecutionEnvironment': 'JavaSE-1.8')
- manifest.attributes('Export-Package': 'org.bouncycastle.*')
+ manifest.attributes('Export-Package': 'org.bouncycastle.{cert|cms|operator|pkix|cmc|openssl|pkcs|tsp}.*')
manifest.attributes('Import-Package': 'java.*;resolution:=optional;javax.*;resolution:=optional')
}
From 0f3735426bd0b61be1f652930ddb9c0925db6883 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Thu, 29 Feb 2024 14:09:44 +1100
Subject: [PATCH 0116/1846] fixed OSGI export
---
mls/build.gradle | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/mls/build.gradle b/mls/build.gradle
index 23a4136c5f..fa4934dcce 100644
--- a/mls/build.gradle
+++ b/mls/build.gradle
@@ -121,6 +121,17 @@ extractIncludeTestProto {
createStartScripts('org.bouncycastle.mls.client.impl.MLSClient')
+jar {
+ from sourceSets.main.output
+ into('META-INF/versions/9') {
+ from sourceSets.java9.output
+ }
+ manifest.attributes('Multi-Release': 'true')
+ manifest.attributes('Bundle-RequiredExecutionEnvironment': 'JavaSE-1.8')
+ manifest.attributes('Export-Package': 'org.bouncycastle.mls.*')
+ manifest.attributes('Import-Package': 'java.*;resolution:=optional;javax.*;resolution:=optional')
+}
+
task sourcesJar(type: Jar) {
archiveBaseName = jar.archiveBaseName
archiveClassifier = 'sources'
@@ -139,4 +150,4 @@ artifacts {
archives jar
archives javadocJar
archives sourcesJar
-}
\ No newline at end of file
+}
From 45ee59e890564f4600cec91350d0702599daaae2 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Thu, 29 Feb 2024 14:11:15 +1100
Subject: [PATCH 0117/1846] fixed OSGI export
---
pg/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pg/build.gradle b/pg/build.gradle
index b838e6306d..7d6c9bea61 100644
--- a/pg/build.gradle
+++ b/pg/build.gradle
@@ -70,7 +70,7 @@ jar {
}
manifest.attributes('Multi-Release': 'true')
manifest.attributes('Bundle-RequiredExecutionEnvironment': 'JavaSE-1.8')
- manifest.attributes('Export-Package': 'org.bouncycastle.*')
+ manifest.attributes('Export-Package': 'org.bouncycastle.{apache|bcpg|gpg|openpgp}.*')
manifest.attributes('Import-Package': 'java.*;resolution:=optional;javax.*;resolution:=optional')
}
From 70e8def0a93d37c6afe9bd1109240416ed9875ef Mon Sep 17 00:00:00 2001
From: David Hook
Date: Thu, 29 Feb 2024 14:11:53 +1100
Subject: [PATCH 0118/1846] added debug stanza for subprojects
---
build.gradle | 3 +++
1 file changed, 3 insertions(+)
diff --git a/build.gradle b/build.gradle
index 2686b0b386..67a90e804e 100644
--- a/build.gradle
+++ b/build.gradle
@@ -245,6 +245,9 @@ subprojects {
reportsDirectory = layout.buildDirectory.dir("jacoco")
}
+ tasks.withType(JavaCompile).configureEach {
+ options.debug = true;
+ }
}
test.dependsOn([':core:test', ':prov:test', ':prov:test11', ':prov:test17', ':prov:test21', ':pkix:test', 'pg:test', ':tls:test', 'mls:test', 'mail:test', 'jmail:test'])
From b90d3b417c049eab1d988752f8ac78762645b73e Mon Sep 17 00:00:00 2001
From: David Hook
Date: Thu, 29 Feb 2024 14:53:54 +1100
Subject: [PATCH 0119/1846] added OSGI/module-info to MLS
---
mls/build.gradle | 44 +++++++++++++++++++++++-----
mls/src/main/jdk1.9/module-info.java | 16 ++++++++++
2 files changed, 52 insertions(+), 8 deletions(-)
create mode 100644 mls/src/main/jdk1.9/module-info.java
diff --git a/mls/build.gradle b/mls/build.gradle
index fa4934dcce..28b33b305d 100644
--- a/mls/build.gradle
+++ b/mls/build.gradle
@@ -3,18 +3,14 @@ plugins {
// OSGI
id "biz.aQute.bnd.builder" version "7.0.0"
// Provide convenience executables for trying out the examples.
- id 'application'
+// id 'application'
id 'com.google.protobuf' version '0.9.4'
// Generate IntelliJ IDEA's .idea & .iml project files
- id 'idea'
+// id 'idea'
}
-apply plugin: 'java'
-apply plugin: 'com.google.protobuf'
-
-// Set Java version to 1.8
-sourceCompatibility = 1.8
-targetCompatibility = 1.8
+//apply plugin: 'java'
+//apply plugin: 'com.google.protobuf'
dependencies {
implementation project(':core')
@@ -48,6 +44,14 @@ dependencies {
// compileOnly "org.apache.tomcat:annotations-api:6.0.53"
// runtimeOnly "io.grpc:grpc-netty-shaded:${grpcVersion}"
// implementation "com.google.protobuf:protobuf-java-util:${protocVersion}"
+
+ java9Implementation project(':core')
+ java9Implementation project(':prov')
+ java9Implementation project(':util')
+ java9Implementation project(':pkix')
+ java9Implementation files(sourceSets.main.output.classesDirs) {
+ builtBy compileJava
+ }
}
def grpcVersion = '1.58.0' // CURRENT_GRPC_VERSION
@@ -59,11 +63,27 @@ checkstyleMain {
}
compileJava {
+ sourceCompatibility = 1.8
+ targetCompatibility = 1.8
+
options.errorprone.disableWarningsInGeneratedCode = true
options.errorprone.errorproneArgs = ["-Xep:IgnoredPureGetter:OFF"]
options.errorprone.errorproneArgs.add("-XepExcludedPaths:.*/build/generated/.*")
}
+compileJava9Java {
+ javaCompiler = javaToolchains.compilerFor {
+ languageVersion = JavaLanguageVersion.of(17)
+ }
+ sourceCompatibility = 9
+ targetCompatibility = 9
+ options.compilerArgs += [
+ '--module-path', "${bc_prov}:${bc_util}:${bc_pkix}"
+ ]
+
+ options.sourcepath = files(['src/main/java', 'src/main/jdk1.9'])
+}
+
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:${protocVersion}"
@@ -89,6 +109,11 @@ sourceSets {
srcDirs 'build/generated/source/proto/main/java'
}
}
+ java9 {
+ java {
+ srcDirs = ['src/main/jdk1.9']
+ }
+ }
}
startScripts.enabled = false
@@ -137,6 +162,9 @@ task sourcesJar(type: Jar) {
archiveClassifier = 'sources'
from sourceSets.main.allSource
duplicatesStrategy = DuplicatesStrategy.INCLUDE
+ into('META-INF/versions/9') {
+ from sourceSets.java9.allSource
+ }
}
diff --git a/mls/src/main/jdk1.9/module-info.java b/mls/src/main/jdk1.9/module-info.java
new file mode 100644
index 0000000000..df6a17016f
--- /dev/null
+++ b/mls/src/main/jdk1.9/module-info.java
@@ -0,0 +1,16 @@
+module org.bouncycastle.mls
+{
+ provides java.security.Provider with org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
+
+ requires java.logging;
+ requires org.bouncycastle.provider;
+ requires org.bouncycastle.util;
+ requires org.bouncycastle.pkix;
+
+ exports org.bouncycastle.mls;
+ exports org.bouncycastle.mls.client;
+ exports org.bouncycastle.mls.protocol;
+ exports org.bouncycastle.mls.codec;
+ exports org.bouncycastle.mls.crypto;
+ exports org.bouncycastle.mls.crypto.bc;
+}
From 26cf352082138f2acb96bc781531468693981455 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Thu, 29 Feb 2024 15:07:10 +1100
Subject: [PATCH 0120/1846] temp rm of mls
---
settings.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/settings.gradle b/settings.gradle
index c54949b153..530566e28b 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -5,6 +5,6 @@ include "pkix"
include "prov"
include "tls"
include "test"
-include "mls"
+//include "mls"
include "mail"
include "jmail"
From cc4c67b0689594aabc831ce0122d411830851db8 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Thu, 29 Feb 2024 15:14:39 +1100
Subject: [PATCH 0121/1846] fix to mls build
---
mls/build.gradle | 35 +++++++++++++++-------------
mls/src/main/jdk1.9/module-info.java | 2 --
settings.gradle | 2 +-
3 files changed, 20 insertions(+), 19 deletions(-)
diff --git a/mls/build.gradle b/mls/build.gradle
index 28b33b305d..573aa1c0e1 100644
--- a/mls/build.gradle
+++ b/mls/build.gradle
@@ -3,14 +3,30 @@ plugins {
// OSGI
id "biz.aQute.bnd.builder" version "7.0.0"
// Provide convenience executables for trying out the examples.
-// id 'application'
+ id 'application'
id 'com.google.protobuf' version '0.9.4'
// Generate IntelliJ IDEA's .idea & .iml project files
// id 'idea'
}
-//apply plugin: 'java'
-//apply plugin: 'com.google.protobuf'
+apply plugin: 'java'
+apply plugin: 'com.google.protobuf'
+
+sourceSets {
+
+ main {
+ java {
+ srcDirs 'build/generated/source/proto/main/grpc'
+ srcDirs 'build/generated/source/proto/main/java'
+ }
+ }
+
+ java9 {
+ java {
+ srcDirs = ['src/main/jdk1.9']
+ }
+ }
+}
dependencies {
implementation project(':core')
@@ -102,19 +118,6 @@ protobuf {
jar.archiveBaseName = "bcmls-$vmrange"
-sourceSets {
- main {
- java {
- srcDirs 'build/generated/source/proto/main/grpc'
- srcDirs 'build/generated/source/proto/main/java'
- }
- }
- java9 {
- java {
- srcDirs = ['src/main/jdk1.9']
- }
- }
-}
startScripts.enabled = false
diff --git a/mls/src/main/jdk1.9/module-info.java b/mls/src/main/jdk1.9/module-info.java
index df6a17016f..836725fd4c 100644
--- a/mls/src/main/jdk1.9/module-info.java
+++ b/mls/src/main/jdk1.9/module-info.java
@@ -1,7 +1,5 @@
module org.bouncycastle.mls
{
- provides java.security.Provider with org.bouncycastle.jsse.provider.BouncyCastleJsseProvider;
-
requires java.logging;
requires org.bouncycastle.provider;
requires org.bouncycastle.util;
diff --git a/settings.gradle b/settings.gradle
index 530566e28b..c54949b153 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -5,6 +5,6 @@ include "pkix"
include "prov"
include "tls"
include "test"
-//include "mls"
+include "mls"
include "mail"
include "jmail"
From d5e9663d9fb6e988001ea11f6986dd6f10e3838d Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 2 Mar 2024 13:20:50 +1100
Subject: [PATCH 0122/1846] removed provider depency from AllTests - not
required
---
prov/src/test/java/org/bouncycastle/test/AllTests.java | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/prov/src/test/java/org/bouncycastle/test/AllTests.java b/prov/src/test/java/org/bouncycastle/test/AllTests.java
index 20a2f1177b..b0afa38aee 100644
--- a/prov/src/test/java/org/bouncycastle/test/AllTests.java
+++ b/prov/src/test/java/org/bouncycastle/test/AllTests.java
@@ -4,7 +4,6 @@
import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.Security;
@@ -36,12 +35,12 @@ public BCTestSetup(Test test)
protected void setUp()
{
- Security.addProvider(new BouncyCastleProvider());
+// Security.addProvider(new BouncyCastleProvider());
}
protected void tearDown()
{
- Security.removeProvider("BC");
+ // Security.removeProvider("BC");
}
}
}
From 8cf1e8eb5869f49905b7296e684bfa9dc1a4be10 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 2 Mar 2024 15:57:45 +1100
Subject: [PATCH 0123/1846] added use of JAVA_VERSION_PREFIX environment
variable
---
ant/bc+-build.xml | 1 +
build1-8+ | 6 ++++++
2 files changed, 7 insertions(+)
diff --git a/ant/bc+-build.xml b/ant/bc+-build.xml
index 567c2a5e7a..c071660291 100644
--- a/ant/bc+-build.xml
+++ b/ant/bc+-build.xml
@@ -991,6 +991,7 @@
+
diff --git a/build1-8+ b/build1-8+
index 94c8a3f32d..f99d5b0ac8 100644
--- a/build1-8+
+++ b/build1-8+
@@ -17,6 +17,12 @@ export JAVA_HOME
PATH=$JDKPATH/bin:$PATH
export PATH
+if [ "${JAVA_VERSION_PREFIX}" = "" ]
+then
+ JAVA_VERSION_PREFIX=1.8
+ export JAVA_VERSION_PREFIX
+fi
+
if [ "$1" = "test" ]
then
ant -f ant/jdk18+.xml test
From b7ecdf1cc27bada10fdba1a6f7641196d5c5eff6 Mon Sep 17 00:00:00 2001
From: Megan
Date: Sat, 2 Mar 2024 11:54:11 +0000
Subject: [PATCH 0124/1846] Update .gitlab-ci.yml file Add artifact for mls
test results.
---
.gitlab-ci.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index add5521b3c..df5b3c245d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -17,7 +17,8 @@ check-code:
- "pkix/build/reports"
- "mail/build/reports"
- "util/build/reports"
- - "tls/build/reports"
+ - "tls/build/reports"
+ - "mls/build/reports"
test-code-8:
stage: test
From f5b225047aa5ad5b4c2c420f9c4cc2febb7fff51 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 4 Mar 2024 16:27:57 +1100
Subject: [PATCH 0125/1846] removed use of UserKeyingMaterialSpecWithPrepend.
minor refactoring to reduce public methods. readded time converters for
backwards compatibility (now call Utils).
---
.../bcpg/sig/KeyExpirationTime.java | 6 ++
.../bcpg/sig/SignatureExpirationTime.java | 6 ++
.../java/org/bouncycastle/bcpg/sig/Utils.java | 4 +-
.../org/bouncycastle/gpg/SExpression.java | 2 +-
.../openpgp/PGPEncryptedData.java | 2 +-
.../openpgp/operator/PGPKeyConverter.java | 5 ++
.../operator/jcajce/JcaJcePGPUtil.java | 9 +--
...ePublicKeyDataDecryptorFactoryBuilder.java | 5 +-
...PublicKeyKeyEncryptionMethodGenerator.java | 4 +-
.../openpgp/test/OperatorJcajceTest.java | 16 +----
.../asymmetric/edec/KeyAgreementSpi.java | 9 ---
.../asymmetric/util/BaseAgreementSpi.java | 16 +++--
.../jcajce/spec/HybridValueParameterSpec.java | 29 ++++++++-
.../UserKeyingMaterialSpecWithPrepend.java | 62 -------------------
14 files changed, 73 insertions(+), 102 deletions(-)
delete mode 100644 prov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpecWithPrepend.java
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyExpirationTime.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyExpirationTime.java
index b0b10430cc..813cd02fc3 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyExpirationTime.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyExpirationTime.java
@@ -9,6 +9,12 @@
public class KeyExpirationTime
extends SignatureSubpacket
{
+ protected static byte[] timeToBytes(
+ long t)
+ {
+ return Utils.timeToBytes(t);
+ }
+
public KeyExpirationTime(
boolean critical,
boolean isLongLength,
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java
index 0fe70c1453..f5293a6a86 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java
@@ -9,6 +9,12 @@
public class SignatureExpirationTime
extends SignatureSubpacket
{
+ protected static byte[] timeToBytes(
+ long t)
+ {
+ return Utils.timeToBytes(t);
+ }
+
public SignatureExpirationTime(
boolean critical,
boolean isLongLength,
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java
index 85b8b5ad9c..33927b0ec8 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java
@@ -1,6 +1,6 @@
package org.bouncycastle.bcpg.sig;
-public class Utils
+class Utils
{
/**
* Convert the given boolean value into a one-entry byte array, where true is represented by a 1 and false is a 0.
@@ -19,7 +19,7 @@ static byte[] booleanToByteArray(boolean value)
return data;
}
- protected static byte[] timeToBytes(
+ static byte[] timeToBytes(
long t)
{
byte[] data = new byte[4];
diff --git a/pg/src/main/java/org/bouncycastle/gpg/SExpression.java b/pg/src/main/java/org/bouncycastle/gpg/SExpression.java
index 5de0cf0dee..102eb335d3 100644
--- a/pg/src/main/java/org/bouncycastle/gpg/SExpression.java
+++ b/pg/src/main/java/org/bouncycastle/gpg/SExpression.java
@@ -192,7 +192,7 @@ else if (c == -1)
}
- public static SExpression parseCanonical(InputStream _src, int maxDepth)
+ static SExpression parseCanonical(InputStream _src, int maxDepth)
throws IOException
{
SExpression expr = new SExpression();
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedData.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedData.java
index 76f08f4f24..8c56d1882d 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedData.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPEncryptedData.java
@@ -254,7 +254,7 @@ public int getAlgorithm()
throw new UnsupportedOperationException("not supported - override required");
}
- protected boolean processSymmetricEncIntegrityPacketDataStream(boolean withIntegrityPacket, PGPDataDecryptor dataDecryptor, BCPGInputStream encIn)
+ boolean processSymmetricEncIntegrityPacketDataStream(boolean withIntegrityPacket, PGPDataDecryptor dataDecryptor, BCPGInputStream encIn)
throws IOException
{
encStream = new BCPGInputStream(dataDecryptor.getInputStream(encIn));
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java
index 73943631a6..ccdea777b4 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java
@@ -19,6 +19,11 @@
public abstract class PGPKeyConverter
{
+ protected PGPKeyConverter()
+ {
+
+ }
+
/**
* Reference: RFC Draft-ietf-openpgp-crypto-refresh-13
*
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaJcePGPUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaJcePGPUtil.java
index 312d2ffd5d..8d1a75b737 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaJcePGPUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaJcePGPUtil.java
@@ -5,6 +5,7 @@
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.PublicKey;
+import java.security.spec.AlgorithmParameterSpec;
import javax.crypto.KeyAgreement;
import javax.crypto.SecretKey;
@@ -15,8 +16,8 @@
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.jcajce.spec.HybridValueParameterSpec;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
-import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpecWithPrepend;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.openpgp.PGPException;
@@ -64,13 +65,13 @@ static X9ECParameters getX9Parameters(ASN1ObjectIdentifier curveOID)
return x9Params;
}
- static UserKeyingMaterialSpecWithPrepend getUserKeyingMaterialSpecWithPrepend(byte[] ephmeralPublicKey, PublicKeyPacket pkp, String algorithmName)
+ static HybridValueParameterSpec getHybridValueParameterSpecWithPrepend(byte[] ephmeralPublicKey, PublicKeyPacket pkp, String algorithmName)
throws IOException
{
- return new UserKeyingMaterialSpecWithPrepend(Arrays.concatenate(ephmeralPublicKey, pkp.getEncoded()), Strings.toByteArray("OpenPGP " + algorithmName));
+ return new HybridValueParameterSpec(Arrays.concatenate(ephmeralPublicKey, pkp.getEncoded()), true, new UserKeyingMaterialSpec(Strings.toByteArray("OpenPGP " + algorithmName)));
}
- static Key getSecret(OperatorHelper helper, PublicKey cryptoPublicKey, String keyEncryptionOID, String agreementName, UserKeyingMaterialSpec ukmSpec, Key privKey)
+ static Key getSecret(OperatorHelper helper, PublicKey cryptoPublicKey, String keyEncryptionOID, String agreementName, AlgorithmParameterSpec ukmSpec, Key privKey)
throws GeneralSecurityException
{
KeyAgreement agreement = helper.createKeyAgreement(agreementName);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
index b3e1722c63..9f636c2501 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyDataDecryptorFactoryBuilder.java
@@ -9,6 +9,7 @@
import java.security.Provider;
import java.security.PublicKey;
import java.security.interfaces.RSAKey;
+import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Date;
@@ -304,7 +305,7 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
System.arraycopy(enc, pLen + 2, keyEnc, 0, keyEnc.length);
PublicKey publicKey = getPublicKey(pEnc, algprithmIdentifier, 0);
Key paddedSessionKey = getSessionKey(converter, privKey, agreementAlgorithm, publicKey, symmetricKeyAlgorithm, keyEnc,
- JcaJcePGPUtil.getUserKeyingMaterialSpecWithPrepend(pEnc, privKey.getPublicKeyPacket(), algorithmName));
+ JcaJcePGPUtil.getHybridValueParameterSpecWithPrepend(pEnc, privKey.getPublicKeyPacket(), algorithmName));
symmetricKeyAlgorithm = enc[pLen + 1] & 0xff;
return Arrays.concatenate(new byte[]{(byte)symmetricKeyAlgorithm}, paddedSessionKey.getEncoded());
}
@@ -315,7 +316,7 @@ private byte[] decryptSessionData(JcaPGPKeyConverter converter, PGPPrivateKey pr
}
private Key getSessionKey(JcaPGPKeyConverter converter, PGPPrivateKey privKey, String agreementName,
- PublicKey publicKey, int symmetricKeyAlgorithm, byte[] keyEnc, UserKeyingMaterialSpec ukms)
+ PublicKey publicKey, int symmetricKeyAlgorithm, byte[] keyEnc, AlgorithmParameterSpec ukms)
throws PGPException, GeneralSecurityException
{
PrivateKey privateKey = converter.getPrivateKey(privKey);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
index d1a4400138..72bb0cb56c 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -25,8 +25,8 @@
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.jcajce.spec.HybridValueParameterSpec;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
-import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpecWithPrepend;
import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
@@ -215,7 +215,7 @@ private byte[] getEncryptSessionInfo(PGPPublicKey pgpPublicKey, String algorithm
KeyPair ephKP = kpGen.generateKeyPair();
byte[] ephPubEncoding = SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes();
- UserKeyingMaterialSpecWithPrepend ukmSpec = JcaJcePGPUtil.getUserKeyingMaterialSpecWithPrepend(ephPubEncoding, pgpPublicKey.getPublicKeyPacket(), algorithmName);
+ HybridValueParameterSpec ukmSpec = JcaJcePGPUtil.getHybridValueParameterSpecWithPrepend(ephPubEncoding, pgpPublicKey.getPublicKeyPacket(), algorithmName);
Key secret = JcaJcePGPUtil.getSecret(helper, cryptoPublicKey, keyEncryptionOID, agreementAlgorithmName, ukmSpec, ephKP.getPrivate());
//No checksum or padding
byte[] sessionData = new byte[sessionInfo.length - 3];
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
index 13ed0483b8..8eb4a5d8f3 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
@@ -15,33 +15,23 @@
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.bcpg.AEADAlgorithmTags;
-import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
-import org.bouncycastle.crypto.Wrapper;
-import org.bouncycastle.crypto.agreement.X25519Agreement;
import org.bouncycastle.crypto.digests.SHA256Digest;
-import org.bouncycastle.crypto.engines.AESEngine;
-import org.bouncycastle.crypto.engines.RFC3394WrapEngine;
-import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
-import org.bouncycastle.crypto.params.HKDFParameters;
-import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
-import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
+import org.bouncycastle.jcajce.spec.HybridValueParameterSpec;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
-import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpecWithPrepend;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openpgp.PGPEncryptedData;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.operator.PGPContentVerifier;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
-import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
@@ -175,7 +165,7 @@ public void testX25519HKDF()
PrivateKey privKey = keyfact.generatePrivate(new PKCS8EncodedKeySpec(PrivateKeyInfoFactory.createPrivateKeyInfo(ephmeralprivateKeyParameters).getEncoded()));
PublicKey pubKey = keyfact.generatePublic(new X509EncodedKeySpec(SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(publicKeyParameters).getEncoded()));
KeyAgreement agreement = KeyAgreement.getInstance("X25519withSHA256HKDF", "BC");
- agreement.init(privKey, new UserKeyingMaterialSpecWithPrepend(Arrays.concatenate(ephmeralKey, publicKey), Strings.toByteArray("OpenPGP X25519")));
+ agreement.init(privKey, new HybridValueParameterSpec(Arrays.concatenate(ephmeralKey, publicKey), true, new UserKeyingMaterialSpec(Strings.toByteArray("OpenPGP X25519"))));
agreement.doPhase(pubKey, true);
Key secretKey= agreement.generateSecret(NISTObjectIdentifiers.id_aes128_wrap.getId());
@@ -188,7 +178,7 @@ public void testX25519HKDF()
// hkdf.init(new HKDFParameters(Arrays.concatenate(ephmeralKey, publicKey, secret), null, "OpenPGP X25519".getBytes()));
// hkdf.generateBytes(output2, 0, 16);
//
- isTrue(Arrays.areEqual(output2, expectedHKDF));
+ isTrue("hkdf failed", Arrays.areEqual(output2, expectedHKDF));
// Wrapper c = new RFC3394WrapEngine(AESEngine.newInstance());
// c.init(false, new KeyParameter(output2));
// byte[] output = c.unwrap(keyEnc, 0, keyEnc.length);
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
index 65d2be360a..dae9d9e0fa 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java
@@ -25,7 +25,6 @@
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi;
import org.bouncycastle.jcajce.spec.DHUParameterSpec;
import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
-import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpecWithPrepend;
import org.bouncycastle.util.Properties;
public class KeyAgreementSpi
@@ -102,14 +101,6 @@ else if (params != null)
}
this.ukmParameters = ((UserKeyingMaterialSpec)params).getUserKeyingMaterial();
this.ukmParametersSalt = ((UserKeyingMaterialSpec)params).getSalt();
- if (params instanceof UserKeyingMaterialSpecWithPrepend)
- {
- this.ukmParametersPrepend = ((UserKeyingMaterialSpecWithPrepend)params).getPrepend();
- }
- else
- {
- this.ukmParametersPrepend = null;
- }
}
else
{
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
index e6126fe97a..75babbdc36 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -25,7 +25,6 @@
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.DerivationFunction;
-import org.bouncycastle.crypto.agreement.X448Agreement;
import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
import org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator;
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
@@ -154,7 +153,6 @@ public abstract class BaseAgreementSpi
protected byte[] ukmParameters;
protected byte[] ukmParametersSalt;
- protected byte[] ukmParametersPrepend;
private HybridValueParameterSpec hybridSpec;
public BaseAgreementSpi(String kaAlgorithm, DerivationFunction kdf)
@@ -252,6 +250,7 @@ protected void engineInit(
if (params instanceof HybridValueParameterSpec)
{
this.hybridSpec = (HybridValueParameterSpec)params;
+
doInitFromKey(key, hybridSpec.getBaseParameterSpec(), random);
}
else
@@ -355,7 +354,7 @@ private byte[] getSharedSecretBytes(byte[] secret, String oidAlgorithm, int keyS
}
else if (kdf instanceof HKDFBytesGenerator)
{
- kdf.init(new HKDFParameters(Arrays.concatenate(ukmParametersPrepend, secret), ukmParametersSalt, ukmParameters));
+ kdf.init(new HKDFParameters(secret, ukmParametersSalt, ukmParameters));
}
else
{
@@ -393,7 +392,16 @@ private byte[] calcSecret()
{
// Set Z' to Z || T
byte[] s = doCalcSecret();
- byte[] sec = Arrays.concatenate(s, hybridSpec.getT());
+ byte[] sec;
+
+ if (hybridSpec.isPrependedT())
+ {
+ sec = Arrays.concatenate(hybridSpec.getT(), s);
+ }
+ else
+ {
+ sec = Arrays.concatenate(s, hybridSpec.getT());
+ }
Arrays.clear(s);
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/HybridValueParameterSpec.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/HybridValueParameterSpec.java
index 6bf38359bc..0e825f55d8 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/spec/HybridValueParameterSpec.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/HybridValueParameterSpec.java
@@ -8,8 +8,9 @@
import org.bouncycastle.util.Arrays;
/**
- * SP 800-56C Hybrid Value spec, to allow the secret in a key agreement to be
- * created as "Z | T" where T is some other secret value as described in Section 2.
+ * SP 800-56C Hybrid Value spec, by default to allow the secret in a key agreement to be
+ * created as "Z | T" where T is some other secret value as described in Section 2. If the
+ * value doPrepend is set to true the spec will be used to calculate "T | Z" instead.
*
* Get methods throw IllegalStateException if destroy() is called.
*
@@ -19,6 +20,8 @@ public class HybridValueParameterSpec
{
private final AtomicBoolean hasBeenDestroyed = new AtomicBoolean(false);
+ private final boolean doPrepend;
+
private volatile byte[] t;
private volatile AlgorithmParameterSpec baseSpec;
@@ -30,9 +33,31 @@ public class HybridValueParameterSpec
* @param baseSpec the base spec for the agreements KDF.
*/
public HybridValueParameterSpec(byte[] t, AlgorithmParameterSpec baseSpec)
+ {
+ this(t, false, baseSpec);
+ }
+
+ /**
+ * Create a spec with T set to t and the spec for the KDF in the agreement to baseSpec.
+ * Note: the t value is not copied.
+ * @param t a shared secret to be concatenated with the agreement's Z value.
+ * @param baseSpec the base spec for the agreements KDF.
+ */
+ public HybridValueParameterSpec(byte[] t, boolean doPrepend, AlgorithmParameterSpec baseSpec)
{
this.t = t;
this.baseSpec = baseSpec;
+ this.doPrepend = doPrepend;
+ }
+
+ /**
+ * Return whether or not T should be prepended.
+ *
+ * @return true if T to be prepended, false otherwise.
+ */
+ public boolean isPrependedT()
+ {
+ return doPrepend;
}
/**
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpecWithPrepend.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpecWithPrepend.java
deleted file mode 100644
index 375cbc0143..0000000000
--- a/prov/src/main/java/org/bouncycastle/jcajce/spec/UserKeyingMaterialSpecWithPrepend.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package org.bouncycastle.jcajce.spec;
-
-import org.bouncycastle.util.Arrays;
-
-/**
- * This class extends {@link UserKeyingMaterialSpec} to store additional information required
- * for HKDF in OpenPGP encryption, as outlined in sections 5.1.6 and 5.1.7 of
- * draft-ietf-openpgp-crypto-refresh-13.
- *
- * The class is designed to hold the concatenated byte arrays of the ephemeral public keys
- * and the shared secret in the {@code prepend} field, and the user keying material (info parameter)
- * in the {@code userKeyingMaterial} field.
- */
-public class UserKeyingMaterialSpecWithPrepend
- extends UserKeyingMaterialSpec
-{
- private final byte[] prepend;
-
- /**
- * Constructs a new UserKeyingMaterialSpecWithPrepend object with the specified prepend bytes
- * and user keying material.
- *
- * @param prepend The bytes to prepend before deriving the key, which should include:
- * - 32/56 octets of the ephemeral X25519 or X448 public key
- * - 32/56 octets of the recipient public key material
- * - 32/56 octets of the shared secret
- * @param userKeyingMaterial The user keying material (info parameter) used for key derivation.
- */
- public UserKeyingMaterialSpecWithPrepend(byte[] prepend, byte[] userKeyingMaterial)
- {
- super(userKeyingMaterial);
- this.prepend = Arrays.clone(prepend);
- }
-
-
- /**
- * Constructs a new UserKeyingMaterialSpecWithPrepend object with the specified prepend bytes,
- * user keying material, and salt.
- *
- * @param prepend The bytes to prepend before deriving the key, which should include:
- * - 32/56 octets of the ephemeral X25519 or X448 public key
- * - 32/56 octets of the recipient public key material
- * - 32/56 octets of the shared secret
- * @param userKeyingMaterial The user keying material (info parameter) used for key derivation.
- * @param salt The salt value used in key derivation (can be {@code null}).
- */
- public UserKeyingMaterialSpecWithPrepend(byte[] prepend, byte[] userKeyingMaterial, byte[] salt)
- {
- super(userKeyingMaterial, salt);
- this.prepend = Arrays.clone(prepend);
- }
-
- /**
- * Get the bytes that are prepended before deriving the key.
- *
- * @return The prepend bytes.
- */
- public byte[] getPrepend()
- {
- return Arrays.clone(prepend);
- }
-}
From 3b8be522806c468c252ca2da1d802af20398e4f8 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Mon, 4 Mar 2024 13:06:38 +0700
Subject: [PATCH 0126/1846] Refactor RSA engines
---
.../crypto/engines/RSABlindedEngine.java | 50 ++++++-------------
.../crypto/engines/RSACoreEngine.java | 20 +++-----
2 files changed, 24 insertions(+), 46 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java
index 3b9edb901b..4ce1fccedd 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/RSABlindedEngine.java
@@ -30,40 +30,20 @@ public class RSABlindedEngine
* @param forEncryption true if we are encrypting, false otherwise.
* @param param the necessary RSA key parameters.
*/
- public void init(
- boolean forEncryption,
- CipherParameters param)
+ public void init(boolean forEncryption, CipherParameters parameters)
{
- core.init(forEncryption, param);
-
- if (param instanceof ParametersWithRandom)
+ SecureRandom providedRandom = null;
+ if (parameters instanceof ParametersWithRandom)
{
- ParametersWithRandom rParam = (ParametersWithRandom)param;
-
- this.key = (RSAKeyParameters)rParam.getParameters();
-
- if (key instanceof RSAPrivateCrtKeyParameters)
- {
- this.random = rParam.getRandom();
- }
- else
- {
- this.random = null;
- }
+ ParametersWithRandom withRandom = (ParametersWithRandom)parameters;
+ providedRandom = withRandom.getRandom();
+ parameters = withRandom.getParameters();
}
- else
- {
- this.key = (RSAKeyParameters)param;
- if (key instanceof RSAPrivateCrtKeyParameters)
- {
- this.random = CryptoServicesRegistrar.getSecureRandom();
- }
- else
- {
- this.random = null;
- }
- }
+ core.init(forEncryption, parameters);
+
+ this.key = (RSAKeyParameters)parameters;
+ this.random = initSecureRandom(key instanceof RSAPrivateCrtKeyParameters, providedRandom);
}
/**
@@ -99,10 +79,7 @@ public int getOutputBlockSize()
* @return the result of the RSA process.
* @exception DataLengthException the input block is too large.
*/
- public byte[] processBlock(
- byte[] in,
- int inOff,
- int inLen)
+ public byte[] processBlock(byte[] in, int inOff, int inLen)
{
if (key == null)
{
@@ -114,6 +91,11 @@ public byte[] processBlock(
return core.convertOutput(result);
}
+ protected SecureRandom initSecureRandom(boolean needed, SecureRandom provided)
+ {
+ return needed ? CryptoServicesRegistrar.getSecureRandom(provided) : null;
+ }
+
private BigInteger processInput(BigInteger input)
{
if (key instanceof RSAPrivateCrtKeyParameters)
diff --git a/core/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java b/core/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java
index 0525948aec..cfc0913212 100644
--- a/core/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java
+++ b/core/src/main/java/org/bouncycastle/crypto/engines/RSACoreEngine.java
@@ -27,24 +27,20 @@ class RSACoreEngine
* @param forEncryption true if we are encrypting, false otherwise.
* @param param the necessary RSA key parameters.
*/
- public void init(
- boolean forEncryption,
- CipherParameters param)
+ public void init(boolean forEncryption, CipherParameters parameters)
{
- if (param instanceof ParametersWithRandom)
+ if (parameters instanceof ParametersWithRandom)
{
- ParametersWithRandom rParam = (ParametersWithRandom)param;
-
- key = (RSAKeyParameters)rParam.getParameters();
- }
- else
- {
- key = (RSAKeyParameters)param;
+ ParametersWithRandom withRandom = (ParametersWithRandom)parameters;
+ parameters = withRandom.getParameters();
}
this.forEncryption = forEncryption;
+ this.key = (RSAKeyParameters)parameters;
- CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties("RSA", ConstraintUtils.bitsOfSecurityFor(key.getModulus()), key, getPurpose(key.isPrivate(), forEncryption)));
+ int bitsOfSecurity = ConstraintUtils.bitsOfSecurityFor(key.getModulus());
+ CryptoServicePurpose purpose = getPurpose(key.isPrivate(), forEncryption);
+ CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties("RSA", bitsOfSecurity, key, purpose));
}
/**
From 98b18399b112fd44b4de660b04ec9876d7117a25 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Mon, 4 Mar 2024 13:14:12 +0700
Subject: [PATCH 0127/1846] Fix timing dependency on RSA output
---
.../crypto/tls/TlsRsaKeyExchange.java | 222 ++++++++++--------
1 file changed, 124 insertions(+), 98 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java b/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
index f5573a2cd3..e9694247d0 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
@@ -25,9 +25,9 @@ private TlsRsaKeyExchange()
public static byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret, RSAKeyParameters privateKey,
int protocolVersion, SecureRandom secureRandom)
{
- if (encryptedPreMasterSecret == null)
+ if (Arrays.isNullOrEmpty(encryptedPreMasterSecret))
{
- throw new NullPointerException("'encryptedPreMasterSecret' cannot be null");
+ throw new IllegalArgumentException("'encryptedPreMasterSecret' cannot be null or empty");
}
if (!privateKey.isPrivate())
@@ -61,20 +61,13 @@ public static byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret, RSA
try
{
- int pkcs1Length = (bitLength - 1) / 8;
- int plainTextOffset = pkcs1Length - 48;
-
BigInteger input = convertInput(modulus, encryptedPreMasterSecret);
- BigInteger output = rsaBlinded(privateKey, input, secureRandom);
- byte[] block = convertOutput(output);
+ byte[] encoding = rsaBlinded(privateKey, input, secureRandom);
- byte[] encoding = block;
- if (block.length != pkcs1Length)
- {
- encoding = new byte[pkcs1Length];
- }
+ int pkcs1Length = (bitLength - 1) / 8;
+ int plainTextOffset = encoding.length - 48;
- int badEncodingMask = checkPkcs1Encoding2(encoding, 48);
+ int badEncodingMask = checkPkcs1Encoding2(encoding, pkcs1Length, 48);
int badVersionMask = -((Pack.bigEndianToShort(encoding, plainTextOffset) ^ protocolVersion) & 0xFFFF) >> 31;
int fallbackMask = badEncodingMask | badVersionMask;
@@ -83,7 +76,7 @@ public static byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret, RSA
result[i] = (byte)((result[i] & fallbackMask) | (encoding[plainTextOffset + i] & ~fallbackMask));
}
- Arrays.fill(block, (byte)0);
+ Arrays.fill(encoding, (byte)0);
}
catch (Exception e)
{
@@ -99,33 +92,55 @@ public static byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret, RSA
return result;
}
+ private static int caddTo(int len, int cond, byte[] x, byte[] z)
+ {
+// assert cond == 0 || cond == -1;
+ int mask = cond & 0xFF;
+
+ int c = 0;
+ for (int i = len - 1; i >= 0; --i)
+ {
+ c += (z[i] & 0xFF) + (x[i] & mask);
+ z[i] = (byte)c;
+ c >>>= 8;
+ }
+ return c;
+ }
+
/**
* Check the argument is a valid encoding with type 2 of a plaintext with the given length. Returns 0 if
* valid, or -1 if invalid.
*/
- private static int checkPkcs1Encoding2(byte[] buf, int plaintextLength)
+ private static int checkPkcs1Encoding2(byte[] buf, int pkcs1Length, int plaintextLength)
{
- // The first byte should be 0x02
- int badPadSign = -((buf[0] & 0xFF) ^ 0x02);
+ // The header should be at least 10 bytes
+ int errorSign = pkcs1Length - plaintextLength - 10;
+ int firstPadPos = buf.length - pkcs1Length;
int lastPadPos = buf.length - 1 - plaintextLength;
- // The header should be at least 10 bytes
- badPadSign |= lastPadPos - 9;
+ // Any leading bytes should be zero
+ for (int i = 0; i < firstPadPos; ++i)
+ {
+ errorSign |= -(buf[i] & 0xFF);
+ }
+
+ // The first byte should be 0x02
+ errorSign |= -((buf[firstPadPos] & 0xFF) ^ 0x02);
// All pad bytes before the last one should be non-zero
- for (int i = 1; i < lastPadPos; ++i)
+ for (int i = firstPadPos + 1; i < lastPadPos; ++i)
{
- badPadSign |= (buf[i] & 0xFF) - 1;
+ errorSign |= (buf[i] & 0xFF) - 1;
}
// Last pad byte should be zero
- badPadSign |= -(buf[lastPadPos] & 0xFF);
+ errorSign |= -(buf[lastPadPos] & 0xFF);
- return badPadSign >> 31;
+ return errorSign >> 31;
}
- public static BigInteger convertInput(BigInteger modulus, byte[] input)
+ private static BigInteger convertInput(BigInteger modulus, byte[] input)
{
int inputLimit = (modulus.bitLength() + 7) / 8;
@@ -141,100 +156,111 @@ public static BigInteger convertInput(BigInteger modulus, byte[] input)
throw new DataLengthException("input too large for RSA cipher.");
}
- public static byte[] convertOutput(BigInteger result)
+ private static BigInteger rsa(RSAKeyParameters privateKey, BigInteger input)
{
- byte[] output = result.toByteArray();
-
- byte[] rv;
- if (output[0] == 0) // have ended up with an extra zero byte, copy down.
- {
- rv = new byte[output.length - 1];
-
- System.arraycopy(output, 1, rv, 0, rv.length);
- }
- else // maintain decryption time
- {
- rv = new byte[output.length];
-
- System.arraycopy(output, 0, rv, 0, rv.length);
- }
-
- Arrays.fill(output, (byte) 0);
-
- return rv;
+ return input.modPow(privateKey.getExponent(), privateKey.getModulus());
}
- private static BigInteger rsa(RSAKeyParameters privateKey, BigInteger input)
+ private static byte[] rsaBlinded(RSAKeyParameters privateKey, BigInteger input, SecureRandom secureRandom)
{
+ BigInteger modulus = privateKey.getModulus();
+ int resultSize = modulus.bitLength() / 8 + 1;
+
if (privateKey instanceof RSAPrivateCrtKeyParameters)
{
- //
- // we have the extra factors, use the Chinese Remainder Theorem - the author
- // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
- // advice regarding the expression of this.
- //
RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)privateKey;
BigInteger e = crtKey.getPublicExponent();
- if (e != null) // can't apply fault-attack countermeasure without public exponent
+ if (e != null) // can't do blinding without a public exponent
{
- BigInteger p = crtKey.getP();
- BigInteger q = crtKey.getQ();
- BigInteger dP = crtKey.getDP();
- BigInteger dQ = crtKey.getDQ();
- BigInteger qInv = crtKey.getQInv();
-
- BigInteger mP, mQ, h, m;
-
- // mP = ((input mod p) ^ dP)) mod p
- mP = (input.remainder(p)).modPow(dP, p);
-
- // mQ = ((input mod q) ^ dQ)) mod q
- mQ = (input.remainder(q)).modPow(dQ, q);
-
- // h = qInv * (mP - mQ) mod p
- h = mP.subtract(mQ);
- h = h.multiply(qInv);
- h = h.mod(p); // mod (in Java) returns the positive residual
-
- // m = h * q + mQ
- m = h.multiply(q).add(mQ);
-
- // defence against Arjen Lenstra’s CRT attack
- BigInteger check = m.modPow(e, crtKey.getModulus());
- if (!check.equals(input))
- {
- throw new IllegalStateException("RSA engine faulty decryption/signing detected");
- }
-
- return m;
+ BigInteger r = BigIntegers.createRandomInRange(ONE, modulus.subtract(ONE), secureRandom);
+ BigInteger blind = r.modPow(e, modulus);
+ BigInteger unblind = BigIntegers.modOddInverse(modulus, r);
+
+ BigInteger blindedInput = blind.multiply(input).mod(modulus);
+ BigInteger blindedResult = rsaCrt(crtKey, blindedInput);
+ BigInteger offsetResult = unblind.add(ONE).multiply(blindedResult).mod(modulus);
+
+ /*
+ * BigInteger conversion time is not constant, but is only done for blinded or public values.
+ */
+ byte[] blindedResultBytes = toBytes(blindedResult, resultSize);
+ byte[] modulusBytes = toBytes(modulus, resultSize);
+ byte[] resultBytes = toBytes(offsetResult, resultSize);
+
+ /*
+ * A final modular subtraction is done without timing dependencies on the final result.
+ */
+ int carry = subFrom(resultSize, blindedResultBytes, resultBytes);
+ caddTo(resultSize, carry, modulusBytes, resultBytes);
+
+ return resultBytes;
}
}
- return input.modPow(privateKey.getExponent(), privateKey.getModulus());
+ return toBytes(rsa(privateKey, input), resultSize);
}
- private static BigInteger rsaBlinded(RSAKeyParameters privateKey, BigInteger input, SecureRandom secureRandom)
+ private static BigInteger rsaCrt(RSAPrivateCrtKeyParameters crtKey, BigInteger input)
{
- if (privateKey instanceof RSAPrivateCrtKeyParameters)
+ //
+ // we have the extra factors, use the Chinese Remainder Theorem - the author
+ // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
+ // advice regarding the expression of this.
+ //
+ BigInteger e = crtKey.getPublicExponent();
+// assert e != null;
+
+ BigInteger p = crtKey.getP();
+ BigInteger q = crtKey.getQ();
+ BigInteger dP = crtKey.getDP();
+ BigInteger dQ = crtKey.getDQ();
+ BigInteger qInv = crtKey.getQInv();
+
+ BigInteger mP, mQ, h, m;
+
+ // mP = ((input mod p) ^ dP)) mod p
+ mP = (input.remainder(p)).modPow(dP, p);
+
+ // mQ = ((input mod q) ^ dQ)) mod q
+ mQ = (input.remainder(q)).modPow(dQ, q);
+
+ // h = qInv * (mP - mQ) mod p
+ h = mP.subtract(mQ);
+ h = h.multiply(qInv);
+ h = h.mod(p); // mod (in Java) returns the positive residual
+
+ // m = h * q + mQ
+ m = h.multiply(q).add(mQ);
+
+ // defence against Arjen Lenstra’s CRT attack
+ BigInteger check = m.modPow(e, crtKey.getModulus());
+ if (!check.equals(input))
{
- RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)privateKey;
-
- BigInteger e = crtKey.getPublicExponent();
- if (e != null) // can't do blinding without a public exponent
- {
- BigInteger m = crtKey.getModulus();
+ throw new IllegalStateException("RSA engine faulty decryption/signing detected");
+ }
- BigInteger r = BigIntegers.createRandomInRange(ONE, m.subtract(ONE), secureRandom);
- BigInteger blind = r.modPow(e, m);
- BigInteger unblind = BigIntegers.modOddInverse(m, r);
+ return m;
+ }
- BigInteger blindedInput = blind.multiply(input).mod(m);
- BigInteger blindedResult = rsa(privateKey, blindedInput);
- return unblind.multiply(blindedResult).mod(m);
- }
+ private static int subFrom(int len, byte[] x, byte[] z)
+ {
+ int c = 0;
+ for (int i = len - 1; i >= 0; --i)
+ {
+ c += (z[i] & 0xFF) - (x[i] & 0xFF);
+ z[i] = (byte)c;
+ c >>= 8;
}
+ return c;
+ }
- return rsa(privateKey, input);
+ private static byte[] toBytes(BigInteger output, int fixedSize)
+ {
+ byte[] bytes = output.toByteArray();
+
+ byte[] result = new byte[fixedSize];
+ System.arraycopy(bytes, 0, result, result.length - bytes.length, bytes.length);
+ return result;
}
}
From 30ace1fe02dc44bc5f1b9541dba1d5825fa1de9a Mon Sep 17 00:00:00 2001
From: mwcw
Date: Mon, 4 Mar 2024 21:07:36 +1100
Subject: [PATCH 0128/1846] Added config stanza for test report output dir.
Updated job dependency for CI.
---
.gitlab-ci.yml | 24 +++++++++++++++---------
build.gradle | 6 ++++++
2 files changed, 21 insertions(+), 9 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index df5b3c245d..de415a8844 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -22,7 +22,7 @@ check-code:
test-code-8:
stage: test
- needs: []
+ needs: ["check-code"]
script:
- "ecr_login"
- "ecr_pull vm_base_intel latest"
@@ -36,11 +36,12 @@ test-code-8:
- "pkix/build/reports"
- "mail/build/reports"
- "util/build/reports"
- - "tls/build/reports"
-
+ - "tls/build/reports"
+ - "mls/build/reports"
+
test-code-11:
stage: test
- needs: []
+ needs: ["check-code"]
script:
- "ecr_login"
- "ecr_pull vm_base_intel latest"
@@ -54,10 +55,12 @@ test-code-11:
- "pkix/build/reports"
- "mail/build/reports"
- "util/build/reports"
- - "tls/build/reports"
-
+ - "tls/build/reports"
+ - "mls/build/reports"
+
test-code-17:
stage: test
+ needs: ["check-code"]
script:
- "ecr_login"
- "ecr_pull vm_base_intel latest"
@@ -71,10 +74,12 @@ test-code-17:
- "pkix/build/reports"
- "mail/build/reports"
- "util/build/reports"
- - "tls/build/reports"
+ - "tls/build/reports"
+ - "mls/build/reports"
+
test-code-21:
stage: test
- needs: []
+ needs: ["check-code"]
script:
- "ecr_login"
- "ecr_pull vm_base_intel latest"
@@ -88,4 +93,5 @@ test-code-21:
- "pkix/build/reports"
- "mail/build/reports"
- "util/build/reports"
- - "tls/build/reports"
\ No newline at end of file
+ - "tls/build/reports"
+ - "mls/build/reports"
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 67a90e804e..be980c4f7b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -248,6 +248,12 @@ subprojects {
tasks.withType(JavaCompile).configureEach {
options.debug = true;
}
+
+ tasks.withType(Test).configureEach {
+ reports {
+ junitXml.outputLocation = layout.buildDirectory.dir("test-results")
+ }
+ }
}
test.dependsOn([':core:test', ':prov:test', ':prov:test11', ':prov:test17', ':prov:test21', ':pkix:test', 'pg:test', ':tls:test', 'mls:test', 'mail:test', 'jmail:test'])
From 3cb9f87c544edbfb3186f001c25a7de7f68523fe Mon Sep 17 00:00:00 2001
From: Jill Kleiber
Date: Mon, 4 Mar 2024 11:46:15 +0100
Subject: [PATCH 0129/1846] pr-1567: Fix bug in createCompressed()
---
.../oer/its/ieee1609dot2/basetypes/EccP256CurvePoint.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP256CurvePoint.java b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP256CurvePoint.java
index 9dcdc6dd31..fa6e4205e4 100644
--- a/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP256CurvePoint.java
+++ b/util/src/main/java/org/bouncycastle/oer/its/ieee1609dot2/basetypes/EccP256CurvePoint.java
@@ -165,7 +165,7 @@ else if (encoded[0] == 0x03)
choice = compressedY1;
}
byte[] copy = new byte[encoded.length - 1];
- System.arraycopy(encoded, 0, copy, 0, copy.length);
+ System.arraycopy(encoded, 1, copy, 0, copy.length);
return new EccP256CurvePoint(choice, new DEROctetString(copy));
}
From feb8b6c849c9d265ed2220bf8e1a4a015f358cfc Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Mon, 4 Mar 2024 20:46:53 +0700
Subject: [PATCH 0130/1846] Move some OID mappings around
---
.../org/bouncycastle/jcajce/provider/asymmetric/EC.java | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
index c51a0d4e76..d9e4f8e465 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EC.java
@@ -108,8 +108,8 @@ public void configure(ConfigurableProvider provider)
registerOid(provider, X9ObjectIdentifiers.id_ecPublicKey, "EC", new KeyFactorySpi.EC());
+ registerOid(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC());
registerOid(provider, X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC());
- registerOid(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
registerOid(provider, SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme, "EC", new KeyFactorySpi.EC());
registerOid(provider, SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme, "EC", new KeyFactorySpi.EC());
@@ -162,14 +162,14 @@ public void configure(ConfigurableProvider provider)
provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA384KDFAndSharedInfo", generalEcAttributes);
provider.addAlgorithm("KeyAgreement." + SECObjectIdentifiers.mqvSinglePass_sha512kdf_scheme, PREFIX + "KeyAgreementSpi$MQVwithSHA512KDFAndSharedInfo", generalEcAttributes);
- registerOid(provider, X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme, "EC", new KeyFactorySpi.EC());
+ registerOid(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
registerOidAlgorithmParameters(provider, X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme, "EC");
registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
- registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme, "EC");
+ registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme, "EC");
registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
- registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme, "EC");
+ registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme, "EC");
registerOid(provider, SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme, "ECMQV", new KeyFactorySpi.ECMQV());
registerOidAlgorithmParameters(provider, SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme, "EC");
From b4d89076305fdddedf4523e3ca2fb8af44e78721 Mon Sep 17 00:00:00 2001
From: mwcw
Date: Tue, 5 Mar 2024 08:51:23 +1100
Subject: [PATCH 0131/1846] Junit test results, report
---
.gitlab-ci.yml | 19 ++++++++++---------
1 file changed, 10 insertions(+), 9 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index de415a8844..38208e7649 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -29,15 +29,16 @@ test-code-8:
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_8.sh\""
artifacts:
when: always
- paths:
- - "core/build/reports"
- - "prov/build/reports"
- - "pg/build/reports"
- - "pkix/build/reports"
- - "mail/build/reports"
- - "util/build/reports"
- - "tls/build/reports"
- - "mls/build/reports"
+ reports:
+ junit:
+ - "core/build/test-results/**/*.xml"
+ - "prov/build/test-results/**/*.xml"
+ - "pg/build/test-results/**/*.xml"
+ - "pkix/build/test-results/**/*.xml"
+ - "mail/build/test-results/**/*.xml"
+ - "util/build/test-results/**/*.xml"
+ - "tls/build/test-results/**/*.xml"
+ - "mls/build/test-results/**/*.xml"
test-code-11:
stage: test
From cbffdf2a24179cb33a0ac60de2ab500b20317e7b Mon Sep 17 00:00:00 2001
From: mwcw
Date: Tue, 5 Mar 2024 10:35:51 +1100
Subject: [PATCH 0132/1846] Gitlab test results for all test tasks.
---
.gitlab-ci.yml | 59 +++++++++++++++++++++++++++-----------------------
1 file changed, 32 insertions(+), 27 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 38208e7649..eee7f79280 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -49,15 +49,17 @@ test-code-11:
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_11.sh\""
artifacts:
when: always
- paths:
- - "core/build/reports"
- - "prov/build/reports"
- - "pg/build/reports"
- - "pkix/build/reports"
- - "mail/build/reports"
- - "util/build/reports"
- - "tls/build/reports"
- - "mls/build/reports"
+ reports:
+ junit:
+ - "core/build/test-results/**/*.xml"
+ - "prov/build/test-results/**/*.xml"
+ - "pg/build/test-results/**/*.xml"
+ - "pkix/build/test-results/**/*.xml"
+ - "mail/build/test-results/**/*.xml"
+ - "util/build/test-results/**/*.xml"
+ - "tls/build/test-results/**/*.xml"
+ - "mls/build/test-results/**/*.xml"
+
test-code-17:
stage: test
@@ -68,15 +70,17 @@ test-code-17:
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_17.sh\""
artifacts:
when: always
- paths:
- - "core/build/reports"
- - "prov/build/reports"
- - "pg/build/reports"
- - "pkix/build/reports"
- - "mail/build/reports"
- - "util/build/reports"
- - "tls/build/reports"
- - "mls/build/reports"
+ reports:
+ junit:
+ - "core/build/test-results/**/*.xml"
+ - "prov/build/test-results/**/*.xml"
+ - "pg/build/test-results/**/*.xml"
+ - "pkix/build/test-results/**/*.xml"
+ - "mail/build/test-results/**/*.xml"
+ - "util/build/test-results/**/*.xml"
+ - "tls/build/test-results/**/*.xml"
+ - "mls/build/test-results/**/*.xml"
+
test-code-21:
stage: test
@@ -87,12 +91,13 @@ test-code-21:
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_21.sh\""
artifacts:
when: always
- paths:
- - "core/build/reports"
- - "prov/build/reports"
- - "pg/build/reports"
- - "pkix/build/reports"
- - "mail/build/reports"
- - "util/build/reports"
- - "tls/build/reports"
- - "mls/build/reports"
\ No newline at end of file
+ reports:
+ junit:
+ - "core/build/test-results/**/*.xml"
+ - "prov/build/test-results/**/*.xml"
+ - "pg/build/test-results/**/*.xml"
+ - "pkix/build/test-results/**/*.xml"
+ - "mail/build/test-results/**/*.xml"
+ - "util/build/test-results/**/*.xml"
+ - "tls/build/test-results/**/*.xml"
+ - "mls/build/test-results/**/*.xml"
From ab0033650de7057910cca8c7fcad7b64d9b6a224 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 5 Mar 2024 17:32:49 +1100
Subject: [PATCH 0133/1846] refactored use of new ErrorBundle to avoid class
loader issues with modules.
---
.../pkix/jcajce/PKIXCertPathReviewer.java | 206 ++++++++++--------
1 file changed, 111 insertions(+), 95 deletions(-)
diff --git a/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCertPathReviewer.java b/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCertPathReviewer.java
index 2464b7e1e9..891b2f4e84 100644
--- a/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCertPathReviewer.java
+++ b/pkix/src/main/java/org/bouncycastle/pkix/jcajce/PKIXCertPathReviewer.java
@@ -180,7 +180,7 @@ public void init(CertPath certPath, PKIXParameters params)
if (certs.isEmpty())
{
throw new CertPathReviewerException(
- new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.emptyCertPath"));
+ createErrorBundle("CertPathReviewer.emptyCertPath"));
}
pkixParams = (PKIXParameters) params.clone();
@@ -461,7 +461,7 @@ private void checkNameConstraints()
}
catch (IOException e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ncSubjectNameError",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.ncSubjectNameError",
new Object[] {new UntrustedInput(principal)});
throw new CertPathReviewerException(msg,e,certPath,index);
}
@@ -472,7 +472,7 @@ private void checkNameConstraints()
}
catch (PKIXNameConstraintValidatorException cpve)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedDN",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.notPermittedDN",
new Object[] {new UntrustedInput(principal.getName())});
throw new CertPathReviewerException(msg,cpve,certPath,index);
}
@@ -483,7 +483,7 @@ private void checkNameConstraints()
}
catch (PKIXNameConstraintValidatorException cpve)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedDN",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.excludedDN",
new Object[] {new UntrustedInput(principal.getName())});
throw new CertPathReviewerException(msg,cpve,certPath,index);
}
@@ -495,7 +495,7 @@ private void checkNameConstraints()
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.subjAltNameExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.subjAltNameExtError");
throw new CertPathReviewerException(msg,ae,certPath,index);
}
@@ -512,7 +512,7 @@ private void checkNameConstraints()
}
catch (PKIXNameConstraintValidatorException cpve)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedEmail",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.notPermittedEmail",
new Object[] {new UntrustedInput(name)});
throw new CertPathReviewerException(msg,cpve,certPath,index);
}
@@ -527,7 +527,7 @@ private void checkNameConstraints()
// }
// catch (CertPathValidatorException cpve)
// {
-// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedEmail",
+// ErrorBundle msg = createErrorBundle("CertPathReviewer.notPermittedEmail",
// new Object[] {new UntrustedInput(email)});
// throw new CertPathReviewerException(msg,cpve,certPath,index);
// }
@@ -538,7 +538,7 @@ private void checkNameConstraints()
// }
// catch (CertPathValidatorException cpve)
// {
-// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedEmail",
+// ErrorBundle msg = createErrorBundle("CertPathReviewer.excludedEmail",
// new Object[] {new UntrustedInput(email)});
// throw new CertPathReviewerException(msg,cpve,certPath,index);
// }
@@ -554,7 +554,7 @@ private void checkNameConstraints()
// catch (CertPathValidatorException cpve)
// {
// X509Name altDNName = new X509Name(altDN);
-// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedDN",
+// ErrorBundle msg = createErrorBundle("CertPathReviewer.notPermittedDN",
// new Object[] {new UntrustedInput(altDNName)});
// throw new CertPathReviewerException(msg,cpve,certPath,index);
// }
@@ -566,7 +566,7 @@ private void checkNameConstraints()
// catch (CertPathValidatorException cpve)
// {
// X509Name altDNName = new X509Name(altDN);
-// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedDN",
+// ErrorBundle msg = createErrorBundle("CertPathReviewer.excludedDN",
// new Object[] {new UntrustedInput(altDNName)});
// throw new CertPathReviewerException(msg,cpve,certPath,index);
// }
@@ -581,7 +581,7 @@ private void checkNameConstraints()
// }
// catch (CertPathValidatorException cpve)
// {
-// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notPermittedIP",
+// ErrorBundle msg = createErrorBundle("CertPathReviewer.notPermittedIP",
// new Object[] {IPtoString(ip)});
// throw new CertPathReviewerException(msg,cpve,certPath,index);
// }
@@ -592,7 +592,7 @@ private void checkNameConstraints()
// }
// catch (CertPathValidatorException cpve)
// {
-// ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.excludedIP",
+// ErrorBundle msg = createErrorBundle("CertPathReviewer.excludedIP",
// new Object[] {IPtoString(ip)});
// throw new CertPathReviewerException(msg,cpve,certPath,index);
// }
@@ -615,7 +615,7 @@ private void checkNameConstraints()
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ncExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.ncExtError");
throw new CertPathReviewerException(msg,ae,certPath,index);
}
@@ -678,7 +678,7 @@ private void checkPathLength()
{
if (maxPathLength <= 0)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.pathLengthExtended");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.pathLengthExtended");
addError(msg);
}
maxPathLength--;
@@ -695,7 +695,7 @@ private void checkPathLength()
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.processLengthConstError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.processLengthConstError");
addError(msg,index);
bc = null;
}
@@ -710,7 +710,7 @@ private void checkPathLength()
}
}
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.totalPathLength",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.totalPathLength",
new Object[]{Integers.valueOf(totalPathLength)});
addNotification(msg);
@@ -731,7 +731,7 @@ private void checkSignatures()
// validation date
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certPathValidDate",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.certPathValidDate",
new Object[] {new TrustedInput(validDate), new TrustedInput(currentDate)});
addNotification(msg);
}
@@ -745,7 +745,7 @@ private void checkSignatures()
if (trustColl.size() > 1)
{
// conflicting trust anchors
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"CertPathReviewer.conflictingTrustAnchors",
new Object[]{Integers.valueOf(trustColl.size()),
new UntrustedInput(cert.getIssuerX500Principal())});
@@ -753,7 +753,7 @@ private void checkSignatures()
}
else if (trustColl.isEmpty())
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"CertPathReviewer.noTrustAnchorFound",
new Object[]{new UntrustedInput(cert.getIssuerX500Principal()),
Integers.valueOf(pkixParams.getTrustAnchors().size())});
@@ -779,7 +779,7 @@ else if (trustColl.isEmpty())
}
catch (SignatureException e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustButInvalidCert");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.trustButInvalidCert");
addError(msg);
}
catch (Exception e)
@@ -794,7 +794,7 @@ else if (trustColl.isEmpty())
}
catch (Throwable t)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"CertPathReviewer.unknown",
new Object[] {new UntrustedInput(t.getMessage()), new UntrustedInput(t)});
addError(msg);
@@ -817,7 +817,7 @@ else if (trustColl.isEmpty())
}
catch (IllegalArgumentException ex)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustDNInvalid",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.trustDNInvalid",
new Object[] {new UntrustedInput(trust.getCAName())});
addError(msg);
}
@@ -828,7 +828,7 @@ else if (trustColl.isEmpty())
boolean[] ku = sign.getKeyUsage();
if (ku != null && (ku.length <= 5 || !ku[5]))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.trustKeyUsage");
+ ErrorBundle msg = createErrorBundle( "CertPathReviewer.trustKeyUsage");
addNotification(msg);
}
}
@@ -866,7 +866,7 @@ else if (trustColl.isEmpty())
}
catch (CertPathValidatorException ex)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustPubKeyError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.trustPubKeyError");
addError(msg);
workingAlgId = null;
}
@@ -901,7 +901,7 @@ else if (trustColl.isEmpty())
}
catch (GeneralSecurityException ex)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.signatureNotVerified",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.signatureNotVerified",
new Object[] {ex.getMessage(),ex,ex.getClass().getName()});
addError(msg,index);
}
@@ -912,19 +912,19 @@ else if (isSelfIssued(cert))
{
CertPathValidatorUtilities.verifyX509Certificate(cert, cert.getPublicKey(),
pkixParams.getSigProvider());
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.rootKeyIsValidButNotATrustAnchor");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.rootKeyIsValidButNotATrustAnchor");
addError(msg, index);
}
catch (GeneralSecurityException ex)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.signatureNotVerified",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.signatureNotVerified",
new Object[] {ex.getMessage(),ex,ex.getClass().getName()});
addError(msg,index);
}
}
else
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.NoIssuerPublicKey");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.NoIssuerPublicKey");
// if there is an authority key extension add the serial and issuer of the missing certificate
byte[] akiBytes = cert.getExtensionValue(Extension.authorityKeyIdentifier.getId());
if (akiBytes != null)
@@ -954,13 +954,13 @@ else if (isSelfIssued(cert))
}
catch (CertificateNotYetValidException cnve)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certificateNotYetValid",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.certificateNotYetValid",
new Object[] {new TrustedInput(cert.getNotBefore())});
addError(msg,index);
}
catch (CertificateExpiredException cee)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certificateExpired",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.certificateExpired",
new Object[] {new TrustedInput(cert.getNotAfter())});
addError(msg,index);
}
@@ -980,7 +980,7 @@ else if (isSelfIssued(cert))
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlDistPtExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlDistPtExtError");
addError(msg,index);
}
@@ -996,7 +996,7 @@ else if (isSelfIssued(cert))
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlAuthInfoAccError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlAuthInfoAccError");
addError(msg,index);
}
@@ -1009,7 +1009,7 @@ else if (isSelfIssued(cert))
Iterator urlIt = crlDistPointUrls.iterator();
while (urlIt.hasNext())
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlDistPoint",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlDistPoint",
new Object[] {new UntrustedUrlInput(urlIt.next())});
addNotification(msg,index);
}
@@ -1018,7 +1018,7 @@ else if (isSelfIssued(cert))
urlIt = ocspUrls.iterator();
while (urlIt.hasNext())
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.ocspLocation",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.ocspLocation",
new Object[] {new UntrustedUrlInput(urlIt.next())});
addNotification(msg,index);
}
@@ -1038,7 +1038,7 @@ else if (isSelfIssued(cert))
// certificate issuer correct
if (workingIssuerName != null && !cert.getIssuerX500Principal().equals(workingIssuerName))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certWrongIssuer",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.certWrongIssuer",
new Object[] {workingIssuerName.getName(),
cert.getIssuerX500Principal().getName()});
addError(msg,index);
@@ -1052,7 +1052,7 @@ else if (isSelfIssued(cert))
if (cert != null && cert.getVersion() == 1)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCACert");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.noCACert");
addError(msg,index);
}
@@ -1067,19 +1067,19 @@ else if (isSelfIssued(cert))
{
if (!bc.isCA())
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCACert");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.noCACert");
addError(msg,index);
}
}
else
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noBasicConstraints");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.noBasicConstraints");
addError(msg,index);
}
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.errorProcesingBC");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.errorProcesingBC");
addError(msg,index);
}
@@ -1089,7 +1089,7 @@ else if (isSelfIssued(cert))
if (keyUsage != null && (keyUsage.length <= KEY_CERT_SIGN || !keyUsage[KEY_CERT_SIGN]))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCertSign");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.noCertSign");
addError(msg,index);
}
@@ -1113,7 +1113,7 @@ else if (isSelfIssued(cert))
}
catch (CertPathValidatorException ex)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.pubKeyError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.pubKeyError");
addError(msg,index);
workingAlgId = null;
workingPublicKeyAlgorithm = null;
@@ -1225,7 +1225,7 @@ private void checkPolicy()
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.policyExtError");
throw new CertPathReviewerException(msg,ae,certPath,index);
}
if (certPolicies != null && validPolicyTree != null)
@@ -1252,7 +1252,7 @@ private void checkPolicy()
}
catch (CertPathValidatorException cpve)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.policyQualifierError");
throw new CertPathReviewerException(msg,cpve,certPath,index);
}
@@ -1306,7 +1306,7 @@ private void checkPolicy()
}
catch (CertPathValidatorException cpve)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.policyQualifierError");
throw new CertPathReviewerException(msg,cpve,certPath,index);
}
List _nodes = policyNodes[i - 1];
@@ -1419,7 +1419,7 @@ else if (_tmp instanceof ASN1ObjectIdentifier)
if (explicitPolicy <= 0 && validPolicyTree == null)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noValidPolicyTree");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.noValidPolicyTree");
throw new CertPathReviewerException(msg);
}
@@ -1439,7 +1439,7 @@ else if (_tmp instanceof ASN1ObjectIdentifier)
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyMapExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.policyMapExtError");
throw new CertPathReviewerException(msg,ae,certPath,index);
}
@@ -1453,12 +1453,12 @@ else if (_tmp instanceof ASN1ObjectIdentifier)
ASN1ObjectIdentifier sp_id = (ASN1ObjectIdentifier) mapping.getObjectAt(1);
if (ANY_POLICY.equals(ip_id.getId()))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicyMapping");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.invalidPolicyMapping");
throw new CertPathReviewerException(msg,certPath,index);
}
if (ANY_POLICY.equals(sp_id.getId()))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicyMapping");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.invalidPolicyMapping");
throw new CertPathReviewerException(msg,certPath,index);
}
}
@@ -1510,13 +1510,13 @@ else if (_tmp instanceof ASN1ObjectIdentifier)
catch (AnnotatedException ae)
{
// error processing certificate policies extension
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.policyExtError");
throw new CertPathReviewerException(msg,ae,certPath,index);
}
catch (CertPathValidatorException cpve)
{
// error building qualifier set
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyQualifierError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.policyQualifierError");
throw new CertPathReviewerException(msg,cpve,certPath,index);
}
@@ -1597,7 +1597,7 @@ else if (policyMapping <= 0)
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyConstExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.policyConstExtError");
throw new CertPathReviewerException(msg,certPath,index);
}
@@ -1621,7 +1621,7 @@ else if (policyMapping <= 0)
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyInhibitExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.policyInhibitExtError");
throw new CertPathReviewerException(msg,certPath,index);
}
}
@@ -1670,7 +1670,7 @@ else if (policyMapping <= 0)
}
catch (AnnotatedException e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.policyConstExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.policyConstExtError");
throw new CertPathReviewerException(msg,certPath,index);
}
@@ -1688,7 +1688,7 @@ else if (policyMapping <= 0)
{
if (pkixParams.isExplicitPolicyRequired())
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.explicitPolicy");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.explicitPolicy");
throw new CertPathReviewerException(msg,certPath,index);
}
intersection = null;
@@ -1699,7 +1699,7 @@ else if (isAnyPolicy(userInitialPolicySet)) // (g) (ii)
{
if (acceptablePolicies.isEmpty())
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.explicitPolicy");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.explicitPolicy");
throw new CertPathReviewerException(msg,certPath,index);
}
else
@@ -1834,7 +1834,7 @@ else if (isAnyPolicy(userInitialPolicySet)) // (g) (ii)
if ((explicitPolicy <= 0) && (intersection == null))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.invalidPolicy");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.invalidPolicy");
throw new CertPathReviewerException(msg);
}
@@ -1866,7 +1866,7 @@ private void checkCriticalExtensions()
}
catch (CertPathValidatorException cpve)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certPathCheckerError",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.certPathCheckerError",
new Object[] {cpve.getMessage(),cpve,cpve.getClass().getName()});
throw new CertPathReviewerException(msg,cpve);
}
@@ -1922,7 +1922,7 @@ private void checkCriticalExtensions()
}
catch (CertPathValidatorException e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.criticalExtensionError",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.criticalExtensionError",
new Object[] {e.getMessage(),e,e.getClass().getName()});
throw new CertPathReviewerException(msg,e.getCause(),certPath,index);
}
@@ -1933,7 +1933,7 @@ private void checkCriticalExtensions()
Iterator it = criticalExtensions.iterator();
while (it.hasNext())
{
- msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.unknownCriticalExt",
+ msg = createErrorBundle("CertPathReviewer.unknownCriticalExt",
new Object[] {new ASN1ObjectIdentifier((String) it.next())});
addError(msg, index);
}
@@ -1961,7 +1961,7 @@ private boolean processQcStatements(
if (QCStatement.id_etsi_qcs_QcCompliance.equals(stmt.getStatementId()))
{
// process statement - just write a notification that the certificate contains this statement
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcEuCompliance");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.QcEuCompliance");
addNotification(msg,index);
}
else if (QCStatement.id_qcs_pkixQCSyntax_v1.equals(stmt.getStatementId()))
@@ -1971,7 +1971,7 @@ else if (QCStatement.id_qcs_pkixQCSyntax_v1.equals(stmt.getStatementId()))
else if (QCStatement.id_etsi_qcs_QcSSCD.equals(stmt.getStatementId()))
{
// process statement - just write a notification that the certificate contains this statement
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcSSCD");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.QcSSCD");
addNotification(msg,index);
}
else if (QCStatement.id_etsi_qcs_LimiteValue.equals(stmt.getStatementId()))
@@ -1983,14 +1983,14 @@ else if (QCStatement.id_etsi_qcs_LimiteValue.equals(stmt.getStatementId()))
ErrorBundle msg;
if (limit.getCurrency().isAlphabetic())
{
- msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcLimitValueAlpha",
+ msg = createErrorBundle("CertPathReviewer.QcLimitValueAlpha",
new Object[] {limit.getCurrency().getAlphabetic(),
new TrustedInput(new Double(value)),
limit});
}
else
{
- msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcLimitValueNum",
+ msg = createErrorBundle("CertPathReviewer.QcLimitValueNum",
new Object[]{Integers.valueOf(limit.getCurrency().getNumeric()),
new TrustedInput(new Double(value)),
limit});
@@ -1999,7 +1999,7 @@ else if (QCStatement.id_etsi_qcs_LimiteValue.equals(stmt.getStatementId()))
}
else
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcUnknownStatement",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.QcUnknownStatement",
new Object[] {stmt.getStatementId(),new UntrustedInput(stmt)});
addNotification(msg,index);
unknownStatement = true;
@@ -2010,7 +2010,7 @@ else if (QCStatement.id_etsi_qcs_LimiteValue.equals(stmt.getStatementId()))
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.QcStatementExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.QcStatementExtError");
addError(msg,index);
}
@@ -2072,7 +2072,7 @@ protected void checkCRLs(
}
catch (IOException e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlIssuerException");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlIssuerException");
throw new CertPathReviewerException(msg,e);
}
@@ -2095,7 +2095,7 @@ protected void checkCRLs(
nonMatchingCrlNames.add(((X509CRL) it.next()).getIssuerX500Principal());
}
int numbOfCrls = nonMatchingCrlNames.size();
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"CertPathReviewer.noCrlInCertstore",
new Object[]{new UntrustedInput(crlselect.getIssuerNames()),
new UntrustedInput(nonMatchingCrlNames),
@@ -2105,7 +2105,7 @@ protected void checkCRLs(
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlExtractionError",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlExtractionError",
new Object[] {ae.getCause().getMessage(),ae.getCause(),ae.getCause().getClass().getName()});
addError(msg,index);
crl_iter = new ArrayList().iterator();
@@ -2124,12 +2124,12 @@ protected void checkCRLs(
if (nextUpdate == null || validDate.before(nextUpdate))
{
validCrlFound = true;
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.localValidCRL", arguments);
+ ErrorBundle msg = createErrorBundle( "CertPathReviewer.localValidCRL", arguments);
addNotification(msg,index);
break;
}
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.localInvalidCRL", arguments);
+ ErrorBundle msg = createErrorBundle( "CertPathReviewer.localInvalidCRL", arguments);
addNotification(msg,index);
}
@@ -2154,7 +2154,7 @@ protected void checkCRLs(
// check if crl issuer is correct
if (!certIssuer.equals(crlIssuer))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.onlineCRLWrongCA",
+ ErrorBundle msg = createErrorBundle( "CertPathReviewer.onlineCRLWrongCA",
new Object[]{ new UntrustedInput(crlIssuer.getName()), new UntrustedInput(certIssuer.getName()),
new UntrustedUrlInput(location) });
addNotification(msg,index);
@@ -2169,14 +2169,14 @@ protected void checkCRLs(
if (nextUpdate == null || validDate.before(nextUpdate))
{
validCrlFound = true;
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.onlineValidCRL",
+ ErrorBundle msg = createErrorBundle( "CertPathReviewer.onlineValidCRL",
arguments);
addNotification(msg, index);
crl = onlineCRL;
break;
}
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.onlineInvalidCRL",
+ ErrorBundle msg = createErrorBundle( "CertPathReviewer.onlineInvalidCRL",
arguments);
addNotification(msg, index);
}
@@ -2198,7 +2198,7 @@ protected void checkCRLs(
if (keyUsage != null && (keyUsage.length <= CRL_SIGN || !keyUsage[CRL_SIGN]))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noCrlSigningPermited");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.noCrlSigningPermited");
throw new CertPathReviewerException(msg);
}
}
@@ -2211,13 +2211,13 @@ protected void checkCRLs(
}
catch (Exception e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlVerifyFailed");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlVerifyFailed");
throw new CertPathReviewerException(msg,e);
}
}
else // issuer public key not known
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlNoIssuerPublicKey");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlNoIssuerPublicKey");
throw new CertPathReviewerException(msg);
}
@@ -2235,7 +2235,7 @@ protected void checkCRLs(
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlReasonExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlReasonExtError");
throw new CertPathReviewerException(msg,ae);
}
if (reasonCode != null)
@@ -2254,20 +2254,20 @@ protected void checkCRLs(
if (!validDate.before(crl_entry.getRevocationDate()))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.certRevoked",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.certRevoked",
new Object[] {new TrustedInput(crl_entry.getRevocationDate()),ls});
throw new CertPathReviewerException(msg);
}
else // cert was revoked after validation date
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.revokedAfterValidation",
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.revokedAfterValidation",
new Object[] {new TrustedInput(crl_entry.getRevocationDate()),ls});
addNotification(msg,index);
}
}
else // cert is not revoked
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.notRevoked");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.notRevoked");
addNotification(msg,index);
}
@@ -2277,7 +2277,7 @@ protected void checkCRLs(
Date nextUpdate = crl.getNextUpdate();
if (!(nextUpdate == null || validDate.before(nextUpdate)))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, "CertPathReviewer.crlUpdateAvailable",
+ ErrorBundle msg = createErrorBundle( "CertPathReviewer.crlUpdateAvailable",
new Object[]{ new TrustedInput(nextUpdate) });
addNotification(msg, index);
}
@@ -2292,7 +2292,7 @@ protected void checkCRLs(
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.distrPtExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.distrPtExtError");
throw new CertPathReviewerException(msg);
}
ASN1Primitive dci;
@@ -2302,7 +2302,7 @@ protected void checkCRLs(
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.deltaCrlExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.deltaCrlExtError");
throw new CertPathReviewerException(msg);
}
@@ -2316,7 +2316,7 @@ protected void checkCRLs(
}
catch (IOException e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlIssuerException");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlIssuerException");
throw new CertPathReviewerException(msg,e);
}
@@ -2327,7 +2327,7 @@ protected void checkCRLs(
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlNbrExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlNbrExtError");
throw new CertPathReviewerException(msg,ae);
}
@@ -2339,7 +2339,7 @@ protected void checkCRLs(
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlExtractionError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlExtractionError");
throw new CertPathReviewerException(msg,ae);
}
while (it.hasNext())
@@ -2353,7 +2353,7 @@ protected void checkCRLs(
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.distrPtExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.distrPtExtError");
throw new CertPathReviewerException(msg,ae);
}
@@ -2366,7 +2366,7 @@ protected void checkCRLs(
if (!foundBase)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noBaseCRL");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.noBaseCRL");
throw new CertPathReviewerException(msg);
}
}
@@ -2381,25 +2381,25 @@ protected void checkCRLs(
}
catch (AnnotatedException ae)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlBCExtError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlBCExtError");
throw new CertPathReviewerException(msg,ae);
}
if (p.onlyContainsUserCerts() && (bc != null && bc.isCA()))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyUserCert");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlOnlyUserCert");
throw new CertPathReviewerException(msg);
}
if (p.onlyContainsCACerts() && (bc == null || !bc.isCA()))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyCaCert");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlOnlyCaCert");
throw new CertPathReviewerException(msg);
}
if (p.onlyContainsAttributeCerts())
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.crlOnlyAttrCert");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.crlOnlyAttrCert");
throw new CertPathReviewerException(msg);
}
}
@@ -2407,7 +2407,7 @@ protected void checkCRLs(
if (!validCrlFound)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.noValidCrlFound");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.noValidCrlFound");
throw new CertPathReviewerException(msg);
}
}
@@ -2490,7 +2490,7 @@ private X509CRL getCRL(String location) throws CertPathReviewerException
}
catch (Exception e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"CertPathReviewer.loadCrlDistPointError",
new Object[] {new UntrustedInput(location),
e.getMessage(),e,e.getClass().getName()});
@@ -2534,7 +2534,7 @@ protected Collection getTrustAnchors(X509Certificate cert, Set trustanchors) thr
}
catch (IOException ex)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,"CertPathReviewer.trustAnchorIssuerError");
+ ErrorBundle msg = createErrorBundle("CertPathReviewer.trustAnchorIssuerError");
throw new CertPathReviewerException(msg);
}
@@ -2560,4 +2560,20 @@ else if (trust.getCAName() != null && trust.getCAPublicKey() != null)
}
return trustColl;
}
+
+ private static ErrorBundle createErrorBundle(String id)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, id);
+ msg.setClassLoader(PKIXCertPathReviewer.class.getClassLoader());
+
+ return msg;
+ }
+
+ private static ErrorBundle createErrorBundle(String id, Object[] arguments)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, id, arguments);
+ msg.setClassLoader(PKIXCertPathReviewer.class.getClassLoader());
+
+ return msg;
+ }
}
From c3624a56eb06179f0f1d1d9d70246667dd61abe8 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 5 Mar 2024 17:38:39 +1100
Subject: [PATCH 0134/1846] refactored to deal with class loader issues in
ErrorBundles for modules
---
.../smime/validator/SignedMailValidator.java | 59 ++++++++++++-------
1 file changed, 37 insertions(+), 22 deletions(-)
diff --git a/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java b/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java
index a0595093e5..cf976aca44 100644
--- a/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java
+++ b/mail/src/main/java/org/bouncycastle/mail/smime/validator/SignedMailValidator.java
@@ -169,7 +169,7 @@ else if (message.isMimeType("application/pkcs7-mime")
}
else
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.noSignedMessage");
throw new SignedMailValidatorException(msg);
}
@@ -215,7 +215,7 @@ else if (message.isMimeType("application/pkcs7-mime")
throw (SignedMailValidatorException)e;
}
// exception reading message
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.exceptionReadingMessage",
new Object[]{e.getMessage(), e, e.getClass().getName()});
throw new SignedMailValidatorException(msg, e);
@@ -258,7 +258,7 @@ protected void validateSignatures(PKIXParameters pkixParam)
}
catch (CertStoreException cse)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.exceptionRetrievingSignerCert",
new Object[]{cse.getMessage(), cse, cse.getClass().getName()});
errors.add(msg);
@@ -273,14 +273,14 @@ protected void validateSignatures(PKIXParameters pkixParam)
validSignature = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert.getPublicKey()));
if (!validSignature)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.signatureNotVerified");
errors.add(msg);
}
}
catch (Exception e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.exceptionVerifyingSignature",
new Object[]{e.getMessage(), e, e.getClass().getName()});
errors.add(msg);
@@ -296,7 +296,7 @@ protected void validateSignatures(PKIXParameters pkixParam)
Attribute attr = atab.get(PKCSObjectIdentifiers.id_aa_receiptRequest);
if (attr != null)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.signedReceiptRequest");
notifications.add(msg);
}
@@ -309,7 +309,7 @@ protected void validateSignatures(PKIXParameters pkixParam)
Date signTime = getSignatureTime(signer);
if (signTime == null) // no signing time was found
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.noSigningTime");
notifications.add(msg);
signTime = pkixParam.getDate();
@@ -327,14 +327,14 @@ protected void validateSignatures(PKIXParameters pkixParam)
}
catch (CertificateExpiredException e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.certExpired",
new Object[]{new TrustedInput(signTime), new TrustedInput(cert.getNotAfter())});
errors.add(msg);
}
catch (CertificateNotYetValidException e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.certNotYetValid",
new Object[]{new TrustedInput(signTime), new TrustedInput(cert.getNotBefore())});
errors.add(msg);
@@ -373,7 +373,7 @@ protected void validateSignatures(PKIXParameters pkixParam)
review.init(certPath, usedParameters);
if (!review.isValidCertPath())
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.certPathInvalid");
errors.add(msg);
}
@@ -383,7 +383,7 @@ protected void validateSignatures(PKIXParameters pkixParam)
catch (GeneralSecurityException gse)
{
// cannot create cert path
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.exceptionCreateCertPath",
new Object[]{gse.getMessage(), gse, gse.getClass().getName()});
errors.add(msg);
@@ -401,7 +401,7 @@ protected void validateSignatures(PKIXParameters pkixParam)
else
// no signer certificate found
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.noSignerCert");
errors.add(msg);
results.put(signer, new ValidationResult(null, false, errors,
@@ -478,7 +478,7 @@ else if (key instanceof DSAPublicKey)
}
if (keyLength != -1 && keyLength <= shortKeyLength)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.shortSigningKey",
new Object[]{Integers.valueOf(keyLength)});
notifications.add(msg);
@@ -488,7 +488,7 @@ else if (key instanceof DSAPublicKey)
long validityPeriod = cert.getNotAfter().getTime() - cert.getNotBefore().getTime();
if (validityPeriod > THIRTY_YEARS_IN_MILLI_SEC)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.longValidity",
new Object[]{new TrustedInput(cert.getNotBefore()), new TrustedInput(cert.getNotAfter())});
notifications.add(msg);
@@ -498,7 +498,7 @@ else if (key instanceof DSAPublicKey)
boolean[] keyUsage = cert.getKeyUsage();
if (keyUsage != null && !keyUsage[0] && !keyUsage[1])
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.signingNotPermitted");
errors.add(msg);
}
@@ -516,7 +516,7 @@ else if (key instanceof DSAPublicKey)
&& !extKeyUsage
.hasKeyPurposeId(KeyPurposeId.id_kp_emailProtection))
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.extKeyUsageNotPermitted");
errors.add(msg);
}
@@ -524,7 +524,7 @@ else if (key instanceof DSAPublicKey)
}
catch (Exception e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.extKeyUsageError", new Object[]{
e.getMessage(), e, e.getClass().getName()}
);
@@ -538,7 +538,7 @@ else if (key instanceof DSAPublicKey)
if (certEmails.isEmpty())
{
// error no email address in signing certificate
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.noEmailInCert");
errors.add(msg);
}
@@ -557,7 +557,7 @@ else if (key instanceof DSAPublicKey)
}
if (!equalsFrom)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.emailFromCertMismatch",
new Object[]{
new UntrustedInput(
@@ -570,7 +570,7 @@ else if (key instanceof DSAPublicKey)
}
catch (Exception e)
{
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.certGetEmailError", new Object[]{
e.getMessage(), e, e.getClass().getName()}
);
@@ -854,7 +854,7 @@ public ValidationResult getValidationResult(SignerInformation signer)
{
// the signer is not part of the SignerInformationStore
// he has not signed the message
- ErrorBundle msg = new ErrorBundle(RESOURCE_NAME,
+ ErrorBundle msg = createErrorBundle(
"SignedMailValidator.wrongSigner");
throw new SignedMailValidatorException(msg);
}
@@ -961,10 +961,25 @@ public boolean isValidSignature()
}
}
-
private static TBSCertificate getTBSCert(X509Certificate cert)
throws CertificateEncodingException
{
return TBSCertificate.getInstance(cert.getTBSCertificate());
}
+
+ private static ErrorBundle createErrorBundle(String id)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, id);
+ msg.setClassLoader(SignedMailValidator.class.getClassLoader());
+
+ return msg;
+ }
+
+ private static ErrorBundle createErrorBundle(String id, Object[] arguments)
+ {
+ ErrorBundle msg = new ErrorBundle(RESOURCE_NAME, id, arguments);
+ msg.setClassLoader(SignedMailValidator.class.getClassLoader());
+
+ return msg;
+ }
}
From 4ff20f7b2a8aa0341a3e8a82026394b688fec4c2 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 5 Mar 2024 17:40:24 +1100
Subject: [PATCH 0135/1846] refactored to deal with class loader issues in
ErrorBundles for modules
---
.../bouncycastle/mail/smime/examples/ValidateSignedMail.java | 2 ++
1 file changed, 2 insertions(+)
diff --git a/mail/src/main/java/org/bouncycastle/mail/smime/examples/ValidateSignedMail.java b/mail/src/main/java/org/bouncycastle/mail/smime/examples/ValidateSignedMail.java
index 9d1238c81a..79b4b80f2c 100644
--- a/mail/src/main/java/org/bouncycastle/mail/smime/examples/ValidateSignedMail.java
+++ b/mail/src/main/java/org/bouncycastle/mail/smime/examples/ValidateSignedMail.java
@@ -148,12 +148,14 @@ public static void verifySignedMail(MimeMessage msg, PKIXParameters param)
{
ErrorBundle errMsg = new ErrorBundle(RESOURCE_NAME,
"SignedMailValidator.sigValid");
+ errMsg.setClassLoader(SignedMailValidator.class.getClassLoader());
System.out.println(errMsg.getText(loc));
}
else
{
ErrorBundle errMsg = new ErrorBundle(RESOURCE_NAME,
"SignedMailValidator.sigInvalid");
+ errMsg.setClassLoader(SignedMailValidator.class.getClassLoader());
System.out.println(errMsg.getText(loc));
// print errors
System.out.println("Errors:");
From 8dce4871d438ab18fc5bc2118405387508673f32 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Oupick=C3=BD?=
Date: Tue, 5 Mar 2024 17:45:52 +0100
Subject: [PATCH 0136/1846] update to draft v13. samples from draft are now
compatible with the exception that the Dilithium private key seems to have a
different encoding. separated samples from CertTest into resource files.
---
.../asn1/misc/MiscObjectIdentifiers.java | 6 +-
.../org/bouncycastle/cert/test/CertTest.java | 446 +-----------------
.../test/compositeCertificateExampleRFC.pem | 88 ++++
.../cert/test/compositePrivateKeyExample.pem | 88 ++++
.../test/compositePublicKeyExampleRFC.pem | 32 ++
.../jcajce/CompositePrivateKey.java | 2 +-
.../jcajce/CompositePublicKey.java | 2 +-
.../asymmetric/CompositeSignatures.java | 3 +
.../compositesignatures/KeyFactorySpi.java | 4 +-
.../KeyPairGeneratorSpi.java | 2 +-
.../compositesignatures/SignatureSpi.java | 6 +-
.../test/CompositeSignaturesTest.java | 1 +
.../provider/test/compositeSignatures.sample | 32 +-
13 files changed, 256 insertions(+), 456 deletions(-)
create mode 100644 pkix/src/test/resources/org/bouncycastle/cert/test/compositeCertificateExampleRFC.pem
create mode 100644 pkix/src/test/resources/org/bouncycastle/cert/test/compositePrivateKeyExample.pem
create mode 100644 pkix/src/test/resources/org/bouncycastle/cert/test/compositePublicKeyExampleRFC.pem
diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
index 6dda4a17f1..8608d2c0a7 100644
--- a/core/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
+++ b/core/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
@@ -167,7 +167,7 @@ public interface MiscObjectIdentifiers
// COMPOSITE SIGNATURES START
// -- To be replaced by IANA
- // Composite signature related OIDs. Based https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-11.html
+ // Composite signature related OIDs. Based https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
// The current OIDs are EXPERIMENTAL and are going to change.
ASN1ObjectIdentifier id_composite_signatures = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1");
ASN1ObjectIdentifier id_MLDSA44_RSA2048_PSS_SHA256 = id_composite_signatures.branch("1");
@@ -183,6 +183,10 @@ public interface MiscObjectIdentifiers
ASN1ObjectIdentifier id_MLDSA87_ECDSA_P384_SHA512 = id_composite_signatures.branch("11");
ASN1ObjectIdentifier id_MLDSA87_ECDSA_brainpoolP384r1_SHA512 = id_composite_signatures.branch("12");
ASN1ObjectIdentifier id_MLDSA87_Ed448_SHA512 = id_composite_signatures.branch("13");
+
+ // Falcon-based composites below were removed from the IETF draft in version 13 and are expected to be included in a later/separate standard.
+ // Most likely due to the fact that the Falcon (FN-DSA) NIST standard is going to be released after the Dilithium (ML-DSA) standard.
+ // However, we still leave their implementation for experimental usage.
ASN1ObjectIdentifier id_Falcon512_ECDSA_P256_SHA256 = id_composite_signatures.branch("14");
ASN1ObjectIdentifier id_Falcon512_ECDSA_brainpoolP256r1_SHA256 = id_composite_signatures.branch("15");
ASN1ObjectIdentifier id_Falcon512_Ed25519_SHA512 = id_composite_signatures.branch("16");
diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java b/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java
index 296b5efc40..b0d4fa2e26 100644
--- a/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java
+++ b/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java
@@ -2,11 +2,11 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.InputStreamReader;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
-import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
@@ -5423,7 +5423,7 @@ private void checkSerialisation()
doSerialize(attrHolder);
}
- // TESTS REGARDING COMPOSITES https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-11.html
+ // TESTS REGARDING COMPOSITES https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
private static String[] compositeSignaturesOIDs = {
"2.16.840.1.114027.80.8.1.1", //id-MLDSA44-RSA2048-PSS-SHA256
"2.16.840.1.114027.80.8.1.2", //id-MLDSA44-RSA2048-PKCS15-SHA256
@@ -5438,6 +5438,7 @@ private void checkSerialisation()
"2.16.840.1.114027.80.8.1.11", //id-MLDSA87-ECDSA-P384-SHA512
"2.16.840.1.114027.80.8.1.12", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512
"2.16.840.1.114027.80.8.1.13", //id-MLDSA87-Ed448-SHA512
+ // Falcon composites below were excluded from the draft. See MiscObjectIdentifiers for details.
"2.16.840.1.114027.80.8.1.14", //id-Falcon512-ECDSA-P256-SHA256
"2.16.840.1.114027.80.8.1.15", //id-Falcon512-ECDSA-brainpoolP256r1-SHA256
"2.16.840.1.114027.80.8.1.16", //id-Falcon512-Ed25519-SHA512
@@ -5456,7 +5457,7 @@ private void checkCompositeSignatureCertificateCreation()
X500Name issuer = new X500Name(subjectName);
BigInteger serial = BigInteger.valueOf(5);
Date notBefore = new Date();
- Date notAfter = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365);
+ Date notAfter = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 365L);
X500Name subject = new X500Name(subjectName);
JcaX509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keyPair.getPublic());
@@ -5480,80 +5481,14 @@ private void checkCompositeSignatureCertificateCreation()
}
}
- //FROM RFC, SEEMS WRONG FORMAT
-// private static String compositePublicKey = "-----BEGIN PUBLIC KEY-----\n" +
-// "MIIFfzANBgtghkgBhvprUAgBBAOCBWwAMIIFZwSCBSAA9DTYoQys3PVrayi9zTam\n" +
-// "kTzpqf6vuNI5+UaMENvnrq3Rps5LmiQ5gSXaQMu0HYjVpCEQVQWl/8nbJavELelk\n" +
-// "gCVn528ndGBQUChAnffxhRdxgaFmOb2SEySTnHIh6QO1UFPO2kGiGx9zU6F9xZGK\n" +
-// "FZFBm8B076UvRHCbaw+BTvu4o+Kg1irOFRPI3hLN4ku3si2nwWSZNhDoiLaPTfJe\n" +
-// "7TRziBznEyrnSV3I2Xn7QdKxIWUFOwPXWBnnk/FGG/A2HdxGpiqIWxZ0gNLNcb+j\n" +
-// "Cz6CWZSJhoOLoJWdOD5zyojPPrH5iFIGM96p0PZ4mv5PhmZDPA/RTIg/PcG1rywn\n" +
-// "OJYqAsazntGyEhHEFLRe8QYOVEbiBuv20tNzkFaaulQRdW+boStcW8NefSkKG/9D\n" +
-// "FgGnyR87W4Z/ieHEyIva4FBamvRm60xrblAyI0Z7II4l7LTStDzL/ghFq06RVria\n" +
-// "au+mY5laq8rAGmRbWkUxNeKeGOVHxjGFYB3uaAkHef0o7tSMMkCSSjiDQlNk5ReQ\n" +
-// "xgJMkuTRE7YRN1bDXv/0uPPjg7zfa3M0tMCD9wTXFhIk04HDLVV5WAsH0EK6Nytd\n" +
-// "gqnsjGCwfZb2+Fw/QytBei50DUBHpIG3da4dBrxcaRTMiQPzPzL8FaDascE0ZIJM\n" +
-// "9ilKvxgq02ryEHLGALFN8eZD1r6zq43KFlRzaynWBWqJ27MiUzK2dk8oC+dH5cz6\n" +
-// "+xGXAhLJ+MipoO9k9dLg8re3dOAufsKaY5DLuuluo7dO6IF7rG9xblbiIzWpyfu3\n" +
-// "7kJvUdwk36QzsQNGsxpELk65LaWYnaebV7wKyIaaniLysuNCG0dIcAicxRNLgpX9\n" +
-// "jic5pi+BzlJI1IuPk+DqOG57pNnU7lTg3op08MUslNyeUH5yaag8DNsLG7uZHzvx\n" +
-// "jcqffaqcqS+v6FVmbV2tDF07jn8a754Fnn/QNgsNcdfw9Ov4w7Ty+q5nT2wg2Lsg\n" +
-// "bAuzN6b6FiWEuHHMw/I5aIL5cLj2GUpjHtlUHL4KEHpxZ2J5jbBgeqpTWEy1TuPQ\n" +
-// "R34lryVASmue/kmk2liah6wNK5RXlGa8uidBm7RT8b5SkIMsrosLx9KpC5lKobzn\n" +
-// "8ttK1NSy0ZuMDw9wtnePUbROGjEuw5Na/K1VgO68dATj/7rscvz7C+ZuQORrt88X\n" +
-// "+OZmoyw+fEDWAocDnhzI6rJIHLPB0p+rSJ8iSKZpFZYeIy+CD0t6E98RJQHll8BJ\n" +
-// "lLyJiMT0xAyelOMzrCJayHxD01aLw6LLOddFbiIRMq4lni5Ha4noWmdO2C80xy3A\n" +
-// "jskUEK5sbD8KFl910JUHwaGvb/gDCqW+n10mRa9+cB0tRVjo5OZeSiB01Bkagu7a\n" +
-// "f+bRv2i8cBa2ZoGVyW3xFFFhIkHzLgHaU+RLaGwJDe0qxKtwKYz5c/YpAsH+lodM\n" +
-// "NV2E/PzHtNY+sg0PijblN6IVO+yiLkxJspKIjf0I1+s8hczhz3QkLRed7dU2nvID\n" +
-// "puJQfgraKyS6rawlqLyWo66/PDtdd3tngw50wnDNZik0hz/usDc6o7IN5J9ha7XO\n" +
-// "0vZQluMb9R5l+W6RLD2nRd4mlKVqm/Yfq0R8PKoIh8f7uLVk1kbN4prkfpsokvqR\n" +
-// "rli5h4URG7WCNvp4bg/i1Ix/CEEjH56LRj83dhVB0O6WXorrZMAChQShMhwnEgeS\n" +
-// "USaB5au7xRAM+9fWvF9cmju3hXSTT1zv0owyoSgp36OHcy2HzwZXxA7YWtRDbhMX\n" +
-// "BEEEkSZvSVDhZlBXhAkaTBxlrRt624URpHlDVrd0njnPiR92XNs+NTjjvAImETMh\n" +
-// "EPbQ/KPspugi6gkrLFhcmy/OiA==\n" +
-// "-----END PUBLIC KEY-----";
-
- private static String compositePublicKey = "-----BEGIN PUBLIC KEY-----\n" +
- "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\n" +
- "dGgRaoHi+K93jgNwPC3Y2ZfSX5xj\n" +
- "-----END PUBLIC KEY-----";
-
private void checkParseCompositePublicKey()
{
try
{
- PEMParser pemParser = new PEMParser(new StringReader(compositePublicKey));
+ //compositePublicKeyExampleRFC.pem contains the sample public key from https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
+ PEMParser pemParser = new PEMParser(new InputStreamReader(this.getClass().getResourceAsStream("compositePublicKeyExampleRFC.pem")));
SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) pemParser.readObject();
- isEquals(subjectPublicKeyInfo.getAlgorithm().getAlgorithm().toString(), "2.16.840.1.114027.80.8.1.4"); //id-MLDSA44-ECDSA-P256-SHA256
+ isEquals(subjectPublicKeyInfo.getAlgorithm().getAlgorithm(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256);
CompositePublicKey compositePublicKey = new CompositePublicKey(subjectPublicKeyInfo);
@@ -5566,191 +5501,17 @@ private void checkParseCompositePublicKey()
}
}
- //FROM RFC, SEEMS WRONG FORMAT
-// private static String compositePrivateKey = "-----BEGIN PRIVATE KEY-----\n" +
-// "MIIPmQIBADANBgtghkgBhvprUAgBBASCD4Mwgg9/BIIPAAD0NNihDKzc9WtrKL3N\n" +
-// "NqaRPOmp/q+40jn5RowQ2+euyt08tCb8n+fyXPTeYUqTRyok4CwyZDOBvRgzjQPo\n" +
-// "ViTIHTQcWno6KkNnRaLLCmpapjHbTJvbRoBb09RllNQwzuM4KaISDYuwUNikESKz\n" +
-// "ZUGAIGIyMiSHReImUtAkEkTGgcQEBIAGIsQ2ZoiERQpEJVsGKRzDiCEHaYnEjBJA\n" +
-// "MeSmKFkIKiAXYUoYaZQkhkEWYSSFLQkkYgoEKiICZhMAIuDEAMu2YJu2aBmXjQCC\n" +
-// "ASMEBVAoaFkiAJhEUcySIaAIEQgyISMTbBM4JqLESIMmRWDISQkHTplGahiQTMQY\n" +
-// "JpQ2ZKQGgWMUaNCEkdAmZQHBKdJAShG0TYCikCNCcNLAcYkgQiOhcUHCZYCGROQo\n" +
-// "YOEkZiRGkFnGiAsoYEsIYCOxaFQSAYy4EYIYRsQYRNuUSNooaUQGIMg0DdioAAsQ\n" +
-// "RYMghgSlUNK4gVLACQgRSAkxDIs0QhEoRoKEQMMoMMSmTWNEDqOkMRw2AWSgUAQR\n" +
-// "MaSiYAgmkeFGbtuIhFRAcSQyUWMYZIKEQNo0KkmkgVsiEcMGJJQgMko2JFKGMBmQ\n" +
-// "RQzHhBsAASQZbNEQcVCGYZkIjkMYKpJChKEUhQSRgCTEIaEkkYSUQeMmkmSibGK0\n" +
-// "TBopYAAmgVogBmIkauGADBKHKAoVQRhCYhoXUsCYgOCYJRDFgYsCLAuiEFE0ghEo\n" +
-// "UQwSAUK2AUSAKMQobSMmcRQVbEQUDgA0MNwEhEjEaAQTaAKCjAMEcAyBSVgUZkAS\n" +
-// "jUIQkWTCCRQVcAA2KllIAAIRQoLELRuzaCIRiZkGbNpIgYBIAQggIuOUTIzCMCI3\n" +
-// "BoIIBcuEBYLIgMmEcZmkkEAwMEGSZRKXQKIEkcGERIFCCeEyIouYaQoEhsM2jdBI\n" +
-// "JhS5YBAycSEEkOSAiGIYJgiQbVKkYZLIARmXTBvJjRIWYMI0RBGUkdQmZuO0QaOg\n" +
-// "gcQGjNI4EFIyBVREAsMkIRoBClRIbgMUgVFIUgNCcVGmhBC3kdtEBBw0EVlEiRsC\n" +
-// "YuKYCZumMFwyCMmCaYAoCgAWLBFAIqBELAGxcBoJQlKmYKCWgMKEUYQGZMqiDMqm\n" +
-// "JRnHIJEoaAJHgByhBBIpCeQiBNAYSSEQQNKUUaMyMYs2DnQ5Y0NY1PJ+TCmdgiin\n" +
-// "NmiycZW2gsYQVPr8uCyDiEcLELhhZoHkFkvKWQP2Y1iviJ+tgiKFSwbMipJmOq/I\n" +
-// "hovLcLpcDIwxtiwJPsGtozGSuMwx/Se6MpI3omJT/z9a3fwV8gLxcbNiWw2UjB3N\n" +
-// "3/BPb7Jr4F7Fu+9G4nwZI4kK4LRJ4/zgcqb0Jq/2vhLIoEQ5TpHdn2KSqrY4nHH7\n" +
-// "Hmh74HaXrY7JHqUgj2xVwZQuW09AnjIpy7NQW8I3oNkRxf2YNqIM6pIgAHDDNbkS\n" +
-// "FeJVp+5EhxmUTDgOwGM3kZg4enFT13auoY8iCbt8PhO3STSpo+A2he1wlmodsBvr\n" +
-// "h42v9TpKJJW/2w0IB432RGbjCW0jiIJa5FO1jh3eH822vLnVs9VescBszHDjQRu3\n" +
-// "+fyxFIAc/0jYYTgIFfrPqEwXZC2FA3UfpqQE7KtjTv2gN64E0/hSuBTrH2NG9Pvt\n" +
-// "zlj04xtjMqiI3vULH9nTRcufSF/xO3POtty3zvEdBf/d+v9DKn7q6qaAB4rW6j4r\n" +
-// "O9+WwiSowZ2lYv7vQnHT90bVKn0jHGGcHgfAlSNg7ecWBL8k+iL/U7zeAUAl9FNT\n" +
-// "44X1eNYZZcy8MqjGiQSTIHFAQd3v93gflbAQVHC/6KDnn1OxbrhOgft2VgjjqggQ\n" +
-// "W/jFfO/TDmaLvS3Igxsgud2H3byHOSLh2nd2bHm8yXXVUMJ3otg2/x8KnDS4Du/b\n" +
-// "ORJSskflf0zUkfiDILHGm48bwYsvDxXc7rnIvqI7B4rrH2DzcG5Ve/kYUtOikvXu\n" +
-// "hx01JbV2xQQfIvGWjpZWoG9GticpP3ZyRzMDSuPudiLBjVhQ0lutNvzuLclqGTVX\n" +
-// "LshLtF1oF5nmFQTi/GExi4oUZ4ckD2V5om/fcG9Wdnn/IFVAqO0DM0SzCw1kdKbP\n" +
-// "X97j9nOmgrrT9lnI4O5cQckjvfvGrbbM4oRNW7aInwA/SpYaXt+BnvkEt/BXTuQx\n" +
-// "lg/g7asWzUSEqKoxM2wC5E8FqiupKMqKrdZP8wRpOrv2KikVMg9d9PM4GrCVcjKI\n" +
-// "Xv1fyZW/H3eugnrr8/Po9J8RZkkqBUTVMXPAIju63yuqcMvU1AQRyiMo8BcdFRo4\n" +
-// "hufRFe2K7APSGybKE5LgVALUGZ70GUl85bYVjnLslcHeZdySnXo82H+HNTM8UqKc\n" +
-// "9BXGAJS+1Zb12fgTemZO/5PBfcgS+axLiRwUCSZDA/Hlev86OgHsjnRt3JjuNfX0\n" +
-// "L3bHZ+9DTzRADJnm7Lyj7ylKlUuvoH+7WaPMmBiduXuuQ/k1iLOMq0TZa/T31UtP\n" +
-// "izx6M9+1+SirJS0Dzgy5XDSCfc/I0u/lUtf1kynwSmAlLSG7YAbt1Ua/2k+5CW31\n" +
-// "UZZdaw2HSVGFnT2PwSlXRnlq+FEdXVbzJA39oS/CNEOM/qdnRL8cU4rU40Xn0sm+\n" +
-// "egIjYlKjKml1Dg+hVFuYvk7tY+ZUEk8mOuTFlsB1f125X80L5EnhYOeTHpn+muEt\n" +
-// "GyoMCpdBwxV5AoQi/5DhzPqO8IPUwsjXHRKONcP2s6ibUC58HqkCmocTRJApAu9K\n" +
-// "GZQnmcXwrSvV09AMhND3oNTIRup+pi1TSfETZGyYqouPJNgf5/3rzICwrxBfBz3c\n" +
-// "+CDn0ELMhADS9lBQ2iLENSTYE9jCaoX+RFKQJIkJWd1GMHs6xoyNxSf9udsShyyS\n" +
-// "aXPor4zprUON9lhzh4wcTZT9gsgkb1TesKRzkUe4/uzeDcAr2K3QgRq4H5a2F4Vt\n" +
-// "ZJ13x+9sSrnAqPF8YMmwHEmky6Ny/m37lGKAbupMfW/vopEyQf4G9F7bqgiTJVPX\n" +
-// "MmsvnYL0UF4LcQ5t22Vw4B1DVkrJ0itoQxFJHl4k1KFIv1k4XYVviKgmLHaNWhQo\n" +
-// "N3rVN8sRQ+adm39D4ckB+btqNbD10hUxDiuJcouslXcYl8AoLJ82PdfItIbECKdA\n" +
-// "zbF8HAKTMHHsexPls0BrDOrgH/Y/tvp2Gmgup56OwQNq2Hpnxnh2yNV64yk1A9Sm\n" +
-// "4UhGenN0vIo2Ro3+RKo1pAEf6MJG7ZeLGb4xFiDfSweKQaIEtDuR86rw/AYGXlfu\n" +
-// "OXJaNWeMDNmu/WltbjSWflpIpIKYFF8sdhkHfQpTX/XUaVZR93rS4ChtORKha+UL\n" +
-// "/56l2DFTItDoOJ4R05PAgq6LEGz5Nr/dCRoAcpsXyj28BS3iD215llxthHMWdB6l\n" +
-// "LUBX4IjSn+ZG8EeDCRy3E5ZBAPQ02KEMrNz1a2sovc02ppE86an+r7jSOflGjBDb\n" +
-// "566t0abOS5okOYEl2kDLtB2I1aQhEFUFpf/J2yWrxC3pZIAlZ+dvJ3RgUFAoQJ33\n" +
-// "8YUXcYGhZjm9khMkk5xyIekDtVBTztpBohsfc1OhfcWRihWRQZvAdO+lL0Rwm2sP\n" +
-// "gU77uKPioNYqzhUTyN4SzeJLt7Itp8FkmTYQ6Ii2j03yXu00c4gc5xMq50ldyNl5\n" +
-// "+0HSsSFlBTsD11gZ55PxRhvwNh3cRqYqiFsWdIDSzXG/ows+glmUiYaDi6CVnTg+\n" +
-// "c8qIzz6x+YhSBjPeqdD2eJr+T4ZmQzwP0UyIPz3Bta8sJziWKgLGs57RshIRxBS0\n" +
-// "XvEGDlRG4gbr9tLTc5BWmrpUEXVvm6ErXFvDXn0pChv/QxYBp8kfO1uGf4nhxMiL\n" +
-// "2uBQWpr0ZutMa25QMiNGeyCOJey00rQ8y/4IRatOkVa4mmrvpmOZWqvKwBpkW1pF\n" +
-// "MTXinhjlR8YxhWAd7mgJB3n9KO7UjDJAkko4g0JTZOUXkMYCTJLk0RO2ETdWw17/\n" +
-// "9Ljz44O832tzNLTAg/cE1xYSJNOBwy1VeVgLB9BCujcrXYKp7IxgsH2W9vhcP0Mr\n" +
-// "QXoudA1AR6SBt3WuHQa8XGkUzIkD8z8y/BWg2rHBNGSCTPYpSr8YKtNq8hByxgCx\n" +
-// "TfHmQ9a+s6uNyhZUc2sp1gVqiduzIlMytnZPKAvnR+XM+vsRlwISyfjIqaDvZPXS\n" +
-// "4PK3t3TgLn7CmmOQy7rpbqO3TuiBe6xvcW5W4iM1qcn7t+5Cb1HcJN+kM7EDRrMa\n" +
-// "RC5OuS2lmJ2nm1e8CsiGmp4i8rLjQhtHSHAInMUTS4KV/Y4nOaYvgc5SSNSLj5Pg\n" +
-// "6jhue6TZ1O5U4N6KdPDFLJTcnlB+cmmoPAzbCxu7mR878Y3Kn32qnKkvr+hVZm1d\n" +
-// "rQxdO45/Gu+eBZ5/0DYLDXHX8PTr+MO08vquZ09sINi7IGwLszem+hYlhLhxzMPy\n" +
-// "OWiC+XC49hlKYx7ZVBy+ChB6cWdieY2wYHqqU1hMtU7j0Ed+Ja8lQEprnv5JpNpY\n" +
-// "moesDSuUV5RmvLonQZu0U/G+UpCDLK6LC8fSqQuZSqG85/LbStTUstGbjA8PcLZ3\n" +
-// "j1G0ThoxLsOTWvytVYDuvHQE4/+67HL8+wvmbkDka7fPF/jmZqMsPnxA1gKHA54c\n" +
-// "yOqySByzwdKfq0ifIkimaRWWHiMvgg9LehPfESUB5ZfASZS8iYjE9MQMnpTjM6wi\n" +
-// "Wsh8Q9NWi8OiyznXRW4iETKuJZ4uR2uJ6FpnTtgvNMctwI7JFBCubGw/ChZfddCV\n" +
-// "B8Ghr2/4Awqlvp9dJkWvfnAdLUVY6OTmXkogdNQZGoLu2n/m0b9ovHAWtmaBlclt\n" +
-// "8RRRYSJB8y4B2lPkS2hsCQ3tKsSrcCmM+XP2KQLB/paHTDVdhPz8x7TWPrIND4o2\n" +
-// "5TeiFTvsoi5MSbKSiI39CNfrPIXM4c90JC0Xne3VNp7yA6biUH4K2iskuq2sJai8\n" +
-// "lqOuvzw7XXd7Z4MOdMJwzWYpNIc/7rA3OqOyDeSfYWu1ztL2UJbjG/UeZflukSw9\n" +
-// "p0XeJpSlapv2H6tEfDyqCIfH+7i1ZNZGzeKa5H6bKJL6ka5YuYeFERu1gjb6eG4P\n" +
-// "4tSMfwhBIx+ei0Y/N3YVQdDull6K62TAAoUEoTIcJxIHklEmgeWru8UQDPvX1rxf\n" +
-// "XJo7t4V0k09c79KMMqEoKd+jh3Mth88GV8QO2FrUQ24TFwR5MHcCAQEEIOu1IEuD\n" +
-// "uM16fyp4k0FSfEP+H1ka3o07lfZmk56nHuiloAoGCCqGSM49AwEHoUQDQgAEkSZv\n" +
-// "SVDhZlBXhAkaTBxlrRt624URpHlDVrd0njnPiR92XNs+NTjjvAImETMhEPbQ/KPs\n" +
-// "pugi6gkrLFhcmy/OiA==\n" +
-// "-----END PRIVATE KEY-----";
-
- private static final String compositePrivateKey = "-----BEGIN PRIVATE KEY-----\n" +
- "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\n" +
- "2NmX0l+cYw==\n" +
- "-----END PRIVATE KEY-----";
-
private void checkParseCompositePrivateKey()
{
try
{
- PEMParser pemParser = new PEMParser(new StringReader(compositePrivateKey));
+ //compositePrivateKeyExample.pem does NOT contain the sample private key from https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
+ //because the at this moment, the Dilithium private key formats don't match.
+ //this sample was generated from this BC implementation
+ PEMParser pemParser = new PEMParser(new InputStreamReader(this.getClass().getResourceAsStream("compositePrivateKeyExample.pem")));
PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) pemParser.readObject();
- isEquals(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm().toString(), "2.16.840.1.114027.80.8.1.4"); //id-MLDSA44-ECDSA-P256-SHA256
+ isEquals(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256);
CompositePrivateKey compositePrivateKey = new CompositePrivateKey(privateKeyInfo);
@@ -5763,194 +5524,17 @@ private void checkParseCompositePrivateKey()
}
}
- //FROM RFC, SEEMS WRONG FORMAT
-// private static final String compositeSelfSignedCertificate = "-----BEGIN CERTIFICATE-----\n" +
-// "MIIP9zCCBhigAwIBAgIUUFXlmVgQD4nQC6Tzr4OlRKxVYYQwDQYLYIZIAYb6a1AI\n" +
-// "AQQwEjEQMA4GA1UEAwwHb3FzdGVzdDAeFw0yMzEyMTkxOTIzNDBaFw0yNDEyMTgx\n" +
-// "OTIzNDBaMBIxEDAOBgNVBAMMB29xc3Rlc3QwggV/MA0GC2CGSAGG+mtQCAEEA4IF\n" +
-// "bAAwggVnBIIFIAD0NNihDKzc9WtrKL3NNqaRPOmp/q+40jn5RowQ2+eurdGmzkua\n" +
-// "JDmBJdpAy7QdiNWkIRBVBaX/ydslq8Qt6WSAJWfnbyd0YFBQKECd9/GFF3GBoWY5\n" +
-// "vZITJJOcciHpA7VQU87aQaIbH3NToX3FkYoVkUGbwHTvpS9EcJtrD4FO+7ij4qDW\n" +
-// "Ks4VE8jeEs3iS7eyLafBZJk2EOiIto9N8l7tNHOIHOcTKudJXcjZeftB0rEhZQU7\n" +
-// "A9dYGeeT8UYb8DYd3EamKohbFnSA0s1xv6MLPoJZlImGg4uglZ04PnPKiM8+sfmI\n" +
-// "UgYz3qnQ9nia/k+GZkM8D9FMiD89wbWvLCc4lioCxrOe0bISEcQUtF7xBg5URuIG\n" +
-// "6/bS03OQVpq6VBF1b5uhK1xbw159KQob/0MWAafJHztbhn+J4cTIi9rgUFqa9Gbr\n" +
-// "TGtuUDIjRnsgjiXstNK0PMv+CEWrTpFWuJpq76ZjmVqrysAaZFtaRTE14p4Y5UfG\n" +
-// "MYVgHe5oCQd5/Sju1IwyQJJKOINCU2TlF5DGAkyS5NETthE3VsNe//S48+ODvN9r\n" +
-// "czS0wIP3BNcWEiTTgcMtVXlYCwfQQro3K12CqeyMYLB9lvb4XD9DK0F6LnQNQEek\n" +
-// "gbd1rh0GvFxpFMyJA/M/MvwVoNqxwTRkgkz2KUq/GCrTavIQcsYAsU3x5kPWvrOr\n" +
-// "jcoWVHNrKdYFaonbsyJTMrZ2TygL50flzPr7EZcCEsn4yKmg72T10uDyt7d04C5+\n" +
-// "wppjkMu66W6jt07ogXusb3FuVuIjNanJ+7fuQm9R3CTfpDOxA0azGkQuTrktpZid\n" +
-// "p5tXvArIhpqeIvKy40IbR0hwCJzFE0uClf2OJzmmL4HOUkjUi4+T4Oo4bnuk2dTu\n" +
-// "VODeinTwxSyU3J5QfnJpqDwM2wsbu5kfO/GNyp99qpypL6/oVWZtXa0MXTuOfxrv\n" +
-// "ngWef9A2Cw1x1/D06/jDtPL6rmdPbCDYuyBsC7M3pvoWJYS4cczD8jlogvlwuPYZ\n" +
-// "SmMe2VQcvgoQenFnYnmNsGB6qlNYTLVO49BHfiWvJUBKa57+SaTaWJqHrA0rlFeU\n" +
-// "Zry6J0GbtFPxvlKQgyyuiwvH0qkLmUqhvOfy20rU1LLRm4wPD3C2d49RtE4aMS7D\n" +
-// "k1r8rVWA7rx0BOP/uuxy/PsL5m5A5Gu3zxf45majLD58QNYChwOeHMjqskgcs8HS\n" +
-// "n6tInyJIpmkVlh4jL4IPS3oT3xElAeWXwEmUvImIxPTEDJ6U4zOsIlrIfEPTVovD\n" +
-// "oss510VuIhEyriWeLkdriehaZ07YLzTHLcCOyRQQrmxsPwoWX3XQlQfBoa9v+AMK\n" +
-// "pb6fXSZFr35wHS1FWOjk5l5KIHTUGRqC7tp/5tG/aLxwFrZmgZXJbfEUUWEiQfMu\n" +
-// "AdpT5EtobAkN7SrEq3ApjPlz9ikCwf6Wh0w1XYT8/Me01j6yDQ+KNuU3ohU77KIu\n" +
-// "TEmykoiN/QjX6zyFzOHPdCQtF53t1Tae8gOm4lB+CtorJLqtrCWovJajrr88O113\n" +
-// "e2eDDnTCcM1mKTSHP+6wNzqjsg3kn2Frtc7S9lCW4xv1HmX5bpEsPadF3iaUpWqb\n" +
-// "9h+rRHw8qgiHx/u4tWTWRs3imuR+myiS+pGuWLmHhREbtYI2+nhuD+LUjH8IQSMf\n" +
-// "notGPzd2FUHQ7pZeiutkwAKFBKEyHCcSB5JRJoHlq7vFEAz719a8X1yaO7eFdJNP\n" +
-// "XO/SjDKhKCnfo4dzLYfPBlfEDtha1ENuExcEQQSRJm9JUOFmUFeECRpMHGWtG3rb\n" +
-// "hRGkeUNWt3SeOc+JH3Zc2z41OOO8AiYRMyEQ9tD8o+ym6CLqCSssWFybL86IoyEw\n" +
-// "HzAdBgNVHQ4EFgQUhcS/LyOtUFUrF+FJxoSERDrtcXQwDQYLYIZIAYb6a1AIAQQD\n" +
-// "ggnIADCCCcMDggl1AMX5C7IKC8y1AX2ANKQWQWycGovPVFkiv+qctjfWt0jaErT1\n" +
-// "XnR80WfR3XX1rIIZ6jG1ulkLdUGx2tFcu8Qeb0umxvYWYC6htzvGw+bjxcRm0DES\n" +
-// "d+bkwWIBzdK23b9WqBNLqvzNccgAPXvP6PwrLxCz+sEnWcCDDqgeHphbYf3vzedR\n" +
-// "uMvIsRYqGO09qt/tWu3JG5nwGiX+6t/YFgE5knii3sXdlHWZQ+nSAnekc2sgtCV4\n" +
-// "cA0Lg01kBi+AZGelNuVK3EtgKJ0VTP5DQn5D1dLn/RGbqlMngsNs4xUlIFyvnJ8l\n" +
-// "UZp6+VtfE2fWRDW4yQ4ob4Ed2KEWMtWa1GaFtIfUjDGyqYLwMOJUjE5fmhLxioqS\n" +
-// "pk/cST+AaK5iNZzlDRC220hGOIOsiyf7UQKw+bFTENVqyXrYgTmns9zg+mc5KeZj\n" +
-// "hE6IMFMtkQyJnRVWUL1eRviu1JL90Tcmvw1gvKdGFPDe4A7FWx0tDyAVY1wVd/sd\n" +
-// "Lylt5QvBaIqgrtc4rDeS5pHGNdgy3zsi1YYpet5pyfQwZCtmqRggBDTCmH7nTfrV\n" +
-// "rXDbsUm0euCK+YMwbi6DbpDV5mQrUqDX1MGk0RFDzlKRtTWrvxhhCVLgV/l/ZVgi\n" +
-// "bEuFQg6POuCn0IA2jFJyza2TK8p82RAZbcvtM8XdJVhM0okKIRyi/8lw2kbX/p5L\n" +
-// "l7vMmD0xPOezi2FQMxev9460Seb6FtOlvFptsLoTw4grUTQHl9brftzPAhVmUBBY\n" +
-// "wGffj4rl70m5fHZzL3YXpxkr4jlqG8tKJc9370Emh9xXV4KMuo2Us+vnRUN+9QeX\n" +
-// "tvDaG70jX3+760hTl4qDqMWfXY1nXhCeHWGCCmn2Yq8ULdYtIjZIMcHCXAvy68jv\n" +
-// "7vkM5xQzDdgRMXop1Pj3aZLRI0boQ4OuR16sxmmpPUIGanfmDbvrdBBNucNcDYDy\n" +
-// "BU5QpuCEZ8yHs94TSWLO9KP9i+IlL35TGG2zIbwbhI15HKOWzZU9ncoC2BOF6zhw\n" +
-// "u60tdBvy5O8pinjMBQKVDPMbrIKjfCUK4f0YQ1/Bk4ssPogQNk3sRYJqWZ0MvElk\n" +
-// "q3674KpN0OVB/kJFdAB1Uqpk4ARnZ7SsO8B/6u7rRNdthHSRsu4Fhe31EE0VUoUh\n" +
-// "x3GQM/7gTk9El2jDBlZxwEpPEtTqARgp0ad6EJnMcIW0PEKr56HUFqfxKVjJWagV\n" +
-// "fhtKzskghDS5lRpDY3vPq1Cq8qSl1ojcij5zm0BxI/cJIjh41RnW5D3kjt3r3Fzo\n" +
-// "an4pPZkXzZm9/iGAoFAy7BThfg4PXVq2BMCNZPdASQjIiPEWklylW9iX+g/12iCV\n" +
-// "Gy7F/JOG0SOH5/2d12gRDDiwn6k1KDwKPDa9htaPBGaNNXLIpr/Wb68GtTkNs1TG\n" +
-// "e7Sf9aigE9BtTGgeniJ1Gn/aV9LGQFqRRQsnqB98bMKABZi0RjZ9yebLj6lwSFXU\n" +
-// "pTdq/YNnBGwAmOm/HXzksOHJOjh20iDPhLjfMB6Fi+XkWVZ0TWzV2ZwOtM56tY+a\n" +
-// "QoauIHR30QYtGZMI38HpVeLSj+iNUEKbE6kY5c69Bjalwa1pCqb9aP5VnKOkMA+3\n" +
-// "qQ6c2ggxgudchBSXK/BZw4n4l7IvHu9wEMvsVh9mt/SAGkK53k28RDkNtX7+jfJR\n" +
-// "5/q7Qp626ts6Sc8rG6BmZoJIJnUXjeOcqlAoDXYRGuxCw6Jm91DL9j4t3m0bQhub\n" +
-// "hUt9diovZ/hw2hOng+xT/oSVvauPHFpxSUu3NVcncjIljD+0U3y6cn9VnE7oFNSU\n" +
-// "G3HadJlVTZncMrWYo954Wt3cwNA1Opcq+5Tlu76laOWJ/4eRcvOwmxrKZHUW8Tmu\n" +
-// "qPPsAOTagFmMxOBkLzIaq39SZxHkw61SdJxXlKAtmZYnNvwT2NGpauF6P6G0FHAO\n" +
-// "Ucfu/DDpAdKZ/GGpVxC2ttfDCzO3iya139M5fbg32RpI0q18swYFhUAqszdAPihc\n" +
-// "4lpCGw9JdrO8i1JhB+IORJegJRPs08DYUNv7nzSbOi03iYY/QHtGw7ka5AGLfkY8\n" +
-// "ajiLzlXwI2xMB6XBqUsAH2VxTRPJ3N/kGTzFvhiGBOYx8+jO/FqEa5E8+cafU+kW\n" +
-// "m9/RCpumizdVzrH5MiFh0NI9iUegdHs+hDW6GDpA3VpGi5MmmeE6Ck8UyOzDNnY9\n" +
-// "t53b9QxuwiYgDdw9z0KpYtGt7tRGd0qDARky8uRQZ6HFS4sNXlUFiAG9ko62CFTD\n" +
-// "WCALXmhtqvPcjfiDDL6qMRLevi31YnhAua/Kb0Mhja+KDM/UwRIVaB3WHhulzn7U\n" +
-// "pFQG0vVnwb0+VWhKsrWVJaJw1Eg9tmy5HJBsnmne+A2qG1ehBFCWJtV2MvyK8H9G\n" +
-// "BxaJbq7PpPlte9ID53apvkhyvag843Ar/pOiTc8J6xncJa6w+mVViUi47/ZkZCkU\n" +
-// "lipgCv1ZqZhQG/CERDxACulTa+0S8nO+g5CBpW6cuQVa052nRV/qhVUkQ9yzm0Pw\n" +
-// "vUOftuX9b/W5QXas/ysUwPAeGd2XPBmK5lByyYaW14d6GBJGmyNYv7vjrbL1xeJr\n" +
-// "smjnaRPipOvwEh6IE1OdsrlqfjG27+aXgfZWbCW28DAeTK7ilLB3ubyvPcoTrmX3\n" +
-// "DxM7OKF+MT6PAtqSM92l76PfECvyUfv/Rf+cSF/CleTIM7xfe7IOwgxPPdMEw2rH\n" +
-// "uS/CeJMsdBW8DwQyRcgK5h17zyaRqztATSAQK3MQ/B2f7MoXf3Z9oLpgqyBT7aiL\n" +
-// "/XdYk8UipIyuRK4Y9Cj2UNc3DgYhzFPQY9SO3gO483uC8Tqc2IyoKaGsNS1rWY/W\n" +
-// "rleqqraEmlMN9NToAa4ftZvqdWQLqH7sJcCQ1EzfbrkyrTKgjRmvRyA4n3t9Yjry\n" +
-// "k+ZI3xkgrUj90xfETb+Vx/JrbegfbfZ70w7yTRnSDB01cbQP4rjI2uGZVRCxXJal\n" +
-// "XRtaOUey+c0ZeIRp2aPrYP2DesL0Fmlc/ooSRgC8f+QHJU/7Js+WYuK8MVK/vil9\n" +
-// "J9FgwoCJImfRzkA9KXYaix/f4XgvFLopb6kAszAff5Zmpcq72gwWv+nEE/3M78PO\n" +
-// "zs9k5+wt65W3h4zelAIUM5hfgmJj4vvq53AeZP42AhcSV+bgsPg2xGM0Im7WAQ0P\n" +
-// "IScqN1pepq7T9/0eMEhRdXiKj5ufub/Nztfc+Ao8RVVidXt8oMnv9vf8FxgfLkpj\n" +
-// "dn6Mjq7Y5OXz9AAAAAAAAAAAAAAAAAAAAAAAAAAOHy09A0gAMEUCIQDD13F6CblJ\n" +
-// "Ll2dp7GZtR5tyKObPtvUc1s16fP3g7xhvgIga8IVcv0k6DUIApPztCsP/UByrm8k\n" +
-// "1nbSe/5A4mF87n0=\n" +
-// "-----END CERTIFICATE-----";
-
- private static final String compositeSelfSignedCertificate = "-----BEGIN CERTIFICATE-----\n" +
- "MIIPxzCCBeagAwIBAgIBBTAPBgtghkgBhvprUAgBBAUAMBIxEDAOBgNVBAMMB1JP\n" +
- "T1QgQ0EwHhcNMjQwMjA4MTA0MjE2WhcNMjQwMjI1MTEyMjQ1WjASMRAwDgYDVQQD\n" +
- "DAdST09UIENBMIIFgTANBgtghkgBhvprUAgBBAOCBW4AMIIFaQOCBSEAbBjwJ4KP\n" +
- "/W9bM1qi0wxfk1AtT7QgnRMUaWsdwOGEatOM4qDPJ0aM6hhMJH9t2yBV7uudt+pr\n" +
- "tFyYpyZpcDBKjKoWP6SthoriJzGYOIxZLrhwhU2tII3nyUk6v+0pdGAgUizRYRpO\n" +
- "Hu/VhmLw1MDDFaGrLcy+HxNAUncExJ8L2QkvEVs8royQnxQ0qRiJopPoqDLTxMHh\n" +
- "4tiDwpdSEAIWFPVtLcBoWLn6bBBSgQq+42PZJIg6yj3+26riHSZLFhTBqJhbIH3y\n" +
- "kdIcGieQTXMNAxpdVqo6studi5f7hxNs+0H/HEXtyivI0Uw7ySwgljLhHQpXPEM5\n" +
- "1MnAnhZU2MmXRGLLUj3o7U1Yr5wjlMbe6h4KDHYpj0yC2CfLXo6GxEp9RaEqK0d+\n" +
- "HD1iL9qf3K2DxZ237d6VhjCvO5Bj6BG99ludVvUeqt2ZbsIincZJVKbni+9iQZm5\n" +
- "FeidmYDmR0atrwoGSyGpqanx9E6PYS4kX1c8bqBKArhnFCKbVWgSwdiMY/ArgW8P\n" +
- "voXVwki63562XAdc4cVYQ7VPUIzh7KV7El/FVrIpYfXg1PWX4Vkl/C+B81HP/NA2\n" +
- "z4dpSMdCwEwO8gK/ikAKxKK1wngcfsntJY7y1wMuMnkq0hVCAHm5mqJ98vIdLGqg\n" +
- "iNeSPnb+i544s++zzhc57Xl7OUE6oDO/NakNgeC3DCWnOi++niwOtcgjdDUK4f8w\n" +
- "SXxoIIkRYZyhPu0rGBg3m6oF5KlZ3qzPhjmdQZmTxa4meRrOiW/JnqQy5CIAjo4B\n" +
- "YvB9Pnozx8a2wHOiymplwxnpT2QaAxtKIr9rvXeDq3eV5gb8t/HQ9aG83IqqMets\n" +
- "KaSpfDxhAAzyJADw6UCRgb/oEYS4uWEwOHAcf+S/QlMH1l01KXfLIjiveosOVWu8\n" +
- "wh5tZUKhqd+PxQUVul62YZryf3QEhf5C8yqBfLVp21jqNjHxnWofcEOhmDbqygVX\n" +
- "FUm0bAt+K6kMrtBDfT0jslj66PXgsmLoO4ba4ZUYfPJLu6afcEvLHFw8o/rMLKvR\n" +
- "k4ycySCMjACl++IjPxDWfpOx1EBsoIoP8/RRMCnDbJTu/hrzs+wtuwjkaFyoOdQh\n" +
- "wwx9vHafwmGrtM34dxubYDRCG4WZ0B3cAXMx5dqxz+a+2zMCHIfzPClYk9CAdoQN\n" +
- "R82jY3u84w0lk1VwwAK77LQYZHCGJKUhURiNyCiv+4cn8sbzK9SY+tM+TYp3+Zf1\n" +
- "0NVzhVInXjG0ORdPP+QqbSxiUSz8aO2ekHDjKMhr78cTG1n1iMK1l3H5EwHR2xVw\n" +
- "r5VbB9FiyMmUOrvuy3wVnrXSK97kI7y2z7AH8JCdVsfuc9IPSVvosZJA2f5maIq7\n" +
- "cUktS0SHC4QLCS1DAWwvnp/zaFcNzEdhJdJyZizU4HK3h3If/1ILdMA84EFAj1bH\n" +
- "eNti7YDRDHrvnWIAs4N4cQnAmSD7acQL2b8e3ghpFlhLsdb5CQ6u4XejpcOBMw4T\n" +
- "45CKsNRFMG8Jt25njRqWjGCA3T3CymCLL9tPub6mynP+2m6BvMpcf5Kt8mx3GKaP\n" +
- "7vXQSdnLvy0ryFKpZ6QO2HMTS/d7WpVDqAcgqHo4RHcx2Nen69IJtWe8K4FJa6Ej\n" +
- "LliVKImVBS/si/kGkgLNzl4dFMTLLM3pQD58nGHgH67E1GQIoCX64y1+cl04+vS8\n" +
- "6v3+wiVNczxMhdFNsj6rlyC1qO0kVnYhhMh3XDEp1Zqw560y7j4Hr+KV/eBEHsl2\n" +
- "7BqaapRgmnIsSQNCAAQdf+2mgJr7DjHsZbxexsyKFEpSrkqzVHDw5zUPE3VxKM1G\n" +
- "yeFMCC/aREdv4GC2ivN+DROVckhw5LZRGERK6X4LMA8GC2CGSAGG+mtQCAEEBQAD\n" +
- "ggnIADCCCcMDggl1AJPi96BeJGm5KTQBOlbLZBEUY1vlzfcR75zsQ+pQAiWNXlCx\n" +
- "skULPvlc1HFT8UHJ4cB1ik8vwplUs3z8n2qbfNz+d2i7kJstfkVJF75cw0HqcNx3\n" +
- "DqbZnaFw2RLs1n2qMoIaCEi7xxn7MBhE6QrYcP4Hi0V3MtukM1HxcyNMBNcvWhav\n" +
- "XurOjXBLZPIcHMhGniMH80apLWc6Z5o/zpT9f2rgeXpUBHw2N2+O/a8jL58feGmX\n" +
- "08SA0mVAo5kCHEq0FW+vQ82Kzos0sOuMURoSu7v0J+0AccI8lC5I/hyyzowCdKSz\n" +
- "tKV1QiF1ujV70eOkxaEdUJAXDhMfjf8UljMzeHewhPhEN1DvdDBvlhdiH4UsIvJt\n" +
- "6bfGBLR+/AIUDWq68LOozDUNwuMPOlAm2CmpoYsb59TySpfVVgS2twSAFA4qTx7h\n" +
- "K/qNnrfuOpEXCBDFlHSk9WTyxKgEjCMpJFtiXau5K9Vo9QxC06BCBco12cap2RxA\n" +
- "zUudh0AWoHhsRwTkJG0PAX5SAcLJW7FFx2Dmz7Yv6ZPVFo34B09DJ0xm0LoVQNbk\n" +
- "R5LwrbomyWDWSwrVybKE9gAB97QUDosOH1XiknAC/rImDBZs5TkZCXHtAk14FopP\n" +
- "Yvkb9vzShbKJdYg+ileU9dDpazuT3Ij3fk+wCxjBlltnN+wgaJj4ec8uYDEJJnq4\n" +
- "IAzi7uxfUlOz4/tXnrU/drxbXgB2WD4PfTwxjG4SxpCYk9IWbdLVhE8Lwl4+UT9K\n" +
- "rBwmi4iAnJGOwIPt4p9V8SO4NupnYgmI70+NVFQh2v06zIRKiduNQ2e7BubppZp2\n" +
- "4xabRq6ExyV8m+GjtxByPLqLI5DuvAdnDtBNRSugLKcU7pzLIAaYjAetk8g+w2Rf\n" +
- "hkRx9KSwdvCeGYUTq/rqkrOx/v/LWFLwYZ3sCjob/B4m8xJM/hcm92Au+l8DNykI\n" +
- "aXds6k3IcvSRFs0X1jLeO93/usguTnaZFbI4u+BvAkx//nM2BXnEBliFXtsythF1\n" +
- "8OH2m5T4FgxRIBDs4KssMazf9co0qO+GEljE+HGbzB9/Cx39a0xHk3Ju/NdwTNON\n" +
- "M+5gUMR8gBqf2jWhCvvLztGRK9+vZvXXLe5UJAlf1Uql3Er1WAW/2O7D69CMOm17\n" +
- "/poPj74p3s2LfnDIxUMESZEcre/c17AbRF26We5hp/ISNxH07rstzdPJrHtqSwJy\n" +
- "1ffkUSPQaWmIK1NQJFW0PMyRvM4Z20dj0rXTEHOFOqodUw+xrZjg5VGX00KIfGXU\n" +
- "nNpo0l3d4M8DsX7UZeS+ZhE51cjKDouJ9OGrGDDXf5+5z949rTES7mz/6obe05E6\n" +
- "Qkpcca34HixK+3kpKXRu/UoPMvn4zkU5dvelA63VyigSF2k3K5mie2LXabnPL7Sz\n" +
- "w7GeQdkmI7gqnj1rpp3RWdPI4+bcgwkvGedHbmy0Ue3jE/aZdooB1R3MY5DaNABn\n" +
- "gZhMNdPDp6NJm8zYgXjaqOXwzAmcnJfvu647RZA6cXvLisVcq7iYYDqs2FeN+w63\n" +
- "FA/C1OGf0fII1BaBPr6hrTZvAtq+ejNY9F3Wh8L3gmeNhLYtNCTz7AAF4HuAWlIi\n" +
- "yKoI1wCEEKKB4yQm73LWo9xDYCxtPXyX0PAfod3/GRK1I+rhJuFkqp7b0ztbY3mm\n" +
- "H3aiNp6NcBH/OZs8C9MEpESdysxPrsPbWD4o3nLB9zFg8dPlLo2fi1XrFngCybS6\n" +
- "66YzB9q+2qhBQpCuYRYGbAWF9xNid5NsS5G7RFM7AdbVN/2xcNnX5MihO5jY2KhP\n" +
- "hB6+Ai6tuH9uqvQteg9s8VpWpa1OXf4I8aX5Mc1qDvjnwX18Ke42vrW4i3lSLlHO\n" +
- "km8UlY8DcLmwgvLFP1ajiDLZcFVflPz4KbbbYd0fafxxLXY8c2IjLd5gGk2rT0Uk\n" +
- "Fjv5ev4MJ7wRo9lTCYvc19nYLxzbm6I0GY2W2E4gkZwze2YPPieNF5rRvXpLcwXg\n" +
- "rZjZnjU4D+RYv8wO41LIto/ovJ4oBrfGatkqNRIdk6BgYfUoA5ZHVLvKCPnqDKgn\n" +
- "eH26bczbc7KGCsQl1x6Y353ginfVvE+tKxEExZGmvqN8jV6qylRbyr8O2KjnP1QS\n" +
- "aFlf+4tmXDUbsItK0uSKa5EOOdivrmC+/I9n2oe2Y0Tyzkf40i3nJ1UiJMW2Q+wl\n" +
- "78E1ZligIdqCrMABEiBbUYCsXvlWNG4ZvpWcbbb5K2kinq4LnRYJ9lCnyWPuL9wQ\n" +
- "mXFET0fZt2D/derdnwEht6+t7mPAjYlEM+DDfjLUSKjXJ2eRPR7Ck3T/mJvbBAtl\n" +
- "U3Ew9zOa824p1yH3nxsh7kwR8BwckyQPXv+9iadp2bz8NOW29BqNXMit6FUhveZ2\n" +
- "jt7rG3SHnp3XwXCYTdpYLwVTBOlidvUf6tw1xJtRopb0bbQLkyGjxNr28DMqTkHY\n" +
- "1OlFoDqdUuTbdYRdITHtrkC1SJUTEVxLPdewELkUSztp/7lUVpzHPwt8/H0bS2zc\n" +
- "qVmLp5VGPlhqP7V5Dq1ZHs8QVz6NLoD+deUCW02YQvH9EVv46kr0XUrLnALagJ0N\n" +
- "drbH2johlEiKS9URxGSIjMd0WITyZjH9kWspM8RSSB/msG+zhRndl3wX8rZTU5mq\n" +
- "aXSyCETWEIkZ3c3UoyycUkjdOMaV9mDSvItQfBIdweARXhAzKVYqOtzB/bA8qZ/+\n" +
- "mefACQ2ijLW0z2Z7GEOeAdRQraht9Y02FWQvtOH0EDv88QbBC6GCch+2n64NZKlx\n" +
- "5aDTbdpHopLzOgoR84/mkx3MzWwjMpnZlwlojoDKjjqJgtO7sKObHaaSzNCJoZbN\n" +
- "KlwE6kDgaZqc9tMnzwSj4KnflBk+3xUE5ynqYbenWQkJuplZVlPR9IuSY9mqoxuJ\n" +
- "pFK6xzPRXHzRRK69NhC+6B3LMPmVwC1dU6ZhN6g9QLaG4UwrXJf6vL56mywzK26+\n" +
- "g5bTScFzUrRQamaYIvosGe9+tQoU7z6BXjviao9hqhghkRey9AlRUtlL6MwvHykY\n" +
- "AyY9v5QK67UJHWgal1K3ufRcobVd2Mif9+fkUOmHKQml40kWdFP2HJZ7Jo3Jmamv\n" +
- "eThJLjAjYlqVgGqd0Enz2M5LFcaBUvZO/OnYwr+kbTS6D/9Nk3J56358/NIYAhRI\n" +
- "W2R6fr3FxuHj7RUiUXicocHF6+zy8xETFTlZcHSVore61ufxDSM0N0FTaWyEs7X/\n" +
- "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANGSczA0gAMEUCIExm7eRgVYXh\n" +
- "TLJ0IPHKXNO4oahKkgJPAgDHaMlo6f+fAiEAvW2RaHsZK9g26XWGxaIQvdj2jO1r\n" +
- "yIoOD/jVCpxqxEE=\n" +
- "-----END CERTIFICATE-----";
-
private void checkParseAndVerifyCompositeCertificate()
{
try
{
- PEMParser pemParser = new PEMParser(new StringReader(compositeSelfSignedCertificate));
+ //compositeCertificateExampleRFC.pem contains the sample certificate from https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
+ PEMParser pemParser = new PEMParser(new InputStreamReader(this.getClass().getResourceAsStream("compositeCertificateExampleRFC.pem")));
X509CertificateHolder certificateHolder = (X509CertificateHolder) pemParser.readObject();
JcaX509CertificateConverter x509Converter = new JcaX509CertificateConverter().setProvider("BC");
X509Certificate certificate = x509Converter.getCertificate(certificateHolder);
- isEquals(certificate.getSigAlgOID(), "2.16.840.1.114027.80.8.1.4"); //id-MLDSA44-ECDSA-P256-SHA256
+ isEquals(certificate.getSigAlgOID(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.toString());
CompositePublicKey compositePublicKey = (CompositePublicKey) certificate.getPublicKey();
diff --git a/pkix/src/test/resources/org/bouncycastle/cert/test/compositeCertificateExampleRFC.pem b/pkix/src/test/resources/org/bouncycastle/cert/test/compositeCertificateExampleRFC.pem
new file mode 100644
index 0000000000..dcabdc5733
--- /dev/null
+++ b/pkix/src/test/resources/org/bouncycastle/cert/test/compositeCertificateExampleRFC.pem
@@ -0,0 +1,88 @@
+-----BEGIN CERTIFICATE-----
+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
+F2ljUsBn8vo47P9JvA==
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/pkix/src/test/resources/org/bouncycastle/cert/test/compositePrivateKeyExample.pem b/pkix/src/test/resources/org/bouncycastle/cert/test/compositePrivateKeyExample.pem
new file mode 100644
index 0000000000..49de731723
--- /dev/null
+++ b/pkix/src/test/resources/org/bouncycastle/cert/test/compositePrivateKeyExample.pem
@@ -0,0 +1,88 @@
+-----BEGIN PRIVATE KEY-----
+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
+l6+7Vd1+Zw==
+-----END PRIVATE KEY-----
diff --git a/pkix/src/test/resources/org/bouncycastle/cert/test/compositePublicKeyExampleRFC.pem b/pkix/src/test/resources/org/bouncycastle/cert/test/compositePublicKeyExampleRFC.pem
new file mode 100644
index 0000000000..a68694ea77
--- /dev/null
+++ b/pkix/src/test/resources/org/bouncycastle/cert/test/compositePublicKeyExampleRFC.pem
@@ -0,0 +1,32 @@
+-----BEGIN PUBLIC KEY-----
+MIIFgTANBgtghkgBhvprUAgBBAOCBW4AMIIFaQOCBSEAJaSzbEOXCT27FgXshv87
+2HLTgePmYCJCH2OVUi/PB9YTyBXXnw+smoXT4w0pcq3WPs7qQXz6GKj7R0mFfTjp
+Rd6uH3hgdS5cbg+PwMWsRKigE6mWFpMwrliS8CfR2yYgjhRav7wGa4ja7RdmZoLz
+T8UBN2Yg6P/KceWA1gX6rdVUalrUvmcfR64ry06IfotXXNFwQc3vI6s7khHSUZX5
+Rsw55RK3E0ElNpZxfFHv17d2xwFkGRAYqJao+qo37WtfG6Ynx4cqQyLJzlRn++5R
+G6K1nCwqhErpk4vDR2uHIwAPiW0StX9ZbBjO2smRTIuWS2WhmhZwJkDqSHmCiRI2
+tPsxCtLpM8t2IhTVy/ObAdQGPDngTNIPH8kuoRrBhWGIiWJMlo8LkImCRt5m/8Di
+aL8C2BQNL+BWBBcak/JZrLkKZOZM7pFwWruHVEd0608XerfiVO3ypqAxImJ2xcdD
+kLys4jDlEMsC3oz4RQGXahj2Pr8Jxu8i0TIDDdV5MZw9wId/m+0/vSD8BOAu09Wu
+V6ppUWkDZLHlzf12zx3ZzBF/CMqZNsxMdTFNbu2qQ2/CZMlEvZ9f0gxn6qNf8NHC
+UqdeRr7p9z8PuGHErLHqCvQMrzia71cD4URV//SR8EUQkoo9imtw3XT2uKGUIjT/
+dDyqWl8BlAZ64dUp9EWmHwG1cyKBcu2dtD0d4BMol1g4TOF7u/3hHcgOoiR+ON/3
+7MoxkX9mHt6tP7hkVWy0Mb3Sjej12DG75D9z8gAzHyQhOs3suNliCzCUmUVYm5Mv
+WdySiuShm6yu+9Ah+GqvESuNr/h6s1gZGbdCe9llGdFPniilhL5J9oDgYMp+wi2I
+EeOugOFoaY1e2OI1OPjBpg1071ko9B3CGD+0PkPvKYmMGs0HTnzFWCLPj5dG2kg7
+PEltarKvLVTIxrbjw03l3SXmqpNPU8SqFJ7hB3OpFJgjqL95IRTa68UM8aaUKLMa
+Qjjx08+e13P3wwY3niCR5U751fus4ArGLN2JgfPB7bPSdz043PIvxsCYZxUQXSW3
+xWhWQqaHJLml19obvnf/tEXQZLheAr7hOEb/UTNUIBj/A6LfB0Gs012B1aXfne4W
+9K/OFXc9p0C7aWIfjfMrA/idOrd1Eoo2NGLid+wp8aXyDZkCf5OUretEFHqQcQ2J
+znh8R4mh2Tf7hT8+Gj5Su6bZggHi9iIJZ1G7i0j4Wm3g6DJAXF6KbChMayKRunDp
+k6Nm5iOeTmT+Vi4OJncuI6HezZMzO2s+2iY33uDL7tFR8fVn7dQiF78c1aNhWjfm
+fIsLNQdZxt6orvnwSrZpdVhOtAu+vYVaEAShdHgfzvPSDHIjgyxs6mGdk0uDsGpP
+f5d3e9KV40rXir2OXaYMOq2KTkLb6KHHxZayLG0D9/qSBOnSE/aXNhh1cHtKeYAe
+jjXmfzsmgNELPNxFRrx8pEHG1Se0GJNJVZE9u6B2r9f09TgTxgPX/6XpBNUrlz21
+fsIvNpRL48cwLHOCgYP/SAgE3gzRC6G5NEE19wQZHsFNGeUeGvrvUQgTyT1YwLx+
+Abvp57bVjgLWli185/K1a8BmJ204RHfDhSFe7sVAIoI2pUcz7ydb178DCAvupP20
+CxUIkgOk3C+cgUzTwsFU4iiix282ZBa8/nTUnH9r3IDJQJwdWtMCnByCc43UeVSh
+WV3isRF+ANl6lSevNj0uzGE07a5gPahctBWMmevh6qFcv5XucwNRe7en96o7CgK+
+5QNCAAReie6V/SXhsV0+AAEPt/7UjJqzbrZU1ZHKBLCDbX1cv1Zkpy+SabE2Pfpd
+K7SzfBpZw0txE+bjIUT4j3zjgIDa
+-----END PUBLIC KEY-----
\ No newline at end of file
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
index d90bd003e0..054ebb6fe0 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
@@ -122,7 +122,7 @@ public String getFormat()
/**
* Returns the encoding of the composite private key.
- * It is compliant with https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-10.html#name-compositesignatureprivateke
+ * It is compliant with https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html#name-compositesignatureprivateke
* as each component is encoded as a PrivateKeyInfo (older name for OneAsymmetricKey).
*
* @return
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
index fef9dd85fd..82e34dd169 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
@@ -125,7 +125,7 @@ public String getFormat()
* Returns the composite public key encoded as a SubjectPublicKeyInfo.
* If the composite public key is legacy (MiscObjectIdentifiers.id_composite_key),
* it each component public key is wrapped in its own SubjectPublicKeyInfo.
- * Other composite public keys are encoded according to https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-10.html#name-compositesignaturepublickey
+ * Other composite public keys are encoded according to https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html#name-compositesignaturepublickey
* where each component public key is a BIT STRING which contains the result of calling
* getEncoded() for each component public key.
*
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java
index 3d85032ad1..00563d06f1 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java
@@ -9,6 +9,9 @@
import java.util.HashMap;
import java.util.Map;
+/**
+ * Experimental implementation of composite signatures according to https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.
+ */
public class CompositeSignatures
{
private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".compositesignatures.";
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java
index 56098b76d3..78a9a88db8 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java
@@ -77,7 +77,7 @@ else if (key instanceof PublicKey)
/**
* Creates a CompositePrivateKey from its PrivateKeyInfo encoded form.
- * It is compliant with https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-10.html where
+ * It is compliant with https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html where
* CompositeSignaturePrivateKey is a sequence of two OneAsymmetricKey which a newer name for PrivateKeyInfo.
*
* @param keyInfo PrivateKeyInfo containing a sequence of PrivateKeyInfos corresponding to each component.
@@ -110,7 +110,7 @@ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo) throws IOException
/**
* Creates a CompositePublicKey from its SubjectPublicKeyInfo encoded form.
- * It is compliant with https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-10.html where
+ * It is compliant with https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html where
* CompositeSignaturePublicKey is a sequence of two BIT STRINGs which contain the encoded component public keys.
* In BC implementation - CompositePublicKey is encoded into a BIT STRING in the form of SubjectPublicKeyInfo.
*
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
index 8650d93408..b9aa0fce1f 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
@@ -45,7 +45,7 @@ public class KeyPairGeneratorSpi extends java.security.KeyPairGeneratorSpi
/**
* Creates a list of KeyPairGenerators based on the selected composite algorithm (algorithmIdentifier).
- * Each component generator is initialized with parameters according to the specification https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-10.html.
+ * Each component generator is initialized with parameters according to the specification https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html.
* Called after initialize() method or right before keypair generation in case initialize() was not called by the user.
*/
private void initializeParameters()
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
index ddc1b83e22..fbdf8d4b3d 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
@@ -39,7 +39,7 @@ public class SignatureSpi extends java.security.SignatureSpi
private final List componentSignatures;
//Hash function that is used to pre-hash the input message before it is fed into the component Signature.
- //Each composite signature has a specific hash function https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-10.html
+ //Each composite signature has a specific hash function https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
private final Digest digest;
private byte[] OIDBytes;
@@ -114,7 +114,7 @@ public class SignatureSpi extends java.security.SignatureSpi
}
//get bytes of composite signature algorithm OID in DER
- //these bytes are used a prefix to the message digest https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-11.html#name-composite-sign
+ //these bytes are used a prefix to the message digest https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html#name-composite-sign
OIDBytes = this.algorithmIdentifierASN1.getEncoded(ASN1Encoding.DER);
}
catch (NoSuchAlgorithmException | NoSuchProviderException | IOException e)
@@ -180,7 +180,7 @@ protected void engineUpdate(byte[] bytes, int off, int len) throws SignatureExce
/**
* Method which calculates each component signature and constructs a composite signature
- * which is a sequence of BIT STRINGs https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-10.html#name-compositesignaturevalue
+ * which is a sequence of BIT STRINGs https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html#name-compositesignaturevalue
*
* @return composite signature bytes
* @throws SignatureException
diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java
index 0c394de669..084c06f714 100644
--- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java
+++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java
@@ -32,6 +32,7 @@ public class CompositeSignaturesTest extends TestCase {
"2.16.840.1.114027.80.8.1.11", //id-MLDSA87-ECDSA-P384-SHA512
"2.16.840.1.114027.80.8.1.12", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512
"2.16.840.1.114027.80.8.1.13", //id-MLDSA87-Ed448-SHA512
+ // Falcon composites below were excluded from the draft. See MiscObjectIdentifiers for details.
"2.16.840.1.114027.80.8.1.14", //id-Falcon512-ECDSA-P256-SHA256
"2.16.840.1.114027.80.8.1.15", //id-Falcon512-ECDSA-brainpoolP256r1-SHA256
"2.16.840.1.114027.80.8.1.16", //id-Falcon512-Ed25519-SHA512
diff --git a/prov/src/test/resources/org/bouncycastle/jcajce/provider/test/compositeSignatures.sample b/prov/src/test/resources/org/bouncycastle/jcajce/provider/test/compositeSignatures.sample
index 1bc7365e51..75507a0544 100644
--- a/prov/src/test/resources/org/bouncycastle/jcajce/provider/test/compositeSignatures.sample
+++ b/prov/src/test/resources/org/bouncycastle/jcajce/provider/test/compositeSignatures.sample
@@ -1,16 +1,16 @@
-2.16.840.1.114027.80.8.1.1;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.2;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.3;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;MIIFYDANBgtghkgBhvprUAgBAwOCBU0AMIIFSAOCBSEAyESPVb0FU/bVHWWehKpIt+AJeobWwZDw+m1B5E6hTIBimkvGlb2ljEr/4F0pCYwkTfMqqRbiSwxRiVZRodVJqjF15faLgZaKXfQuu7g2Fy3yDddhNW5zhklBId8yCIrYgmicSNnzU8zs/fxGcIW6USciYBYbUhmrc9B835Z7RFjveGrlAXtccqpLyB59BLYGXi9edtFiuLXS5/nER/Wec5+FF/Jojh/SzBsi3FccFQDbnWH8A0bVwJ1eNoLGiGhRYKjrKFawIIefamvuf+vgTBT7DO82DwMp6T/iaEorCeRwKqJSL4JiJnky1+XwW7GUqO4bc9au3GPW0rwWQc0b2+dSjdJEJxmxWBJlDTIY/YftMPLghvklXB2G/CF1cQddm3ZrnprAIJ5tFTDijWP7atL8vSEna8RcpbF6F2z8iivC9wWoBDrlNAZUvxeVVmaR/gYXvROnLclnAAawGzvji9u5YgHVdvD4w85PK7HTAReBCXnvc+8SZIkJErOJOUANoxmF5yboucwZrk8ejNRkFlsxSAw+OS4xoFXOFE28UYc0MoZ526jAyaImFCOsgEY15n4+ohQpg7sE0gF3GaUT9h8kOJNxUnuWqoWV/Ym9MIwW2Uf/XltVveJ7mrHbL1+aUqqe+lTuUGXJq0E1AYnvDipt+2zd/76lUh4EawK1gw6/TyWm1mrMiXOxPx9ZMSBcqnIWEaJSajcxqGKIbg5HkpFMTHxfeCOQ6TMvQ5kpDZhZR4iPTMGApmo41ir2nIooBmuRYK26lSNiK3doigX/+IOBe3Cz9AqQtUaIvqjxfMen+y2S/4grst35tsk9INg7DgYUub/AjnjqEzOQBEcYw2INSrBclj6261HmTU1FwJ9hS+M3uxt8tsWhNia/h8PRJi8OqyL2qkvpbLYnaVzOkqyXgnv5NDvpVS8VKMJ2BmSLezukAbVMWbGtGFRqT+jFj9UXuhzqL3uAfasigzuguZt4MdX5VamWPNimJjnOm8zHlXw7gk5r8hhnny0Ejo8s5d2gDX3XXSv7iGV1kZHU6WGhD/OUZzqV9GuXc5/X3ggLbinf0oQ4rKzUkpQ1p451H2bK5vM/sOH0GLyvO87jQA29p9YMtiWx/rHgdbua1oACOa84cvZ5MD/duHl2j4la3bst6kghEAZC+bmfiUJet5+r4ihT4koJDzFNqOCSZYK89BUXv4J2UDw+xZVpmm4MsRkpbfiqyqNNkZ1YzRW45EUvb+QdopYEP6SNkf9Oas00G799eN+ahDs+QmOJ1J5+8MaS0a5RFvXi/nt4id39r5jEdEpa3z2vzpmXH5Od7yrS5KALXqmbf5//SvW44OlaPLIJnUWJ/U7BLP3oT4xmYCsQsg4oayfp8OYfrm+t4LuHrt46flq6O6o0Fh62nY38+lfFk20AflhztarSy4KKMTnTTfcQ5pAKnRKAbkb7cEfk51qG4pEBdetqsOnSFjeL/fVPd5WpWGwEfywFQtdF6pwfP9YJ+Y9p5MCE5c2xiKfEM3NAmdgU+0cDhvCH6HL1SF7AXS4dwX035QqiQo0FjqE7NWqDab5TznbSSb3SSLL3RbVx8/UQRdsHGC5yMApRfqKjLLpnpSKCfQI93YW3APLYDHyJ79tvbEbWsXcTN/hZd5ruZEckQUYyLRqPdnsMr1B7w5GcLg+pgQAeCVQES9EbHnlW+sxDsk6DTq5QBFhXQSpLZmi0J3bT3Vq6RuUywTm7rRN7zgJjOKqRfGR+yQMhAPOzCA4bqYj2noA65lVZ0tZ8FA2G0TFPfz0nGTkbw4Wx;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.4;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;MIIFgTANBgtghkgBhvprUAgBBAOCBW4AMIIFaQOCBSEAU8Y3PnGCbpTRsNHyRb/vepHuxJnNc1zGQfdND0pKCLsh2WhsAWaFerGp7nUsycYbeUMbzaj9+hMj47uftHRdfjLN+72Dgr/Lt49nNPj+QiaIdZuNS8s6IfssXuknsTIToiZk3IhBAOUjTmC1up4xz1tlRxohJCR7ZOIAxFeJM1Ml/jxH5Yg8kAtOIykgY95PD4u1Cq/W5cXMu7vdKdoVn38qzrBQr7vrzb88VqNG81U/J2VANHT8FDxbnt7J1OfpfLV34Hh3nYsN61egep296izot+5im9SvJbkzGByYIpxCEE2pmJKtZjJn9uonOXunNLvFKwXy18dhO1Mpk2VarQn6ZWwjJ36hrgmtpmz2gIBrSsqVfviU5DtEE6ZWMkecpi3zl9NmH9eyq+dCsyf/tDA1C+niD/XxGeLzitH/UjKqD7hYhBJgYKa6GjcQIuV6dimJXuXfkfhIxzGny7Y8fRLFJ13ElElqeDIpODXImU7Q+wQUuya+nFUamP43onmiitC2OBUYflK9S4ggTP/APvWEvPcIidrPMSNYEQAnRDCCGb0OO0AVVVpEWc9c8rQq31xFJVglem3ueOHcTp3ofvwx9g3+va4EGCauCi2azkrP9zseNS3Tl31Fc6U3hgPe6+azVjT/yiyzNcles4TPH5RV0aCnK4ry1iDdPVslSJ3IO8/aSk2mJZEKP8wuX55Ww36m/oOfaLVxAo83WrJoHq0bEcD9CTLPD0kWRzDpBaVTwTO58xhMtajgQvjMa5khHCu7apVd4sYCl4S1QuPjCO/y3Q1j/gvn5xx8aGF9z8yHsv3yROTam7h2CbB6BpM7CR7VQZISk3GBU/i9F2Wpg/zRxM74CPM375HjxU/LbNTOoQZjYGOnJHEXMzrbJjTZ6ZoeYQAV1y64pwUKEFkgGsowko903NuAovLrBvo7bjs1hKWiIrmMrKGHNM7RUFubyIhanRQiudEuJ4Kqi+B/nYQwlnd7mdHwkp+Zd3x3DGsEfy7a2o5oe2Mi8xjrCo8u2103OeHulAFtCW8+190u8VS1BHvDj9dQ4t5V+miuRZYl2RGhGIZHAnonj+q6P6zg2t/wGpqtob7YZLOmj7bGoocc0OBWsUn0dwp26i339HoPIWVM4rronKCNqS1DoceS+22MIIESf8kksmhcPzwyMSk/OW8YaFHJzd6bTUcz3SXY3ohKe9s2hp4dCl/sXNcOiT8FuU4m4N5yEMEyh3pcqaxINy125KIoHaCiOGbzP1XGu2z/eqCgkRQuRqMmkyYviOtSGepojhMnd3ster3cTgzYbJ1F0t1/RKx1QdTd5o0pSTg15JDYtPfox6Qhz9mOGupjd839n4GSPQhuU/BYtzhCLKCu5EoryFGPXurzJnvcBnsJuC1JK4VVY8bd0/evpjyJcZ1Kvwwyx7ZFoq/LwSE2EhCcK1n6T/hHpaL2QgFPVNbVaUUTEyhyM3JMXjxzsZ+Jg0Qrgc/3eZch24CzJcy8CEqtLNBZSJ8tvC3BJzNeqLdTP6Ppzr4p+p6ACNKTXb4UmPt9224mDSKN1qe+Pi3kR+q/PjLZfUGFRcG/zp7rjkRuM2ap18J4PlekBJ7NHknaZORyQOsYTSE2yxDTYW9nwBwCxgxVu+HEqy+XONGJe71HMVh0VqsGjJ/KEU7RjgS2I3DMkEjtb3fALn9O63WbLIqqQWP5aSrqhzW5zfg4nl7+mnKMOoGKRU48B8obeoPVvTjcMd2g6efuBdtGrANCAAQrbuIby+s5BXEQSn7cQ9ES3gOyiUWbSNbbWjzBJde54IQwGcLV2p11frKOYLvd1qnLhpfPglgaZ8Q2sZq6Raon;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.5;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;MIIFgTANBgtghkgBhvprUAgBBQOCBW4AMIIFaQOCBSEAGdF+ts5X/FtbP5OZo0DzYiebnmqF5TJ3gYgBfAWIJz3FQi4I/I2JlHDAnzHO4gMYnA4tMLEj9xmRuaKYpXqBLe94PIgVtnJnctbQj/dCZyfKOsWzEfbdyVrBn1RQJjaGG1XCFeBvjmE6DtDp8VOS5qR23n7eY1nlP7+3Rj+ynsIE/Tdltq7+b/1prxpVNGI6DwbZB/FUOyEJK97xCBL7yHJn6MQycowzsV6Bmsv5PHMmHtyhNe77t+Ddk25Bk+p4JuUU1QnNFSQL5f6QGgz1eggoYvJ9hwF7Bqqmvm19T5qyspEQV9kPjDih+//JLXlTKbS820u/DEQgarIYVJOV3Q/HxaIAF+toAjTTyJRQzRQunNAPTXAG+YhCV4R93bQM2bJg8fLa8EPXbHrzBQWQsIS72QUl06rWG18BfWXCG34LKFzeQt4QOEG0eu5/YpYuidwZ6OFgLwJ9SMkjYcq51523X0dmNwH4DiVheHNmUj06t36/Lsylv/IbBroaHJOizZ8Hcfgy5KDvXJHbTh1UQZS8hZy3bziG+sIY/YYCRefLrJDSsdVlch5bxCYruPom6kZDO1nbFoT6tq7kdmohcwYihq4pm5gA62EA7wJxFWs4fNP27fYWiODWVxtzy4T1IfkPBIOosIQa3XHusGUq0lIIJRqUiG+7zQL9TffWmXfLaBr4VQT2hy1A4xHuYhqhMr/NSEjeTqEJ14uq+ukH5kZfBB+qc/aDEhDocnz8E7mWCCvr5c3TMaDvnxZxk9RUNpd808Q/DEbIg5p7Cww2DMUBXjibX1wul00ULGkRz+BKAZ6qctNF4LRcLqXKjWSYVAlf09aAdMoLwhqJZPZJsD28/Emyi0c7FkDkECLJ0UsUz2DvRdNHirqRzNLCED8g6CMBGUXNI3NG8SluS5SWbCd8sN2wwpFZzfvrVo9301TItFzShUc8nBHiwwrdDlPyqGgg6PoAQFIVd42dvmrUPbANT0N7h8TjK1ILUlW7frCdeEuUK0h1Uu88WUrpvLOqbXiA43FszSWNZjbyjS5cd2vVFRqJmcy66aUcoe2dMGvYhZv0Mpldfavs9h/j0lqkVGAA9V8R35MrPvX6SoRdBJgEZAYXd4TxtI/wbWNa9bLAMqUKCzzReJGsfvw8Qk01RQmGBWLxBqfHkgdiQRf3py+yjLaDz+uRJEkltDtduIBp825otGNOJuzgqXuBGirYZ63YIDuiNTCd2H0cNjZgDLQE0dN6NtohR9L/07jSDuaFekITp1rSMLM6EWPLM87yc23utwgYHFvGx/xc2ABMKi16ht9zK2+5e+6c1EvC9X/whvNEAt0q6NGWQodvlhBVaLcn+e2cZm6doNT1Xd/SA5HVk2wUx1GyaLbx7+PhZmbVwYruoUfqCQHotR3zR64KP68b25l6PMo60v5111RvHhuLK5TgAs9VcDpmlC4bDs3jwxIK0855iMgg9JliyuQh63QGsCeeZZSBaBDRZnSriZUZffySzcYOxPVj0oV1bgYFGTrsav2iDrgUeBqGuBCvujMXk0BOzxtzkXxR5+8uGHcSV9tPiGXZ9QErcvrz+QmA9x8ZoI9LZiQ/cVlvCQT9uBSepmm4wNGQ1SBDAHLd98jblXEpsCLpbXe0P1lIS+aioTyBVtWCoRf316lSeIQUZl6C5+weDjThpYD57V/WQpYwcC3tbmcyhVX1b3BIRlxE7p5GdB9q28V5y38DAhQfkWu93UVAq6UcGCBk+PoD3wNCAASoGMnHHUjXK6E2cMwYwLRSFbHJD0Ld1z0qTJUnxGugT4qDLOOK89Kv+lQZj8TtvHLsK22dBgezoP7r4d9KESJ3;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.6;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.7;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.8;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.9;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.10;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.11;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.12;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.13;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.14;MIIC4gOCApMAOV/sx4VuI2pdmYS6AAzMT6hnT/7GDnob6HzmrVl2HXDvjCHJiFE6as5ly1fpgkLd2+YqLC9JUYWlzJlNxixceGNC1Z6OhGsYYij7Vk5ah+ciVterQzV9twUvWKz7MDb7hlsAcWfftXEt8BCWMp6nrux1ncif4x9mY2c3q1uhztxVTny91nklbwLJEAdGTJKNg3lD6Wt2PjN1cFnR9wIxNWoYos0WQhDMavSy7KYJeQFtVeV1nXJQ1Np2kNNoVvy7bXaGULY1ZjrtNjp3SRLnMt9jfo5/mYwWkmBi6ZK6inGW4jJ7YdOHGEGJwZfskj7lXiSRtJEzSbhsNWk/rnKi/DNEvzCuNAZ5joSHLJYhh9yTZH8Xbjdts1GZxZEP7DIDmM0gYgk4SXTNfPdNe+xjPvPXxWJNlNdCi9RsoU77yynAOYR7hYJL1AQ1CjLcLNKggzYZSf5T1qSVCyVoeigrHiGcLagTobNGmRyqOLtVNGJ4qOwS9Ltg1yKcsue2cVkt+klQ+iFFmSVLGM5GVJ5JmI/yW9Ey7vxO9yuOGHRr3Rpc4PL7kcWPF1yaVdhdub+0rWJn8AShAGPdVHPs7kfsGK2rn5Bf4UumGoL3RY2p7ctJx4YySCSoGz7LIsj2ysow93Rd03HVFzIQ++luszczVGDN9Lstntlmfoh6yex/kaZ5oeGUulW0/G9gim8vK658jUUT4teexRT1MNBXjwxGIn5Mi220vt1eLPoKe/TV/rIrWEym1H3esuNmwqHvPBSicpUYRcCTZPPsSWG3kPoTn4B6cbQYqq2xLQte68PPNBMCLtrrC+2/Jpwmcen7yT/8n2ZthLfID3wXh7pEGGdGPSSEN5pEycuzaHsskc3XY912cgNJADBGAiEAvyY/vhqhrNJKdfn2YOmWKDjyyXhSlo3Yb24xdYh6lJsCIQCNKxnjfEsuO8tiXLGkFab7X0f7k3tnMLSN7x+ZQNQuSg==;MIID4jANBgtghkgBhvprUAgBDgOCA88AMIIDygOCA4IACZ6mzub3HA82yGep6sHXE2Rc4ewuxmcdALSwZTKGWZwkP5dHS5wFSyDhR7SYFtJyG0uffoznVw5mWhHoU2ac+4INdyuRZra99m6F74gMdLW/uFeQTi4se5J5QutOpTuCjx+7Nrn3l6Iauym2ijWnmuK1XX0QvC84NDKLhESgCU+oNcPRQtJ81NhE4BEQB7V90IeMOrfaDFB55c2MusUgbA5cCn4Ix0WGUSlChtbi05doJUyUT63dLFAygi1fvmDdEukwxx8bwdcy2ccybPUqwGRWBZvFqxPEbmBzUn+08m5Ki9KWgZQr0GwaeLkQKgxpptq6gNcfbF4OIn6XW6YMgJKsRpyJ6RuBsIJ9rrXQqzjt3TPhomOZFGV2hSvCfNxTtwTex/WdQV0KsSQuJyO9/bbrZE1chnptWiGDfDatuvVPAFx47T2J/FDKg6wtk3OGZ4zBxQcOyV0BaFvjzOa+Tw3WRQiXYZV6yIjAjSiHZpyksO9aokrCx+9sKXjuBiZ1qZd35Innj5Scaajm8fjMqIOmrNp9mPodsJNn7IB/Jcrtm1gozBxNReTvn4QD5JN67Y6kre4UKVuRrba6HvpQhm+/lsCWsxWQPUH0e+2RbXOds2t4gwE/JDqRQp5HWuHe0kFNjK9oQIKIy7gXBXDz/in3jvpVZpcTw2eMeNFXlAhckBfSoixAeQDhytrDZTzKMPSrhsgj/v52CVHBXoG86yCQzBU6nznc30YE8WNbDG17tqpvJppcWYqsk1s2QRwEvl7VWgwdtvkdyN4U6ld8karWGOw0qhu0mkJGm2Y5Ftyi24U4+9c0LyG96LIBhUCMCOFaMv1RFXz0V7bKLB9YjkZY61ivLnS0lwimOE9iSEUV6mJ1QEcb9cM0aZ4WcjyA/CNSX2mkLsFbyulmNmnBs/lhIqEIAI+QxWqSnG0tlmJgxSOws5lyQ5wemS4Vx5N4mcpBsXthHtYAOXgwUTGm565y11VYkAgsRG0pkFnQUjAv4+gFGEyKo9W/rKZv0Ok32cXyeUohJqhETSfUb7qQzqccni/XOaCjvHh6B0DXUFrQTXNALQuSxXPo4KG7LczYkOsfPCBZOHe4S9KIlrw7PIPrhXKBhe3v36hMUNAFUNgOqDuEIcN/oT2TajpRICCmVCa5WqA0dJG0fekvsQnfA/yKA10OuyhpUmeL1aRiUINlA0IABInqYBEg+iYFVeTT21g4qmllXON+VhF1WJw49IDIKQoS4kBn0tvfP1wg7s0c1v7NQc4vFYMxgZPQBtHUGjWjRdE=;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.15;MIIC3AOCAo8AOUkWu2SIWEtDRM6cFQ+30XXy8ySg8BmAMnIevw2q53Rip+R95Wp5n96dRNg9vBGSgZvpC93h5+NXCgagXeN77t1hDGIrxh2NW+JNwptC2qkf4jO3geTezfIuxUswQzDCSuDKYhre8hFmnbnowp1pt0p/UEzRtm52sySENh+sTaj1ZVF+b3vUKFS/zuFeaZg1D8yJww72Kdr5q5XXKgmwcWZ9Ywcny6QlBjt3sXLaGOIU7tNUu7ziy0OR0+YOvSHcZSbwto7a1BH7X9d3GBbbDkTDSTbbRQq/sLA2UNCeTC5VqPWCEkIozo6jNRZE5qO/q55UYVpdIjsxZoh3WTbt+Tf9FE6+N+nZACl6DIebRW0s7LzpbWAM5dXQoRx8vjmbvC4pf19vY7VRGvMGnsJ1dPtSBqz02HRpQIDN2qZThGCT7HI432QyaWwDHOpb49b4BKmkkEUZMTlySXzxia4s+OfxX8korOTwh5GpCZPh9XoMPokPNEhvr0/qWmRSj/aXDtHQP6py5Mlr5lifbRTcYOQyTo+lDtZGpe+Wn1PCrHJQhipaoMnT7JTLyx9p9pY2AU9Uuskvwa2IqbaCVHp2ZrChQG93XR9puWddJYMStbNsijzKc9m8oaa0aji9NI5xcuDLbzZ1wx9A4jjMyziMHCJ/k0RYYTVuopLLvaT2SI53zksyIsTSesCgfTWE6rEGopdJhiV0a+NOYERVZ6zXZfE7Tn53pHl+/oWBVv9Bcmzia2Cl+aKs65XsJ6nK7KwyG/p5wWIcmt4KcwmwtNCV7Q5dUAYSw1exlic7rzp4ozuli+8VZ5QO5VNfJ0kMVAjHEMoCJ0OxMUZVMcGnSCDWdjFQk0cVvW602dF0TRoSA0cAMEQCID32qNm4OXz4vFlISEFbW9rXocFNYJoTa1a32UZRIHqEAiBuLzkylobN06TuoKoDTGgS9yAV6BQcmHj/n2m0cI3BRg==;MIID4jANBgtghkgBhvprUAgBDwOCA88AMIIDygOCA4IACS9BQAlflXFwhSZ2mxhVm00ziP4rn7CFj3ZSmLlXJRgK89QUJK18Y4oJbrOEsFhoTMO+rtsGStaTIvTq5I3fyDLRhHALm4JxcXl2fSlxu1GzSKzlgQCQxxYKI+qCkYyyN1AKmOCqJ82QQ6627TfKjWtr2BYE7QxLfzkbCBTq1yLN7Mj9k6pQXDv1gO/zSIgy6gyeC2N8p7g+SDgrbIbZwS6ojEBv9mgLyaiRWscLpquzbl6mUZVblhwTdyGDprY9qfGfofkumSllBo0mMd2+2hfFKXKSZElzSdhspEioPqssiMAkV89U0zziL5EZji+kGQJxutxVPtg3hL9bcjcOAGlRoQGRLtIDOCZyGGqid8rlTj+ZPHMfk9WurhxQCYmyYWRTBgQPUDcwfzbSBgQ76O6UCB92II2oJWLPi7YcW3SPplti2qlHaEHlX1WSd+VHzabFQhe+AOxRLtJUluF7N7GZyHqnA1ouSGUmhXK76uDE92TLvk50twuBHXMhQWp0UdQc8SnxhcCzOSp/BxSAT0KMdLNxZ3AtQoJBruBvpRlAaVbYB5KEMcYBSJS7OGaF8ixFkop30JAU5U724EKfGnerslirvQbpS3hkuFcnkYfOsGLIiZyxeodVENKFp1U06V8ZhjDAKSTfm+tJUM9IaI3UgH3zqyHq+BcNhTidWiB48MX6mqrFS6Z/JoKChzuFvjK6R2FhoY0qqdr7TgEfiAJjdidOpZNlL1kDfmGjxGkEesyGyxHQpE5h23lSzT2gSBjZFW2waPqYwAUOnTgE57fp6jIoYUlU58KiPPXmxyMQqnSKNiO8QlFtpJDZ0GG0mLrUcOWpcjUESKCbgxWNHu54rtYcd2lIkqUS9J868zRv6kdPIhbKT28YsDWbalhCry3NLsVg6yRL8FJzBCvYK+T4sLTVMEP+X5qE1dVo4Xmo/2PFaRloc7PVi4JJBPJepl23hWKRVsOOWHUQk0TicSjmXFswxIOc5vV7IZ0xBF1PBCML6LDW41CYyToYgZq5B2LQqQR0A60SQ0xk61uymvpN5DtytwbeP8ktmZHPxAWSI6T1KcoTiFUXDAzPRQ62iZCJ3wr1YRkFSKsMdBdj7qzbPzhbOacsNbC4d+gzb9dVZvFQ56KjiLj/44clKJjVXPcWkoMd0j0YaUyebOhEOJxJJWks50CBl2OVfTvGU6GBA0IABIY0LUXLYSEexjEiRyXRxpP8hLg3nRivJpg1F0DILxKlTF1KVWTXmho1Sa5XuWpPEjpaIPYuXX1iSNeSFC7j/vE=;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
-2.16.840.1.114027.80.8.1.16;MIIC1QOCAo4AOTsr2WiqHZENaYDd+In5E8sXyAp7nv6BDVd4fafv/nDScXn2ibRjcOYYU3NIYGyjbEKGTeZPfMFr9nR4C89dYWCQKxs8r1SP5F42o0BMXV3apXTdBllrYwgkBcGbEV3/DpSqRFALLwin4Fiq9nDH93WQTYNvlHqz9w3v8kGfIXAXBwKS97yFwzuS9XnruVgYihz/Es8Ko+415F/CZt7YY7OEdegal8MsapW9K0hLTVI/qnOU+PJYRx4Oh5NFPEVMvS44sEiPLlmKr1/n9w1WxvrGkX05dc/gkE2k9L4+j8NOy1yyr9xDnKKdmQrBss7i1phobxIKJb4K6Pp9Fyr9DT7mRbXaFoKxZpvce0gGZprMT5kmhn8lbto3AhbPQpRixXFPcktk8yL3zhhV0f2CeZQPvzRuBklDv8T77pxS2E1w6UshZUB2TdJflte+mH+WFE3mGVbEi7xVCuMgaKaNWIOmtl17LiNt3x8iplf7+TnkN4mOleM1GTH/yOuymbaKYzY8/BZnJC87QnHTnCkJFUnCaKr+LalhKhBUBxWE35BijznRTVsY1mIy+dIbpDoOj08l/C0bttnK8y/VSh+zS6Grs4XAr7deaGeoyBkswVBSowcWAup4Wtm6jS6vyB+e0T5+tcjcc5coh0b5UQnyu89hM5PnQR1CFGg93mFujvs4+ImUMMhFobX7HkeVaWSu51MFf9rTcegZ2T8YhLJ2nsP4zsYbJ+pxa4l/58eWj9niVz0s1LFapg0lHM+SVvII7OF/KgYwpJ31bNGkLNKDWYcqfz9nY8zPsTEq3wrxz6cYd76JBFPuLLIF+vxaY9q45RrLxJ668WJOor0Xfkp/0qoyaBmFh1bou4WXTkADQQA4+MPQQyTSq+KDdRcWbr2ZwlCEU0DX+5V38/0to74+yEHthKyGs/A79CSKhRv3vR97hsDsLG2aRVF1RwPKBywI;MIIDwTANBgtghkgBhvprUAgBEAOCA64AMIIDqQOCA4IACVFQ6FHXrNqQtctGTWalePCAd4PmyJukFxfdol+C7l27pixrq0goUaLqThUS1lYfKWyHrUiouMK/fFVbw6HAQJtmLIQuo6ksaK0YZNsUdhlWAiCh+mMsEwtAHywePQ3xduvBgbLoVIlmBSqgTqUKREi9GV3XOKQoazgFU8TCGJ1dqFPlw/eJYjB4xCRCluztytcEfkvB71qcigGEoFmnkMOAs+KPgITDJwPEmDjbSRBKGb0op4MeNjb599CEvQoeyEu8Rr8VfIfBRmp0ANHbQMJDgyQeHTAYTS5BHBxJCFQFijFUFjkuLRPVMVD9z4sxlBT51ZfpSs6hstbDT47wnojr6SOBRGmosqJjdG1Bi2kTpn2ZGYb+iqclRD4rTtoVYy2cJLxCK2/kOtBTkTAuZLvq+9VcINQ/+cMftIzCi3WtgnFQtWWq2iDAXwKRIOnmfVX8XNNnyvKU9ffrgYs2lQWj64+gXbFFQyQuSzY7oprlm1pcCPVao/hL8Zl2ngL0qapwoPrlXa3OAnH2t0vo2lBkjGUZ0ctt3CKpkofHeY13NHwlOXa1wWdNiK+zFTgq+2LULLBQh03rm4b+/dYDJA2wfG8XX2AqUFWUA95c8WqudkHlhJdnJoima22YQ0mLt7AqHX4g8kjsp1KzZCC3U6TfDQl/aPsuo59VH4Ow2lxPAa3g2UkCbKYWwIQkwCudhqSwoctK+rsKSoxplnUaMkeHGbeYcyFDAwporWhTARNrX2JmWP6jJZ9E1RCJElOB7ohopMPeLqRhudkmICUOfFfFiEkgYvQJZ5f5pyYXV4PRwXBU7tKIpiAmSVzWAVgOWukcANBEwg4SIcfubhujEXHL9522f9gkpDDULqIq1LgHa443kVBEhJwMvu7rogQqO28AX+bT151HBjF2GOwzPU3lOaxYWYH5uKVLIkycICxILEvUvN0BiGPN5Tmi0oYTXJNiZr92xxaKuvTk4fFQFAJoiKOarXuBHgD4F1rRQ8zHOP8teynuiEoam1OnVfKk32O7HM3odHPV1xrY6ETLnmO7ymWVt87tmdkT0oeUB53u9aJX1c2oJWznUJOrtkhmpgZpNwz0SmffYIqi8YCFsmvAKyxEBQACsq7oXHCsmDkuRqugvQ+OArzNqQwUu2zIzBvCQQVROmGEStMgmwz4FHXVb2rIcpQQgdKlYRLITxIkAyEAsYftBxFj8nGv4n7o289Cp48Ndgvzc9pfFW6GHs+QQ2U=;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
\ No newline at end of file
+2.16.840.1.114027.80.8.1.1;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.2;MIIKfgOCCXUAfSF6hmDgOA9OJ8Sa/wMe1S38P/RzcHDJed45w1zs1sL/WPKhg2NPUNiVGfD6uLzjCjd2nyniBvBNoMmhbmL8f428G1pxl3JSkFVU0hdihdWHRYqPSxP7HD1BKLSEpwace+Fa2S2HqSuYNJZ8mipGlWRlUfVBBB+Mr0htkTgVMUwaLvWl1TEk9VFvEdYiipw3L7mF5Pcckxk6hWfQz/huFw8u0Etm43YZopZivgJO8Ir3IaaDOgHS/gw5zL6nqBISbnYUvXKI4EbPXXOEXqfKY4mkr2uXSSXGR/HNGU9FV6LeXBWZA1DP2D+vBFVfziG91CeDPi5eK0z5MV+6O6BMAyxtIJ3uoX9WsT3jy1j+MdNIBv09nRZcXacpdly/MD+cnWJslnmaC6Mbkutixjrfeq31ALbCpb7tp/24pjd6Brjp9my6Fqixd5A6xjufit/GuNUuDKX00xTEH8g2mtfe5PX2aFYKYdyWL4PRqLVcSLT/rXJqZ0WYs7wr7OSLZDAyWdgqvsRNNzFU2GiB7NMO6NFPZ/4GQDCSI+Gp/XxQx1U7iN2gSttfDu8A1cCa1UKh5elVn0TajOFRSMzEjL/W8PiqgUevUREGNeuPy+N05mYaZDNHQwAVc/GSefinV3gUJe37LtYTUsHWPJe+UiUR1sYMaclDFFTWN/TSZgKmwb9ySyj+xWiXd9lsa0IbXiLOGzr2ty9rPbpkRUzynWUOkPy/epV2U6i2PgRdLKSWD56S9lJ2fjL43MIAowMkPoV8n9OgMX013xaKrp35aqp1+n+fbX3N3XSVSZRAE1omt2JqlBwFu87fJ7qJNOXBd+uhYOUx7PoBHwdOBqbhHaQ7ztGUa727ZWxk9H+eDLk4+IUFFLRmiYvS8AoQdtEBE+gX2176LU88LSnWo9hcVaBymbLvdO+XZUboGiIOQsSQ+MHnWWwB1MuES8oAWoNUtHJdvN8RqaAk0D8KQyuM293v7N+mZyFTGLdmOL4a58RjEdBDUC55f7gq9RQkc9kYVVqIBen2W0daBLxsBKEv34hBc5uPoSeBd0zYpBmbW+2fWsnrZdn/RVyTKDk99rcuF8TZRfurEUGwQofYAydyx6c5I7GmOzAYO95GeOKx9QvaIKZT/Ohjwcg0J9gb0oogL6uC0ZIEzbzyiMTOvFXFSPTlPzNt6AcMjak5Nb10/UOxfERLZgLzRQEWLSgPW+iLvGiNYq3wsV/keaPF5sptndL06G4ClZgFMdp46WRMUoTKMdmUM5GfVTZ5c2Ah5WWi1Ijtwjrc4lR/SKEZMcuJPhZ0CQX4S/F3zqSnc0FIh9NKwGQoL9A0fMUYfDqdGQB2kuG7G3BSwtGqsggDQk2ccK8G6MSVrsvq6u7bDROBPgYGq6aqCLf7t8eOQa4hZHYYU6ff+YQttiI2IrQ+EU7oI3ZdzUzyY2gFJOadx47cWzY2Lhg+ij+ttHQwXqw4jHQ5MNK/pbwkIyKJqM8OjUfj1JBmnkxq5pZ8eBWBEnG4bI/7B1WztyrTHh9Tgf1m6RhkMBSFHbnRpnAmBViMCyU5ARSrT6vM43nAtl8iV4dShJY1gXAosKffqyUBWrE+WhgRsAlCbb0/g+epWUuMCc70u5TeZ/GSlAHhn+Ml9Bj3WETAuqv1vkKIHfESKlhg31eBT5V2pxDDwniIoFPQGbQ7tc7LLrwbQ9GQjM4SK01wqo+HypFZPI0DxXRqrCPoLq/YbG7mSDWqby68VndRWFxaWlxszGIXm57OvACivZvsjCafMHbYD2wwrpHv6qChBrZbZL6T5wYMK/4Ip0zNpHIeSCGe0Qp/swwyhbT+bAlgUnly6jcGXPUSZqLyKdTssBNsEJroR2vNNe2qoq5PNuTuvfPExdtDF4r1pEgyshAeyTwSZvUoQrvQ7OnvIJqtnLvoNK4C1OEU9DIBMbpcuXjGH6ttr+uRkEgPtG0SW7PckDcWePb/+lT0yfj2rfka11Q+TcHzDvhYbhvC0s5WfV5d1li8PA7PmLAcffF9A0iiH1wHcygAamIQhZuDZRXsL9a4oYlDSKCUHCo8dIT87bmQOyM6crHFg1lVBi839Fa44UJ+73agelTFN1aNG/VNsRIevN4oqS10BYaTmW8KX7dT22oNngYyVc6oOyFuniW/PUHPvcwZVMOd0J/zqvt26/yYWernoE7Frtpo4af7tgTBgo1ChTYR2oq9UPeU6BmHjonLY+vXjNf7f0GNFwRM2T7uPh5Qhx3BrhTotiXqts3B264Yrw4kYIEUhnxMZsnmn8QQ5QvqJkLolxtiaqnhud97Zr91TUKCc3Vqx+MzZOEUhGSYvzbpAVHSKab0foWxpk/72Es0YNQ4+9KLMF3uoScu+xxK/tKe1dB7vojHfRgLP2chY7XD8W3ZQNDMP0PwdaOwumjvaHdLysuHL9H9rynWFsdn8CHFYFlqwiq3pDZQelOQSX095rCBsmhY7IU1YYtDrIFVwn2lZXnuYB9Gt8ms+YlE96AbSfkmlkm5WP6aUnlvhe0cYsTwTxw8JC6uJ2xgzrN0OVH9VqaXI8ozgkVAb+kKsTOS2pXDIdmpkGelAecOw3rTJdZC75MLNhXhrejvhVRudLW3d5j9yVPEOCmU5t4oc6hPSIAe3TIdM+JxgERDT05Y07oywApIMcqT0J2Jw7vlLntCN33HHzO13Wt7TzXdua3+GMlodcLg+gKjnaKu4sLFWV137vIOqHBxy6Hn3ZCIEOhaU1GmJdoHNo+m8lY/2m8mIv2zmP04rYehg7WJlHsOLtpVlsKONJ3wH4grUjDYFJL+E99/p9BOMASVx2o2zo8Eyz6EBvtX0vT8Vi6pWqSSWdILDl5B4IDC4uHFdNxwG/ykUK7F40yo9IQleya34KBiEz4maj+mkJVSR7R1GOreUKl+6EJOUeVfUegf0y3Gd5n0Ra9TjT5J6zulBvHa4wTtswNDroTA+wOIGVyqzLKHUy9chRWpy5nZ2KdP2rb4Byd6i9cMbM4T7dToGbENYsj+Y9vodrlznl67CR1RGSk3/VG7Xe8Zdtvt6S7Y3dtaeVR6N3fTq7yS7azBdXpKTm010bWrkYY7HRkeb/oieoWDV+biG0os66R2HEO1E20UFxwoOz0+Q0RkaH2ipb3Q4en6CA4PEBEXIyREU3J8l8bO2dzq9PsTGh9DTWRocXagvM3Q4P8DFiwxSEtneJueo8LO1t33/gAAAAAAAAAAABMnNkcDggEBAIrJaKNrvMnU8eAKvBg8EvDcIBKN56FEu13+ZYW+GKfPUxPiSIv8puo47ZsYs5FVcuaJHaosJb60ZA7kspmWSBVz774DcTf1m0dJIjYxi6sz1xM5lDgOgLWRE9zN/UR8gloRIRulqVY9jtYk0XFRkXFbWlR6YkLBkrSJ/ZCmKO+s/dyw26mbteP0Pgi5i3SGozc65pywAXaec75QiVm3CAYfp6EVnEgN8zHFXNeMsQJmgFiKxlaLdiWuJGxnaxTzFJpuHkgCzB7vZ3UgC13GNgXY42Z7jWyjMmZER3fZkBKrgtUKwzxR1fXKbg2feZII2Nryi66F/ZpZoUNc3SYuffk=;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.3;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;MIIFYDANBgtghkgBhvprUAgBAwOCBU0AMIIFSAOCBSEA4v8bjZOva59sP4n7xdA9ThLf2HiWCSOqEfxGBxHSfJMjenXJPXZAIBKfu7UJOjuQuigjzKxozkcC6CvwgrTa4+iVOyjydPdjY0RN7Oo+aX3wOA+Axepdiu/9+eKEuCcvcNMKpJ1k3GPOKEFhkxv1BHjJSXxQN0SGQ469/erl5qFQTG4/gY2B+5CbEhBHoIB1m6fbBBFmm3aEqmxXFmVVRKCJUsIBsNMiN5FByjrCxECnil4kPo7EqhesRPOPbtgEezqUHCEUEiw4ZtLWoLvATk9KtMaSKyE6URgwhdfmO+weNNGOu7vi6DeAQMjLbuLWgro5YbBqHocZ75h6mPoOYgvrwuLoBNZSaq4zE1/KlS00kl+n/YlTDUpC8oceeAHF4R8umpcO+xDQ1O2UWaiqAxRdrT+rxNpZB/IO2ToDW/1RRBBmT640RdPv+uRhLC6r1sFFENaH7JJIJ+zqB0Mo4cmctl+D0f36ZdyKTn1uEIm+tAuwLzIiGzOSnaekDuN+vfHJKR4y0troqGvDrb9m39OEcZvpF0QBzTYrLyrNPwWu+7HYjwfsl3xHLP3tAPMlmdC2+iPqU9qSPbk7m/StHS01hwKK3Psyaw0+35clMJyLrwPUaNOT5hpovA9nuF9cF2KFLsxernN0LGr9OFZwTAFJ/N0AzuGDGxy/kmBHor3NtlEAB8Cwc9dTOrd30DzX70H1RZS5nij1dAbFBXLm0h6eGDabL4hbTwxyflC0KHoFRi2h2HfzEEgL9eUqIQREbBiSCVkleRS0HsCFRzydngZZE8yulKbSy6f/RfsKMKt4j33W9ths2b/HuS4Kc/E4Db1ZWx2ifmiO9anGBT4snZwu5vADXG8iMWehjVjhBSEkDJNa9yW80Ew5utKrKqkLMR/DXtNSEvPFU1E3mcC4aYSWUfH+U7IWCbBtJGVNdAA/coJR4SRFw0JHXfFOZxPz7ajM/XHCERNDA0GZrEN5+dePoejXAzZ5rRGar0lTuEyuzv8OM/LedJsYO+ahKVWvLrULG/FdHf63ea7WZITkbna1LBQSqy75qZKIPf6OVKX8FlbYOz2OnSHovV5umV6G7/WjMpX+k5qohHMEyMqpxP0cXE9YD8F+rEFGiiTluLxV6x4SviTaSx2uP4Y00i0Dneh/PAsmolv1kNIh3lYAvJVJK3s9MGmbdPpcmr235Ei9o57KX2JVeswJPjVQLLLEPLeaYRhwPIO6k8TOej+5Y7zl6tiPy4Y/l8NTc7G5Y7h2mMX9YsjuUMNPOD1mCthV0VhpndrFYl4DL8OB6fRgcGzCyHbJxaY8+CrpZBCWtoqjEXsUmlOt2OfLHrUZ+QgZVgcq30fIE7emIgBbNvcbngQtLsHyi6vjlQ71gsE+1w6/Zktet+o0H1cj7MhlubDVcZrHvbbpbr3hYcW+wWYzewjAdNr+iV7dbtPAzTGsHM6JirkwgjPXQlPspXcdpC9LIGJwDC85SlK9Q0gF6DEl08brcxgytL0ljSEgG48/veM3zTocZ7NRHhx7bmwWDai47aG6KQuAsKfPBH7uaWbUdZEf4p0M7O8msyThW2Z9TkU0Y4wcsGGwYiAqWjEm2PDfMAXnN7qAB5itEKPAryNcObrv1Q/prcjiZ/Yo2Q/a4feeFz6sGn0DOGfin5+8gz63QtSnPvQgc1XJ+IhgDX2GEqrlxZxGzu0crfWy6lUpO+t828XEpSRKMjiC6/rBHivnk2koU7stw/YpC11BMlML1QMhAFTUAkl/UZuyH+kqGbD15kqrPii9d2kdClr6hOxCHzzd;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.4;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;MIIFgTANBgtghkgBhvprUAgBBAOCBW4AMIIFaQOCBSEALeYOOpyH63M8TOf8to5z3XPRFhW0WKbhqzMcd/7Y+CFHTPC4JmC6P9F/ioxISN6cjEiw7JjwExEvSZXOqY7ykf2v2d8g6GU4KqoE403FgqLaeTS089XsHX7HxVsQ4JA5iGG0JewEabLppVR3hEJydieRMd1KeKS0NI+qefUMAt31QqXsk/q/DzPn6n8LARF+kpUWmP4XJiURUyNDjAjBcid8wMYyoRjPeeHVRqdyCWPNanyEbgjyjBTGi7fNols92tmaq7MKsVGeeiZkMLux4RytfaP1/ypPX/kPgDv6txJUQABw8UQyyURUc3QpCy9xSs+xcpccBOELjgCC+fhXMCf571SoeHKD8MrXHevVtYWFOch3dke5lf3h2V8m6bmy2itFSBdNI1DGW6xOye/wESr78EOnfU0Zq4tqq3hZ1CiqpHGCWdOkEQ/XuGh383MUJGppKaM6JqRLMA5MztRHQmMO9MvhagzgCRwSKXquku/Mkx+05xmyKQLkool1C3txEUO3UQSfRDLkS48hp5PP0kUBnCKzR0kr3/jun1s5Lw9r2wO1J6EwNKZGu+svwy8zoeZ3fGZOLoijNId2Q4Xlr9qDtMuDQYQjIDpjPepAh1fBDlu/PcetPJvIBqhf7ZxwLiAYToerse7I2DwEk1BOGb6CspZD8LqPTsduj2X6mSzIfvW2eDizF7mHPPGCk6Javec/VsSnBFiDEbz4ciQmMHlP7Lv9BQ7AiCYrMYLP+D+gkl3W6L0ARApPxZFpFMX7J4ARvU1+FfUmjvzqq2hdqjrd4nU4/sQ0cuDRBRurSpVNqn8pMtysb+WyJSzDyLdJifee8xLzrT7JRvPmeUyBlwYwYAKmY6XNWa21JzvAyhW0pHYQneEdD1Zk7VPAdBjbs2UmfVhTZDm0bKwiRKjjXnHVO25W5fUnhVn4bMjZ0BDEK1D+jicphenp1YVBmp2njw73DYU2YsjciVAPgPs646wEZ9nvS/wXkpoKy0iCe9/QEFA0hX3fwCbRwPqq0cj4wm9FViqrIwhSaZpjbqwRzR7ltSPyeElUoT6ytj5uvoiqCfWu4oRNoyaVLKikvM3PhdUoTbmkmY2Cu1Vlnc6/ZODX0nVg4Qt/nhW2O7lZzc+me5430gJDps9kR+DwusSy7gSAtG3kS7ecU2c8OJGxoohLIEmJt2A5zwMpb3HGsL4SZ7Fnn0q8ODNNm6sUQZBrLXKEAczf7a7tsOWlWzoekFfBqsUgOV7gQ9oyde7kZqYzOQtGEGx/VBCrhTesprL5UFqyYTIoZTvw8aI83oydUuk0iIRTFap/ziw/B2DEi7/qVbG3lnZjIWMjKYYrDknJZERI0K15IYSp70U6sh8Nib3Rl+MY1ix6f4EvGGT4CZx49t2gbXN0kQiXiwQFW6NW3+X3eT3YfbHM+MAVPeidDT1miTVwX4L5F8QLVUlAu4rs8nJCnmdY/sclqnpqHvlVsy46D1hbSoO4tRS786txvhgmS0G4+Gcz8i16Yvo0s4LyD+virVj6lQdObPWo69LGG0J57C/PfuAreC4XaEYq3wmok5I3ndpcGaLpikN4JcAMPvlJj3Dpj97CA1O7idiQsGCVvneflxkXmzEurvkTe7EJz2/5YQ3q3d2tMukMIY0NknH1acT3QRqXkEJXrvDYOrouCxEOiS0XQcXN4E2pYDF1NM3kgTr8flixX67cMVdvlt/uuUYDzp1Qs1LEwYsRjTfZh6tG0kwp/2XIwhMPQgNCAAQijIJ9pRO+5hQk7DHQbZa1GoyRMh7g+26znZRRsrzeb0oP4kHzP99ARwqMNWlt6XOpnovUo9s+lthE7zX07w7X;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.5;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;MIIFgTANBgtghkgBhvprUAgBBQOCBW4AMIIFaQOCBSEAfRhMCExU23yxuusCmMVSlylW9kB/5zn1pYiPvux0mvddx8fUw7hJT2/9WsEZwR/JGT/4fElQi1+OP44QuIFn6KfaV2IIPFTGsNUuuAbAsc0xQgNrkrfaV6uGnvewU/J+C/7ambUmg6CIRDMsSiL7lkgFTl5hwOdqt23KqMw8yXjqRGhwYl4c0/yRePNbGGVB4ySY2+F4PMiDapQIx/Ksgl8WE2np25bZSY6GV3VybGarxA5VIlVQLWY3oxJlQbcXmkGZrSQbUbkrWsFXHQEC0tl0l4qpsZPMPifGnRIQN/BOPCavsWBgelmq+djI6Q/bDe8zuu7PeylPAxF8UBTQN7JLb8Ps/gB5jVgsorXpjAbq4GiqqOWMNcNxLn5V9/NrMr/rmwIJzAuzqGZr55uPv5lOfVo5QfhqLsVbOSmFywmTA4WnGp8dmIYWkYOGgp6UnMki/+AJ3UD2k0Ha/+UN3IN/Z5bGFBPrAYXw9FDxMptAEbjROoie+qsZFP22+wV4+o8jyfTIc6VNzoyyrYIxttR4jYN21q3n5/2QyQfVH1hdlhashfwXHNZl/boq5FD94QrBzdtGR4Vw2VEotABmYC4+IposCBG3akOU381KCYlcsHmXR7RydEKnYLcPxY1VELfgsExbn0v4zbe1/HJs5NEi7Eotq8WyC/gU2+0jbJ53sqxtvMR19bml+5U4WWiHgpiLjTZo4squDPH/6jONn6p36QSHxlq9nh6S32jTkc9ZDcA74v4k6K+pJ7ohvpLWpKN8PbSmJOtAFU8Z9iYsXbQKNpNaU5iSBgv4VKeYR1jK/sqXfO/B7zhzjmT8eiU5/OmZWe7OJTTslvlynJQ2x88nlCBG/V+bXremoA/K7TVYvBKF6ke5YVQsDB45hPhlxGWEmVDeHVEqhwmUI1jp+TTExoOROP0o8PQoCnwXtKq0X4fNQHuULTXr5/yow7fGSFO+JHhqrb1M+H6+f0bllZoVQsIls25aMNT9TL1uXwwzOpNh4JF2zhQPeZJFu7IBuSltyAs27OYIz2vBEIAVnJsFsGrKjusymWJaW+f8LVe647YpsZG9vU9AyaQUILkwcbNWraEwxiqY1fC3jpT9Mc/Vh/GoHygnvCu9HfTgHsbreMau3O0IG6Sq6EXNk4RU6n7TacLmEBBF9zJiLB9XGOYBqpsHCyXI6uRrKxSFLkOAFjliQP3QjwF6prZXo2LulW1/KdPLXVA0oj2w1ifswbEKRXK/sKLvbsJl781h5UTKYnZfhKMIja0Txp5eHI2DmH7dF0VrQQNH54NGr+jHWN2VYpExFHIayZMFIuPhIcs9RS9F2OY/IpZd2twGqjaRQ6psAbalHh1I4TbzNnB9fjHBXA7UiCBJHFMliYamXbtid+gJX7LSJbIhfX2KmWdwMMK6Q0WxigUWQgDY23SPbBMizzTNMQ80gDv6M7o2BJzYGMXaBU1wJE4gcz7pLGXVXazcoUSFS8iXIRbi/TV5+snU86J01JLtvZGbMHseqNWCsWSys6Ec71k0fDzUkzRqtEQczH/9ke4+nkIUmNDeaFzNe/k3azx1GZepAtx1Ylr+6CkzWdgLGc65uwpAROI7G+aw9psjRlk/o2J6JzZ7pKSSxjOR7mKZEainIZCcE0R7w8g9sY2szUtkA2YWvaFTWEKhStHPY/H5AEPmnHor1AULd6tcHzUTftRdfUDw27/LC3ebZoFmL31/UoPHamixOH0VeTAbEEaN2Oqf0NVRjQNCAARR39MBLB5b85JZZx0GnNv2q3gymyONUGEnHRfrcZ1vn0H7x7/GDkClWG+D9+fLB4dQmHcW+SzaVwcrPNOKJgup;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.6;MIIOdwOCDO4AGYxUPWcdJoZklzASUMV9PQPEuvEVtMhkgiCzkDOoVUS0WP8BtEXpw/v20pqnrKjq0jvpoNHeQat8IBLX/cGkF7NHdUCvnFKwhgUjNggrRj4wg+FF9xY5kKHMcq2E9B5QU67cL6gUqioCA1G9dNwBAzi7NTpMQ+pQ9omX5yfF8yL0U6dB5WgOKtx6oGtEt/nvXfe54eMZXk0Hua+9KlaPLqiJGYSU+um8+qmYQ6AZ5gVGKKBKxOA6mgdElL0puo6R+Z+uhum+2dPqr+6+VikBXcSQEOqE07jj2sjeRVCS3KNrOsYN4PgQrjOJ0sNEeWoROY1Ydid2Pys12q505e8sBxim238NC+SsCbo55bzI44a6qzi9gypyp/nQdnWFYAIg+3rVRVkv+//tGZc/Z5HvSLKTkGkl0ySg8N6GeTiJRhSRnPeH6cn1Vqw0EkymKwa6ssmFXDdRQ1mRbcd85UTooGWd113Zcb4X6gHqw7lnZnqB97J6ud1jwp4iYbCzyFinBOemrLiFBCnVoXhS7HgxBFDnPQBMDdDeJ/WqIEH2p2Q0h1LUAs86XAFcLyomlEVRmt40rFlsriKYS6QUubAgwO1BuPOX6QKxlWzIlhjlDMFAvgMgvfTC3eMkdqm9AYhKWW7FpzYD8XHOCygQw2k8SS6AGlrDxAL2eh/YkPxVwf5OFQ1ZMrs62r66RyqvIOuxZLA6b0nkJ1vivr83hb9sc6Zfdc43GzzKassOhS5gGbs1TP1U5YKLb2fesldv9uuDc3OR4sf3RlBVdb8uHO0Gmrq+1E8N3eWDdrwEi1BvAgZbYt3S8gvYcCviAjnZ2rTahhfjvRHYsXDEXfh/o8F3aTSVLcPkgBjYF7Zo2h5Coduq2ftMiVx//Zbz+NC7VeamUK4+in9oua8vkeoJ3A7WCdaVynjaqHNLhyHwZdFuojmxNQmFRAFCqvWLQF0KcSgpsUTLwHaIkqW0YhVU0WWKEWCSma82diHx27pIWHbD6lb8O9pLrNSo8EdXg5IGJjo7DxTcn2o+c1ppcYHBtYPNDX8MD0fu/EMiN/I4j0/MTqbBLxumEUo3HxJpak2DV0ZYI/AA9tFHWiSiYZybv6qILGQFFGYCToD+lWpXGyAv9DEoQ5CS9lOa+UsgXxKfsTXpobLPe9IMpNVxQ0rGgLHY2sjHpNQul2ucdNUj+vii1Su5nuVvvOccuqGS9uXaFCMKCDWniAptsDKCVBNwJq23aAbrdFHfxZkK8oNPL8e5MCg7Vxk/RSgklhEkaJKXdOdDss+wD2ivxAtbhIwLleSsFma+33XxZ1G6cXtaaKA97VDrbb9QsgOSvCQMin57v8e8rJgpGidIkoXupHel9vom4PBnuWqGZiKh5zd4lvL2gWwmAGghzwflAZWTsIfNK5+vqYPaB5vdo966YSUB46qqZ9le3yXTlsm4v94h4cMDOC8eelIWNf/jl0mbg8nhyOJXsFsRLDPPm0B4xW8bKSuAmhP742UMEbnXf3lF7fQtDEtGi13xUXJEvlis2G6FaVES0521NaSOC/vEvk4G9vzPADFE6RlUN+Ha8fUTcOovS1DIpU3JiPtey3g92iKXwvjjisODzwqAzEIOz72y+Rn/BjeUYeOcIS8XONyar1dlfqXyU35G8aZgFaHtZS4HU+VKkgwDerbltC+0s7cBr3/V9uAzkQQmooUPuxqfroBrtb3yvkUHh/LGlcaCep2lhstv+pWgp7c2QTMbihU8aLql9qb28zCRCiZo7/vKOD1lqwtN1gcRH+VCir5z41464/ifWxrB5LpvzPSBJOT3tH9Y6vpypOo1q6Q14JXNfWNsQulNZOiPyXSyTALOTyo9chY0+/EsoImICPlTL2Zpr//7v/LdFmRnmG7f47PpUMP/ANDAuQmD7UW4pk9MV3Ezuc7VNtSglld3r1WNLFeSAMjGvRGP5nIQ6T02MoFwCfYPPqclLbO0RKC43XWSEBbHge7HGemiai0QypORq/acJY34ety0qLKA/P0xv+LuuF72dm6NZLjsclBdQFxFOEFYEm/G5AHPREwF4zJvnrxapAaCUEDKHap+F5jq/kWNyuYPIh37tFmEvq5neib9OOIMlKAwAKTSSOK2mA3x8JjEkR44sdrqKDvpf2p9k/JlMUE2Svq2F23gGfBFsYQQVcIGcHj6D8EyXsKC0K8+4z2srQmCzHDpdUeMSXoDHZ/cKjXgSuSaqPUvVMWenSdmrL7B5j7dKoNEG8MdyR6PgHnqfJhXvO2VwDhLA8I6E9Jla3lfCbMk8wDO8dAnt2PYFKlHemsceGMaN0LVgPUIwRQrGPLGSIObxmhak31o7K6nuLUkc9/7q9EneQg3qAxGBglerRNSF2SRt36U91kCsuB6mvV8acottrx1XbO4bCYt9OVTCCz47DGX36HPJKJxAOOYe5jii+R9UqjGHwXRdBuDCvQPp7dbIBz9HVXwCL8kuGpY5PKJbr+DA2khHxYecqxOYNjwt/6NVXY65aZyShgoB/HVt2M228ij6CsXJRhTJ1Mh97qdcwia4HpZafennGQAnNOI00A4gEVNNINEKHKGcMy+d4tci+Z0e3GR3kqMPbCXkls0uzJD4Pq3LyDVm4ZQk2ZbeA/8pJ0iXO89ZhPBNSQf/MUhzvztwwAIW/Q5bCmTgHDVTkzsgDeHdWzcamDO6PF/u3pPPIt6U5W/szcI9xQj6KQTQ/vdazUa4DH0Ur/utO4P08wFVzxXpub1gStOihdVW8/lHOR49wT71NcZJgdPNbiMZnH6jHon97RtEIeS622a6SwjVo4Ll5bYqBSlQp7eXTjknsxw8u978c2MXBGDtu/Y6NB0AoEUzaKhBElwnqxv2zEbLKfCBZZs8mIdRRPD/U6Xg+kv+dt408MvgauemRcXK/bd+rup9mlyQksy2r1iQAhcSzA9E8XZ6WGHeynqSoC8QeCRHMX6A2ZGHyKXf++rOmtZxQ79pgnn6ghKgaL/wwhWClH7HlVkw61urbrYGo+RbqPBjKi9ixl2R9caZ6nCgPmgLaGi2OtbTe3X/FlHTsl9M/2AHEH14brmnhL/3H9FyWA0Szajgnag3kT6tnEEXdXDw3o02T8V7wFh9wwilCgiOPmFARTvlP0opEk17yQmuCDSYjEsSNqwuRrMOFamwyGdpWsCeM8iLwtp4kOwLfdMspjkk7ije21Q+xwDc/gFW6njWONgvVW+hwHSviqEOE2J9lIyPwnT019Mo8UGJJto6P7WT7ENDPfYvI5RbnQ6Db1rXlVYbGnOXKNjqFExSTJgC61edJgUzym/HOqZSQMIpT7yB/lwkUdqcheL0nrfte3OW721e8toGBy0KJyJoAdVuQbZGVha/IDizAXErzkRwV6wRWxT5znysca9YPcjQi+hRHTGjn16plRq7qjifbjKBbuQdFRVSsx2gODqXTYMOJIwNTDS16Pyo4j2MoZM6EpXyAuO9ienNoKWWfJriIPmzNxpWK86RAApqtGRGXb4dazQRfn0Hc0hMdZQfCdNxZJNlNDW6yOWHlmdPWWqkx2qv/QuW+t+0rmfGsWJLxVB/hSQugGe6xJUWBisEqVn0NDkIJfURyrfBGSS/op6vmusiRVaMDExLRt51ACF42yw8vLB+YwgTezOONWQ06FcM4l0Rjg3e6hIMQer9B6ypIt47q9W2CXN/BnsAuxXqgdQr+PEXhweGy6HysPphqW9rcoY9BNEhArnvbuTj4HV1FWrFDOdQ2rV5PzfS55mMhtl9vXZfnqGaYl6FxV8sXE65wLhkW+GKJKQWsZvwdxWcb5z+roq6Ju6RgMMUwKbJl4onmw9pPxK6Pp6quITB95ug4sq/YxX9mWNOmqCgEQAfYkYQ1gw3WQ2vhJRxVVjzTRMSarSVnTjPtTrvkm7E/cO7LmISdRptBtRE/jbJJJoa6wyvt70wHDpG2rE7luz8Gl997JubiU04bMPmPbAVlKX2ge6ouLp2hYujjg8ZmigPts6q407Hi5XXw4I2NxD+wjNuIWwB6Ei02+zeYDry172DdGjxmaXWTWYt3+7Bj/2FM3a8JH7TwUabSfvGrUZcV1WbYMfHccO2KP61vAA+AnZZznqcZWqE6TxtHQLg9xeOOI2fNcghiZ7C3iYjqNr8pUSEhe/EWSJu5K760ksWjQVlaGc1oBn6L+o4+MOOwKn+i9oZc+K/n9tyl01vmrXVQ+qbkTlBAsq1uvIgqx5sYWpe5tGdZR/K6ULqdYE3pxrfNgX0BfZ4RqRuUpgBUj3ov+IGCTARDpY++CVbf/U7gnHtDhYnFnBI6iqsxwQlXhn2F/V2HQyFEIc0DTbyosBJ7r0Eh0nXm9zuL3X5Q4SWJrH7Q6kxSImP5GSnZ7K3+kAWn+Qp+j2AAAAAAAAAAAAAAAAAAAABA4UFyEoA4IBgQBhHiCs5S4OOOWDBELY/8VNw4Q9wfVjnpwoxnFT/2pE6gfWQCf5jyevFmNi67itvY1mcJa5IasU7uePZjTffbwKSJxAhSdaPB5XSeBSGLxURaPdy/lGAQ1AcXxnNbV8hGHjeSgmTze3mIogNulDW9yTWbgG/bKmziCdwYf/F4/EkoFZhKDpFn/YvTqJpWl6S6CxqnI6YSmYZseFN4IjmhA7t0+fd28jrK+KtJ5uFXS9vUm+8LV1k6F7W4jQS6CohsMkMXaaj3FN6nK+0VVtotnGBZZPftU6xVs+TC4ZCgWbeHyW5/gULhk+7NfC/UjlkF/n80/Yqa7jI4Gjkark0tdpYb/qrAtLyp8xuoQwYrGK+fyJVjy08URaDjdVzE9pi3kXyj9MSAU2g+ehT0sM9Qu2rQhOh5TnkEr1vwj8KmukwXGb4h4JDJLCYUhGmyEsKXfTqcXx99xYBwPZTV+4m6McdKd0ok/jAEUGQbL/HnpJ0BQfhyGj4PcWnNEzfPfg/98=;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.7;MIIOdwOCDO4A2TW4lIpg+/Q1DqbGhUcgLHMH6dQJQFHPs+Y6+8p+rnBvsC9hWlMUVULPQhm+aP0YyWwM+yT0vP4pmeiGqbS8Ih5iAO2NsQoVSqZzpEzxEwYGusDxw2o0dckGTgFVOjDKTWFKfuSsyytqMhbEhhmUtPWJGcM+Sw9tJQXNKTj+jG7yGn31U8A7slewozFETw36ejRW1t1NU/Vp/tjXMYz1hA9V+NhTePA1JfX0g/ELXx2vPlkNysmiG7WtL76A72OaZhZ0J14oqwf4eL0Yz1+rwRNn6rozWQ8iQ/aD7I0znsA5q46n4KTKI09/Ka/DMj8aTuNpCjDrOqFQdJ/1T6kOlU+s0Igs4WGwCjAXckc4/yXCS9xP2Ho0nszsHDRLvtNgs6xnxhy0L4MamLUttHikZEoBrC15Yt9BYh+I0EcG0fU9Nahr4LG1H8ItutLkh7+9WZsn5mX5w+0PnO0jOtHA+OCcwdFJqpS6A0wtgFgpFqpSiz2V7Gzzl0MQWR8w/FWmGUlUBc2id4pCIrpovrbueFIRD5Dp6GMEp9ymzLZGi1VaztTS0qt3nu2eYgQUN0fQrwtrw+1lfsmYKA+FyaGdpwVBArozKubxDlU35YP0rQYdxUFWCOX2Vi4T5SNfq1ruMQl+5RsNnpv/jM9qE0YQ5TNnmGpiYnOJWt3ItD9qomcNv+wxekqNkfnIGoaG8HqYL75bLohVT5Ynyc9U87xB/LuUCgMb2Cus3f7YzSceg15WvAylOIH3P6RUCdWUrSBttxHK2BBCpaLYedBE8eGY9ptf7jx95vJbfcKYoOB6+JvE78lT/fi8049yoNLNvZkNG/93qcQC87fmL9Bn21ANKiavHF4FePQE1gLl00uKLNDwlU3XfKDCWgHm5MpaV53VFDtaldbmFzhLNVfy5eGuv/4UAQeyEzVHrP2rMdyRot00Gi/a+J0QGddDA2DwzuaSvQSO2AcWOl55yayRCghRcQHHdFxhwWWBDFQQhhXItawnQflb3+NcCF3SoJ6j5b4vO8OQxREGoRe+ItZtK8OGJ9kDTa4DUO0SuA4IhGMay1K47xtEV4T86sayaj5phnxxhlIeORIrTxRNPbNkw7XcyGdGorQn3K6mosMnZbg1W+Ec7SkzZxbPmt3jC8PZQN7v8Jmp8JUUp6gmR2/NjmwqmHrSaNz6FeBkLL+aPONiiP6ETU2IGzqtvFRjnACWwU/UjJL9EJq4mYyfyuqS2VAlmecmfR8DUdbBj1Ur088Aou5mYk5FkY3lAHwCUSKoYV8hSLx4FaJ9GucaYmPXCpQB4ea+8CYwW5A7ADHwBs8ix00vK4yfJ/41Jj/VPOifQMNhTNmIlRjiuSG5X/OUxdaziWDXadkd/OCRpGYaxEOuyR7c+exXmCkghfIUD7q5GkGp2IJ6R1cnxVBrLfS6zDz7JaqtFgt0KEBeRniVfXA6tuWBzQSA2ErQpZ+jk2Rzt83CaQSgDF/2ClWXJE32ovz8dpPjrI8KXRcYMmiF/CiKTWQXhVIybie6I7Wi6BiD2jfi0V3Vk21jFAOYSRpLuj8eNnOfM9lCZpDVxGJtzy7SRBopodkChIytOSUjUYC661PmX9JZ2zl3V4QteD1JA8vfuBI6Ubf1g3nPMFvMm3QGIHmqT702NyhozuNj1Z/E8oUzDH2/Tve6+aRDUkLSFqgOKdhL0LuIYAN8/F6HDajmMl1YbM/8gEEfDeGKt9MhwH5mY9kGFEaHUNZsVNH/Tadgn19/7n2MrZKTSwERh4Auex8FwcLEoNemWwhiYa6O2KZ869kKVvxd7il4KSUtIj+w0pnoMItofXeFmKOcOtecRG1Hx5R0/1d2mZuOQNPz/lJaB4yd2W909ryKDPlYj+HB9vGoafPwnhkqoPXRG7SGdrXNV8RJ11RyRJjifJetAMR8tl4FUFw1ltOFiw9UrlWqRvWvfrlm4akFSq8G0SalDkHvdiqKhfT8mIW1q67AkF99gPzBsDlRVvplN6tJ2mbbo2iUv1M7lPqi20vwR0rh6sDROftTSDWEnURIVIsDumbFFpmSwYlUINu/KmYlnuLl8c5az7Hw0r6f5R7J5iFQ8yPHLBpo2QiL7QvOafAtBbpAM1rMCj8VV7P5tFsmtW0limVgG49IvAufZ/Zjh9x9TnABfo7UCMWLs/2mTEfyFAts/Oosj1BdhsVA+jAoJqRQaoDNwsPPHMVEuvekVRhxpheg2OlDhUL6A4nZm1yUWxA2aKjwwLJHJZwhj0qFGJgMyYYVgXziZmQtunyBVqSW23hk6rzMeV9sfNCgxYuY3peBJl+EDMgoFhnzeTQCh0lUlt9iU9C/Iic6JSENE63p3ecrD24rfTFaW32XAs+EpzB95IphjmIdKeuFuJX0P9Kud/1HMk8T52uNqYZhMUDaqOXIvLkp+BPw6HSB3CpKc86hgTEUI5Uw0WO6yRnT7i7MWDxgV95tZA14JTuCnAMlnGBCAkPwR9d8BNub7qX7ytYYoiKpisMj2wBloDAzKQCy808+ZhYBkAMLw3kump9oNgQupOhRnGm2U8XWJEGI4dy99DLOT7zqWV0puoUu3IRGbu87epXrO8rSjD2wFiCwQHD0QystJBHWxr9uZcYuni7qcHYIl01YWF4ry53cLx+m5FWI23TKqSbEshnEPy2orfmdOEi980FXeYSj/wGa/GnpwnRRa0780KyRXt+bLemRN0/5YOnkWpXbg2McoKieVFiaap/YRtR5pNI9JZurSy8JiiX4oDWmmdJMNhHnE7w74+/RhSRbaQmnhA7vg4LaN0Yb8nybvsEE3nAo017D1tLjc/PeGnJbY34n0+C8ev1jkdfXhNXpwKgML07crKsjwDXr7KZWtO5C6772MdFucvm+pFvNTiKuZh35yNpPlj8l2B5xwxNgUYU1HXVBhKT7gcTrfKygH90/Fskp7KAGzrP4ApPtLO+O0GqvSkuCtEygE0ixuPK0FvKqr5iOdHTbLB+bl1jhbXD1weJswHrhQcPOosC+dtmw/yo4trWFQkHoGaMa4UYJFbzg068SK5Mszl4eWCfoE+/dp02IxX+6zxOgCWTGIToucKqgxLbJtXTdgEhevuAyG87CiAep5ZpZ201OBh6PSytNHiUhPzSpF9yqzfIGnXecND6WBt0HMWZw3WGhDGsuGwLIyJXwKS1iVL0jX+ucN14QFH/jvgaCncANz4xAC+1m6aocjE1g+WozVoKDtlAYgO+Vw967AmM5L2gNVmr7Q6AafeX9FbC2MzDv1wmtAelKvVRgpwG2NHbHjs5kX0VPh/My2AuxXLqFURwKCnI/PisbeCKqK95Yfor9aNR3Za3NkAU8Rl5cQEalLq80bMQG2vkmzWQG5vUcuKvwQIq0GnbWnyY+exkmwFI5SLbmw9hjbqZH6iyT5kDW3rEP+wBKpT/g++wYmTAq5XjEWx1sBBysGmr9FCFXk66u6TBaous1FRbfXBs05ST1AwTGZL8c8x6uS8GTFQ5TWY9/eWsa/UECpYJDkT1E5URuUwiZNGTlccNmLz/VuqySVb9w7xiTypllkv+Y+wfWA3H9DkNFY44Vz73Z5tLo+dfq6z6zEH/y39LC46OLnal7yDYmLaYc+Hl1e+1eKnsjwQXlHM5Wsj3CDcGpc+mvNUEGFkhTUlccbZcyY4w1bondqrzWsqYLhXk6QbY9IADT0n8DP0/z2rDBBAMLpmwbFs1+jfOjgmWrVNEIrlkU1o8B2dubGXYeHwjfRlVcMFfeF8a9wcG2gDHnR1xwN9nnNvJRybDZygHPWrXcI9ORNP5PwsvcOXzHuOPtfVuK5F/2iEyg047hONhNX0Knnin6yykEmp5AZUoxPkBSzcbKzH7lUSr74Lv8mzY6EjCG4YR9pU+Tg1q1hLnoFmSaRjV+mXsLtWDh1XQzYK29RIlga8SfqrDIM+O0zkRkkjdLH9uWydOUcDce8Fa+8SGawIld7Xyv/b4YkI3GHrUbBLM8uXetERp5lzm4cEa++ql9tkwsOXj+X4q1ta1eVvJZCn+3U0WFzHv9fsp0Ie0TlioKYWff5qCIhW3ry6Mw8qk6CA51oZxZmg7b/3Oim9xmePEbXPQTb/ouMcMt9Shh9zOQ+Z35bzsmCXpOidWCDlHG3Bm1rgyaMagB6bJvDo6HgWN7frmDicsm8WlrLe5asHZ14X79QKzXvU2CetBFC9afEKRsMo057uStn1Htv8aEm4wssxcNmzDX0Kof69s6Crg9cY6j7ESa4F/exP/WG70eOFrrv+oGgDdeayxTIaEbA0cGyxEFFS9MP+C1NHQw3gq8CV5dQsoGJxR7C2mIVpFkvlZxOTo7tMXP/gQKDWhveX6cCSxOgpe07PgRK0R6fbHJ9gEOIymSmKKnqLu9PGzDzd/rAAAAAAAAAAAABQ0VHSguA4IBgQBJTHfqE/cHO6XRJD+CQdrYFHVHAMqZDip0GbuNOPP9vx7T4HhDRQ6cq/axFUxVScSmI3iseN3RGKp98hFo7pFgsDiuTsVo9kuS4M/kve/yJSxOUc8cwF6n/ctBTF1UZeOIdaTmAYU1zhGa5pyl7L7Ws5qMQFvdR+3VRlUxdalNGjqXJ20UG00pnQWg77EkmKMgbecQITWw7dugD4NWIIcCh5a8BqZSWY5AjRvaHo7Ero7kQZx5TSkW3KemLuLufc6nCJaIXnjYXvZ4UL8z2o/N87ioHuYw7xhGRg4F+O90SaMxBrNkXomUZ4Ez/RAwGNUBps40TRVRW14+zYGVanXaNKUU2OaA2HGLHoPedvtrId6DghLvf6C7x0YpejBv+t/njcfWgPbtvbFn64XyvB7V6XFIR+c4HkgUE8vqmmLfWRWpGQrqSvAxYP0Kywo9zq4xs+RDVCISj0b+vLA1TMrG/6wLwhSKtXJDWxcJjExqO8gSLqBmCrZ9sudcoOyNqto=;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.8;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.9;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.10;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.11;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.12;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.13;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;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;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.14;MIIC3AOCAo8AObovp4vy+l++0lscF7YDb5ZYnxV1sIYlTS5vTT9CWFL2R+w63liqRC8sq2E+34eun12HE6khKmSVOOsPGq+XhwPXds8RBzj20yOSaaG1Lln4W6UKjbakJrc4Lzn6kwjB2pYSVk93WHmWZSgrvHa7DPqjTiaJ12hL5A7Yky+wZDvXEpHEz6VZKGZOp6sIQ9RMnHVNpakW9Mcg36B5Y+LJbuSBM+y5WxoVSUqFddwLIjO9cx6ImRvKIcluNQrwVbmnCva7I/rya8XeT/C0Rn8ubpp10XO06Ks5TsFZnTNqhwUmFQbD2IkzX0yMvhSbKpTYNLMRBXVjX2T1nxFNCg3NM/D1jzHNh/g/ObSiyQiNpZjsugTSQdasul6Lu7gU7GP7bO7qiev59FZk63U/VNR2H0hd+7lIahzxwPffXyZvolDaRueN7vX07VPeUbNz2Fzeov2Wbz0TSKs869EmCl1S8zU3Msw+XceMPNNWHqmi+fWXB1GpOLlKSju8+GOkV+YY0E34Fr0xFHV8855ESbFa6dDHqaC7pcpPv3/BVmg7LkcnkMq5TPrFsvac3GpZ2qHhRg0DSl4P7IH+mKBmxyloyuklz4SbNm/qyCFJQmmMim9bXVPHIwm+pxLImzTDlEZU3VYkSJOY1UYR1Y5e18iNWtKXvIzcknDWM49aZZunUCaNWVlvUMiq4cnFYx19DGnjjsNVQmRKonnZEns94cmehoczhAq+lkS6Lo7cRZfubV9DmcWDSGMrfAJDea2RjC/1FtR18kq+P5zCpkeP1PDYpmx6EsHO2sWDPuTomt3SL+dz863kk8DbO/q4bemLFkxlJvLLc+zVPRsZh4T1qg+Lcs/lLbBkNTN8z+NShyeQA0cAMEQCIEkzL/EGbUJlvfM5f/BRYMr9PRw1LOVBK0zYrfZ1XPH5AiA9KKISoKPtEGxpu+nplm7xXgjKBQIFEHMKZpvsbw3prQ==;MIID4jANBgtghkgBhvprUAgBDgOCA88AMIIDygOCA4IACbl9OhBOrJmZagTY2meKGdbVtuRQe7kU/wfN7qmyOsGY1lsoa3V51TLOTRsc0NWpYg+F4vJmdOhKYFmUYrsJ+LCuhtlsBbYNqYcg9AmzSCLyNZGRDbfmSsMxrHtwHQyJ0IWpWY0hZKQeNzjWk7lcj4VbuCVYLlp1vu3bhT8s2SVsGdHyoiYGZlYJ3Ml3dIrkKE1dwKU6KFIAgJlQzqt0O27NuIbp139F1rjkiYBMaA82igk3BCurJC6NAyWcGaN9tspza7wG2PnzLKIZKWx2NlBUHSXqvTMrrsB29ofVv4fiC9grJ0sTsAQhbrBwb+oF8Tvai0UmCVIABnsYM5wi5Iuqw5cwulyCBupPeVkWGDlIWQXO7DV6RIusqLt3pmisUgHZ+D5Lag6qVlbsLJhs1kKixItvSBWwVqUuUbpMTiHoHgwdUGZ4jZr3j6FfMuBoeK5oR8Mvzug/lMBb6MWNH11quGXKF3I1fjpxRxAHzQ7ywZCXBjH/R66vTaB0C0sSwwVSKlGpDdrYix1EJ+yTJyrdhzNSzRRVnV0Lsx0EdPRxaH0CM5BUEnq0REa5TOSxJ4swMfnI1y1YnWhQgtL5RlOs/PvFKCrzlm3mYUGMnhyM52gSBTJpVKmRhQJRh2F3UoXHtSTsptH7YzWYsS8m7UiGVqiIRYRIUQ4sDOhAxMGXuflq9g1JHY11WUQi5pqFaLga5PsjuINagEFilSrkIXZoRjKalmsb5K4TuNE77FzuVRW29iydoHjNOEt7XfBK7ipUcmKlFLnMi6YJyXmcHMcelARWXRjZ8IQpRZohYS7lVX4lgZbe7U4a0vp0I2R3X50geUnUnnrMHBNHRvp62Ph5HyehZkBLeWcpKr4NR5jIx5p8wq+qcsrRkiXH+dnOKncYAigxonexTSgJTNOUewLBwEveFHusMAaDT1eWgmWZWQFuBckA1SwmcTkAUknObYGK0ai3kM8zv+oO5zKPNiNmqTlmjm9BNUZGc4AVezz2qCntBFoekHn1zLG8RiKW9SwZIJorInzbKDzZvHSL3RGTcI4XalGnBtD0GartYwO8OMhLyscFyrJzgZx3W23RIARqM7bMs/RWaQookm0zLS1xkgQAgBoL2iXgglOsDbIG4BEKvkCSucGUSXYIMA1opLZH11GewEdFRNI1linmszvmwX464DLz3n4ebowD+E7dA0IABNUNz/50Ec7PERnJeyDGKz0YhVKXJtp9sbKjcu2aCpfkRPZ6mi9SZdZoTfFg+y9cDuu1DQKPn0+ecoYdhAlH/EI=;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.15;MIIC2gOCAo0AOc7Y5dJKUUlO2GCqCklrAl3hdAsY1K2MFKB9Y+xvz86XUYdyrTO+nxiK6afR/ZY/nxzc0jiGiTmDbLW05YJ5E0ka3tNmUFjnL1jM05rF51uWZSAxSNKFTNig6gNG3LlvjA3uiGNLWJ0sktjiBkwuzsbUxfr+cnsf4nuaftz2OYqpPJaIHjlp4PIkWr3tS42Z7E1zJBfSnLE5zLF1eJ9NchSZV78VmIPb/05xCsW56ttBdCIXoli9SdSufJqj98xfnQ5EJKW3pu1lWQ9isZDQLMo/72Ejm0llMWVajK0z0f0m8nXBZGZZ3v0tgnZgqTc6TWlK4+QbiMHp+vcPJgYG8t0fHUOel2/+XX40YriekMGzmWiWPjNkSHRL8wmZu3+t92YmZ4xWpyTdjWJZ555CatRlC8Zn6Ipl3o6ze9Y41slzhJT2e5snM6y3FQJMv4chsaIw07gPYuMMjxMWxS/r3E1G8e/En2ZVNnKW5oefidOi037GvT5PfvrHvZzEtubtCUAb5Hz80nL0mlzZjMA7/Vw1MblPMySWWMs3yQ5aFzN4P981OElnGSVmC8ZJYYgJwauZm7RLxrBva082vRth13dbpz54XPlswya7bIr1kh4vGMLmxPphSqR6E3CC7zI+CTsLlp5OESV8f/OIbA4yQxw4y5/KwL48ZgYnl9BAo70MKbelmR2JmV93DQfFzcMXg+Oqz3ilpf0Vdtz99E4ehPYzRiCf9nubi9bHSIeyjqxWRwhEUcxUUwdAaggtPUznYz+uM3WAWD5fdVfIUJwM/CTYmeYTxe3N5KpJFvnxjZyu9DbD510H98FfiVHlZt7ywsTW7GoEy6Pz/94lxJc3G9rRDPgycQ4a00XpIANHADBEAiA4aPrA+ZZGCdgMqGokEjjdZrnpSumqF3PUaMAlvs5eNgIgJJ03i9H9gVPBIxOukmwydbDR7iZ6a6EOaCsE/d71XYk=;MIID4jANBgtghkgBhvprUAgBDwOCA88AMIIDygOCA4IACQuK5nX8gzhq+tUHfBYRLtrIBv4B30mh8pLxB8oTWFe3oJjOGyi/OxNZNYoc7/lEZkWzmLY3qxqKTtFkCFYtnBExj/NfyPiayYWJUcqbjJiVJI9gIxLqXwNO20SzFH9l8dlTbYy/t48KDHucIMb8kqGfuAwZQB9boc7C9pbfmzNQ8fMe37MSVDCEnCRisALMxFIPKbV4MDsQTrxJBaakoyjKRkLOkA1H62T1PCmOJBVhsfEQwgczFgmhCF9ixSFO9jhmUQWYafDR0FitbAmrE45QdpGyHUBxS0VQ9h5GY4KmCpTfZdTAPYx8sScrYboO9gVB1M1fuDmG0HcUkgq9h3S2UvcGkdY4yy3fXNbn+W6uwkVkTPeFp94lxKboco1gLdRRi3epIhYhQGHd7rdtqFsxZJsBu+pMynEXUA2wAleLxUk9GLMF7VvxejJ8dGdsu6DxxzN5TBaZJL0apCbnqdjRJkMfan5YEJckmBakzsR7ftKFjzb10s1Yf4dplrPJHjJtZpokUFFEhLLQgmqfWpoSp8Mz3wuX6q/7mJSQBrqxeJDA2W5e2omdBICzZmtVKFEbrVFSeksQ+7E4G3S1i+gpFTaKqWnBLELgVZdnVW0mfGefKL0YXt4mCNm4WKBjlCHV9Z1K/yRK3TpZziOYSwN4TSV0UHsH473BVqDjHJQYyZCYwRpLuHn6lXmAyVZq3eBWGSGhaCrnlZggiX7aOV0dtQHdFNS373kh6T8XZWBWS3z+lPIg111y3ddUQrwOyIuLGATZTJ7Qo68h/XQElLSGYSRhYF/WnIDIY+7Es3zjaEIgtahSLIaBITP56Yv1QCVliATSDmqUutDonfwIrnn6MN8heZ1mU9JiZXjwrer6WBESgrfXGUIvpaYmte5uDSmN82F9VM4wpMRWq1VsKnnNadvo4EXUa+JeKvm0KUA0tE9PpvlLCnKCD61youd9yWpLFNfYeRzWhBWbgyMkexgUXeV0JWFuqNAK4150jFzymfPXlZ+iJtcP4U5HhZ/glq7FLiR9CPMRmQpAmiSkwdOmxZMAWQCJtsUrCnoY7wnipyqi6YGAdJ154AuSc5zuJVYBdo31GbL1H/NG8sd60AX6qpFWJFHqn5qmZWR016RxgULqIh4LviIM4QxYSQpCHIjhFsBaRjRpdIfHbf0E+G1tNGad89ZwanN/xgw6CopeA0IABJE8dtM43I7ZwSS24NCx3NXUUBZ/p56SsqowpEyp8gpxYmoMx5OUf2YtqBJ4oVl4V5qz17VQ6CEepozceZedlHU=;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
+2.16.840.1.114027.80.8.1.16;MIIC2AOCApEAOcz175Bxb80uT1CkYk+hEIOMNaD5m8COQAhXLmICXQtx2dPGD1VIn+s+jc0dir49JyPIZL58hsSy9Ne6Laj5Q6csfnIdrCpsrwYy66CLstaNjvUvpPFDVL9vdJLxCxOrb2Dd54YGbt3UNJvQavRO4iXGVxgjIN45LDMhl06neDw2DqLKPRh0Mbj2QR+dFBtO/PNoMjLRGYBbMDDTHdbA3LYKSx2Qezn8YZ0l+7zieI6aqXVN0JC+GhNWRKz7Gq0RpUStn4zim6DZmLzCqRxWG12zix7uyf8HehZ2pGXHkOhOEDmdY+3axSwetEGz6HPiDWYSvjGYVy/K0gksbiI+7AH4cQUpuf5c4L15gQuOKBhUVuUueyJil0hqBj55Hrl1Zx3+1KrDCbP49ayCeR1hNqnkTKUw8WZOBG3dZstTDH5gTr2l3d5XstK81E1gIBSm8OolGjyB0iFiBc+201yYSPMkDKsK3+ediC1bAL/odZVHblJWT4rPb6u4F4rKXsa2nJ5Eae2xzCe1VTcxwF8TgrzZyvJ3Lh3bHEQOkuJl6tq25cD7RGPu+wcycuNcaF0xteo1kCNS2MbQAgRIE0x+eztYgeJJUw4nCR0jFPq8uQdmZpcWiXwq3TSozvXahSiEaFoHL+ZZ5yJQPjFEItZru/iSIzFGIil3U2jDzXwKn+deZnd9xcOVSN7du1j25v82tnoQqHMaIpg2b/ueduWv35DYRj59tgVRxiMpypQmzYbDhFIeBVuc2cjXYiDEc6Ak1bi36De7qUFHovw7Xl/tf6SZzE4EN2sa9dtmwqWPPgkZxIgiOWZ2h7NPHeGCdaUdkkM5r0yR52isbjVZPFTDY1qaoO+t3jNopbetPbcpNCADQQDMn8+g+5HDOOa/UxQ+ns+abXCdmBwf2SrL0qxJaepCyvfpxngANql5poulwsxnqDpumTuv9JTohB1o/79EoA4P;MIIDwTANBgtghkgBhvprUAgBEAOCA64AMIIDqQOCA4IACTde8oLllUMUAqy1d19MMKBwECmCDG7clZWRqH9cBOcQ210kf6zuiG/RlX2O43W8EhguAt2bbWAdrHTz6/NHSmRsN2ITGsAZaSVHIMIwX8pPBw9v9QSGdIU/HDietOu7QdzqUWFN8D3GY3cO4kC1BbYBvhXj5FEGTj35KbljNI6I7nJPWsInrD9L1iBVTpjVK2nmij9mPVcsJDKlDgoDj9d7LGxt5gfbf1ltYFKQZZ5j0l0pPEc8JQoug/bS4l2+VJMXA6atCQIjnkKsS3VGwK/ZClTw8+BsaRUq0T0UqMNlB1DlWh7Tq64SWptTnJwN9SPpFOBeCxDiuBrSCnBI+Kf/GzpPgV8nL6TuOG2CZnmkV04yltSqyb9D6IXLYJhNoLIr1k2qSgb4pJShy9kOVqTWJm+nB6ERxf5u8DLVN+KmZIC1eV5mkKVpPJah66HtXwtFW/PJxt2DLTLCq4OwOdLXlc/DEauNe5CH02eQEQQR52T3I3Zu+eNuNZnNDjUfDV4LGk1bLpBIrzw9mwPq1GYNTKLW4uyglXUSgdlGvhmXwotAbb8koXC6QMAXKB30Ai7sfiC4ydBVzJTRFJRgEGAENIFS905rKzbpOvtZj14sYWAZiqcZ2MrxzIprq8EsyfzSFYzBmBkbRhl1DhUYvICGQmCtufbAcCLGJ8eaSdZRCECma8lyq1WJmjPphbNpgzbzAHVCaYr0jNUTNG0x1k9YhnJU3bsizvxsPOlrxJANJ9ZCiO4fIY6sX/joYmOLTBLEuxfQKAKYgkbNxqiRJfErqYIpNp1bOK9HgDIiqejuXJqhIcX9qdgUDKhXAV8UqRR0evnpKwmJY/hnjnUX9r+xSW9WMY7gkH9nzJ1ZVOKmy6J8AWS4ngnlUgaBIcDipo2KMlA6T6wnVK0BpCndmyXj168orrj1Kblhae8LISwRhsNEQr30qd3jBZ78wUOS5haZVoJ2pky/tRKpeqUoomIa+8C+2c1yFBThYUymIe1ZCt6gTASO01KW1PFYTU2zVEsxeOkQY/tUgoD550YRQTKxMLqI9g+Fnz1vxqbmlThxmOogjgOcjtc2rCfTG84zi37K7F9x3jgtR/xF/olL+CTBi8o/ZxmjvbjZnmup3vpD8gkFJNk5UEE2dkLOPnmFE3DG1x8wBn97mi9fO0L5kDZQsy68fLognKmLDQ2i0eCXAyEA/QaYVysUj17vYWgQFEDzagbkM9dN+abW20JpEJNSSPs=;SGVsbG8sIGhvdyBhcmUgeW91IHRvZGF5PyA6KQ==
\ No newline at end of file
From 63acae91b92d67753033889e5bf7fdf89e7b587e Mon Sep 17 00:00:00 2001
From: Phil Brown
Date: Tue, 5 Mar 2024 14:56:13 -0500
Subject: [PATCH 0137/1846] Add targets for build-util and build-pkix.
---
ant/jdk18+.xml | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/ant/jdk18+.xml b/ant/jdk18+.xml
index 0240febb22..ce9441866c 100644
--- a/ant/jdk18+.xml
+++ b/ant/jdk18+.xml
@@ -107,6 +107,14 @@
+
+
+
+
+
+
+
+
From 22bab0c4157061729efc23e8262a1e564d406690 Mon Sep 17 00:00:00 2001
From: royb
Date: Tue, 5 Mar 2024 16:33:47 -0500
Subject: [PATCH 0138/1846] reverted otherInfo to null fixed exceptions added
testKEMVec() uses sntrup653 count 0 for testing no kdf (ss & ct)
---
.../ntruprime/SNTRUPrimeDecapsulatorSpi.java | 2 +-
.../ntruprime/SNTRUPrimeEncapsulatorSpi.java | 4 +-
.../provider/test/SNTRUPrimeKEMTest.java | 48 ++++++++++++++++++-
3 files changed, 50 insertions(+), 4 deletions(-)
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java
index 4a7c7b3139..847fd006e0 100644
--- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeDecapsulatorSpi.java
@@ -68,7 +68,7 @@ public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, Strin
}
catch (InvalidKeyException e)
{
- throw new RuntimeException(e);
+ throw new IllegalStateException(e);
}
}
byte[] secretKey = Arrays.copyOfRange(secret, from, to);
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java
index e5b7fceced..e15d83eed6 100644
--- a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntruprime/SNTRUPrimeEncapsulatorSpi.java
@@ -68,13 +68,13 @@ public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm)
}
catch (InvalidKeyException e)
{
- throw new RuntimeException(e);
+ throw new IllegalStateException(e);
}
}
secretKey = Arrays.copyOfRange(secret, from, to);
- return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, parameterSpec.getOtherInfo());
+ return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, null); //TODO: DER encoding for params
}
diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
index 33ed7d8485..05ec5c93e4 100644
--- a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
+++ b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
@@ -15,6 +15,8 @@
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
import org.bouncycastle.pqc.jcajce.spec.SNTRUPrimeParameterSpec;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
+import org.bouncycastle.util.test.FixedSecureRandom;
public class SNTRUPrimeKEMTest
@@ -27,7 +29,51 @@ public void setUp()
Security.addProvider(new BouncyCastlePQCProvider());
}
}
-
+
+ // Test for no KDF
+ public void testKEMVec()
+ throws Exception
+ {
+ Security.addProvider(new BouncyCastlePQCProvider());
+
+ // count 0
+// byte[] seed = Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1");
+// byte[] pk = Hex.decode("01031FE0C4328B956E9AFA7B5D86DE2CBF1F0728A1236F685DD2FD221ACDD05CAB64B01AF7A5F3C2837A5B7FE5FE31E366F7F04C5B77C1D6BD3B25A765A84CF9AA08FD9ABA3BB6A4B5C3504064D0803687A04F06B2BB5F7BB95AABF6CB823ACC6E74E98FC468C3E07BCAE284797221A8C8A16168A91A03D066F0EC93F26C8BB6E948BECB9919A72E0FB86F380F1F2C1A2EFCEF871D6ACE4F5E0AD226A80117F7CEEFE566193D872A9ABADB9873D3E9ABB0119CF4133D06F0DA9F0ECB6319CEE796F2FF5B85B4A6754AD4C94346E325BAFF9CC922561CF02B827E2A487ECE6A4AD9ABBDE1D81C218CD5D50A66B8E3EB9870C9F68457BC813A2D827EA7C87951439DD394DA1ED071E8AAEE175BDBFC5CE2ACDE12F78C9B82D9653B970F035A130A1DFBE5B2D4C186C909B9ADF4FB821B2FA21EC03D8D8E095D68F4CC12CEDBE1DE7428A201B04A9575BE758D58340E73602C3467876A4B18218C34A3126DBCC877144E4A42A45005217D9C50F38DBAFAC6477011DA1A1FC749F26B6C747DDADF1F1E4707440A34C22046A6145D3033408212254FBEFAE6A4FCF5AA41BA14EF3C6CA23F3E04CA53A5C2AA03C717A04E928E5DD392ADFBA921528E54944B4183ACBED4D21DFFA3F33D35B9679068B3711AC438F7CAF3042436A9C0BB296ED1C7891B7B782EAABFCE080BDC54CB4EAE3E75536171BF1235397ED37A4394D05D31D7274A1640C1B42912CD9AEBB6B323C370130A854E5BB2253D6F3CA7AFA061C241646C28A8D1EA7AACA73A028920C2BA5DC9EC21F1645B92B35FE810E024CB764CE53F611E61DFC62CEDD8BCD445870D50EBD4DD8021924CC366FADE330AC3826DBF43A328254C367B15718967D72EB4F7EC3BFB692B5BEF357BEF0974739400113F766922F3171964E303D255FE2453BE85AA7B9B9B6408D1655D475BE7EF0351273BC084C9E71B794FAC5C256E87CFEDE5FD8E03EC272B24675B947BB5C1711D894285E026221A152D19DDE65ED293710D195D31968D18E9E2ACF3A0BF5C9F4760B1C20DDCB49FD9A24A3027025A5C090C708E97CD0F273E89DD43180ABEAC4665478732683325406CFBF20BF3059AE57756FAF185612EC199424EC64EC444BC190F0FAA6B2E9A2D96E7814E2FC3BF673B87B7CEC8D6F3A814B5774CF95490E258F0B10269E1ADD8C1D1C4BDD5346ABD921CE3E02A2D051A95E56DFE9A0C655D926FCA45D445170498F6D0870BC8D3F444982E55DE23D59A385E1F18732F7D7F6526289C6659D4363009EBCDF2066411E49E3A8E3D6B312DDCC49169BBF9B13C827A88ACFD5B3E61A9116916F41052A3AAF50ABDA2E7CAA9DB7EA816F44C0F315CB86700F62E25E05C90294FBD55342D62BAFA8BA55BEE7B532D50CD947065E704E625");
+// byte[] sk = Hex.decode("5515559645A956544158655545514489451621815999295514A25949655418096985596A011900615556598565956A6866A916555455214551995455460640548011661525945242549500A515565165659455A52545A6A5445050A2054599A4659591541906682494418654A68A969155864655419119405555105595842994525415591649A569515155058551859A565A8854655454848415444169519555149656009A284AA0664A42991A8809015AA6555A54AA551010460084421102809A028A940502189698410446514812188888644650A081288196648158A61261A94A50908918A5810846011A9925260685A244404A0A585A0289066611A85A5A12408668A6A6591565185058559A18658821104418281602A994A6505012A82A662412A40255690122299A0954295A946110669299104014952500529294624041461249AA142A0201031FE0C4328B956E9AFA7B5D86DE2CBF1F0728A1236F685DD2FD221ACDD05CAB64B01AF7A5F3C2837A5B7FE5FE31E366F7F04C5B77C1D6BD3B25A765A84CF9AA08FD9ABA3BB6A4B5C3504064D0803687A04F06B2BB5F7BB95AABF6CB823ACC6E74E98FC468C3E07BCAE284797221A8C8A16168A91A03D066F0EC93F26C8BB6E948BECB9919A72E0FB86F380F1F2C1A2EFCEF871D6ACE4F5E0AD226A80117F7CEEFE566193D872A9ABADB9873D3E9ABB0119CF4133D06F0DA9F0ECB6319CEE796F2FF5B85B4A6754AD4C94346E325BAFF9CC922561CF02B827E2A487ECE6A4AD9ABBDE1D81C218CD5D50A66B8E3EB9870C9F68457BC813A2D827EA7C87951439DD394DA1ED071E8AAEE175BDBFC5CE2ACDE12F78C9B82D9653B970F035A130A1DFBE5B2D4C186C909B9ADF4FB821B2FA21EC03D8D8E095D68F4CC12CEDBE1DE7428A201B04A9575BE758D58340E73602C3467876A4B18218C34A3126DBCC877144E4A42A45005217D9C50F38DBAFAC6477011DA1A1FC749F26B6C747DDADF1F1E4707440A34C22046A6145D3033408212254FBEFAE6A4FCF5AA41BA14EF3C6CA23F3E04CA53A5C2AA03C717A04E928E5DD392ADFBA921528E54944B4183ACBED4D21DFFA3F33D35B9679068B3711AC438F7CAF3042436A9C0BB296ED1C7891B7B782EAABFCE080BDC54CB4EAE3E75536171BF1235397ED37A4394D05D31D7274A1640C1B42912CD9AEBB6B323C370130A854E5BB2253D6F3CA7AFA061C241646C28A8D1EA7AACA73A028920C2BA5DC9EC21F1645B92B35FE810E024CB764CE53F611E61DFC62CEDD8BCD445870D50EBD4DD8021924CC366FADE330AC3826DBF43A328254C367B15718967D72EB4F7EC3BFB692B5BEF357BEF0974739400113F766922F3171964E303D255FE2453BE85AA7B9B9B6408D1655D475BE7EF0351273BC084C9E71B794FAC5C256E87CFEDE5FD8E03EC272B24675B947BB5C1711D894285E026221A152D19DDE65ED293710D195D31968D18E9E2ACF3A0BF5C9F4760B1C20DDCB49FD9A24A3027025A5C090C708E97CD0F273E89DD43180ABEAC4665478732683325406CFBF20BF3059AE57756FAF185612EC199424EC64EC444BC190F0FAA6B2E9A2D96E7814E2FC3BF673B87B7CEC8D6F3A814B5774CF95490E258F0B10269E1ADD8C1D1C4BDD5346ABD921CE3E02A2D051A95E56DFE9A0C655D926FCA45D445170498F6D0870BC8D3F444982E55DE23D59A385E1F18732F7D7F6526289C6659D4363009EBCDF2066411E49E3A8E3D6B312DDCC49169BBF9B13C827A88ACFD5B3E61A9116916F41052A3AAF50ABDA2E7CAA9DB7EA816F44C0F315CB86700F62E25E05C90294FBD55342D62BAFA8BA55BEE7B532D50CD947065E704E62500D57230D15E762228DA98178A193D7D95284B20E82D74228146FDF68D59B37C5E7F78C0E14E7C40BD4F4D9CF0B189B69983DD39E29AA6439ECAB0A5B294D2A1216CE31CAC6D1B2358D2B0476C4D8002519B6D63639B2D4564E2458C8E06BDEEBE82262570777780F43B110A96547415A69A38EF0ECE0C2AF16B9CF11FF8326E2DE6DD0333B2EDE445AA3A1057824478BFC71FD00DEE601938734810D816F4DADD35F4C152B10CF13957945F8CC47FEF0CE3BDD1F0C5D8CD24B07E3F6D2A5D01717CFD06");
+ byte[] ct = Hex.decode("BC60F537CD5FE3038DACE613B8819A0DC920B8FE092474F763A1BD05F69137A1A084AA1A45A5BF1055F9340368D60CE415217C2C382E7EFFCD289D62A0A9E1E7FA2EFD07EF4B75B02DD436535AED897AECD520763AC7F8DFAFEBC122594388F210DF28DE472E748CFB640E8899B07CB4514401DEF9E9C542DC89733F20F9605F641DD1DD6F332DC051C2E5B2C391ACE70FD00FBC251EE1EA2AB27D165F966DA338F8AA970AAF66931F7CC68E2846EE5AD7EAF8E15B9CA333AD1260163E2BE2324C03094E249D3418164A655BD469E506F5B8420BF4FF6080DA230373B18D74AF03F11C9B545E3791CCC9B3B9927B2222983B7A6DE620BE8520B215ECDA45302695C0229C2A9607260BFD3C6EB9D7EAFAB5E47FD5760FA23067BAC1E6A980C4727B0C187A5B6397AC43D3BE24C42A1D2FCFE43512494A7BFC5CC19455DF6AA6F2698A2903831CA2E5F4F84442E6A74BC9D3CC3D6FBEE97D5CF4B6C58D3DC9ADB359FB56CF35FE21F96E885624498ACDF0BAF3A52B7F2564D1EA384DDA7FD32167786C5E010C3BCF5D2E7164BD6ECE815366887250D184F8061E57C3935214F191B38E982132EF4262E91808FF1CFD902B5248F6E7C031A98234DE0D578D1234B7453F2F575A88B622B0F11902C2146F45912E9BDAFA0846AF7B6789E621ABE3C65A4D990A96488B6307BE210887E82BBADFB026B60CA7DF3C9D429D8FEFCCC93A82E345F3B17756F6341F5DB3151974B1B9C7AC4AA33E80923475FE38FFC0AE7F47529360787AC283008971D87FB07369BAD111F1B99FAA59F2E1B5C088A5F31A47ED6A8E30FF6465A7DC79967EA78891C8EBD462D2566A4EA30EDFB8B7BEDD3C4E2ABFEEE7B366125A19B6372CEE2EB2F85514648AE920D292F444E6F90346DF87FD7C107848796219027BA581B3D87704FA8605108CA88ACF262C5C07D9BFB42635A1944634AF0633B471D0D2B2E4D6284894E0E48D58AE5D07E95130C9FBA77A0F124F9348E1A570BA0D009B7B46E03CEB201B17114B935AA91691A7F830346636FD34ECE2CC295D0124AD8CA76CC81E942C1607699F0DFFD3BDB509392FAF8212363F562554B05F756FF252765E6FCAFB04C6F2CF6A76F2E59E14F5BD4EA8E2ECF50B17E632F346D697FFB7AEB82ADDEF5B4DEC0DEE73D2D96B1A33C6AB4BCF7A160B79114A48F224FA037315ADF0485AB63DC2BF09F02606DAD80F13F0ED0241E6F53B21BBBE584794F77D0B783A7093F53AC916A848FF0F9FA3FB08A053C4");
+ byte[] ss = Hex.decode("2FFCE8C89E97BBA86A7ECD68088FB116A20601B88B8E88A3783CF2D2ED439769");
+
+ byte[] fixedRandomBytes = Hex.decode("7c9935a0912822144249e045d113b6e7cca2aa19b94d210a458e4c8dffc19aa7053095f130f12e7d79262cf801e5f36f63bf9ba079264c836bb02cd0a45a6dee06b7ccda4d18d429cfb5c7784eedcf12e28519d7da3ffcd65731b6d5b773204a55671a9d60940059720a74baa026a7777cd11dd3f81dbf836a06906d60aea820cdb70b606781805857448d6233a8e174b9c5e89cace15b40002c75a3b2c820a2846de5d6bf7c655a9b794d36e4eacbefaebadc20b9b7018c4fb60bb77f17d924db45bfbf74d2d052f8ec84b04cd70f6693f2eac613a0b55d9ad4d951d3808e66cd9d716ed9338a25aa41a9fdad9f7b46f10c6c8338bf52f8b4e2bf25e5e4071beb03e83b558e5db80a224da29951496268ae19980cea3c200e489eeeed9c16e2f0ac2d8daa9822958a84a0ba2fc08d4dba8fe84a3e60acab2183d1e795e74e58ee25a9e6d1fbcb30e564f9628bab26a674f9969d2625b7b7473c29bcc926486d1620bb9e9fcc107f1dded7c80189e7fa361fe8dd996b9c2d8f683847caa95d1542678bd200063bdb5757a4b6a72e8071b246df24fd5b30cf94eedef6ac59c892eebb3d4288fcf80182fc36db2946706dad5059ade4674341081ea63cd695aed3afcf51d66d01b5e61623d4fce329dc33835317f300dd58a9624153d0f8a25518c946046de3d55fb45a09396f4c8816c7f359a1999e32a4eba8d25920002f0bbf2e3b9850cd67f90fc11d1e3da7a9abf920d4007a952b77a9c9c1ac449abbdb1cd35ff17ef9182ed94b50e5b60c6400735362dfc37b59d23606e265aba4e88d617daff717c07b15d63c59e7e72aa19fe6f360ba4cae860c9045ad03dc845edaf2786583fb53bcdf05d21b336d25901204d7794cd3b7dddc30d28b5ac4563be1a6515d323d821ae873d0b6e5ff48dec06d8f9585ed64f0bcca2a353b64c7dcf0d6ae9084529a30db3a40163bf8acac48251c7f82b5ade896d66f15ed82850bb86689746b0144561a25634a8b2f5f62470990d4a67e105183d208ccfdb9ed024c52ffe5f0afd3219022e95d10289de8a31ce0666f8ab7ee89583ca70109d7bc4fde5922bbc35c31691d4874e0a3c9c2b9f3731029fb14c6533b650a31242a3b33002c01a2add52c76d828acfecb87193e28ea8fcc99f2cc2d51c7f512ace14f864749f20fa8c554db03c2d8fd1cb5a2274ec97a470e18783d2ba66165798d0b1c0652615e5b5cf9941474a66dda526c474c7c8d2189058db7f1cb6cc3687e5c6fe322aa8a615cefbf6abdf0a0c36cbb32a0a58183c460a692e2e89a21fa709aa3da00270c6e7368b1a0178459c96c2c539074a72f7d1867a6aa8d9f545cd270930bb05c99a8c394357b0377eb66f90529882093cb5cd5b8ad08f538966fab56c5a29883214009c76d69de18aabbbc4f5cb757e8b5422d5d7869e91e3850ddbec01bc40ed11b2134d40d109508d812e7b7be26278c585a1703e935737ae3bff4ebf9bfa383ebba7e2f7d0fb9f4b78479a70c6a6d1c0394919fd1cda8600fd284418d6f4d3cae2b213f4078df0de5a860a23738fd7f85450f3d7f9903b306f863c7808296419c06a4a12a6149a0b699719aa762ba72f0a052e971b58ac97185ec95a5b8784b60355f163c4dbea0b1fea3e8e5f23eef6abbfc155846052f396d5d97731678e48ad0668391935a6594fabd5b33440b647f343601e909a3926719bae73df1cd6af5904bce016a4934b27b01b45288ab1c13a3d72531ad31adc304e7d38291b35e2f8c3cfc153127d5465a8b953a3af7f7e5cdc22174919e50d7c195cf5a7463facc8f17baf75118259bbf5316369bd70c7211a240def65fa94dfb58f3984985b9815e32c3591c93cc9fc47e75ebac8aa0044681e34791a1b847068386520e36bdba90735c870a3cc9fc8b7be1c084d4200c5f02b7476cc7c406e1b8335c4b3e05a98f6567a942a0dddf9d0c4e26a700454b34a6f174c776978dbb7c18c40070ab899752040fa824ccf63d31f15f7f86c44905e4898f0ed731becc9d20b9b35b92a57de9f5e42c38842ae6c7d94c8b246825f8d722db09b138db117d112968ebd1ff4bb835bff94cfed81fe6f22915d2e0ce4bd1cd743788ac146fe4aa7e2ed023f88e8f96715c97548bbaf0549f1e38fc16ca351206745e7ebb59649e9e534c1633289f8cb0071bbdee509cb131bcc7f26d3b548c17fd413a3a3101583b18f3335e0380098a3cfba480f7e0ff0b606c03338790d6d2e5b2307edfc311721f1587ca55501f4b4b5aeab9773ef78f27c40e8a42bcb57c887f99a6d56be4647f12a52367936bf3b63bea50319990cb58436a5dfb819c09c27299e778a68347f40ef386c6ae97e25f9fdfb7da6b8c6efd04ec9eb83e6cf431b2661a29f4203b286d4dfd860aed5eb5456b8e4a5b9cba46fdfa83aea1e043b3182784c8cef3feeee0343be2ff4d5cfae8c202049a53a20b35fdc1c82e7b246ad7cc7e0a2b05368d873d948284a206d12ff366456ecb1123a121c8d2eaa53a423aa6b4e4c36257b7a18d1ebdb28c0f5a76a3938cbff7b0e1b43dc5237a3fa7b6266bcfba4ee44d7ca17a84e0a97d8f4baf6b9843af217d5275e07336413a3a0790856b8a25c67f6d2822dd85120dc18d70d6ffa1501b3880d036876322c1769f08bb767e9c6a7948e9e8d87ba0fad66ed655973ce1bccb8dedd9c7f2c80250769e247ce679126cb3f2fe64ae05110691ea91626d8ea26f4cf674626e62850e4523ebbfef5a926c90d9d33fa67f6bc50d35737801604e5f5b119e08c306ba7b0c09f79f871e10b2261cd8f489ccc14bc17ace710a407e0ae21732192ab6febcf4d58c53ca415f0d53e4746267874ee026106209cf1ca11099ef5e59122f4cf17d50131d0197d3b7a1fbde22d3d40635b106b27315e033e2d8e8a0cd45ba504848b470cfb1fc78d47f65226cf0968aa51fd62568b9108adffcc25193d747e735dd5e06766ee213f5ae9032ddb28cfcef714ade717c9d18b7d63e4fc057ef88fcc0894a23d36f2aa16dd530086239279cdbe14764656bc51f78f4d448c38320e32e110bbe4e90bbcf11d924563469001ea8561f5710352f44619ca1c2f108d021f520008b542071ca87c936bbd87cf42c3a06e10976cd82e074974601ad86662b283ef5d2fd63486a98acc91758160a5e008333ad3b365be36836a196643b4136fbec90ef50bb944cb17ee0b55adc5a60dd81809e74d3f4ab5751a4c1b94fe7082f86c6935b867d15bc27328c3a7d9e5215fc8a2fc7f3d088446353ec9c92d3b5d01fa372540d1de064ea02030a300eaf73eb4eb40e5b2ec2b0c6d3d52f63369bdcc63d268a065e18aeee15474393c08eebfcb9d2a795e5422fd50fd099f85759966ba28127bf5b1eae0851b5c567c23ac33469791cbf78e827f98c4269b997008ac745188aa2a77cddd83574858a7a321f46cb0db5b89b100318c818500dd4d5a8aaf16c38bf32831099cac8b121e191ea8c50573f395bc70753839643e602b3b2242eaba726ec243a643392df202c6fde7e8436609969436aa1707fee35a08e0aafdfcd6471db08b9814e4547689f04e5f8b918fc0a8fd82784865ef5cbcc53da7e2fb1adc45e5a429833003b159edd94f3e1400b784181c81a270517c22fcaa0fd7286adafe160b3b17495ca6186e7e15c878be4c228cb5f79a4d940dbdfaf94392aec9aaa252c9eb0b58dded996e081fc1bad2a7a229f715b4690d8871ae7b086961f7b7d44e1f9a2bd093042919d0543007e29e222c057540f0ead016575771f85811d93583af887ca5f8094c9274b4b933f528788661c9eac7d6f736024051df17028b8d06f4ca6d33dcef7fcb6cb4a063b764706fd0d457c6119b6ce77fe47d40881bbc41d5fc042717fe4b599132af01cdb6032fcec422410c071f3d83eae54264ac430927e85a468308f96dfa26ede5fa047df6d63fadfd3861bd3507ae199274d6e0b3e329a10a58cef6535747ee4a6c5ca9ec10a39f2acff29a33b82d09b899d6c4c1271ac8e6721c0c77dbb6af1b4b4cb7fca8dfb716a76f6f587950d2ae419c4bfcdfbfe4fc08605627964b126c39ded0e22260c7450b7ae8e9397a27ad0f614577524224eed1976a085dbc1889d2495ce1b94a32153d9e433b27beecbd7e87a411248aeadb5c6d155148336bb55f23bfec0efc2d32463b46c2293206137ded47fe3c1cc7f64e135222308209640dadff7c9da43f9939894b7a67c298d7a790a5ec56391076f8c9518d85aa1d5df44cf3043c15ceaf489e6b7eeaad05907373c4fd7a16a4982299b66791d3436ddbdf438bfd98e2d94f0d41835c604b992d69249d798fc66ff358905dc801c79d60ae1a498898a7faded0502cbb751bb56ec28ce4069b4531c7c20c7dcdba2b0f21691bc776d7eb4295124f8411832f8941229c43b0881aee44425f6eb418143ed19d1fe79fe55cb5744259a4bc13c3512227c06a8c42563c9951516327ea8e90b9f4313e146e8b452814a93fac4564ea1bcd51360c8d19bbc07331ee161bff595e330397dfa532b2b2d25a428a999bf9b357335196ad4a7d7d2db12ca056549223039379aaaf5f89d281e04e986f5dba96ecaee589032db3d66118e4ce169a6a3034394baec899bc5eab4385973728be47fbdaba1d6cf6db50d77d394306727244eca23f2b68af3e38d275799bc81c840fd425e06d516cc33ca100c0d704ba1606ef4199d1b47d9a756a171309746ba0cdf48e9a0ee457cfe19a99d4112405d3318968ca97e13f72f271df0a5b487b3c5869fdddc6d53c1e7190ebcccad22f5d52bb99780a1887ac2fa0b933a0ca708ab7f20e1bb46ec6238351ecfee46cb42bb574270b46f4a3626ba8af5b5b3c96ccb7f1acd772b13277412fdd4ea740f8c6ea0d2383377115f8d17c095b8325ffc82ce966150413de37d622bc426c3f8ceb1cde12069e3c41e90d248ac627be702482c4efb2f028e2b2a607e2bbff190ddb710d7e36a7811621baab0f134434c254cbef59e86af197b6289e72d24714ca1ea3784bacb250676a778bf9d6ce2549799af999b917c8df2db58ec799ad51f10d0bd3707aa5f3c3aca8b8a105914825e6b78709eed6190de883b34bfe6f4bd0c91001a5a5d168a5212c95ec4ba15c700c937fd359e401899e56e3db259da628943951e8b2a366c94ec46b9f6b5d4da72943ba738d662d2cdb4fef6091ead96cc74d272c4c89077765ab6e93cafc737c82ab30b13b40d14c595d7a5efe4e89cccfb81275776c2b8df49db7c37f8a149a1a53703a255095021c125679d6929d8b46de63254204b79f43bef2f2bd7f0e2143de50616e19346239acb7db9a980baf1f212d2c26c69fae7d759c46da0aa97f443031d06f8b6a85794ec9fc778d30f08a4292a5e13488767741ff120121e0037c3830d32b6181008b47a8d48126af48719a7e7396ca1d6e787fba426a54410364baf076426f4c72dbddf964e5dc617bebfe8d381320150ec065cdd87288245115a18ded71c70b06cc02bdae6d695cbbb5b3d8a2aa16cdf80d84d511ac1b754f472f66ea6c5e312b4c67a66067e1f9d32de4d1d14c4c4e2cab3f40c2895c18a56b94fa40b75641723e7c147a594c89511956f046f0fbd26f3d3814c13ab717c7e164bdc9f8c0e5ca120724989897db7def83513e8325176d04a774021ba934b174af4b063e8764a8cf7c81822f8eb2c5870ad4b876051fe5c18c352cc03b885f74c65d22a5f9eb0fa399782ad33639c0ade4a2c1ff3ceab622373b98410f25c3de2d570f847fcb8492ba5b06661287a4e09af59374ccd9d080fcbce8ece50bc61c96d3b5ecfada0a974f04329d6f245083c3e7d49e7c59e2cc437de2add8bde7518f0b8961c7565705cafa86ff93a9f3fe8d22a7f76446e4e26a7534f8714081433b4f5c95d68a1cd7bf0e5cd74adfadc851287f9ac437cf0c67d3c5e7bfd49fb44f4277b860d657035303cb2d872fe8530e406d3607e3e33b45f47a8a42a229362cb0208cd5de79a7c0069b7fa8263c606b2f80b66d7562d975b9f096fe599cd28ba85521cd123f665d6c101665af1d4f6c850e28b3ee8b8f74d2c63e7331a55edea8024059810071122e0f8ec7c3776a148a28a987e2db7eef4f493c4e69e20f2ce2caeb305a23bede1aff4bcd706f87be91340d48eee4f8ea2fa7f496e882ee68c9f60daac3ef08c95452d936a8762d15a47659e4a791b03ab52cd0407cbe3677b4cb3b9c2d3f19b8f21250b28abfe1eb6c4e4bc92014fc4f10b165a594c30131f571aceb009e5574219584e2fd3f3281bd6156697e8347bffb50c3b699807bff24fabf9a7ced1d796078dce628d3ae6445b81c8fb6a633b9f25dd4d25a5a6d64b8af3c71c5b392822aa9e5748f3ce90b0c44f7857ec8dbe90d15c9b31152430b245139da98c63cf1efb6d89c674b15e51d30a282f779a6dc4b23a5e546fcf8cb0bdabaf6640651b98b6e8c7afc5c084938ef0d099f87466cd1648cb9aff11054c70ebd8921e459d6245b89ea05cc218d48c331e3138a7613a1500dbdc8b5077e9063b39a4a6aa8971e910228f026d3437b1344dc8f746bcc34a94605fa855200afc964565df617bd3c04d4998c162623cc4975fdea827256f8f61da092fef0e4a3023a03c6aa606579111dc80c118a470b9a690409b125cee61d64472d40eec1c222cffe7c3a59f8a00fe2fe51b072644af0be728bbf948f2848d1371b34d09f0fcf3fcc31d084ad69d7edc2e1aff6651f7f0123e1a83c44891567a34357b114e060e82464d18cb73a2e7e2b5f604c09938eb06df26a0141a55e7fc84f219c7728b022ecba2f1c71266a5e6aa7bd784a8c6e0db32b53cc03aa500fff71b06855acf22b8335531655fa414693b3fe9a320a98781ca9f60b955b3817f54873915ad3fcc843b172a4cbc5d3091dc4b301b4417a391b66895ee37ab81a6fe186fcf6ee7f61fe3b89556edda3130153e2562aa190be6994ef738fab5c2dda559e63f4b5b1f08faecf5e3cd9afc5d6336c45273ad5f93dd26d0894e2dc587f7fc1b26ea6b2428e55f07d9e175fdf9d9e0b58df7e169079cf203f21e5aafcd3a7710a0259d87be594ba30bcb2a6a2e26b28f499c3145889198e5aef16fafdbd1c440c300d83100d11d0a0647f0066608e847b6b109e9853b2549ffae9498ab5042823f0fe0ab248ca6ef9de115ecec752dcd1bf2e4e55e79cc0d17866c97ddff73f7e35eb598e60ecc8ac4cab0db57c948aca8750b1543bc926d2cd7a6239a683cba85400d0bcad56e943a4f614bea94990bc426e1eae75046b6baed05a59bf0084eb777d824d0d212e9819e2ea7db881c44fbb85bc374a0d6235f8392a3d9a761a5747d75d96cdc3c8dd7272eade200d57230d15e762228da98178a193d7d95284b20e82d74228146fdf68d59b37c5e7f78c0e14e7c40bd4f4d9cf0b189b69983dd39e29aa6439ecab0a5b294d2a1216ce31cac6d1b2358d2b0476c4d8002519b6d63639b2d4564e2458c8e06bdeebe82262570777780f43b110a96547415a69a38ef0ece0c2af16b9cf11ff8326e2de6dd0333b2ede445aa3a1057824478bfc71fd00dee601938734810d816f4dadd35f4c130598b9678682552d0d9bbf0116e52f71e30f449c6e70b673af7186d562e4591cfb9fcc9c591cfa471b8e3ea987e8e6b5f57d6ea8dd522e74d63169f343b20f9816236320cb16a04fc7b629e6240bc1686651f69bf37db30dde39875d57beccdc24c9d5575b0bb0b86f6d2e06f857152874f3a9034cb6018c5f83c55665f22a4195cb93fde9d0294d0769969423c54cdea07300e6f2bcda80f8e35f2631ceddbe3d29cfbb81a94d60b576e5c471ae1dacac226e9178369177bae4f33fec7b710b587ce317d3781e5fa8bae55167b7b93cdd061782786fe574fb7296b7c338edcd16642149ef44e694f8d30eb602193457a9956acb38b8ffdbf22b7bd93bda15b79cf2ed4c8e4606052696fbf38a852bef0ef9e8cecc8faa42493ff945a0b6cf235f7a64b03e4cf567ffe3687b6208c42c7df3272008f9c57ef92801444faf4932120223aa8882a57ed3cd8fdce71fe4ac4ea41dec00b74c0310d25260e0f95a4b89b5cd96ae446b33bc433181db39d0b4e48de172186f9c50ef7ac72adaebb2202b358a1250070349c66516d7f5d895ecf2dec601759abe52e2c7fec904db0b8a4390a4f8367db536a6a1eedc4435a6de58b62b3d4a946061b77adc10d21535a026657ec07ce19d9e097f93da31ef963ec7cfb971edaa8acea7537f5280b51188d88de355a79408f5c1fac07234ef9629ee992abfc874b33572362b95722ff1714cc238c68be7850c3bfa7bb5bf2c41122192cea2783f79cb558a65198c93a6009fd3102ed3d7cf677c5c632ec1a31abc087e2ab717c9abd04caf709a3855ddbfb70a81099f22ec5f49f3122e6633882f813bb76e2597670e37f36240e00a75b4b90a132cf2b4a652269ab8be1697087fa262593a16639f496edb72b0c906eee57a219c51dd548a697295bfac80d400d834c486a7642aab0d12aa4617abf1f604b5d6c9cf40c57fc8454761ba7fe54cebd8ec43daa495a6feba2e7524b6b771348100b3af4eb145642d006c3acf26262f8de8a6465f4eef60bea55615c19c50790daa8a0a39d42d66f89e4e6e3a5029cda85b50bb256ce3c57ee6aed2ae47db1d10b05bea586992a0b3a282d36d7c8d254badfa4a8b7f91d0fef5bc971b99b7c2d0aaf904a42b11139cc22d6450b6467c9453f1392193fd16b9aa565c757fa9457a9723fbfc6ce3b2f8381f0393b4eb984068adb273a50ccbe4e8fb708902179e0b8d645481a7f3919e07f758cfd12a3496bdd5b063d99ef127cb36dffefc4a29c23e63da9f4ab05a20faf7d73d70c619d48a92c653d415b7a9aca0c499937fd2acc6b1e6842d5f15c00bfa3b1d1c1655f8601c13f94291bcf76979b2c45d30384e4ce99a60ec088c9328a393581a8bf247609e5f9f025d98df1ed6c25ed4d6dfc67c98ec93b9158e7ccb8e8a50f4548479444ca7386ae077140d8a26459123dc28c9bcd531e3287f74cea298cd4f475c45e51792e439ba4368171a5ff60656c1ec132ce5affd6814f5f0fd786b15479a8bd2d2d3874bae96ab58e3b603bb251746b67bd00bb210f3d00e3725ad2a9441a11c8d320aa18e83383815f1eae1a7f195034f9dfe7ff7c4fd84acb7c2e22ec131d928e425cf96b64b562de90593cd61f237c11e2a4fc33a7f5333e1c6085a8f0d393e346646f36b3c4767c3681ce53c75414d72c57121fb10ac3f0eb8b784794cf2dcafcf0fe0c7b003d6171c20a3d63b44d168ef4bb79da894b5555c6f69a4d6e82fa558526e1bb75c63dc8e0fcbe3b9d462c0933eec9f034d4e917f30d48e98a93755c7c8771648711b81e5cb6f4e30680b7ce662cee5c8a02df4d1cc8f6aef8e632eaa09474321f231b7ed4cc9ba2a993693f4169b7752402bea7309d0412c9269799914894ebfaa9785716406225a18101a6f393dad47dc052c45bcad6f8bad49f108d6d179588d1c08db51ec9a50ce2702c9ecc1f9ad68633060579801e2d131d1044effa20ac6fe815f15d64e900c7d72d57ce8a398ac34119490d71b1058ffc111e089617145d592119352203f341c0ba91941455c29d5c253bd219bfed0d556212098a969a38b6d561be89635273ae7e4531210dd7b0d0310f2806a6e7a46c9f908c19862f9e05206d8408b246f4b8a508b9e78824cb9da63e4b6fcc2bdc9c391f2d4b9e3008dba425a937e025130b7cdd946dafe43e3a18f7331c04e063df4ee19cdd09e2c652acf3f4ced146b3b38f0fb8f8dae0f9fb1f87881cb1e7cbe6c33da4b704f03921810fbf3368a11c3014d2a4bfca1396ed43b3c3a3c6de41ee3740d40eb28983b2967f74a5a2a0515f68f70f4746dc94f29607f14b671c088df491386a38cc6f9765cc9b2ac7e91d80a2506624a9b0864aea397eddf2a9647d6f42cbdc68f4e8667f3d5614faf151b94acde040329ebcacd4d6ad474306c990998423ad8fb307e4a47e4e73463d913c812e3316a77bf238b89f69178dc0924253c110ca5396095d7c1689526e1cbf8dadb924f19df73aa7c97b59e013d6c4ddc687e06e10f82c7aeb21011e931222a777ab3a87759cb893b380ce15a22491ef3dacf62512e3d0561a137aa294d981601813767e44decfff7e84b4c33d6d73022f20faea96ce49976f75c85b390bfdd508a8c2a1f77681add20cfb715fffef359dda3e824d607ae19f298d7323210b7bd3fa6db1bdbdf613d13b6b7ef349278eabd1ec4ae836ad0307e3f5956e753b39c5edb973a6f90012962e3bb75f673461c211e711109320152825f5c9fe4b516f85eb0ba33e8719843f1ca4c965bacdf870dcd53dc05ea444696c615be7cb9214235f008b4c458fd0cff1b313e3433eed9ac1495785a57c4da01fded6650a61d29cecd2462a84faea9b689d050021f4b7d883edb39ad74a5eeec5a898f73f40fff5b74948fbf96ad6afd14d48a2f4b15782d163f219b069f2da414905b5b97576f4486fea35e93d2aaa4b41afeff1db600782acd9658479c960603aaaccf3fdb10bbe916936ca4526e2a3751ecef7abe2500bf18512d52006bc80c2fe5481727125e0a27d4342f3046e626b753b40eb210dbd64c8f67059fbe0c93146d09f30550cd33f3d03986f842a9421f07fc94f09ca898526e4cd51ba9b268beffeaa5f381c59964b5ca8b04918433b9229080b54be25920c8c3ddfa2b98d5c095a6800c1d3d03c8b30e989198fc96c3c8dae0d8d2ca09365d23c9e46abb40591d30817eb8e33985dedd0387b3ddc66fb655d37e41efbad4c05af86ce280afa66e591a619bf9236e5b7b7b31bdc87f63257aa652630afbe9ad8363750c04042c43ad5f392076f7481b3ca6b3dd83d7e87c604f8b08b0f13234fe8d8e5ab60756ae91d0d69eb144a3db813dd6095bcbee564b04a713152e40cf86285c1d51088832d18184b90f8db1d7e7d55bc79a2178b833523e0af31c027172271477162fc13d848d082b37bd1fc5700383cbb36ccc550ee3ec492266f9a86075bb32171abab9a335317d47a85de18d44809c6fbdbe76d2e5a5aec7cf00250eb24f453038b89e6cddb09e646676419c252e14f0d661f85747cc17f67732ca487012c3bb8ca822a9518695e68620af1ee12d2c6e48e0775128992922364c7bef20448e44025d399918109fc3ecc93f1c57c04be4409df78823aa4f098e3883282d7f9cbdac7aaa49dc8795c67578c862a0e45097499bbdf0b0e37");
+ FixedSecureRandom fixedRandom = new FixedSecureRandom(fixedRandomBytes);
+
+ // Receiver side
+ KeyPairGenerator g = KeyPairGenerator.getInstance("SNTRUPrime");
+ g.initialize(SNTRUPrimeParameterSpec.sntrup653, fixedRandom);
+ KeyPair kp = g.generateKeyPair();
+ BCSNTRUPrimePublicKey pkR = (BCSNTRUPrimePublicKey) kp.getPublic();
+
+ // Sender side
+ KEM kemS = KEM.getInstance("SNTRUPrime"); //Should the name be "SNTRUPrime-KEM" ?
+ KTSParameterSpec ktsSpec = null;
+ KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsSpec, fixedRandom);
+ KEM.Encapsulated enc = e.encapsulate();
+ SecretKey secS = enc.key();
+ byte[] em = enc.encapsulation();
+ byte[] params = enc.params();
+
+ assertTrue(Arrays.areEqual(em, ct));
+ assertTrue(Arrays.areEqual(enc.key().getEncoded(), ss));
+
+ // Receiver side
+ KEM kemR = KEM.getInstance("SNTRUPrime");
+ KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec);
+ SecretKey secR = d.decapsulate(em);
+
+ // secS and secR will be identical
+ assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
+ assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
+
+ }
public void testKEM()
throws Exception
{
From f85dda0785319af0ba39883760dc9e03a95d70df Mon Sep 17 00:00:00 2001
From: royb
Date: Tue, 5 Mar 2024 18:03:26 -0500
Subject: [PATCH 0139/1846] excluded broken mls test (waiting for fixed tests)
---
.../bouncycastle/mls/test/ClientVectorTest.java | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java b/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java
index 4b96ccc867..28fb0f13d9 100644
--- a/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java
+++ b/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java
@@ -57,14 +57,15 @@ public void testPassiveClientWelcome() throws Exception
{
runPassiveClientTest("passive-client-welcome.txt");
}
- public void testPassiveClientRandom() throws Exception
- {
- runPassiveClientTest("passive-client-random.txt");
- }
- public void testPassiveClientHandlingCommit() throws Exception
- {
- runPassiveClientTest("passive-client-handling-commit.txt");
- }
+ //TODO: Replace with new test vectors when available
+// public void testPassiveClientRandom() throws Exception
+// {
+// runPassiveClientTest("passive-client-random.txt");
+// }
+// public void testPassiveClientHandlingCommit() throws Exception
+// {
+// runPassiveClientTest("passive-client-handling-commit.txt");
+// }
private void runPassiveClientTest(String filename)
throws Exception
From 603c88eab46541d21f1587b3585dc29f6a73107a Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 6 Mar 2024 13:35:32 +1100
Subject: [PATCH 0140/1846] fixed unknown type error
---
.../bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
index 05ec5c93e4..bee58d3d5f 100644
--- a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
+++ b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
@@ -14,6 +14,7 @@
import org.bouncycastle.jcajce.spec.KTSParameterSpec;
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
import org.bouncycastle.pqc.jcajce.spec.SNTRUPrimeParameterSpec;
+import org.bouncycastle.pqc.jcajce.interfaces.SNTRUPrimeKey;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.FixedSecureRandom;
@@ -50,7 +51,7 @@ public void testKEMVec()
KeyPairGenerator g = KeyPairGenerator.getInstance("SNTRUPrime");
g.initialize(SNTRUPrimeParameterSpec.sntrup653, fixedRandom);
KeyPair kp = g.generateKeyPair();
- BCSNTRUPrimePublicKey pkR = (BCSNTRUPrimePublicKey) kp.getPublic();
+ SNTRUPrimeKey pkR = (SNTRUPrimeKey)kp.getPublic();
// Sender side
KEM kemS = KEM.getInstance("SNTRUPrime"); //Should the name be "SNTRUPrime-KEM" ?
From c929cacc4a3ea68b42eca8040b8cfa89bec367bd Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 6 Mar 2024 14:37:23 +1100
Subject: [PATCH 0141/1846] added missing cast...
---
.../bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
index bee58d3d5f..e20c3838dd 100644
--- a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
+++ b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/SNTRUPrimeKEMTest.java
@@ -56,7 +56,7 @@ public void testKEMVec()
// Sender side
KEM kemS = KEM.getInstance("SNTRUPrime"); //Should the name be "SNTRUPrime-KEM" ?
KTSParameterSpec ktsSpec = null;
- KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsSpec, fixedRandom);
+ KEM.Encapsulator e = kemS.newEncapsulator((PublicKey)pkR, ktsSpec, fixedRandom);
KEM.Encapsulated enc = e.encapsulate();
SecretKey secS = enc.key();
byte[] em = enc.encapsulation();
From 30a7eb7a90c9a79cf04a99c543716d76545443e1 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 6 Mar 2024 15:05:29 +1100
Subject: [PATCH 0142/1846] move of oiw, cryptlib and mozilla to util package
---
.../asn1/pkcs/RSAESOAEPparams.java | 2 +-
.../asn1/pkcs/RSASSAPSSparams.java | 2 +-
.../asn1/x9/ECNamedCurveTable.java | 2 +-
.../crypto/ec/CustomNamedCurves.java | 2 +-
.../util/AlgorithmIdentifierFactory.java | 6 +-
.../crypto/util/CipherFactory.java | 2 +-
.../util/CipherKeyGeneratorFactory.java | 2 +-
.../crypto/util/PrivateKeyFactory.java | 4 +-
.../crypto/util/PublicKeyFactory.java | 4 +-
.../cryptlib/CryptlibObjectIdentifiers.java | 12 ++++
.../internal/asn1/oiw/ElGamalParameter.java | 68 +++++++++++++++++++
.../asn1/oiw/OIWObjectIdentifiers.java | 50 ++++++++++++++
.../bouncycastle/pqc/crypto/util/Utils.java | 2 +-
.../bouncycastle/pqc/crypto/util/Utils.java | 2 +-
.../bouncycastle/pqc/crypto/util/Utils.java | 2 +-
.../asn1/test/BiometricDataUnitTest.java | 2 +-
.../asn1/test/GenerationTest.java | 4 +-
.../asn1/test/GetInstanceTest.java | 6 +-
.../pqc/crypto/test/CrystalsKyberTest.java | 2 +-
.../pqc/crypto/test/NTRUTest.java | 2 +-
.../pqc/crypto/test/NewHopeTest.java | 2 +-
prov/src/main/ext-jdk1.9/module-info.java | 3 -
.../jcajce/provider/asymmetric/ElGamal.java | 2 +-
.../jcajce/provider/asymmetric/RSA.java | 2 +-
.../provider/asymmetric/dsa/DSAUtil.java | 2 +-
.../elgamal/AlgorithmParametersSpi.java | 2 +-
.../elgamal/BCElGamalPrivateKey.java | 4 +-
.../elgamal/BCElGamalPublicKey.java | 4 +-
.../asymmetric/elgamal/KeyFactorySpi.java | 2 +-
.../asymmetric/rsa/DigestSignatureSpi.java | 2 +-
.../asymmetric/util/BaseAgreementSpi.java | 2 +-
.../provider/asymmetric/util/DESUtil.java | 2 +-
.../asymmetric/x509/X509SignatureUtil.java | 3 +-
.../jcajce/provider/digest/SHA1.java | 2 +-
.../keystore/bcfks/BcFKSKeyStoreSpi.java | 4 +-
.../keystore/pkcs12/PKCS12KeyStoreSpi.java | 2 +-
.../jcajce/provider/symmetric/DES.java | 2 +-
.../jcajce/provider/symmetric/DESede.java | 2 +-
.../jcajce/provider/util/DigestFactory.java | 2 +-
.../bouncycastle/jcajce/util/JcaJceUtils.java | 2 +-
.../jcajce/util/MessageDigestUtils.java | 2 +-
.../jce/PKCS10CertificationRequest.java | 2 +-
.../jce/provider/JCEElGamalPrivateKey.java | 4 +-
.../jce/provider/JCEElGamalPublicKey.java | 4 +-
.../provider/ProvOcspRevocationChecker.java | 4 +-
.../jce/provider/ProvRevocationChecker.java | 6 +-
.../jce/provider/X509SignatureUtil.java | 2 +-
.../pqc/jcajce/provider/mceliece/Utils.java | 2 +-
.../java/org/bouncycastle/x509/X509Util.java | 2 +-
.../asymmetric/rsa/DigestSignatureSpi.java | 2 +-
.../asymmetric/x509/SignatureUtil.java | 2 +-
.../asymmetric/x509/X509SignatureUtil.java | 2 +-
.../org/bouncycastle/x509/X509Util.java | 2 +-
.../asymmetric/x509/SignatureUtil.java | 2 +-
.../asymmetric/x509/X509SignatureUtil.java | 2 +-
.../keystore/bcfks/BcFKSKeyStoreSpi.java | 2 +-
.../jce/PKCS10CertificationRequest.java | 2 +-
.../org/bouncycastle/x509/X509Util.java | 2 +-
.../keystore/bcfks/BcFKSKeyStoreSpi.java | 2 +-
.../jce/provider/X509SignatureUtil.java | 2 +-
prov/src/main/jdk1.9/module-info.java | 3 -
.../jce/provider/test/RSATest.java | 2 +-
.../cryptlib/CryptlibObjectIdentifiers.java | 0
.../asn1/mozilla/PublicKeyAndChallenge.java | 0
.../mozilla/SignedPublicKeyAndChallenge.java | 0
.../asn1/oiw/ElGamalParameter.java | 0
.../asn1/oiw/OIWObjectIdentifiers.java | 0
util/src/main/jdk1.9/module-info.java | 3 +
68 files changed, 203 insertions(+), 81 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/cryptlib/CryptlibObjectIdentifiers.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/oiw/ElGamalParameter.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/oiw/OIWObjectIdentifiers.java
rename {core => util}/src/main/java/org/bouncycastle/asn1/cryptlib/CryptlibObjectIdentifiers.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/mozilla/SignedPublicKeyAndChallenge.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java (100%)
diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
index 45b93fcbe1..3aecefff09 100644
--- a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
+++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java
@@ -9,8 +9,8 @@
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
public class RSAESOAEPparams
extends ASN1Object
diff --git a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
index fb89370c9a..713f83720e 100644
--- a/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
+++ b/core/src/main/java/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java
@@ -11,8 +11,8 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
public class RSASSAPSSparams
extends ASN1Object
diff --git a/core/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java b/core/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java
index dd2f7ca674..a74facfcc7 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x9/ECNamedCurveTable.java
@@ -5,13 +5,13 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.anssi.ANSSINamedCurves;
-import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.nist.NISTNamedCurves;
import org.bouncycastle.asn1.sec.SECNamedCurves;
import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.internal.asn1.cryptlib.CryptlibObjectIdentifiers;
/**
* A general class that reads all X9.62 style EC curve tables.
diff --git a/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java b/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java
index 7d82474590..07de1a6a81 100644
--- a/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java
+++ b/core/src/main/java/org/bouncycastle/crypto/ec/CustomNamedCurves.java
@@ -6,12 +6,12 @@
import java.util.Vector;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ECParametersHolder;
import org.bouncycastle.asn1.x9.X9ECPoint;
+import org.bouncycastle.internal.asn1.cryptlib.CryptlibObjectIdentifiers;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.WNafUtil;
import org.bouncycastle.math.ec.custom.djb.Curve25519;
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
index 9ec8b8420e..c9ac1dd41f 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
@@ -5,16 +5,16 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.internal.asn1.cms.CCMParameters;
-import org.bouncycastle.internal.asn1.cms.GCMParameters;
import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.misc.CAST5CBCParameters;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.internal.asn1.cms.CCMParameters;
+import org.bouncycastle.internal.asn1.cms.GCMParameters;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
/**
* Factory methods for common AlgorithmIdentifiers.
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
index 9323f43819..e976dc2c3a 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
@@ -11,7 +11,6 @@
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -38,6 +37,7 @@
import org.bouncycastle.crypto.params.RC2Parameters;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.internal.asn1.cms.GCMParameters;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
/**
* Factory methods for creating Cipher objects and CipherOutputStreams.
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java
index 35284ba3c9..83c4f4c705 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java
@@ -6,12 +6,12 @@
import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.generators.DESKeyGenerator;
import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
/**
* Factory methods for generating secret key generators for symmetric ciphers.
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
index a8b13deebe..ef34cb4af0 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -15,8 +15,6 @@
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.ElGamalParameter;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.DHParameter;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
@@ -47,6 +45,8 @@
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.X448PrivateKeyParameters;
+import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.util.Arrays;
/**
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
index 7da525ff0a..9d0c5f1a75 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -18,8 +18,6 @@
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.ElGamalParameter;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.DHParameter;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
@@ -61,6 +59,8 @@
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
import org.bouncycastle.crypto.params.X448PublicKeyParameters;
+import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/cryptlib/CryptlibObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/cryptlib/CryptlibObjectIdentifiers.java
new file mode 100644
index 0000000000..b6ede69975
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/cryptlib/CryptlibObjectIdentifiers.java
@@ -0,0 +1,12 @@
+package org.bouncycastle.internal.asn1.cryptlib;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public class CryptlibObjectIdentifiers
+{
+ public static final ASN1ObjectIdentifier cryptlib = new ASN1ObjectIdentifier("1.3.6.1.4.1.3029");
+
+ public static final ASN1ObjectIdentifier ecc = cryptlib.branch("1").branch("5");
+
+ public static final ASN1ObjectIdentifier curvey25519 = ecc.branch("1");
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/oiw/ElGamalParameter.java b/core/src/main/java/org/bouncycastle/internal/asn1/oiw/ElGamalParameter.java
new file mode 100644
index 0000000000..d281f78269
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/oiw/ElGamalParameter.java
@@ -0,0 +1,68 @@
+package org.bouncycastle.internal.asn1.oiw;
+
+import java.math.BigInteger;
+import java.util.Enumeration;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERSequence;
+
+public class ElGamalParameter
+ extends ASN1Object
+{
+ ASN1Integer p, g;
+
+ public ElGamalParameter(
+ BigInteger p,
+ BigInteger g)
+ {
+ this.p = new ASN1Integer(p);
+ this.g = new ASN1Integer(g);
+ }
+
+ private ElGamalParameter(
+ ASN1Sequence seq)
+ {
+ Enumeration e = seq.getObjects();
+
+ p = (ASN1Integer)e.nextElement();
+ g = (ASN1Integer)e.nextElement();
+ }
+
+ public static ElGamalParameter getInstance(Object o)
+ {
+ if (o instanceof ElGamalParameter)
+ {
+ return (ElGamalParameter)o;
+ }
+ else if (o != null)
+ {
+ return new ElGamalParameter(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public BigInteger getP()
+ {
+ return p.getPositiveValue();
+ }
+
+ public BigInteger getG()
+ {
+ return g.getPositiveValue();
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector(2);
+
+ v.add(p);
+ v.add(g);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/oiw/OIWObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/oiw/OIWObjectIdentifiers.java
new file mode 100644
index 0000000000..2bd88e78d0
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/oiw/OIWObjectIdentifiers.java
@@ -0,0 +1,50 @@
+package org.bouncycastle.internal.asn1.oiw;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * OIW organization's OIDs:
+ *
+ * id-SHA1 OBJECT IDENTIFIER ::=
+ * {iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 }
+ */
+public interface OIWObjectIdentifiers
+{
+ /** OID: 1.3.14.3.2.2 */
+ static final ASN1ObjectIdentifier md4WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.2");
+ /** OID: 1.3.14.3.2.3 */
+ static final ASN1ObjectIdentifier md5WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.3");
+ /** OID: 1.3.14.3.2.4 */
+ static final ASN1ObjectIdentifier md4WithRSAEncryption = new ASN1ObjectIdentifier("1.3.14.3.2.4");
+
+ /** OID: 1.3.14.3.2.6 */
+ static final ASN1ObjectIdentifier desECB = new ASN1ObjectIdentifier("1.3.14.3.2.6");
+ /** OID: 1.3.14.3.2.7 */
+ static final ASN1ObjectIdentifier desCBC = new ASN1ObjectIdentifier("1.3.14.3.2.7");
+ /** OID: 1.3.14.3.2.8 */
+ static final ASN1ObjectIdentifier desOFB = new ASN1ObjectIdentifier("1.3.14.3.2.8");
+ /** OID: 1.3.14.3.2.9 */
+ static final ASN1ObjectIdentifier desCFB = new ASN1ObjectIdentifier("1.3.14.3.2.9");
+
+ /** OID: 1.3.14.3.2.17 */
+ static final ASN1ObjectIdentifier desEDE = new ASN1ObjectIdentifier("1.3.14.3.2.17");
+
+ /** OID: 1.3.14.3.2.26 */
+ static final ASN1ObjectIdentifier idSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.26");
+
+ /** OID: 1.3.14.3.2.27 */
+ static final ASN1ObjectIdentifier dsaWithSHA1 = new ASN1ObjectIdentifier("1.3.14.3.2.27");
+
+ /** OID: 1.3.14.3.2.29 */
+ static final ASN1ObjectIdentifier sha1WithRSA = new ASN1ObjectIdentifier("1.3.14.3.2.29");
+
+ /**
+ *
+ * ElGamal Algorithm OBJECT IDENTIFIER ::=
+ * {iso(1) identified-organization(3) oiw(14) dirservsig(7) algorithm(2) encryption(1) 1 }
+ *
+ * OID: 1.3.14.7.2.1.1
+ */
+ static final ASN1ObjectIdentifier elGamalAlgorithm = new ASN1ObjectIdentifier("1.3.14.7.2.1.1");
+
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
index df8d39bc6f..8e7421fe24 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
@@ -7,12 +7,12 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.digests.SHA512Digest;
import org.bouncycastle.crypto.digests.SHAKEDigest;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
import org.bouncycastle.pqc.crypto.bike.BIKEParameters;
diff --git a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/Utils.java b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/Utils.java
index f917017f44..076e69ae32 100644
--- a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/Utils.java
+++ b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/Utils.java
@@ -7,7 +7,7 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
diff --git a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/Utils.java b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/Utils.java
index 3f32a577aa..b7095f4950 100644
--- a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/Utils.java
+++ b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/Utils.java
@@ -7,7 +7,7 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA256Digest;
diff --git a/core/src/test/java/org/bouncycastle/asn1/test/BiometricDataUnitTest.java b/core/src/test/java/org/bouncycastle/asn1/test/BiometricDataUnitTest.java
index 81c78d12ea..f2f0db8aba 100644
--- a/core/src/test/java/org/bouncycastle/asn1/test/BiometricDataUnitTest.java
+++ b/core/src/test/java/org/bouncycastle/asn1/test/BiometricDataUnitTest.java
@@ -9,10 +9,10 @@
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.qualified.BiometricData;
import org.bouncycastle.asn1.x509.qualified.TypeOfBiometricData;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.util.test.SimpleTest;
public class BiometricDataUnitTest
diff --git a/core/src/test/java/org/bouncycastle/asn1/test/GenerationTest.java b/core/src/test/java/org/bouncycastle/asn1/test/GenerationTest.java
index 01867e5808..a90f144ecb 100644
--- a/core/src/test/java/org/bouncycastle/asn1/test/GenerationTest.java
+++ b/core/src/test/java/org/bouncycastle/asn1/test/GenerationTest.java
@@ -13,8 +13,6 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.oiw.ElGamalParameter;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
import org.bouncycastle.asn1.x500.X500Name;
@@ -38,6 +36,8 @@
import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.test.SimpleTest;
diff --git a/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java b/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java
index 5e89452ecb..3dd2c02689 100644
--- a/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java
+++ b/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java
@@ -6,7 +6,6 @@
import java.util.Vector;
import junit.framework.TestCase;
-
import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Enumerated;
@@ -32,10 +31,8 @@
import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
import org.bouncycastle.asn1.cryptopro.GOST3410ParamSetParameters;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
-
import org.bouncycastle.asn1.misc.CAST5CBCParameters;
import org.bouncycastle.asn1.misc.IDEACBCPar;
-import org.bouncycastle.asn1.mozilla.PublicKeyAndChallenge;
import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
import org.bouncycastle.asn1.ocsp.CertID;
import org.bouncycastle.asn1.ocsp.CertStatus;
@@ -51,7 +48,6 @@
import org.bouncycastle.asn1.ocsp.Signature;
import org.bouncycastle.asn1.ocsp.SingleResponse;
import org.bouncycastle.asn1.ocsp.TBSRequest;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
import org.bouncycastle.asn1.pkcs.CertificationRequest;
import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
@@ -139,6 +135,7 @@
import org.bouncycastle.asn1.x9.DHValidationParms;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.util.Integers;
import org.bouncycastle.util.encoders.Base64;
@@ -362,7 +359,6 @@ public void testGetInstance()
CAST5CBCParameters.getInstance(null);
IDEACBCPar.getInstance(null);
- PublicKeyAndChallenge.getInstance(null);
BasicOCSPResponse.getInstance(null);
BasicOCSPResponse.getInstance(null);
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsKyberTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsKyberTest.java
index 45346a5206..e085dca826 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsKyberTest.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsKyberTest.java
@@ -9,11 +9,11 @@
import junit.framework.Assert;
import junit.framework.TestCase;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.SecretWithEncapsulation;
import org.bouncycastle.crypto.util.DEROtherInfo;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKEMExtractor;
import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKEMGenerator;
import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKeyGenerationParameters;
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java
index ce3fa733a7..76d5875fa8 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java
@@ -8,11 +8,11 @@
import junit.framework.Assert;
import junit.framework.TestCase;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.SecretWithEncapsulation;
import org.bouncycastle.crypto.util.DEROtherInfo;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.pqc.crypto.ntru.NTRUKEMExtractor;
import org.bouncycastle.pqc.crypto.ntru.NTRUKEMGenerator;
import org.bouncycastle.pqc.crypto.ntru.NTRUKeyGenerationParameters;
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NewHopeTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NewHopeTest.java
index c8ce5677fb..a9ca786ca7 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NewHopeTest.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NewHopeTest.java
@@ -3,11 +3,11 @@
import java.io.IOException;
import java.security.SecureRandom;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.util.DEROtherInfo;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.pqc.crypto.ExchangePair;
import org.bouncycastle.pqc.crypto.newhope.NHAgreement;
import org.bouncycastle.pqc.crypto.newhope.NHExchangePairGenerator;
diff --git a/prov/src/main/ext-jdk1.9/module-info.java b/prov/src/main/ext-jdk1.9/module-info.java
index 96f9ea0588..507d5776b3 100644
--- a/prov/src/main/ext-jdk1.9/module-info.java
+++ b/prov/src/main/ext-jdk1.9/module-info.java
@@ -13,7 +13,6 @@
exports org.bouncycastle.asn1.anssi;
exports org.bouncycastle.asn1.bc;
exports org.bouncycastle.asn1.cryptopro;
- exports org.bouncycastle.asn1.cryptlib;
exports org.bouncycastle.asn1.edec;
exports org.bouncycastle.asn1.gm;
exports org.bouncycastle.asn1.gnu;
@@ -23,12 +22,10 @@
exports org.bouncycastle.asn1.kisa;
exports org.bouncycastle.asn1.microsoft;
exports org.bouncycastle.asn1.misc;
- exports org.bouncycastle.asn1.mozilla;
exports org.bouncycastle.asn1.nist;
exports org.bouncycastle.asn1.nsri;
exports org.bouncycastle.asn1.ntt;
exports org.bouncycastle.asn1.ocsp;
- exports org.bouncycastle.asn1.oiw;
exports org.bouncycastle.asn1.pkcs;
exports org.bouncycastle.asn1.rosstandart;
exports org.bouncycastle.asn1.sec;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ElGamal.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ElGamal.java
index 279e95129e..cac64a80ca 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ElGamal.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ElGamal.java
@@ -1,6 +1,6 @@
package org.bouncycastle.jcajce.provider.asymmetric;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.elgamal.KeyFactorySpi;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
index 60e65294ea..4bafaa48a9 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/RSA.java
@@ -5,11 +5,11 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.internal.asn1.cms.CMSObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
index f7ebf959e5..2a55d0256a 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSAUtil.java
@@ -9,12 +9,12 @@
import java.security.interfaces.DSAPublicKey;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.DSAParameters;
import org.bouncycastle.crypto.params.DSAPrivateKeyParameters;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Fingerprint;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParametersSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParametersSpi.java
index 9280f80190..cea8a6e2b9 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParametersSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/AlgorithmParametersSpi.java
@@ -8,7 +8,7 @@
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.oiw.ElGamalParameter;
+import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
import org.bouncycastle.jce.spec.ElGamalParameterSpec;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPrivateKey.java
index f0f83fa454..8c6a9627a8 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPrivateKey.java
@@ -14,11 +14,11 @@
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.oiw.ElGamalParameter;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
+import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPublicKey.java
index cd31cc57b9..78c5f49b13 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/BCElGamalPublicKey.java
@@ -11,11 +11,11 @@
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Integer;
-import org.bouncycastle.asn1.oiw.ElGamalParameter;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
+import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jce.interfaces.ElGamalPublicKey;
import org.bouncycastle.jce.spec.ElGamalParameterSpec;
import org.bouncycastle.jce.spec.ElGamalPublicKeySpec;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/KeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/KeyFactorySpi.java
index 92e655f776..426d26413c 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/KeyFactorySpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/elgamal/KeyFactorySpi.java
@@ -14,11 +14,11 @@
import javax.crypto.spec.DHPublicKeySpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
import org.bouncycastle.jce.interfaces.ElGamalPublicKey;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
index bc00222ed0..0046767e3e 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
@@ -15,7 +15,6 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -32,6 +31,7 @@
import org.bouncycastle.crypto.encodings.PKCS1Encoding;
import org.bouncycastle.crypto.engines.RSABlindedEngine;
import org.bouncycastle.crypto.util.DigestFactory;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.util.Arrays;
public class DigestSignatureSpi
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
index 75babbdc36..07b5f6d9b9 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -22,7 +22,6 @@
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.DerivationFunction;
import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
@@ -31,6 +30,7 @@
import org.bouncycastle.crypto.params.DESParameters;
import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.crypto.params.KDFParameters;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.spec.HybridValueParameterSpec;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Integers;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DESUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DESUtil.java
index a62602d7a6..89e5dffd78 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DESUtil.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/DESUtil.java
@@ -3,8 +3,8 @@
import java.util.HashSet;
import java.util.Set;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.util.Strings;
public class DESUtil
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
index 73b6cd1596..4b62d9bfa6 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -14,17 +14,16 @@
import java.util.Map;
import org.bouncycastle.asn1.ASN1Encodable;
-import org.bouncycastle.asn1.ASN1Null;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.util.MessageDigestUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Objects;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
index 17a5462abc..055d14ff36 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
@@ -1,11 +1,11 @@
package org.bouncycastle.jcajce.provider.digest;
import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
index 2e3b01bf35..997c99a549 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
@@ -61,14 +61,12 @@
import org.bouncycastle.asn1.bc.PbkdMacIntegrityCheck;
import org.bouncycastle.asn1.bc.SecretKeyData;
import org.bouncycastle.asn1.bc.SignatureCheck;
-import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.misc.ScryptParams;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.nsri.NSRIObjectIdentifiers;
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.EncryptionScheme;
import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
@@ -89,6 +87,8 @@
import org.bouncycastle.crypto.util.PBKDF2Config;
import org.bouncycastle.crypto.util.PBKDFConfig;
import org.bouncycastle.crypto.util.ScryptConfig;
+import org.bouncycastle.internal.asn1.cms.CCMParameters;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.BCFKSLoadStoreParameter;
import org.bouncycastle.jcajce.BCFKSStoreParameter;
import org.bouncycastle.jcajce.BCLoadStoreParameter;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
index 96c775cfc4..b0e0b664ee 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -69,7 +69,6 @@
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
import org.bouncycastle.asn1.pkcs.CertBag;
import org.bouncycastle.asn1.pkcs.ContentInfo;
@@ -96,6 +95,7 @@
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.util.DigestFactory;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.BCLoadStoreParameter;
import org.bouncycastle.jcajce.PKCS12Key;
import org.bouncycastle.jcajce.PKCS12StoreParameter;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java
index 91a25ecf2b..311d0f1251 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DES.java
@@ -14,7 +14,6 @@
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
@@ -32,6 +31,7 @@
import org.bouncycastle.crypto.params.DESParameters;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.PBKDF1Key;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
index 66368a6871..91e95411ab 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/DESede.java
@@ -12,7 +12,6 @@
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.KeyGenerationParameters;
@@ -25,6 +24,7 @@
import org.bouncycastle.crypto.macs.CMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.paddings.ISO7816d4Padding;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
index 6f98980783..b1f8259e22 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/util/DigestFactory.java
@@ -7,9 +7,9 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.util.Strings;
public class DigestFactory
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/util/JcaJceUtils.java b/prov/src/main/java/org/bouncycastle/jcajce/util/JcaJceUtils.java
index b4ede4aca6..52d6da90ed 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/util/JcaJceUtils.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/util/JcaJceUtils.java
@@ -8,9 +8,9 @@
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
/**
* General JCA/JCE utility methods.
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java b/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
index 9ca15cffdc..d7c645c3dc 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
@@ -11,10 +11,10 @@
import org.bouncycastle.asn1.iso.ISOIECObjectIdentifiers;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
public class MessageDigestUtils
{
diff --git a/prov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java b/prov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
index f6e2676be1..cf7933d714 100644
--- a/prov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
+++ b/prov/src/main/java/org/bouncycastle/jce/PKCS10CertificationRequest.java
@@ -32,7 +32,6 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.CertificationRequest;
import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -42,6 +41,7 @@
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Strings;
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/JCEElGamalPrivateKey.java b/prov/src/main/java/org/bouncycastle/jce/provider/JCEElGamalPrivateKey.java
index 6c21f876ab..64a1228d0f 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/JCEElGamalPrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/JCEElGamalPrivateKey.java
@@ -13,11 +13,11 @@
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.oiw.ElGamalParameter;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters;
+import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/JCEElGamalPublicKey.java b/prov/src/main/java/org/bouncycastle/jce/provider/JCEElGamalPublicKey.java
index 30780c85aa..ebfa328fb5 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/JCEElGamalPublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/JCEElGamalPublicKey.java
@@ -10,11 +10,11 @@
import javax.crypto.spec.DHPublicKeySpec;
import org.bouncycastle.asn1.ASN1Integer;
-import org.bouncycastle.asn1.oiw.ElGamalParameter;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.params.ElGamalPublicKeyParameters;
+import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
import org.bouncycastle.jce.interfaces.ElGamalPublicKey;
import org.bouncycastle.jce.spec.ElGamalParameterSpec;
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java b/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
index 1713f8ed30..e2a51904d8 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
@@ -30,7 +30,6 @@
import org.bouncycastle.asn1.ASN1String;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.internal.asn1.bsi.BSIObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
@@ -44,7 +43,6 @@
import org.bouncycastle.asn1.ocsp.ResponseData;
import org.bouncycastle.asn1.ocsp.RevokedInfo;
import org.bouncycastle.asn1.ocsp.SingleResponse;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
@@ -59,7 +57,9 @@
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.internal.asn1.bsi.BSIObjectIdentifiers;
import org.bouncycastle.internal.asn1.eac.EACObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.PKIXCertRevocationChecker;
import org.bouncycastle.jcajce.PKIXCertRevocationCheckerParameters;
import org.bouncycastle.jcajce.util.JcaJceHelper;
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java b/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java
index bfdf940255..58dbd0c24c 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java
@@ -11,15 +11,15 @@
import java.util.Set;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.internal.asn1.bsi.BSIObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.internal.asn1.eac.EACObjectIdentifiers;
import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.internal.asn1.bsi.BSIObjectIdentifiers;
+import org.bouncycastle.internal.asn1.eac.EACObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.PKIXCertRevocationChecker;
import org.bouncycastle.jcajce.PKIXCertRevocationCheckerParameters;
import org.bouncycastle.jcajce.util.JcaJceHelper;
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java b/prov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
index eb1e556ed5..8f57457418 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/X509SignatureUtil.java
@@ -16,12 +16,12 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
class X509SignatureUtil
{
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java
index 4f1a59f6bb..e4481abff2 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/mceliece/Utils.java
@@ -1,10 +1,10 @@
package org.bouncycastle.pqc.jcajce.provider.mceliece;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.util.DigestFactory;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
class Utils
{
diff --git a/prov/src/main/java/org/bouncycastle/x509/X509Util.java b/prov/src/main/java/org/bouncycastle/x509/X509Util.java
index c72169e529..2be58a87f6 100644
--- a/prov/src/main/java/org/bouncycastle/x509/X509Util.java
+++ b/prov/src/main/java/org/bouncycastle/x509/X509Util.java
@@ -27,12 +27,12 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.util.Strings;
diff --git a/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java b/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
index 8d127434dc..4d18dbfd1c 100644
--- a/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
+++ b/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/rsa/DigestSignatureSpi.java
@@ -15,7 +15,7 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
diff --git a/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java b/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
index ef35f6a14c..8f32eaa550 100644
--- a/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
+++ b/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
@@ -17,7 +17,7 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
diff --git a/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
index c1eb4df3ae..18468c7191 100644
--- a/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
+++ b/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -20,7 +20,7 @@
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
diff --git a/prov/src/main/jdk1.1/org/bouncycastle/x509/X509Util.java b/prov/src/main/jdk1.1/org/bouncycastle/x509/X509Util.java
index 7677c48dc0..d97acd59b7 100644
--- a/prov/src/main/jdk1.1/org/bouncycastle/x509/X509Util.java
+++ b/prov/src/main/jdk1.1/org/bouncycastle/x509/X509Util.java
@@ -25,7 +25,7 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
index 158a0768d3..1b8cba63bb 100644
--- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
+++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/SignatureUtil.java
@@ -17,7 +17,7 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
index 143b358dc0..50dbe4c9e6 100644
--- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
+++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -20,7 +20,7 @@
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
index 5c460ed506..eecbda31f4 100644
--- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
+++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
@@ -54,7 +54,7 @@
import org.bouncycastle.asn1.bc.SecretKeyData;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.EncryptionScheme;
import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jce/PKCS10CertificationRequest.java b/prov/src/main/jdk1.3/org/bouncycastle/jce/PKCS10CertificationRequest.java
index c448324b21..d4f15cbf52 100644
--- a/prov/src/main/jdk1.3/org/bouncycastle/jce/PKCS10CertificationRequest.java
+++ b/prov/src/main/jdk1.3/org/bouncycastle/jce/PKCS10CertificationRequest.java
@@ -29,7 +29,7 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.CertificationRequest;
import org.bouncycastle.asn1.pkcs.CertificationRequestInfo;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
diff --git a/prov/src/main/jdk1.3/org/bouncycastle/x509/X509Util.java b/prov/src/main/jdk1.3/org/bouncycastle/x509/X509Util.java
index 7815c1144f..c275362438 100644
--- a/prov/src/main/jdk1.3/org/bouncycastle/x509/X509Util.java
+++ b/prov/src/main/jdk1.3/org/bouncycastle/x509/X509Util.java
@@ -25,7 +25,7 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
index 37647b803d..d2db7db4ae 100644
--- a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
+++ b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
@@ -61,7 +61,7 @@
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.misc.ScryptParams;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.EncryptionScheme;
import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/X509SignatureUtil.java b/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/X509SignatureUtil.java
index a31d41904e..3338e07046 100644
--- a/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/X509SignatureUtil.java
+++ b/prov/src/main/jdk1.4/org/bouncycastle/jce/provider/X509SignatureUtil.java
@@ -11,7 +11,7 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
diff --git a/prov/src/main/jdk1.9/module-info.java b/prov/src/main/jdk1.9/module-info.java
index 819fea2612..779cedda2d 100644
--- a/prov/src/main/jdk1.9/module-info.java
+++ b/prov/src/main/jdk1.9/module-info.java
@@ -15,7 +15,6 @@
exports org.bouncycastle.asn1.anssi;
exports org.bouncycastle.asn1.bc;
exports org.bouncycastle.asn1.cryptopro;
- exports org.bouncycastle.asn1.cryptlib;
exports org.bouncycastle.asn1.edec;
exports org.bouncycastle.asn1.gm;
exports org.bouncycastle.asn1.gnu;
@@ -25,12 +24,10 @@
exports org.bouncycastle.asn1.kisa;
exports org.bouncycastle.asn1.microsoft;
exports org.bouncycastle.asn1.misc;
- exports org.bouncycastle.asn1.mozilla;
exports org.bouncycastle.asn1.nist;
exports org.bouncycastle.asn1.nsri;
exports org.bouncycastle.asn1.ntt;
exports org.bouncycastle.asn1.ocsp;
- exports org.bouncycastle.asn1.oiw;
exports org.bouncycastle.asn1.pkcs;
exports org.bouncycastle.asn1.rosstandart;
exports org.bouncycastle.asn1.sec;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java
index a2a7ea147f..81a406175a 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/RSATest.java
@@ -41,7 +41,6 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.RSAESOAEPparams;
@@ -50,6 +49,7 @@
import org.bouncycastle.asn1.x509.DigestInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
+import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec;
import org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptlib/CryptlibObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/cryptlib/CryptlibObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/cryptlib/CryptlibObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/cryptlib/CryptlibObjectIdentifiers.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java b/util/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java
rename to util/src/main/java/org/bouncycastle/asn1/mozilla/PublicKeyAndChallenge.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/mozilla/SignedPublicKeyAndChallenge.java b/util/src/main/java/org/bouncycastle/asn1/mozilla/SignedPublicKeyAndChallenge.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/mozilla/SignedPublicKeyAndChallenge.java
rename to util/src/main/java/org/bouncycastle/asn1/mozilla/SignedPublicKeyAndChallenge.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java b/util/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java
rename to util/src/main/java/org/bouncycastle/asn1/oiw/ElGamalParameter.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/oiw/OIWObjectIdentifiers.java
diff --git a/util/src/main/jdk1.9/module-info.java b/util/src/main/jdk1.9/module-info.java
index 36886ceda4..8e37e85d0e 100644
--- a/util/src/main/jdk1.9/module-info.java
+++ b/util/src/main/jdk1.9/module-info.java
@@ -8,6 +8,7 @@
exports org.bouncycastle.asn1.cms;
exports org.bouncycastle.asn1.cms.ecc;
exports org.bouncycastle.asn1.crmf;
+ exports org.bouncycastle.asn1.cryptlib;
exports org.bouncycastle.asn1.dvcs;
exports org.bouncycastle.asn1.eac;
exports org.bouncycastle.asn1.esf;
@@ -17,6 +18,8 @@
exports org.bouncycastle.asn1.isismtt;
exports org.bouncycastle.asn1.isismtt.ocsp;
exports org.bouncycastle.asn1.isismtt.x509;
+ exports org.bouncycastle.asn1.mozilla;
+ exports org.bouncycastle.asn1.oiw;
exports org.bouncycastle.asn1.smime;
exports org.bouncycastle.asn1.tsp;
exports org.bouncycastle.oer;
From c7a425cafb91c66503566bea345e36951d2cc0a6 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 6 Mar 2024 15:24:23 +1100
Subject: [PATCH 0143/1846] move of ASN.1 gnu, ntt and iana to util package
---
.../util/AlgorithmIdentifierFactory.java | 2 +-
.../crypto/util/CipherFactory.java | 2 +-
.../util/CipherKeyGeneratorFactory.java | 2 +-
.../asn1/gnu/GNUObjectIdentifiers.java | 111 ++++++++++++++++++
.../asn1/iana/IANAObjectIdentifiers.java | 60 ++++++++++
.../asn1/ntt/NTTObjectIdentifiers.java | 25 ++++
prov/src/main/ext-jdk1.9/module-info.java | 3 -
.../asymmetric/util/BaseAgreementSpi.java | 4 +-
.../jcajce/provider/digest/MD5.java | 2 +-
.../jcajce/provider/digest/RIPEMD160.java | 2 +-
.../jcajce/provider/digest/SHA1.java | 2 +-
.../jcajce/provider/digest/Tiger.java | 2 +-
.../keystore/bcfks/BcFKSKeyStoreSpi.java | 2 +-
.../keystore/pkcs12/PKCS12KeyStoreSpi.java | 2 +-
.../jcajce/provider/symmetric/Camellia.java | 2 +-
.../jcajce/provider/symmetric/Serpent.java | 2 +-
.../jcajce/provider/util/SecretKeyUtil.java | 2 +-
.../jcajce/util/MessageDigestUtils.java | 2 +-
prov/src/main/jdk1.9/module-info.java | 3 -
.../jce/provider/test/CamelliaTest.java | 17 +--
.../jce/provider/test/HMacTest.java | 2 +-
.../asn1/gnu/GNUObjectIdentifiers.java | 0
.../asn1/iana/IANAObjectIdentifiers.java | 0
.../asn1/ntt/NTTObjectIdentifiers.java | 0
util/src/main/jdk1.9/module-info.java | 3 +
25 files changed, 224 insertions(+), 30 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/gnu/GNUObjectIdentifiers.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/ntt/NTTObjectIdentifiers.java
rename {core => util}/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java (100%)
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
index c9ac1dd41f..f305dd65d6 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
@@ -8,12 +8,12 @@
import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.misc.CAST5CBCParameters;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.internal.asn1.cms.GCMParameters;
+import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
/**
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
index e976dc2c3a..7af9c6a010 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
@@ -10,7 +10,6 @@
import org.bouncycastle.asn1.misc.CAST5CBCParameters;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -37,6 +36,7 @@
import org.bouncycastle.crypto.params.RC2Parameters;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.internal.asn1.cms.GCMParameters;
+import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
/**
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java
index 83c4f4c705..2e1f10e4c8 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java
@@ -5,12 +5,12 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.generators.DESKeyGenerator;
import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
+import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
/**
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/gnu/GNUObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/gnu/GNUObjectIdentifiers.java
new file mode 100644
index 0000000000..f038c9eeaa
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/gnu/GNUObjectIdentifiers.java
@@ -0,0 +1,111 @@
+package org.bouncycastle.internal.asn1.gnu;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * GNU project OID collection
+ * { iso(1) identifier-organization(3) dod(6) internet(1) private(4) } == IETF defined things
+ */
+public interface GNUObjectIdentifiers
+{
+ /**
+ * 1.3.6.1.4.1.11591.1 -- used by GNU Radius
+ */
+ ASN1ObjectIdentifier GNU = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.1"); // GNU Radius
+ /**
+ * 1.3.6.1.4.1.11591.2 -- used by GNU PG
+ */
+ ASN1ObjectIdentifier GnuPG = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2"); // GnuPG (Ägypten)
+ /**
+ * 1.3.6.1.4.1.11591.2.1 -- notation
+ */
+ ASN1ObjectIdentifier notation = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2.1"); // notation
+ /**
+ * 1.3.6.1.4.1.11591.2.1.1 -- pkaAddress
+ */
+ ASN1ObjectIdentifier pkaAddress = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2.1.1"); // pkaAddress
+ /**
+ * 1.3.6.1.4.1.11591.3 -- GNU Radar
+ */
+ ASN1ObjectIdentifier GnuRadar = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.3"); // GNU Radar
+ /**
+ * 1.3.6.1.4.1.11591.12 -- digestAlgorithm
+ */
+ ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.12"); // digestAlgorithm
+ /**
+ * 1.3.6.1.4.1.11591.12.2 -- TIGER/192
+ */
+ ASN1ObjectIdentifier Tiger_192 = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.12.2"); // TIGER/192
+ /**
+ * 1.3.6.1.4.1.11591.13 -- encryptionAlgorithm
+ */
+ ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13"); // encryptionAlgorithm
+ /**
+ * 1.3.6.1.4.1.11591.13.2 -- Serpent
+ */
+ ASN1ObjectIdentifier Serpent = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2"); // Serpent
+ /**
+ * 1.3.6.1.4.1.11591.13.2.1 -- Serpent-128-ECB
+ */
+ ASN1ObjectIdentifier Serpent_128_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.1"); // Serpent-128-ECB
+ /**
+ * 1.3.6.1.4.1.11591.13.2.2 -- Serpent-128-CBC
+ */
+ ASN1ObjectIdentifier Serpent_128_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.2"); // Serpent-128-CBC
+ /**
+ * 1.3.6.1.4.1.11591.13.2.3 -- Serpent-128-OFB
+ */
+ ASN1ObjectIdentifier Serpent_128_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.3"); // Serpent-128-OFB
+ /**
+ * 1.3.6.1.4.1.11591.13.2.4 -- Serpent-128-CFB
+ */
+ ASN1ObjectIdentifier Serpent_128_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.4"); // Serpent-128-CFB
+ /**
+ * 1.3.6.1.4.1.11591.13.2.21 -- Serpent-192-ECB
+ */
+ ASN1ObjectIdentifier Serpent_192_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.21"); // Serpent-192-ECB
+ /**
+ * 1.3.6.1.4.1.11591.13.2.22 -- Serpent-192-CCB
+ */
+ ASN1ObjectIdentifier Serpent_192_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.22"); // Serpent-192-CBC
+ /**
+ * 1.3.6.1.4.1.11591.13.2.23 -- Serpent-192-OFB
+ */
+ ASN1ObjectIdentifier Serpent_192_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.23"); // Serpent-192-OFB
+ /**
+ * 1.3.6.1.4.1.11591.13.2.24 -- Serpent-192-CFB
+ */
+ ASN1ObjectIdentifier Serpent_192_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.24"); // Serpent-192-CFB
+ /**
+ * 1.3.6.1.4.1.11591.13.2.41 -- Serpent-256-ECB
+ */
+ ASN1ObjectIdentifier Serpent_256_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.41"); // Serpent-256-ECB
+ /**
+ * 1.3.6.1.4.1.11591.13.2.42 -- Serpent-256-CBC
+ */
+ ASN1ObjectIdentifier Serpent_256_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.42"); // Serpent-256-CBC
+ /**
+ * 1.3.6.1.4.1.11591.13.2.43 -- Serpent-256-OFB
+ */
+ ASN1ObjectIdentifier Serpent_256_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.43"); // Serpent-256-OFB
+ /**
+ * 1.3.6.1.4.1.11591.13.2.44 -- Serpent-256-CFB
+ */
+ ASN1ObjectIdentifier Serpent_256_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB
+
+ /**
+ * 1.3.6.1.4.1.11591.14 -- CRC algorithms
+ */
+ ASN1ObjectIdentifier CRC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms
+ /**
+ * 1.3.6.1.4.1.11591.14,1 -- CRC32
+ */
+ ASN1ObjectIdentifier CRC32 = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32
+
+ /**
+ * 1.3.6.1.4.1.11591.15 - ellipticCurve
+ */
+ ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.15");
+
+ ASN1ObjectIdentifier Ed25519 = ellipticCurve.branch("1");
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java
new file mode 100644
index 0000000000..97a97d0680
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/iana/IANAObjectIdentifiers.java
@@ -0,0 +1,60 @@
+package org.bouncycastle.internal.asn1.iana;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * IANA:
+ * { iso(1) identifier-organization(3) dod(6) internet(1) } == IETF defined things
+ */
+public interface IANAObjectIdentifiers
+{
+
+ /** { iso(1) identifier-organization(3) dod(6) internet(1) } == IETF defined things */
+ static final ASN1ObjectIdentifier internet = new ASN1ObjectIdentifier("1.3.6.1");
+ /** 1.3.6.1.1: Internet directory: X.500 */
+ static final ASN1ObjectIdentifier directory = internet.branch("1");
+ /** 1.3.6.1.2: Internet management */
+ static final ASN1ObjectIdentifier mgmt = internet.branch("2");
+ /** 1.3.6.1.3: */
+ static final ASN1ObjectIdentifier experimental = internet.branch("3");
+ /** 1.3.6.1.4: */
+ static final ASN1ObjectIdentifier _private = internet.branch("4");
+ /** 1.3.6.1.5: Security services */
+ static final ASN1ObjectIdentifier security = internet.branch("5");
+ /** 1.3.6.1.6: SNMPv2 -- never really used */
+ static final ASN1ObjectIdentifier SNMPv2 = internet.branch("6");
+ /** 1.3.6.1.7: mail -- never really used */
+ static final ASN1ObjectIdentifier mail = internet.branch("7");
+
+
+ // id-SHA1 OBJECT IDENTIFIER ::=
+ // {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ipsec(8) isakmpOakley(1)}
+ //
+
+
+ /** IANA security mechanisms; 1.3.6.1.5.5 */
+ static final ASN1ObjectIdentifier security_mechanisms = security.branch("5");
+ /** IANA security nametypes; 1.3.6.1.5.6 */
+ static final ASN1ObjectIdentifier security_nametypes = security.branch("6");
+
+ /** PKIX base OID: 1.3.6.1.5.6.6 */
+ static final ASN1ObjectIdentifier pkix = security_mechanisms.branch("6");
+
+
+ /** IPSEC base OID: 1.3.6.1.5.5.8 */
+ static final ASN1ObjectIdentifier ipsec = security_mechanisms.branch("8");
+ /** IPSEC ISAKMP-Oakley OID: 1.3.6.1.5.5.8.1 */
+ static final ASN1ObjectIdentifier isakmpOakley = ipsec.branch("1");
+
+ /** IPSEC ISAKMP-Oakley hmacMD5 OID: 1.3.6.1.5.5.8.1.1 */
+ static final ASN1ObjectIdentifier hmacMD5 = isakmpOakley.branch("1");
+ /** IPSEC ISAKMP-Oakley hmacSHA1 OID: 1.3.6.1.5.5.8.1.2 */
+ static final ASN1ObjectIdentifier hmacSHA1 = isakmpOakley.branch("2");
+
+ /** IPSEC ISAKMP-Oakley hmacTIGER OID: 1.3.6.1.5.5.8.1.3 */
+ static final ASN1ObjectIdentifier hmacTIGER = isakmpOakley.branch("3");
+
+ /** IPSEC ISAKMP-Oakley hmacRIPEMD160 OID: 1.3.6.1.5.5.8.1.4 */
+ static final ASN1ObjectIdentifier hmacRIPEMD160 = isakmpOakley.branch("4");
+
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/ntt/NTTObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/ntt/NTTObjectIdentifiers.java
new file mode 100644
index 0000000000..d84297c24c
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/ntt/NTTObjectIdentifiers.java
@@ -0,0 +1,25 @@
+package org.bouncycastle.internal.asn1.ntt;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * From RFC 3657
+ * Use of the Camellia Encryption Algorithm
+ * in Cryptographic Message Syntax (CMS)
+ */
+public interface NTTObjectIdentifiers
+{
+ /** id-camellia128-cbc; OID 1.2.392.200011.61.1.1.1.2 */
+ static final ASN1ObjectIdentifier id_camellia128_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.2");
+ /** id-camellia192-cbc; OID 1.2.392.200011.61.1.1.1.3 */
+ static final ASN1ObjectIdentifier id_camellia192_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.3");
+ /** id-camellia256-cbc; OID 1.2.392.200011.61.1.1.1.4 */
+ static final ASN1ObjectIdentifier id_camellia256_cbc = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.1.4");
+
+ /** id-camellia128-wrap; OID 1.2.392.200011.61.1.1.3.2 */
+ static final ASN1ObjectIdentifier id_camellia128_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.2");
+ /** id-camellia192-wrap; OID 1.2.392.200011.61.1.1.3.3 */
+ static final ASN1ObjectIdentifier id_camellia192_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.3");
+ /** id-camellia256-wrap; OID 1.2.392.200011.61.1.1.3.4 */
+ static final ASN1ObjectIdentifier id_camellia256_wrap = new ASN1ObjectIdentifier("1.2.392.200011.61.1.1.3.4");
+}
diff --git a/prov/src/main/ext-jdk1.9/module-info.java b/prov/src/main/ext-jdk1.9/module-info.java
index 507d5776b3..7c7275aaef 100644
--- a/prov/src/main/ext-jdk1.9/module-info.java
+++ b/prov/src/main/ext-jdk1.9/module-info.java
@@ -15,8 +15,6 @@
exports org.bouncycastle.asn1.cryptopro;
exports org.bouncycastle.asn1.edec;
exports org.bouncycastle.asn1.gm;
- exports org.bouncycastle.asn1.gnu;
- exports org.bouncycastle.asn1.iana;
exports org.bouncycastle.asn1.isara;
exports org.bouncycastle.asn1.iso;
exports org.bouncycastle.asn1.kisa;
@@ -24,7 +22,6 @@
exports org.bouncycastle.asn1.misc;
exports org.bouncycastle.asn1.nist;
exports org.bouncycastle.asn1.nsri;
- exports org.bouncycastle.asn1.ntt;
exports org.bouncycastle.asn1.ocsp;
exports org.bouncycastle.asn1.pkcs;
exports org.bouncycastle.asn1.rosstandart;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
index 07b5f6d9b9..70323de34d 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -17,11 +17,9 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.DerivationFunction;
import org.bouncycastle.crypto.agreement.kdf.DHKDFParameters;
@@ -30,6 +28,8 @@
import org.bouncycastle.crypto.params.DESParameters;
import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.crypto.params.KDFParameters;
+import org.bouncycastle.internal.asn1.gnu.GNUObjectIdentifiers;
+import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.spec.HybridValueParameterSpec;
import org.bouncycastle.util.Arrays;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java
index 93a7d71617..c176c4c05f 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/MD5.java
@@ -1,10 +1,10 @@
package org.bouncycastle.jcajce.provider.digest;
-import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/RIPEMD160.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/RIPEMD160.java
index f081713a36..3e9d13aaf5 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/RIPEMD160.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/RIPEMD160.java
@@ -1,10 +1,10 @@
package org.bouncycastle.jcajce.provider.digest;
-import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.digests.RIPEMD160Digest;
import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
index 055d14ff36..3aee85f1db 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/SHA1.java
@@ -1,10 +1,10 @@
package org.bouncycastle.jcajce.provider.digest;
-import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Tiger.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Tiger.java
index 3d248aadaf..16434d882b 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Tiger.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Tiger.java
@@ -1,9 +1,9 @@
package org.bouncycastle.jcajce.provider.digest;
-import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.digests.TigerDigest;
import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
index 997c99a549..8f581f8558 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
@@ -66,7 +66,6 @@
import org.bouncycastle.asn1.misc.ScryptParams;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.nsri.NSRIObjectIdentifiers;
-import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.EncryptionScheme;
import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
@@ -88,6 +87,7 @@
import org.bouncycastle.crypto.util.PBKDFConfig;
import org.bouncycastle.crypto.util.ScryptConfig;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
+import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.BCFKSLoadStoreParameter;
import org.bouncycastle.jcajce.BCFKSStoreParameter;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
index b0e0b664ee..3b33ff4e5f 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -68,7 +68,6 @@
import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
import org.bouncycastle.asn1.pkcs.CertBag;
import org.bouncycastle.asn1.pkcs.ContentInfo;
@@ -95,6 +94,7 @@
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.util.DigestFactory;
+import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.BCLoadStoreParameter;
import org.bouncycastle.jcajce.PKCS12Key;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java
index 139810c301..6d82f21a2c 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Camellia.java
@@ -7,7 +7,6 @@
import javax.crypto.spec.IvParameterSpec;
-import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
@@ -18,6 +17,7 @@
import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
+import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java
index 52a7e1e69e..4d1351c71b 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Serpent.java
@@ -1,6 +1,5 @@
package org.bouncycastle.jcajce.provider.symmetric;
-import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
@@ -12,6 +11,7 @@
import org.bouncycastle.crypto.modes.CFBBlockCipher;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.modes.OFBBlockCipher;
+import org.bouncycastle.internal.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java
index 56d6c5b326..686d6b8461 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/util/SecretKeyUtil.java
@@ -5,8 +5,8 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.util.Integers;
public class SecretKeyUtil
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java b/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
index d7c645c3dc..cb97cf8fea 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
@@ -7,13 +7,13 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
-import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.asn1.iso.ISOIECObjectIdentifiers;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.internal.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
public class MessageDigestUtils
diff --git a/prov/src/main/jdk1.9/module-info.java b/prov/src/main/jdk1.9/module-info.java
index 779cedda2d..5fef8c2ce4 100644
--- a/prov/src/main/jdk1.9/module-info.java
+++ b/prov/src/main/jdk1.9/module-info.java
@@ -17,8 +17,6 @@
exports org.bouncycastle.asn1.cryptopro;
exports org.bouncycastle.asn1.edec;
exports org.bouncycastle.asn1.gm;
- exports org.bouncycastle.asn1.gnu;
- exports org.bouncycastle.asn1.iana;
exports org.bouncycastle.asn1.isara;
exports org.bouncycastle.asn1.iso;
exports org.bouncycastle.asn1.kisa;
@@ -26,7 +24,6 @@
exports org.bouncycastle.asn1.misc;
exports org.bouncycastle.asn1.nist;
exports org.bouncycastle.asn1.nsri;
- exports org.bouncycastle.asn1.ntt;
exports org.bouncycastle.asn1.ocsp;
exports org.bouncycastle.asn1.pkcs;
exports org.bouncycastle.asn1.rosstandart;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/CamelliaTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/CamelliaTest.java
index 9ee56c77be..3d64eb5752 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/CamelliaTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/CamelliaTest.java
@@ -1,13 +1,5 @@
package org.bouncycastle.jce.provider.test;
-import org.bouncycastle.asn1.ntt.NTTObjectIdentifiers;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.util.encoders.Hex;
-
-import javax.crypto.Cipher;
-import javax.crypto.CipherInputStream;
-import javax.crypto.CipherOutputStream;
-import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -15,6 +7,15 @@
import java.security.Key;
import java.security.Security;
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.encoders.Hex;
+
/**
* basic test class for Camellia
*/
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java
index bddf60cee7..a86bfd3b9f 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java
@@ -14,11 +14,11 @@
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
-import org.bouncycastle.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.ua.UAObjectIdentifiers;
+import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
diff --git a/core/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/iana/IANAObjectIdentifiers.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/ntt/NTTObjectIdentifiers.java
diff --git a/util/src/main/jdk1.9/module-info.java b/util/src/main/jdk1.9/module-info.java
index 8e37e85d0e..ed7737ddcb 100644
--- a/util/src/main/jdk1.9/module-info.java
+++ b/util/src/main/jdk1.9/module-info.java
@@ -14,11 +14,14 @@
exports org.bouncycastle.asn1.esf;
exports org.bouncycastle.asn1.ess;
exports org.bouncycastle.asn1.est;
+ exports org.bouncycastle.asn1.gnu;
+ exports org.bouncycastle.asn1.iana;
exports org.bouncycastle.asn1.icao;
exports org.bouncycastle.asn1.isismtt;
exports org.bouncycastle.asn1.isismtt.ocsp;
exports org.bouncycastle.asn1.isismtt.x509;
exports org.bouncycastle.asn1.mozilla;
+ exports org.bouncycastle.asn1.ntt;
exports org.bouncycastle.asn1.oiw;
exports org.bouncycastle.asn1.smime;
exports org.bouncycastle.asn1.tsp;
From e05e4b78ae963f96daa28bfd86077bc4d8a14f5b Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 6 Mar 2024 15:29:56 +1100
Subject: [PATCH 0144/1846] move of ASN.1 isara, iso, kisa, and microsoft to
util package
---
.../util/AlgorithmIdentifierFactory.java | 2 +-
.../crypto/util/CipherFactory.java | 2 +-
.../util/CipherKeyGeneratorFactory.java | 2 +-
.../asn1/isara/IsaraObjectIdentifiers.java | 22 ++++++++++++
.../asn1/iso/ISOIECObjectIdentifiers.java | 35 +++++++++++++++++++
.../asn1/kisa/KISAObjectIdentifiers.java | 31 ++++++++++++++++
.../microsoft/MicrosoftObjectIdentifiers.java | 30 ++++++++++++++++
.../pqc/crypto/util/PublicKeyFactory.java | 2 +-
.../util/SubjectPublicKeyInfoFactory.java | 2 +-
.../pqc/crypto/util/PublicKeyFactory.java | 2 +-
.../util/SubjectPublicKeyInfoFactory.java | 2 +-
.../pqc/crypto/util/PublicKeyFactory.java | 2 +-
.../util/SubjectPublicKeyInfoFactory.java | 2 +-
prov/src/main/ext-jdk1.9/module-info.java | 4 ---
.../asymmetric/util/BaseAgreementSpi.java | 2 +-
.../jcajce/provider/digest/Whirlpool.java | 2 +-
.../keystore/bcfks/BcFKSKeyStoreSpi.java | 2 +-
.../jcajce/provider/symmetric/SEED.java | 2 +-
.../jcajce/util/MessageDigestUtils.java | 2 +-
.../jce/provider/BouncyCastleProvider.java | 2 +-
.../provider/ProvOcspRevocationChecker.java | 2 +-
.../jce/provider/ProvRevocationChecker.java | 2 +-
.../pqc/jcajce/provider/XMSS.java | 2 +-
prov/src/main/jdk1.9/module-info.java | 4 ---
.../jce/provider/test/DigestTest.java | 2 +-
.../jce/provider/test/SEEDTest.java | 17 ++++-----
.../asn1/isara/IsaraObjectIdentifiers.java | 0
.../asn1/iso/ISOIECObjectIdentifiers.java | 0
.../asn1/kisa/KISAObjectIdentifiers.java | 0
.../microsoft/MicrosoftObjectIdentifiers.java | 0
util/src/main/jdk1.9/module-info.java | 4 +++
31 files changed, 150 insertions(+), 35 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/isara/IsaraObjectIdentifiers.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/iso/ISOIECObjectIdentifiers.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/kisa/KISAObjectIdentifiers.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/microsoft/MicrosoftObjectIdentifiers.java
rename {core => util}/src/main/java/org/bouncycastle/asn1/isara/IsaraObjectIdentifiers.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/iso/ISOIECObjectIdentifiers.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/microsoft/MicrosoftObjectIdentifiers.java (100%)
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
index f305dd65d6..3d4b4b1629 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
@@ -5,7 +5,6 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.misc.CAST5CBCParameters;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -13,6 +12,7 @@
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.internal.asn1.cms.GCMParameters;
+import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
index 7af9c6a010..3e93d08183 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
@@ -6,7 +6,6 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.misc.CAST5CBCParameters;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
@@ -36,6 +35,7 @@
import org.bouncycastle.crypto.params.RC2Parameters;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.internal.asn1.cms.GCMParameters;
+import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java
index 2e1f10e4c8..740995444f 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java
@@ -3,13 +3,13 @@
import java.security.SecureRandom;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.KeyGenerationParameters;
import org.bouncycastle.crypto.generators.DESKeyGenerator;
import org.bouncycastle.crypto.generators.DESedeKeyGenerator;
+import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/isara/IsaraObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/isara/IsaraObjectIdentifiers.java
new file mode 100644
index 0000000000..47ad51b651
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/isara/IsaraObjectIdentifiers.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.internal.asn1.isara;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface IsaraObjectIdentifiers
+{
+ /*
+ id-alg-xmss OBJECT IDENTIFIER ::= { itu-t(0)
+ identified-organization(4) etsi(0) reserved(127)
+ etsi-identified-organization(0) isara(15) algorithms(1)
+ asymmetric(1) xmss(13) 0 }
+ */
+ static ASN1ObjectIdentifier id_alg_xmss = new ASN1ObjectIdentifier("0.4.0.127.0.15.1.1.13.0");
+
+ /*
+ id-alg-xmssmt OBJECT IDENTIFIER ::= { itu-t(0)
+ identified-organization(4) etsi(0) reserved(127)
+ etsi-identified-organization(0) isara(15) algorithms(1)
+ asymmetric(1) xmssmt(14) 0 }
+ */
+ static ASN1ObjectIdentifier id_alg_xmssmt = new ASN1ObjectIdentifier("0.4.0.127.0.15.1.1.14.0");
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/iso/ISOIECObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/iso/ISOIECObjectIdentifiers.java
new file mode 100644
index 0000000000..5b9ae28ce9
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/iso/ISOIECObjectIdentifiers.java
@@ -0,0 +1,35 @@
+package org.bouncycastle.internal.asn1.iso;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * OIDS from ISO/IEC 10118-3:2004
+ */
+public interface ISOIECObjectIdentifiers
+{
+ ASN1ObjectIdentifier iso_encryption_algorithms = new ASN1ObjectIdentifier("1.0.10118");
+
+ ASN1ObjectIdentifier hash_algorithms = iso_encryption_algorithms.branch("3.0");
+
+ ASN1ObjectIdentifier ripemd160 = hash_algorithms.branch("49");
+ ASN1ObjectIdentifier ripemd128 = hash_algorithms.branch("50");
+ ASN1ObjectIdentifier whirlpool = hash_algorithms.branch("55");
+
+
+
+ /**
+ * -- ISO/IEC 18033-2 arc
+
+ is18033-2 OID ::= { iso(1) standard(0) is18033(18033) part2(2) }
+ */
+ ASN1ObjectIdentifier is18033_2 = new ASN1ObjectIdentifier("1.0.18033.2");
+
+ ASN1ObjectIdentifier id_ac_generic_hybrid = is18033_2.branch("1.2");
+
+ /**
+ id-kem-rsa OID ::= {
+ is18033-2 key-encapsulation-mechanism(2) rsa(4)
+ }
+ */
+ ASN1ObjectIdentifier id_kem_rsa = is18033_2.branch("2.4");
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/kisa/KISAObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/kisa/KISAObjectIdentifiers.java
new file mode 100644
index 0000000000..89ac25559c
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/kisa/KISAObjectIdentifiers.java
@@ -0,0 +1,31 @@
+package org.bouncycastle.internal.asn1.kisa;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * Korea Information Security Agency (KISA)
+ * ({iso(1) member-body(2) kr(410) kisa(200004)})
+ *
+ * See RFC 4010
+ * Use of the SEED Encryption Algorithm
+ * in Cryptographic Message Syntax (CMS),
+ * and RFC 4269
+ * The SEED Encryption Algorithm
+ */
+public interface KISAObjectIdentifiers
+{
+ /** RFC 4010, 4269: id-seedCBC; OID 1.2.410.200004.1.4 */
+ static final ASN1ObjectIdentifier id_seedCBC = new ASN1ObjectIdentifier("1.2.410.200004.1.4");
+
+ /** RFC 4269: id-seedMAC; OID 1.2.410.200004.1.7 */
+ static final ASN1ObjectIdentifier id_seedMAC = new ASN1ObjectIdentifier("1.2.410.200004.1.7");
+
+ /** RFC 4269: pbeWithSHA1AndSEED-CBC; OID 1.2.410.200004.1.15 */
+ static final ASN1ObjectIdentifier pbeWithSHA1AndSEED_CBC = new ASN1ObjectIdentifier("1.2.410.200004.1.15");
+
+ /** RFC 4010: id-npki-app-cmsSeed-wrap; OID 1.2.410.200004.7.1.1.1 */
+ static final ASN1ObjectIdentifier id_npki_app_cmsSeed_wrap = new ASN1ObjectIdentifier("1.2.410.200004.7.1.1.1");
+
+ /** RFC 4010: SeedEncryptionAlgorithmInCMS; OID 1.2.840.113549.1.9.16.0.24 */
+ static final ASN1ObjectIdentifier id_mod_cms_seed = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.0.24");
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/microsoft/MicrosoftObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/microsoft/MicrosoftObjectIdentifiers.java
new file mode 100644
index 0000000000..9565f1062b
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/microsoft/MicrosoftObjectIdentifiers.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.internal.asn1.microsoft;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * Microsoft
+ *
+ * Object identifier base:
+ *
+ * iso(1) identified-organization(3) dod(6) internet(1) private(4) enterprise(1) microsoft(311)
+ *
+ * 1.3.6.1.4.1.311
+ */
+public interface MicrosoftObjectIdentifiers
+{
+ /** Base OID: 1.3.6.1.4.1.311 */
+ static final ASN1ObjectIdentifier microsoft = new ASN1ObjectIdentifier("1.3.6.1.4.1.311");
+ /** OID: 1.3.6.1.4.1.311.20.2 */
+ static final ASN1ObjectIdentifier microsoftCertTemplateV1 = microsoft.branch("20.2");
+ /** OID: 1.3.6.1.4.1.311.21.1 */
+ static final ASN1ObjectIdentifier microsoftCaVersion = microsoft.branch("21.1");
+ /** OID: 1.3.6.1.4.1.311.21.2 */
+ static final ASN1ObjectIdentifier microsoftPrevCaCertHash = microsoft.branch("21.2");
+ /** OID: 1.3.6.1.4.1.311.21.4 */
+ static final ASN1ObjectIdentifier microsoftCrlNextPublish = microsoft.branch("21.4");
+ /** OID: 1.3.6.1.4.1.311.21.7 */
+ static final ASN1ObjectIdentifier microsoftCertTemplateV2 = microsoft.branch("21.7");
+ /** OID: 1.3.6.1.4.1.311.21.10 */
+ static final ASN1ObjectIdentifier microsoftAppPolicies = microsoft.branch("21.10");
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
index e784ac00d1..f9914f5c38 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
@@ -12,11 +12,11 @@
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
-import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.pqc.asn1.CMCEPublicKey;
import org.bouncycastle.pqc.asn1.KyberPublicKey;
import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey;
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
index 834c9dee39..a6062e2ce2 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
@@ -4,11 +4,11 @@
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.pqc.asn1.McElieceCCA2PublicKey;
import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
import org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
diff --git a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
index f4d06f57a5..10908bd5a4 100644
--- a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
+++ b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
@@ -12,7 +12,7 @@
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
-import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
+import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
diff --git a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
index 18ecff89cd..66e3ae3960 100644
--- a/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
+++ b/core/src/main/jdk1.1/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
@@ -4,7 +4,7 @@
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
+import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
diff --git a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
index 49877b80fd..ce82d7c6c5 100644
--- a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
+++ b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
@@ -12,7 +12,7 @@
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
-import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
+import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
diff --git a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
index 7f7aa2a228..8de43144a4 100644
--- a/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
+++ b/core/src/main/jdk1.4/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
@@ -4,7 +4,7 @@
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
+import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
diff --git a/prov/src/main/ext-jdk1.9/module-info.java b/prov/src/main/ext-jdk1.9/module-info.java
index 7c7275aaef..0794f6ef0b 100644
--- a/prov/src/main/ext-jdk1.9/module-info.java
+++ b/prov/src/main/ext-jdk1.9/module-info.java
@@ -15,10 +15,6 @@
exports org.bouncycastle.asn1.cryptopro;
exports org.bouncycastle.asn1.edec;
exports org.bouncycastle.asn1.gm;
- exports org.bouncycastle.asn1.isara;
- exports org.bouncycastle.asn1.iso;
- exports org.bouncycastle.asn1.kisa;
- exports org.bouncycastle.asn1.microsoft;
exports org.bouncycastle.asn1.misc;
exports org.bouncycastle.asn1.nist;
exports org.bouncycastle.asn1.nsri;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
index 70323de34d..8536d28944 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -17,7 +17,6 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -29,6 +28,7 @@
import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.crypto.params.KDFParameters;
import org.bouncycastle.internal.asn1.gnu.GNUObjectIdentifiers;
+import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.spec.HybridValueParameterSpec;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Whirlpool.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Whirlpool.java
index e9d22d301f..853db86d10 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Whirlpool.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Whirlpool.java
@@ -1,9 +1,9 @@
package org.bouncycastle.jcajce.provider.digest;
-import org.bouncycastle.asn1.iso.ISOIECObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.digests.WhirlpoolDigest;
import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.internal.asn1.iso.ISOIECObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
index 8f581f8558..ac92fbf6ab 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
@@ -61,7 +61,6 @@
import org.bouncycastle.asn1.bc.PbkdMacIntegrityCheck;
import org.bouncycastle.asn1.bc.SecretKeyData;
import org.bouncycastle.asn1.bc.SignatureCheck;
-import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.misc.ScryptParams;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
@@ -87,6 +86,7 @@
import org.bouncycastle.crypto.util.PBKDFConfig;
import org.bouncycastle.crypto.util.ScryptConfig;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
+import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.BCFKSLoadStoreParameter;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java
index 62a4efaa97..d0ef6116c7 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SEED.java
@@ -7,7 +7,6 @@
import javax.crypto.spec.IvParameterSpec;
-import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
@@ -18,6 +17,7 @@
import org.bouncycastle.crypto.macs.GMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
+import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java b/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
index cb97cf8fea..8e14c61466 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
@@ -7,13 +7,13 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
-import org.bouncycastle.asn1.iso.ISOIECObjectIdentifiers;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.internal.asn1.gnu.GNUObjectIdentifiers;
+import org.bouncycastle.internal.asn1.iso.ISOIECObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
public class MessageDigestUtils
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
index 92df956374..5a2555d78d 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/BouncyCastleProvider.java
@@ -15,7 +15,6 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
-import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
@@ -23,6 +22,7 @@
import org.bouncycastle.crypto.CryptoServiceProperties;
import org.bouncycastle.crypto.CryptoServicePurpose;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.config.ProviderConfiguration;
import org.bouncycastle.jcajce.provider.symmetric.util.ClassUtil;
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java b/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
index e2a51904d8..99e11cb7f4 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
@@ -31,7 +31,6 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
import org.bouncycastle.asn1.ocsp.CertID;
@@ -59,6 +58,7 @@
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.internal.asn1.bsi.BSIObjectIdentifiers;
import org.bouncycastle.internal.asn1.eac.EACObjectIdentifiers;
+import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.PKIXCertRevocationChecker;
import org.bouncycastle.jcajce.PKIXCertRevocationCheckerParameters;
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java b/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java
index 58dbd0c24c..809ef05843 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java
@@ -12,13 +12,13 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.internal.asn1.bsi.BSIObjectIdentifiers;
import org.bouncycastle.internal.asn1.eac.EACObjectIdentifiers;
+import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.PKIXCertRevocationChecker;
import org.bouncycastle.jcajce.PKIXCertRevocationCheckerParameters;
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/XMSS.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/XMSS.java
index 5b76edb8e4..0bcfecd70b 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/XMSS.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/XMSS.java
@@ -1,7 +1,7 @@
package org.bouncycastle.pqc.jcajce.provider;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
-import org.bouncycastle.asn1.isara.IsaraObjectIdentifiers;
+import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
import org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
diff --git a/prov/src/main/jdk1.9/module-info.java b/prov/src/main/jdk1.9/module-info.java
index 5fef8c2ce4..8b5d40d169 100644
--- a/prov/src/main/jdk1.9/module-info.java
+++ b/prov/src/main/jdk1.9/module-info.java
@@ -17,10 +17,6 @@
exports org.bouncycastle.asn1.cryptopro;
exports org.bouncycastle.asn1.edec;
exports org.bouncycastle.asn1.gm;
- exports org.bouncycastle.asn1.isara;
- exports org.bouncycastle.asn1.iso;
- exports org.bouncycastle.asn1.kisa;
- exports org.bouncycastle.asn1.microsoft;
exports org.bouncycastle.asn1.misc;
exports org.bouncycastle.asn1.nist;
exports org.bouncycastle.asn1.nsri;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/DigestTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/DigestTest.java
index 99d72de5e2..b466f35f49 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/DigestTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/DigestTest.java
@@ -3,12 +3,12 @@
import java.security.MessageDigest;
import java.security.Security;
-import org.bouncycastle.asn1.iso.ISOIECObjectIdentifiers;
import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.ua.UAObjectIdentifiers;
+import org.bouncycastle.internal.asn1.iso.ISOIECObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/SEEDTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/SEEDTest.java
index 203646470a..f1c9a21c56 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/SEEDTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/SEEDTest.java
@@ -1,13 +1,5 @@
package org.bouncycastle.jce.provider.test;
-import org.bouncycastle.asn1.kisa.KISAObjectIdentifiers;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.util.encoders.Hex;
-
-import javax.crypto.Cipher;
-import javax.crypto.CipherInputStream;
-import javax.crypto.CipherOutputStream;
-import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -15,6 +7,15 @@
import java.security.Key;
import java.security.Security;
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import javax.crypto.CipherOutputStream;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.encoders.Hex;
+
/**
* basic test class for SEED
*/
diff --git a/core/src/main/java/org/bouncycastle/asn1/isara/IsaraObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/isara/IsaraObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/isara/IsaraObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/isara/IsaraObjectIdentifiers.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/iso/ISOIECObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/iso/ISOIECObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/iso/ISOIECObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/iso/ISOIECObjectIdentifiers.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/kisa/KISAObjectIdentifiers.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/microsoft/MicrosoftObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/microsoft/MicrosoftObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/microsoft/MicrosoftObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/microsoft/MicrosoftObjectIdentifiers.java
diff --git a/util/src/main/jdk1.9/module-info.java b/util/src/main/jdk1.9/module-info.java
index ed7737ddcb..3522889a05 100644
--- a/util/src/main/jdk1.9/module-info.java
+++ b/util/src/main/jdk1.9/module-info.java
@@ -17,9 +17,13 @@
exports org.bouncycastle.asn1.gnu;
exports org.bouncycastle.asn1.iana;
exports org.bouncycastle.asn1.icao;
+ exports org.bouncycastle.asn1.isara;
exports org.bouncycastle.asn1.isismtt;
exports org.bouncycastle.asn1.isismtt.ocsp;
exports org.bouncycastle.asn1.isismtt.x509;
+ exports org.bouncycastle.asn1.iso;
+ exports org.bouncycastle.asn1.kisa;
+ exports org.bouncycastle.asn1.microsoft;
exports org.bouncycastle.asn1.mozilla;
exports org.bouncycastle.asn1.ntt;
exports org.bouncycastle.asn1.oiw;
From 6a4e8d67ed06a6abea9bf478f9b21bbc88709300 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Thu, 7 Mar 2024 12:46:58 +0700
Subject: [PATCH 0145/1846] Refactoring
---
.../crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
index 7d8aa929e2..46093002ac 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
@@ -4,7 +4,6 @@
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.RSAKeyParameters;
-import org.bouncycastle.crypto.tls.TlsRsaKeyExchange;
import org.bouncycastle.tls.Certificate;
import org.bouncycastle.tls.ProtocolVersion;
import org.bouncycastle.tls.TlsCredentialedDecryptor;
@@ -79,9 +78,9 @@ protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
{
ProtocolVersion expectedVersion = cryptoParams.getRSAPreMasterSecretVersion();
- byte[] M = TlsRsaKeyExchange.decryptPreMasterSecret(encryptedPreMasterSecret, rsaServerPrivateKey,
- expectedVersion.getFullVersion(), crypto.getSecureRandom());
+ byte[] preMasterSecret = org.bouncycastle.crypto.tls.TlsRsaKeyExchange.decryptPreMasterSecret(
+ encryptedPreMasterSecret, rsaServerPrivateKey, expectedVersion.getFullVersion(), crypto.getSecureRandom());
- return crypto.createSecret(M);
+ return crypto.createSecret(preMasterSecret);
}
}
From 379872cd402a92e202dbe0628874ccaff66d8f01 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Thu, 7 Mar 2024 19:27:56 +0700
Subject: [PATCH 0146/1846] Fix headings
---
docs/releasenotes.html | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/docs/releasenotes.html b/docs/releasenotes.html
index 3f6c1446a2..b4d15ce855 100644
--- a/docs/releasenotes.html
+++ b/docs/releasenotes.html
@@ -21,15 +21,15 @@ 2.0 Release History
2.1.1 Version
Release: 1.78
Date: TBD
-2.1.3 Notes.
-
-- An implementation of MLS (RFC 9420 - The Messaging Layer Security Protocol) has been added as a new module.
-
2.1.2 Defects Fixed
- Issues with a dangling weak reference causing intermittent NullPointerExceptions in the OcspCache have been fixed.
-2.1.2 Notes.
+2.1.3 Additional Features and Functionality
+
+- An implementation of MLS (RFC 9420 - The Messaging Layer Security Protocol) has been added as a new module.
+
+2.1.4 Notes.
- Both versions of NTRUPrime have been updated to produce 256 bit secrets in line with Kyber. This should also bring them into line with other implementations such as those used in OpenSSH now.
@@ -65,7 +65,7 @@ 2.2.3 Additional Features and Functionality
TLS: RSA key exchange cipher suites are now disabled by default.
Support has been added for PKCS#10 requests to allow certificates using the altSignature/altPublicKey extensions.
-2.2.3 Notes.
+2.2.4 Notes.
- Kyber and Dilithium have been updated according to the latest draft of the standard. Dilithium-AES and Kyber-AES have now been removed. Kyber now produces 256 bit secrets for all parameter sets (in line with the draft standard).
- NTRU has been updated to produce 256 bit secrets in line with Kyber.
From ee8ea02dfb120dce808c75a8863be3d4c27d2f09 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Thu, 7 Mar 2024 19:35:50 +0700
Subject: [PATCH 0147/1846] Belated release note for BCJSSE change
---
docs/releasenotes.html | 3 +++
1 file changed, 3 insertions(+)
diff --git a/docs/releasenotes.html b/docs/releasenotes.html
index b4d15ce855..60e2b90bf1 100644
--- a/docs/releasenotes.html
+++ b/docs/releasenotes.html
@@ -32,6 +32,9 @@ 2.1.3 Additional Features and Functionality
2.1.4 Notes.
- Both versions of NTRUPrime have been updated to produce 256 bit secrets in line with Kyber. This should also bring them into line with other implementations such as those used in OpenSSH now.
+- BCJSSE: The boolean system property 'org.bouncycastle.jsse.fips.allowRSAKeyExchange" now defaults to false. All RSA
+key exchange cipher suites will therefore be disabled when the BCJSSE provider is used in FIPS mode, unless this system
+property is explicitly set to true.
2.2.1 Version
From 3b77ea5d90ace95ab943cfcb3d466950245a568a Mon Sep 17 00:00:00 2001
From: David Hook
Date: Fri, 8 Mar 2024 10:17:04 +1100
Subject: [PATCH 0148/1846] move of ASN.1 edec, misc, nsri, and rosstandart to
util package
---
.../asn1/cryptopro/ECGOST3410NamedCurves.java | 2 +-
.../util/AlgorithmIdentifierFactory.java | 2 +-
.../crypto/util/CipherFactory.java | 4 +-
.../crypto/util/PBKDF2Config.java | 2 +-
.../crypto/util/PrivateKeyFactory.java | 4 +-
.../crypto/util/PrivateKeyInfoFactory.java | 4 +-
.../crypto/util/PublicKeyFactory.java | 4 +-
.../crypto/util/ScryptConfig.java | 2 +-
.../util/SubjectPublicKeyInfoFactory.java | 5 +-
.../asn1/edec/EdECObjectIdentifiers.java | 16 ++
.../asn1/misc/CAST5CBCParameters.java | 79 +++++++++
.../internal/asn1/misc/IDEACBCPar.java | 82 +++++++++
.../asn1/misc/MiscObjectIdentifiers.java | 166 ++++++++++++++++++
.../internal/asn1/misc/NetscapeCertType.java | 60 +++++++
.../asn1/misc/NetscapeRevocationURL.java | 19 ++
.../internal/asn1/misc/ScryptParams.java | 147 ++++++++++++++++
.../asn1/misc/VerisignCzagExtension.java | 19 ++
.../asn1/nsri/NSRIObjectIdentifiers.java | 58 ++++++
.../RosstandartObjectIdentifiers.java | 52 ++++++
.../asn1/test/GetInstanceTest.java | 4 +-
.../org/bouncycastle/asn1/test/MiscTest.java | 10 +-
.../asn1/test/NetscapeCertTypeTest.java | 2 +-
.../crypto/test/GOST3410Test.java | 2 +-
prov/src/main/ext-jdk1.9/module-info.java | 4 -
.../jcajce/CompositePrivateKey.java | 2 +-
.../jcajce/CompositePublicKey.java | 2 +-
.../jcajce/provider/asymmetric/COMPOSITE.java | 2 +-
.../jcajce/provider/asymmetric/ECGOST.java | 2 +-
.../jcajce/provider/asymmetric/EdEC.java | 2 +-
.../ecgost12/BCECGOST3410_2012PrivateKey.java | 2 +-
.../ecgost12/BCECGOST3410_2012PublicKey.java | 2 +-
.../asymmetric/ecgost12/KeyFactorySpi.java | 2 +-
.../asymmetric/edec/BCEdDSAPrivateKey.java | 2 +-
.../asymmetric/edec/BCEdDSAPublicKey.java | 2 +-
.../asymmetric/edec/BCXDHPrivateKey.java | 2 +-
.../asymmetric/edec/BCXDHPublicKey.java | 2 +-
.../asymmetric/edec/KeyFactorySpi.java | 2 +-
.../asymmetric/edec/KeyPairGeneratorSpi.java | 2 +-
.../asymmetric/util/BaseAgreementSpi.java | 2 +-
.../asymmetric/x509/X509CertificateImpl.java | 8 +-
.../asymmetric/x509/X509SignatureUtil.java | 4 +-
.../jcajce/provider/digest/Blake2b.java | 2 +-
.../jcajce/provider/digest/Blake2s.java | 2 +-
.../jcajce/provider/digest/Blake3.java | 2 +-
.../jcajce/provider/digest/GOST3411.java | 2 +-
.../keystore/bcfks/BcFKSKeyStoreSpi.java | 6 +-
.../keystore/pkcs12/PKCS12KeyStoreSpi.java | 2 +-
.../jcajce/provider/symmetric/ARIA.java | 2 +-
.../jcajce/provider/symmetric/Blowfish.java | 2 +-
.../jcajce/provider/symmetric/CAST5.java | 4 +-
.../jcajce/provider/symmetric/GOST28147.java | 2 +-
.../jcajce/provider/symmetric/IDEA.java | 4 +-
.../jcajce/provider/symmetric/SCRYPT.java | 2 +-
.../jcajce/spec/EdDSAParameterSpec.java | 2 +-
.../jcajce/spec/GOST28147ParameterSpec.java | 2 +-
.../spec/GOST28147WrapParameterSpec.java | 2 +-
.../jcajce/spec/GOST3410ParameterSpec.java | 2 +-
.../jcajce/spec/XDHParameterSpec.java | 2 +-
.../jcajce/util/MessageDigestUtils.java | 2 +-
.../provider/ProvOcspRevocationChecker.java | 2 +-
.../jce/provider/ProvRevocationChecker.java | 2 +-
.../jce/provider/X509CertificateObject.java | 8 +-
.../asymmetric/x509/X509SignatureUtil.java | 2 +-
.../jce/provider/X509CertificateObject.java | 8 +-
.../asymmetric/edec/KeyFactorySpi.java | 2 +-
.../asymmetric/edec/KeyPairGeneratorSpi.java | 2 +-
.../asymmetric/edec/KeyFactorySpi.java | 2 +-
.../asymmetric/edec/KeyPairGeneratorSpi.java | 2 +-
.../asymmetric/x509/X509CertificateImpl.java | 8 +-
.../asymmetric/x509/X509SignatureUtil.java | 2 +-
.../jce/provider/JDKAlgorithmParameters.java | 3 +-
.../jce/provider/X509CertificateObject.java | 8 +-
.../jcajce/CompositePrivateKey.java | 2 +-
.../jcajce/CompositePublicKey.java | 2 +-
.../jcajce/provider/asymmetric/ECGOST.java | 2 +-
.../asymmetric/edec/KeyFactorySpi.java | 2 +-
.../asymmetric/edec/KeyPairGeneratorSpi.java | 2 +-
.../keystore/bcfks/BcFKSKeyStoreSpi.java | 4 +-
prov/src/main/jdk1.9/module-info.java | 4 -
.../jce/provider/test/ARIATest.java | 2 +-
.../jce/provider/test/BCFKSStoreTest.java | 4 +-
.../provider/test/CertPathValidatorTest.java | 8 +-
.../jce/provider/test/DigestTest.java | 4 +-
.../jce/provider/test/EdECTest.java | 2 +-
.../jce/provider/test/GOST3410Test.java | 2 +-
.../jce/provider/test/HMacTest.java | 2 +-
.../jce/provider/test/PKCS12StoreTest.java | 2 +-
.../jce/provider/test/TestCertificateGen.java | 2 +-
.../jce/provider/test/TestUtils.java | 2 +-
.../jce/provider/test/EdECTest.java | 2 +-
.../asn1/edec/EdECObjectIdentifiers.java | 0
.../asn1/misc/CAST5CBCParameters.java | 0
.../bouncycastle/asn1/misc/IDEACBCPar.java | 0
.../asn1/misc/MiscObjectIdentifiers.java | 0
.../asn1/misc/NetscapeCertType.java | 0
.../asn1/misc/NetscapeRevocationURL.java | 0
.../bouncycastle/asn1/misc/ScryptParams.java | 0
.../asn1/misc/VerisignCzagExtension.java | 0
.../asn1/nsri/NSRIObjectIdentifiers.java | 0
.../RosstandartObjectIdentifiers.java | 0
util/src/main/jdk1.9/module-info.java | 4 +
.../bouncycastle/asn1/util/test/AllTests.java | 2 +-
.../asn1/misc/test/CMPUpdates16Test.java | 2 +-
.../asn1/misc/test/GetInstanceTest.java | 7 +-
104 files changed, 821 insertions(+), 130 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/edec/EdECObjectIdentifiers.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/misc/CAST5CBCParameters.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/misc/IDEACBCPar.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/misc/NetscapeCertType.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/misc/NetscapeRevocationURL.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/misc/ScryptParams.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/misc/VerisignCzagExtension.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/nsri/NSRIObjectIdentifiers.java
create mode 100644 core/src/main/java/org/bouncycastle/internal/asn1/rosstandart/RosstandartObjectIdentifiers.java
rename {core => util}/src/main/java/org/bouncycastle/asn1/edec/EdECObjectIdentifiers.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/misc/ScryptParams.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java (100%)
rename {core => util}/src/main/java/org/bouncycastle/asn1/rosstandart/RosstandartObjectIdentifiers.java (100%)
rename util/src/test/java/org/bouncycastle/{ => internal}/asn1/misc/test/CMPUpdates16Test.java (98%)
rename util/src/test/java/org/bouncycastle/{ => internal}/asn1/misc/test/GetInstanceTest.java (99%)
diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java
index 80b2c83903..27cf2d664b 100644
--- a/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java
+++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java
@@ -5,10 +5,10 @@
import java.util.Hashtable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.asn1.x9.X9ECParametersHolder;
import org.bouncycastle.asn1.x9.X9ECPoint;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
index 3d4b4b1629..ea575f8ab2 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java
@@ -5,7 +5,6 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.misc.CAST5CBCParameters;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
@@ -13,6 +12,7 @@
import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.internal.asn1.cms.GCMParameters;
import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.CAST5CBCParameters;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
index 3e93d08183..04e53d2d36 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/CipherFactory.java
@@ -6,8 +6,6 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.misc.CAST5CBCParameters;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
@@ -36,6 +34,8 @@
import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.internal.asn1.cms.GCMParameters;
import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.CAST5CBCParameters;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PBKDF2Config.java b/core/src/main/java/org/bouncycastle/crypto/util/PBKDF2Config.java
index f5639b3dd2..8f672bbb66 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/PBKDF2Config.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/PBKDF2Config.java
@@ -9,8 +9,8 @@
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.util.Integers;
/**
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
index ef34cb4af0..edc436365d 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyFactory.java
@@ -14,12 +14,10 @@
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.DHParameter;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.sec.ECPrivateKey;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.DSAParameter;
@@ -45,8 +43,10 @@
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.X448PrivateKeyParameters;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.util.Arrays;
/**
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java
index cd4bf4d36c..1b00473f5e 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java
@@ -14,11 +14,9 @@
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.RSAPrivateKey;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.sec.ECPrivateKey;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.DSAParameter;
@@ -39,6 +37,8 @@
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.X448PrivateKeyParameters;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.math.ec.FixedPointCombMultiplier;
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
index 9d0c5f1a75..a8c7055e48 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/PublicKeyFactory.java
@@ -17,11 +17,9 @@
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.DHParameter;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.ua.DSTU4145BinaryField;
import org.bouncycastle.asn1.ua.DSTU4145ECBinary;
import org.bouncycastle.asn1.ua.DSTU4145NamedCurves;
@@ -59,8 +57,10 @@
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
import org.bouncycastle.crypto.params.X448PublicKeyParameters;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.ElGamalParameter;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.Arrays;
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/ScryptConfig.java b/core/src/main/java/org/bouncycastle/crypto/util/ScryptConfig.java
index bb02683b38..2ebbc53397 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/ScryptConfig.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/ScryptConfig.java
@@ -1,6 +1,6 @@
package org.bouncycastle.crypto.util;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
/**
* Configuration class for a PBKDF based around scrypt.
diff --git a/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java b/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java
index 40e4c39b1d..3ade492281 100644
--- a/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java
+++ b/core/src/main/java/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java
@@ -8,15 +8,12 @@
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.DSAParameter;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
@@ -36,6 +33,8 @@
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
import org.bouncycastle.crypto.params.X448PublicKeyParameters;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
/**
* Factory to create ASN.1 subject public key info objects from lightweight public keys.
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/edec/EdECObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/edec/EdECObjectIdentifiers.java
new file mode 100644
index 0000000000..5ef798e84e
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/edec/EdECObjectIdentifiers.java
@@ -0,0 +1,16 @@
+package org.bouncycastle.internal.asn1.edec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+/**
+ * Edwards Elliptic Curve Object Identifiers (RFC 8410)
+ */
+public interface EdECObjectIdentifiers
+{
+ ASN1ObjectIdentifier id_edwards_curve_algs = new ASN1ObjectIdentifier("1.3.101");
+
+ ASN1ObjectIdentifier id_X25519 = id_edwards_curve_algs.branch("110").intern();
+ ASN1ObjectIdentifier id_X448 = id_edwards_curve_algs.branch("111").intern();
+ ASN1ObjectIdentifier id_Ed25519 = id_edwards_curve_algs.branch("112").intern();
+ ASN1ObjectIdentifier id_Ed448 = id_edwards_curve_algs.branch("113").intern();
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/misc/CAST5CBCParameters.java b/core/src/main/java/org/bouncycastle/internal/asn1/misc/CAST5CBCParameters.java
new file mode 100644
index 0000000000..78c4066245
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/misc/CAST5CBCParameters.java
@@ -0,0 +1,79 @@
+package org.bouncycastle.internal.asn1.misc;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.util.Arrays;
+
+public class CAST5CBCParameters
+ extends ASN1Object
+{
+ ASN1Integer keyLength;
+ ASN1OctetString iv;
+
+ public static CAST5CBCParameters getInstance(
+ Object o)
+ {
+ if (o instanceof CAST5CBCParameters)
+ {
+ return (CAST5CBCParameters)o;
+ }
+ else if (o != null)
+ {
+ return new CAST5CBCParameters(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public CAST5CBCParameters(
+ byte[] iv,
+ int keyLength)
+ {
+ this.iv = new DEROctetString(Arrays.clone(iv));
+ this.keyLength = new ASN1Integer(keyLength);
+ }
+
+ private CAST5CBCParameters(
+ ASN1Sequence seq)
+ {
+ iv = (ASN1OctetString)seq.getObjectAt(0);
+ keyLength = (ASN1Integer)seq.getObjectAt(1);
+ }
+
+ public byte[] getIV()
+ {
+ return Arrays.clone(iv.getOctets());
+ }
+
+ public int getKeyLength()
+ {
+ return keyLength.intValueExact();
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * cast5CBCParameters ::= SEQUENCE {
+ * iv OCTET STRING DEFAULT 0,
+ * -- Initialization vector
+ * keyLength INTEGER
+ * -- Key length, in bits
+ * }
+ *
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector(2);
+
+ v.add(iv);
+ v.add(keyLength);
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/misc/IDEACBCPar.java b/core/src/main/java/org/bouncycastle/internal/asn1/misc/IDEACBCPar.java
new file mode 100644
index 0000000000..ae70d167dc
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/misc/IDEACBCPar.java
@@ -0,0 +1,82 @@
+package org.bouncycastle.internal.asn1.misc;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.util.Arrays;
+
+public class IDEACBCPar
+ extends ASN1Object
+{
+ ASN1OctetString iv;
+
+ public static IDEACBCPar getInstance(
+ Object o)
+ {
+ if (o instanceof IDEACBCPar)
+ {
+ return (IDEACBCPar)o;
+ }
+ else if (o != null)
+ {
+ return new IDEACBCPar(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ public IDEACBCPar(
+ byte[] iv)
+ {
+ this.iv = new DEROctetString(Arrays.clone(iv));
+ }
+
+ private IDEACBCPar(
+ ASN1Sequence seq)
+ {
+ if (seq.size() == 1)
+ {
+ iv = (ASN1OctetString)seq.getObjectAt(0);
+ }
+ else
+ {
+ iv = null;
+ }
+ }
+
+ public byte[] getIV()
+ {
+ if (iv != null)
+ {
+ return Arrays.clone(iv.getOctets());
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Produce an object suitable for an ASN1OutputStream.
+ *
+ * IDEA-CBCPar ::= SEQUENCE {
+ * iv OCTET STRING OPTIONAL -- exactly 8 octets
+ * }
+ *
+ */
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector(1);
+
+ if (iv != null)
+ {
+ v.add(iv);
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java
new file mode 100644
index 0000000000..a88c98e0d0
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java
@@ -0,0 +1,166 @@
+package org.bouncycastle.internal.asn1.misc;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface MiscObjectIdentifiers
+{
+ //
+ // Netscape
+ // iso/itu(2) joint-assign(16) us(840) uscompany(1) netscape(113730) cert-extensions(1) }
+ //
+ /**
+ * Netscape cert extensions OID base: 2.16.840.1.113730.1
+ */
+ ASN1ObjectIdentifier netscape = new ASN1ObjectIdentifier("2.16.840.1.113730.1");
+ /**
+ * Netscape cert CertType OID: 2.16.840.1.113730.1.1
+ */
+ ASN1ObjectIdentifier netscapeCertType = netscape.branch("1");
+ /**
+ * Netscape cert BaseURL OID: 2.16.840.1.113730.1.2
+ */
+ ASN1ObjectIdentifier netscapeBaseURL = netscape.branch("2");
+ /**
+ * Netscape cert RevocationURL OID: 2.16.840.1.113730.1.3
+ */
+ ASN1ObjectIdentifier netscapeRevocationURL = netscape.branch("3");
+ /**
+ * Netscape cert CARevocationURL OID: 2.16.840.1.113730.1.4
+ */
+ ASN1ObjectIdentifier netscapeCARevocationURL = netscape.branch("4");
+ /**
+ * Netscape cert RenewalURL OID: 2.16.840.1.113730.1.7
+ */
+ ASN1ObjectIdentifier netscapeRenewalURL = netscape.branch("7");
+ /**
+ * Netscape cert CApolicyURL OID: 2.16.840.1.113730.1.8
+ */
+ ASN1ObjectIdentifier netscapeCApolicyURL = netscape.branch("8");
+ /**
+ * Netscape cert SSLServerName OID: 2.16.840.1.113730.1.12
+ */
+ ASN1ObjectIdentifier netscapeSSLServerName = netscape.branch("12");
+ /**
+ * Netscape cert CertComment OID: 2.16.840.1.113730.1.13
+ */
+ ASN1ObjectIdentifier netscapeCertComment = netscape.branch("13");
+
+ //
+ // Verisign
+ // iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) }
+ //
+ /**
+ * Verisign OID base: 2.16.840.1.113733.1
+ */
+ ASN1ObjectIdentifier verisign = new ASN1ObjectIdentifier("2.16.840.1.113733.1");
+
+ /**
+ * Verisign CZAG (Country,Zip,Age,Gender) Extension OID: 2.16.840.1.113733.1.6.3
+ */
+ ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3");
+
+ ASN1ObjectIdentifier verisignPrivate_6_9 = verisign.branch("6.9");
+ ASN1ObjectIdentifier verisignOnSiteJurisdictionHash = verisign.branch("6.11");
+ ASN1ObjectIdentifier verisignBitString_6_13 = verisign.branch("6.13");
+
+ /**
+ * Verisign D&B D-U-N-S number Extension OID: 2.16.840.1.113733.1.6.15
+ */
+ ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15");
+
+ ASN1ObjectIdentifier verisignIssStrongCrypto = verisign.branch("8.1");
+
+ //
+ // Novell
+ // iso/itu(2) country(16) us(840) organization(1) novell(113719)
+ //
+ /**
+ * Novell OID base: 2.16.840.1.113719
+ */
+ ASN1ObjectIdentifier novell = new ASN1ObjectIdentifier("2.16.840.1.113719");
+ /**
+ * Novell SecurityAttribs OID: 2.16.840.1.113719.1.9.4.1
+ */
+ ASN1ObjectIdentifier novellSecurityAttribs = novell.branch("1.9.4.1");
+
+ //
+ // Entrust
+ // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
+ //
+ /**
+ * NortelNetworks Entrust OID base: 1.2.840.113533.7
+ */
+ ASN1ObjectIdentifier entrust = new ASN1ObjectIdentifier("1.2.840.113533.7");
+ /**
+ * NortelNetworks Entrust VersionExtension OID: 1.2.840.113533.7.65.0
+ */
+ ASN1ObjectIdentifier entrustVersionExtension = entrust.branch("65.0");
+
+ /**
+ * cast5CBC OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) nt(113533) nsn(7) algorithms(66) 10} SEE RFC 2984
+ */
+ ASN1ObjectIdentifier cast5CBC = entrust.branch("66.10");
+
+ //
+ // HMAC-SHA1 hMAC-SHA1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
+ // dod(6) internet(1) security(5) mechanisms(5) 8 1 2 }
+ //
+ ASN1ObjectIdentifier hMAC_SHA1 = new ASN1ObjectIdentifier("1.3.6.1.5.5.8.1.2");
+
+ //
+ // Ascom
+ //
+ ASN1ObjectIdentifier as_sys_sec_alg_ideaCBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2");
+
+ //
+ // Peter Gutmann's Cryptlib
+ //
+ ASN1ObjectIdentifier cryptlib = new ASN1ObjectIdentifier("1.3.6.1.4.1.3029");
+
+ ASN1ObjectIdentifier cryptlib_algorithm = cryptlib.branch("1");
+ ASN1ObjectIdentifier cryptlib_algorithm_blowfish_ECB = cryptlib_algorithm.branch("1.1");
+ ASN1ObjectIdentifier cryptlib_algorithm_blowfish_CBC = cryptlib_algorithm.branch("1.2");
+ ASN1ObjectIdentifier cryptlib_algorithm_blowfish_CFB = cryptlib_algorithm.branch("1.3");
+ ASN1ObjectIdentifier cryptlib_algorithm_blowfish_OFB = cryptlib_algorithm.branch("1.4");
+
+ //
+ // Blake2b/Blake2s
+ //
+ ASN1ObjectIdentifier blake2 = new ASN1ObjectIdentifier("1.3.6.1.4.1.1722.12.2");
+
+ ASN1ObjectIdentifier id_blake2b160 = blake2.branch("1.5");
+ ASN1ObjectIdentifier id_blake2b256 = blake2.branch("1.8");
+ ASN1ObjectIdentifier id_blake2b384 = blake2.branch("1.12");
+ ASN1ObjectIdentifier id_blake2b512 = blake2.branch("1.16");
+
+ ASN1ObjectIdentifier id_blake2s128 = blake2.branch("2.4");
+ ASN1ObjectIdentifier id_blake2s160 = blake2.branch("2.5");
+ ASN1ObjectIdentifier id_blake2s224 = blake2.branch("2.7");
+ ASN1ObjectIdentifier id_blake2s256 = blake2.branch("2.8");
+
+ ASN1ObjectIdentifier blake3 = blake2.branch("3");
+
+ ASN1ObjectIdentifier blake3_256 = blake3.branch("8");
+
+ //
+ // Scrypt
+ ASN1ObjectIdentifier id_scrypt = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.4.11");
+
+ // Composite key/signature oid - prototyping
+ //
+ // id-alg-composite OBJECT IDENTIFIER ::= {
+ // iso(1) identified-organization(3) dod(6) internet(1) private(4)
+ // enterprise(1) OpenCA(18227) Algorithms(2) id-alg-composite(1) }
+ ASN1ObjectIdentifier id_alg_composite = new ASN1ObjectIdentifier("1.3.6.1.4.1.18227.2.1");
+
+ // -- To be replaced by IANA
+ //
+ //id-composite-key OBJECT IDENTIFIER ::= {
+ //
+ // joint-iso-itu-t(2) country(16) us(840) organization(1) entrust(114027)
+ //
+ // Algorithm(80) Composite(4) CompositeKey(1)
+ ASN1ObjectIdentifier id_composite_key = new ASN1ObjectIdentifier("2.16.840.1.114027.80.4.1");
+
+ ASN1ObjectIdentifier id_oracle_pkcs12_trusted_key_usage = new ASN1ObjectIdentifier("2.16.840.1.113894.746875.1.1");
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/misc/NetscapeCertType.java b/core/src/main/java/org/bouncycastle/internal/asn1/misc/NetscapeCertType.java
new file mode 100644
index 0000000000..b8ea5a0193
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/misc/NetscapeCertType.java
@@ -0,0 +1,60 @@
+package org.bouncycastle.internal.asn1.misc;
+
+import org.bouncycastle.asn1.ASN1BitString;
+import org.bouncycastle.asn1.DERBitString;
+
+/**
+ * The NetscapeCertType object.
+ *
+ * NetscapeCertType ::= BIT STRING {
+ * SSLClient (0),
+ * SSLServer (1),
+ * S/MIME (2),
+ * Object Signing (3),
+ * Reserved (4),
+ * SSL CA (5),
+ * S/MIME CA (6),
+ * Object Signing CA (7) }
+ *
+ */
+public class NetscapeCertType
+ extends DERBitString
+{
+ public static final int sslClient = (1 << 7);
+ public static final int sslServer = (1 << 6);
+ public static final int smime = (1 << 5);
+ public static final int objectSigning = (1 << 4);
+ public static final int reserved = (1 << 3);
+ public static final int sslCA = (1 << 2);
+ public static final int smimeCA = (1 << 1);
+ public static final int objectSigningCA = (1 << 0);
+
+ /**
+ * Basic constructor.
+ *
+ * @param usage - the bitwise OR of the Key Usage flags giving the
+ * allowed uses for the key.
+ * e.g. (X509NetscapeCertType.sslCA | X509NetscapeCertType.smimeCA)
+ */
+ public NetscapeCertType(
+ int usage)
+ {
+ super(getBytes(usage), getPadBits(usage));
+ }
+
+ public NetscapeCertType(
+ ASN1BitString usage)
+ {
+ super(usage.getBytes(), usage.getPadBits());
+ }
+
+ public boolean hasUsages(int usages)
+ {
+ return (intValue() & usages) == usages;
+ }
+
+ public String toString()
+ {
+ return "NetscapeCertType: 0x" + Integer.toHexString(intValue());
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/misc/NetscapeRevocationURL.java b/core/src/main/java/org/bouncycastle/internal/asn1/misc/NetscapeRevocationURL.java
new file mode 100644
index 0000000000..f8ac5e65e3
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/misc/NetscapeRevocationURL.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.internal.asn1.misc;
+
+import org.bouncycastle.asn1.ASN1IA5String;
+import org.bouncycastle.asn1.DERIA5String;
+
+public class NetscapeRevocationURL
+ extends DERIA5String
+{
+ public NetscapeRevocationURL(
+ ASN1IA5String str)
+ {
+ super(str.getString());
+ }
+
+ public String toString()
+ {
+ return "NetscapeRevocationURL: " + this.getString();
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/misc/ScryptParams.java b/core/src/main/java/org/bouncycastle/internal/asn1/misc/ScryptParams.java
new file mode 100644
index 0000000000..38641ab2a9
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/misc/ScryptParams.java
@@ -0,0 +1,147 @@
+package org.bouncycastle.internal.asn1.misc;
+
+import java.math.BigInteger;
+
+import org.bouncycastle.asn1.ASN1EncodableVector;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1Object;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.util.Arrays;
+
+/**
+ * RFC 7914 scrypt parameters.
+ *
+ *
+ * scrypt-params ::= SEQUENCE {
+ * salt OCTET STRING,
+ * costParameter INTEGER (1..MAX),
+ * blockSize INTEGER (1..MAX),
+ * parallelizationParameter INTEGER (1..MAX),
+ * keyLength INTEGER (1..MAX) OPTIONAL
+ * }
+ *
+ */
+public class ScryptParams
+ extends ASN1Object
+{
+ private final byte[] salt;
+ private final BigInteger costParameter;
+ private final BigInteger blockSize;
+ private final BigInteger parallelizationParameter;
+ private final BigInteger keyLength;
+
+ public ScryptParams(byte[] salt, int costParameter, int blockSize, int parallelizationParameter)
+ {
+ this(salt, BigInteger.valueOf(costParameter), BigInteger.valueOf(blockSize), BigInteger.valueOf(parallelizationParameter), null);
+ }
+
+ public ScryptParams(byte[] salt, int costParameter, int blockSize, int parallelizationParameter, int keyLength)
+ {
+ this(salt, BigInteger.valueOf(costParameter), BigInteger.valueOf(blockSize), BigInteger.valueOf(parallelizationParameter), BigInteger.valueOf(keyLength));
+ }
+
+ /**
+ * Base constructor.
+ *
+ * @param salt salt value
+ * @param costParameter specifies the CPU/Memory cost parameter N
+ * @param blockSize block size parameter r
+ * @param parallelizationParameter parallelization parameter
+ * @param keyLength length of key to be derived (in octects)
+ */
+ public ScryptParams(byte[] salt, BigInteger costParameter, BigInteger blockSize, BigInteger parallelizationParameter, BigInteger keyLength)
+ {
+ this.salt = Arrays.clone(salt);
+ this.costParameter = costParameter;
+ this.blockSize = blockSize;
+ this.parallelizationParameter = parallelizationParameter;
+ this.keyLength = keyLength;
+ }
+
+ public static ScryptParams getInstance(
+ Object o)
+ {
+ if (o instanceof ScryptParams)
+ {
+ return (ScryptParams)o;
+ }
+ else if (o != null)
+ {
+ return new ScryptParams(ASN1Sequence.getInstance(o));
+ }
+
+ return null;
+ }
+
+ private ScryptParams(ASN1Sequence seq)
+ {
+ if (seq.size() != 4 && seq.size() != 5)
+ {
+ throw new IllegalArgumentException("invalid sequence: size = " + seq.size());
+ }
+
+ this.salt = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(0)).getOctets());
+ this.costParameter = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue();
+ this.blockSize = ASN1Integer.getInstance(seq.getObjectAt(2)).getValue();
+ this.parallelizationParameter = ASN1Integer.getInstance(seq.getObjectAt(3)).getValue();
+
+ if (seq.size() == 5)
+ {
+ this.keyLength = ASN1Integer.getInstance(seq.getObjectAt(4)).getValue();
+ }
+ else
+ {
+ this.keyLength = null;
+ }
+ }
+
+ public byte[] getSalt()
+ {
+ return Arrays.clone(salt);
+ }
+
+ public BigInteger getCostParameter()
+ {
+ return costParameter;
+ }
+
+ public BigInteger getBlockSize()
+ {
+ return blockSize;
+ }
+
+ public BigInteger getParallelizationParameter()
+ {
+ return parallelizationParameter;
+ }
+
+ /**
+ * Return the length in octets for the derived key.
+ *
+ * @return length for key to be derived (in octets)
+ */
+ public BigInteger getKeyLength()
+ {
+ return keyLength;
+ }
+
+ public ASN1Primitive toASN1Primitive()
+ {
+ ASN1EncodableVector v = new ASN1EncodableVector(5);
+
+ v.add(new DEROctetString(salt));
+ v.add(new ASN1Integer(costParameter));
+ v.add(new ASN1Integer(blockSize));
+ v.add(new ASN1Integer(parallelizationParameter));
+ if (keyLength != null)
+ {
+ v.add(new ASN1Integer(keyLength));
+ }
+
+ return new DERSequence(v);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/misc/VerisignCzagExtension.java b/core/src/main/java/org/bouncycastle/internal/asn1/misc/VerisignCzagExtension.java
new file mode 100644
index 0000000000..833fb49e1d
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/misc/VerisignCzagExtension.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.internal.asn1.misc;
+
+import org.bouncycastle.asn1.ASN1IA5String;
+import org.bouncycastle.asn1.DERIA5String;
+
+public class VerisignCzagExtension
+ extends DERIA5String
+{
+ public VerisignCzagExtension(
+ ASN1IA5String str)
+ {
+ super(str.getString());
+ }
+
+ public String toString()
+ {
+ return "VerisignCzagExtension: " + this.getString();
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/nsri/NSRIObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/nsri/NSRIObjectIdentifiers.java
new file mode 100644
index 0000000000..5ca5d0be62
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/nsri/NSRIObjectIdentifiers.java
@@ -0,0 +1,58 @@
+package org.bouncycastle.internal.asn1.nsri;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface NSRIObjectIdentifiers
+{
+ ASN1ObjectIdentifier nsri = new ASN1ObjectIdentifier("1.2.410.200046");
+
+ ASN1ObjectIdentifier id_algorithm = nsri.branch("1");
+
+ ASN1ObjectIdentifier id_sea = id_algorithm.branch("1");
+ ASN1ObjectIdentifier id_pad = id_algorithm.branch("2");
+
+ ASN1ObjectIdentifier id_pad_null = id_algorithm.branch("0");
+ ASN1ObjectIdentifier id_pad_1 = id_algorithm.branch("1");
+
+ ASN1ObjectIdentifier id_aria128_ecb = id_sea.branch("1");
+ ASN1ObjectIdentifier id_aria128_cbc = id_sea.branch("2");
+ ASN1ObjectIdentifier id_aria128_cfb = id_sea.branch("3");
+ ASN1ObjectIdentifier id_aria128_ofb = id_sea.branch("4");
+ ASN1ObjectIdentifier id_aria128_ctr = id_sea.branch("5");
+
+ ASN1ObjectIdentifier id_aria192_ecb = id_sea.branch("6");
+ ASN1ObjectIdentifier id_aria192_cbc = id_sea.branch("7");
+ ASN1ObjectIdentifier id_aria192_cfb = id_sea.branch("8");
+ ASN1ObjectIdentifier id_aria192_ofb = id_sea.branch("9");
+ ASN1ObjectIdentifier id_aria192_ctr = id_sea.branch("10");
+
+ ASN1ObjectIdentifier id_aria256_ecb = id_sea.branch("11");
+ ASN1ObjectIdentifier id_aria256_cbc = id_sea.branch("12");
+ ASN1ObjectIdentifier id_aria256_cfb = id_sea.branch("13");
+ ASN1ObjectIdentifier id_aria256_ofb = id_sea.branch("14");
+ ASN1ObjectIdentifier id_aria256_ctr = id_sea.branch("15");
+
+ ASN1ObjectIdentifier id_aria128_cmac = id_sea.branch("21");
+ ASN1ObjectIdentifier id_aria192_cmac = id_sea.branch("22");
+ ASN1ObjectIdentifier id_aria256_cmac = id_sea.branch("23");
+
+ ASN1ObjectIdentifier id_aria128_ocb2 = id_sea.branch("31");
+ ASN1ObjectIdentifier id_aria192_ocb2 = id_sea.branch("32");
+ ASN1ObjectIdentifier id_aria256_ocb2 = id_sea.branch("33");
+
+ ASN1ObjectIdentifier id_aria128_gcm = id_sea.branch("34");
+ ASN1ObjectIdentifier id_aria192_gcm = id_sea.branch("35");
+ ASN1ObjectIdentifier id_aria256_gcm = id_sea.branch("36");
+
+ ASN1ObjectIdentifier id_aria128_ccm = id_sea.branch("37");
+ ASN1ObjectIdentifier id_aria192_ccm = id_sea.branch("38");
+ ASN1ObjectIdentifier id_aria256_ccm = id_sea.branch("39");
+
+ ASN1ObjectIdentifier id_aria128_kw = id_sea.branch("40");
+ ASN1ObjectIdentifier id_aria192_kw = id_sea.branch("41");
+ ASN1ObjectIdentifier id_aria256_kw = id_sea.branch("42");
+
+ ASN1ObjectIdentifier id_aria128_kwp = id_sea.branch("43");
+ ASN1ObjectIdentifier id_aria192_kwp = id_sea.branch("44");
+ ASN1ObjectIdentifier id_aria256_kwp = id_sea.branch("45");
+}
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/rosstandart/RosstandartObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/rosstandart/RosstandartObjectIdentifiers.java
new file mode 100644
index 0000000000..047ce1e4be
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/rosstandart/RosstandartObjectIdentifiers.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.internal.asn1.rosstandart;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
+public interface RosstandartObjectIdentifiers
+{
+ static final ASN1ObjectIdentifier rosstandart = new ASN1ObjectIdentifier("1.2.643.7");
+
+ static final ASN1ObjectIdentifier id_tc26 = rosstandart.branch("1");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3411_12_256 = id_tc26.branch("1.2.2");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3411_12_512 = id_tc26.branch("1.2.3");
+
+ static final ASN1ObjectIdentifier id_tc26_hmac_gost_3411_12_256 = id_tc26.branch("1.4.1");
+
+ static final ASN1ObjectIdentifier id_tc26_hmac_gost_3411_12_512 = id_tc26.branch("1.4.2");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_256 = id_tc26.branch("1.1.1");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_512 = id_tc26.branch("1.1.2");
+
+ static final ASN1ObjectIdentifier id_tc26_signwithdigest_gost_3410_12_256 = id_tc26.branch("1.3.2");
+
+ static final ASN1ObjectIdentifier id_tc26_signwithdigest_gost_3410_12_512 = id_tc26.branch("1.3.3");
+
+ static final ASN1ObjectIdentifier id_tc26_agreement = id_tc26.branch("1.6");
+
+ static final ASN1ObjectIdentifier id_tc26_agreement_gost_3410_12_256 = id_tc26_agreement.branch("1");
+
+ static final ASN1ObjectIdentifier id_tc26_agreement_gost_3410_12_512 = id_tc26_agreement.branch("2");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_256_paramSet = id_tc26.branch("2.1.1");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_256_paramSetA = id_tc26_gost_3410_12_256_paramSet.branch("1");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_256_paramSetB = id_tc26_gost_3410_12_256_paramSet.branch("2");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_256_paramSetC = id_tc26_gost_3410_12_256_paramSet.branch("3");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_256_paramSetD = id_tc26_gost_3410_12_256_paramSet.branch("4");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_512_paramSet = id_tc26.branch("2.1.2");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_512_paramSetA = id_tc26_gost_3410_12_512_paramSet.branch("1");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_512_paramSetB = id_tc26_gost_3410_12_512_paramSet.branch("2");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_3410_12_512_paramSetC = id_tc26_gost_3410_12_512_paramSet.branch("3");
+
+ static final ASN1ObjectIdentifier id_tc26_gost_28147_param_Z = id_tc26.branch("2.5.1.1");
+}
diff --git a/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java b/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java
index 3dd2c02689..faff2ffb3c 100644
--- a/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java
+++ b/core/src/test/java/org/bouncycastle/asn1/test/GetInstanceTest.java
@@ -31,8 +31,6 @@
import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
import org.bouncycastle.asn1.cryptopro.GOST3410ParamSetParameters;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
-import org.bouncycastle.asn1.misc.CAST5CBCParameters;
-import org.bouncycastle.asn1.misc.IDEACBCPar;
import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
import org.bouncycastle.asn1.ocsp.CertID;
import org.bouncycastle.asn1.ocsp.CertStatus;
@@ -135,6 +133,8 @@
import org.bouncycastle.asn1.x9.DHValidationParms;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.internal.asn1.misc.CAST5CBCParameters;
+import org.bouncycastle.internal.asn1.misc.IDEACBCPar;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.util.Integers;
import org.bouncycastle.util.encoders.Base64;
diff --git a/core/src/test/java/org/bouncycastle/asn1/test/MiscTest.java b/core/src/test/java/org/bouncycastle/asn1/test/MiscTest.java
index 6352e7592b..bc87ad3bdb 100644
--- a/core/src/test/java/org/bouncycastle/asn1/test/MiscTest.java
+++ b/core/src/test/java/org/bouncycastle/asn1/test/MiscTest.java
@@ -12,11 +12,11 @@
import org.bouncycastle.asn1.BERSequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERIA5String;
-import org.bouncycastle.asn1.misc.CAST5CBCParameters;
-import org.bouncycastle.asn1.misc.IDEACBCPar;
-import org.bouncycastle.asn1.misc.NetscapeCertType;
-import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
-import org.bouncycastle.asn1.misc.VerisignCzagExtension;
+import org.bouncycastle.internal.asn1.misc.CAST5CBCParameters;
+import org.bouncycastle.internal.asn1.misc.IDEACBCPar;
+import org.bouncycastle.internal.asn1.misc.NetscapeCertType;
+import org.bouncycastle.internal.asn1.misc.NetscapeRevocationURL;
+import org.bouncycastle.internal.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.test.SimpleTest;
diff --git a/core/src/test/java/org/bouncycastle/asn1/test/NetscapeCertTypeTest.java b/core/src/test/java/org/bouncycastle/asn1/test/NetscapeCertTypeTest.java
index e5aa96ecab..6238f170f8 100644
--- a/core/src/test/java/org/bouncycastle/asn1/test/NetscapeCertTypeTest.java
+++ b/core/src/test/java/org/bouncycastle/asn1/test/NetscapeCertTypeTest.java
@@ -2,7 +2,7 @@
import java.io.IOException;
-import org.bouncycastle.asn1.misc.NetscapeCertType;
+import org.bouncycastle.internal.asn1.misc.NetscapeCertType;
import org.bouncycastle.util.test.SimpleTest;
public class NetscapeCertTypeTest
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/GOST3410Test.java b/core/src/test/java/org/bouncycastle/crypto/test/GOST3410Test.java
index 63afd4dff8..cb25e1fc66 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/GOST3410Test.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/GOST3410Test.java
@@ -7,7 +7,6 @@
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
@@ -27,6 +26,7 @@
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
diff --git a/prov/src/main/ext-jdk1.9/module-info.java b/prov/src/main/ext-jdk1.9/module-info.java
index 0794f6ef0b..5b7cb1c5d2 100644
--- a/prov/src/main/ext-jdk1.9/module-info.java
+++ b/prov/src/main/ext-jdk1.9/module-info.java
@@ -13,14 +13,10 @@
exports org.bouncycastle.asn1.anssi;
exports org.bouncycastle.asn1.bc;
exports org.bouncycastle.asn1.cryptopro;
- exports org.bouncycastle.asn1.edec;
exports org.bouncycastle.asn1.gm;
- exports org.bouncycastle.asn1.misc;
exports org.bouncycastle.asn1.nist;
- exports org.bouncycastle.asn1.nsri;
exports org.bouncycastle.asn1.ocsp;
exports org.bouncycastle.asn1.pkcs;
- exports org.bouncycastle.asn1.rosstandart;
exports org.bouncycastle.asn1.sec;
exports org.bouncycastle.asn1.teletrust;
exports org.bouncycastle.asn1.ua;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
index 038eed6f6c..407f6aad5d 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
@@ -9,9 +9,9 @@
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
/**
* A composite private key class.
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
index 7491ad5fc5..49680281d3 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
@@ -9,9 +9,9 @@
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
/**
* A composite key class.
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/COMPOSITE.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/COMPOSITE.java
index db24653442..b77e4a47db 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/COMPOSITE.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/COMPOSITE.java
@@ -9,9 +9,9 @@
import java.util.Map;
import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.CompositePrivateKey;
import org.bouncycastle.jcajce.CompositePublicKey;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ECGOST.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ECGOST.java
index 948b341de0..56c298fe86 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ECGOST.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ECGOST.java
@@ -1,7 +1,7 @@
package org.bouncycastle.jcajce.provider.asymmetric;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.ecgost.KeyFactorySpi;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java
index aba481467f..06c2bab8df 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java
@@ -3,7 +3,7 @@
import java.util.HashMap;
import java.util.Map;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.edec.KeyFactorySpi;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java
index 4b532f461f..2c80490e48 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java
@@ -23,7 +23,6 @@
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X962Parameters;
@@ -31,6 +30,7 @@
import org.bouncycastle.asn1.x9.X9ECPoint;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java
index 26a42ff3a3..f06f96ab81 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java
@@ -18,7 +18,6 @@
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X962Parameters;
@@ -27,6 +26,7 @@
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECGOST3410Parameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyFactorySpi.java
index 5b5ced5871..1f90727f9d 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyFactorySpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyFactorySpi.java
@@ -12,8 +12,8 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java
index d5875cd304..8444dea21c 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java
@@ -7,7 +7,6 @@
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
@@ -15,6 +14,7 @@
import org.bouncycastle.crypto.params.Ed448PrivateKeyParameters;
import org.bouncycastle.crypto.params.Ed448PublicKeyParameters;
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.jcajce.interfaces.EdDSAPrivateKey;
import org.bouncycastle.jcajce.interfaces.EdDSAPublicKey;
import org.bouncycastle.util.Arrays;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java
index 504eda19d4..dc19a4a000 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java
@@ -6,11 +6,11 @@
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
import org.bouncycastle.crypto.params.Ed448PublicKeyParameters;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.jcajce.interfaces.EdDSAPublicKey;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Properties;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPrivateKey.java
index f84805affa..ec917ae9e1 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPrivateKey.java
@@ -7,7 +7,6 @@
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Set;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
@@ -15,6 +14,7 @@
import org.bouncycastle.crypto.params.X448PrivateKeyParameters;
import org.bouncycastle.crypto.params.X448PublicKeyParameters;
import org.bouncycastle.crypto.util.PrivateKeyInfoFactory;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.jcajce.interfaces.XDHPrivateKey;
import org.bouncycastle.jcajce.interfaces.XDHPublicKey;
import org.bouncycastle.util.Arrays;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPublicKey.java
index fb6cee747d..48ab3f77f0 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPublicKey.java
@@ -7,11 +7,11 @@
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
import org.bouncycastle.crypto.params.X448PublicKeyParameters;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.jcajce.interfaces.XDHPublicKey;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Properties;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
index 2d6aa67c77..d33fea6931 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
@@ -14,7 +14,6 @@
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
@@ -26,6 +25,7 @@
import org.bouncycastle.crypto.params.X448PublicKeyParameters;
import org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil;
import org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.jcajce.interfaces.EdDSAPublicKey;
import org.bouncycastle.jcajce.interfaces.XDHPublicKey;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
index 7fca5cae81..1268706469 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
@@ -7,7 +7,6 @@
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
@@ -19,6 +18,7 @@
import org.bouncycastle.crypto.params.Ed448KeyGenerationParameters;
import org.bouncycastle.crypto.params.X25519KeyGenerationParameters;
import org.bouncycastle.crypto.params.X448KeyGenerationParameters;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
import org.bouncycastle.jcajce.spec.XDHParameterSpec;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
index 8536d28944..cd9699033d 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java
@@ -17,7 +17,6 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.crypto.DerivationFunction;
@@ -29,6 +28,7 @@
import org.bouncycastle.crypto.params.KDFParameters;
import org.bouncycastle.internal.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.spec.HybridValueParameterSpec;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java
index bb4fa38bd2..6097daff76 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java
@@ -43,10 +43,6 @@
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1String;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.misc.NetscapeCertType;
-import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
-import org.bouncycastle.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.RFC4519Style;
@@ -57,6 +53,10 @@
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.TBSCertificate;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.NetscapeCertType;
+import org.bouncycastle.internal.asn1.misc.NetscapeRevocationURL;
+import org.bouncycastle.internal.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.jcajce.CompositePublicKey;
import org.bouncycastle.jcajce.interfaces.BCX509Certificate;
import org.bouncycastle.jcajce.io.OutputStreamFactory;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
index 4b62d9bfa6..dbf2d9ff93 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -17,12 +17,12 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.util.MessageDigestUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake2b.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake2b.java
index 0eb978a924..b7000e581c 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake2b.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake2b.java
@@ -1,7 +1,7 @@
package org.bouncycastle.jcajce.provider.digest;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.crypto.digests.Blake2bDigest;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
public class Blake2b
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake2s.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake2s.java
index a79fbe974b..7d6fabb965 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake2s.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake2s.java
@@ -1,7 +1,7 @@
package org.bouncycastle.jcajce.provider.digest;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.crypto.digests.Blake2sDigest;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
public class Blake2s
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake3.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake3.java
index 2ebe1bacac..500903d2e3 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake3.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/Blake3.java
@@ -1,7 +1,7 @@
package org.bouncycastle.jcajce.provider.digest;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.crypto.digests.Blake3Digest;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
public class Blake3
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/GOST3411.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/GOST3411.java
index 6d5dfa3d00..fa732adea7 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/GOST3411.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/digest/GOST3411.java
@@ -1,12 +1,12 @@
package org.bouncycastle.jcajce.provider.digest;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.digests.GOST3411Digest;
import org.bouncycastle.crypto.digests.GOST3411_2012_256Digest;
import org.bouncycastle.crypto.digests.GOST3411_2012_512Digest;
import org.bouncycastle.crypto.macs.HMac;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseMac;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
index ac92fbf6ab..007d53ab64 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
@@ -61,10 +61,7 @@
import org.bouncycastle.asn1.bc.PbkdMacIntegrityCheck;
import org.bouncycastle.asn1.bc.SecretKeyData;
import org.bouncycastle.asn1.bc.SignatureCheck;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.misc.ScryptParams;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.nsri.NSRIObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
import org.bouncycastle.asn1.pkcs.EncryptionScheme;
import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
@@ -87,6 +84,9 @@
import org.bouncycastle.crypto.util.ScryptConfig;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.internal.asn1.kisa.KISAObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.ScryptParams;
+import org.bouncycastle.internal.asn1.nsri.NSRIObjectIdentifiers;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.BCFKSLoadStoreParameter;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
index 3b33ff4e5f..be99ffcd9a 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -66,7 +66,6 @@
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.AuthenticatedSafe;
import org.bouncycastle.asn1.pkcs.CertBag;
@@ -94,6 +93,7 @@
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.util.DigestFactory;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.jcajce.BCLoadStoreParameter;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARIA.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARIA.java
index 0bf2001543..9f851a19ef 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARIA.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/ARIA.java
@@ -9,7 +9,6 @@
import javax.crypto.spec.IvParameterSpec;
-import org.bouncycastle.asn1.nsri.NSRIObjectIdentifiers;
import org.bouncycastle.crypto.BlockCipher;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
@@ -27,6 +26,7 @@
import org.bouncycastle.crypto.modes.OFBBlockCipher;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
import org.bouncycastle.internal.asn1.cms.GCMParameters;
+import org.bouncycastle.internal.asn1.nsri.NSRIObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
index efcd0d8df9..cfa3bb1766 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/Blowfish.java
@@ -1,10 +1,10 @@
package org.bouncycastle.jcajce.provider.symmetric;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.engines.BlowfishEngine;
import org.bouncycastle.crypto.macs.CMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST5.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST5.java
index 13ced70267..14a01438fa 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST5.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/CAST5.java
@@ -10,12 +10,12 @@
import javax.crypto.spec.IvParameterSpec;
import org.bouncycastle.asn1.ASN1InputStream;
-import org.bouncycastle.asn1.misc.CAST5CBCParameters;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.engines.CAST5Engine;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.internal.asn1.misc.CAST5CBCParameters;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GOST28147.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GOST28147.java
index 86580190da..558aa9d54d 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GOST28147.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/GOST28147.java
@@ -17,7 +17,6 @@
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.GOST28147Parameters;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.crypto.BufferedBlockCipher;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
@@ -27,6 +26,7 @@
import org.bouncycastle.crypto.macs.GOST28147Mac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
import org.bouncycastle.crypto.modes.GCFBBlockCipher;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/IDEA.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/IDEA.java
index 66848efe31..189bcb723c 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/IDEA.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/IDEA.java
@@ -9,14 +9,14 @@
import javax.crypto.spec.IvParameterSpec;
-import org.bouncycastle.asn1.misc.IDEACBCPar;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.crypto.CipherKeyGenerator;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.engines.IDEAEngine;
import org.bouncycastle.crypto.macs.CBCBlockCipherMac;
import org.bouncycastle.crypto.macs.CFBBlockCipherMac;
import org.bouncycastle.crypto.modes.CBCBlockCipher;
+import org.bouncycastle.internal.asn1.misc.IDEACBCPar;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameterGenerator;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseAlgorithmParameters;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SCRYPT.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SCRYPT.java
index 6dd3d9b99d..6af45cca0b 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SCRYPT.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/symmetric/SCRYPT.java
@@ -5,11 +5,11 @@
import javax.crypto.SecretKey;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.PasswordConverter;
import org.bouncycastle.crypto.generators.SCrypt;
import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey;
import org.bouncycastle.jcajce.provider.symmetric.util.BaseSecretKeyFactory;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/EdDSAParameterSpec.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/EdDSAParameterSpec.java
index 1f0f203f2f..08865867c2 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/spec/EdDSAParameterSpec.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/EdDSAParameterSpec.java
@@ -2,7 +2,7 @@
import java.security.spec.AlgorithmParameterSpec;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
/**
* ParameterSpec for EdDSA signature algorithms.
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST28147ParameterSpec.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST28147ParameterSpec.java
index d06dc5a05a..faf67b5762 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST28147ParameterSpec.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST28147ParameterSpec.java
@@ -6,8 +6,8 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.crypto.engines.GOST28147Engine;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.util.Arrays;
/**
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST28147WrapParameterSpec.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST28147WrapParameterSpec.java
index 3ee336495a..7f1ee947f6 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST28147WrapParameterSpec.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST28147WrapParameterSpec.java
@@ -6,8 +6,8 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.crypto.engines.GOST28147Engine;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.util.Arrays;
/**
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST3410ParameterSpec.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST3410ParameterSpec.java
index 474c1856ae..273f928c13 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST3410ParameterSpec.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/GOST3410ParameterSpec.java
@@ -5,7 +5,7 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
/**
* ParameterSpec for a GOST 3410-1994/2001/2012 algorithm parameters.
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/XDHParameterSpec.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/XDHParameterSpec.java
index 600e2d613c..2e11f22635 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/spec/XDHParameterSpec.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/XDHParameterSpec.java
@@ -2,7 +2,7 @@
import java.security.spec.AlgorithmParameterSpec;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
/**
* ParameterSpec for XDH key agreement algorithms.
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java b/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
index 8e14c61466..681c6aeabf 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/util/MessageDigestUtils.java
@@ -7,13 +7,13 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.internal.asn1.gnu.GNUObjectIdentifiers;
import org.bouncycastle.internal.asn1.iso.ISOIECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
public class MessageDigestUtils
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java b/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
index 99e11cb7f4..b172f62107 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
@@ -44,7 +44,6 @@
import org.bouncycastle.asn1.ocsp.SingleResponse;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.BCStrictStyle;
import org.bouncycastle.asn1.x509.AccessDescription;
@@ -60,6 +59,7 @@
import org.bouncycastle.internal.asn1.eac.EACObjectIdentifiers;
import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.PKIXCertRevocationChecker;
import org.bouncycastle.jcajce.PKIXCertRevocationCheckerParameters;
import org.bouncycastle.jcajce.util.JcaJceHelper;
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java b/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java
index 809ef05843..86f03e8ae5 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/ProvRevocationChecker.java
@@ -14,12 +14,12 @@
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.internal.asn1.bsi.BSIObjectIdentifiers;
import org.bouncycastle.internal.asn1.eac.EACObjectIdentifiers;
import org.bouncycastle.internal.asn1.isara.IsaraObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.PKIXCertRevocationChecker;
import org.bouncycastle.jcajce.PKIXCertRevocationCheckerParameters;
import org.bouncycastle.jcajce.util.JcaJceHelper;
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java b/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
index feeed3c6d4..6d6994abea 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/X509CertificateObject.java
@@ -43,10 +43,6 @@
import org.bouncycastle.asn1.ASN1String;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.misc.NetscapeCertType;
-import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
-import org.bouncycastle.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.RFC4519Style;
@@ -56,6 +52,10 @@
import org.bouncycastle.asn1.x509.Extensions;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.KeyUsage;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.NetscapeCertType;
+import org.bouncycastle.internal.asn1.misc.NetscapeRevocationURL;
+import org.bouncycastle.internal.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl;
import org.bouncycastle.jce.X509Principal;
import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
diff --git a/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
index 18468c7191..21391a5323 100644
--- a/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
+++ b/prov/src/main/jdk1.1/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -19,7 +19,7 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
diff --git a/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CertificateObject.java b/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CertificateObject.java
index 2ae4e814a1..1e4c262dd3 100644
--- a/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CertificateObject.java
+++ b/prov/src/main/jdk1.1/org/bouncycastle/jce/provider/X509CertificateObject.java
@@ -42,10 +42,10 @@
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.misc.NetscapeCertType;
-import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
-import org.bouncycastle.asn1.misc.VerisignCzagExtension;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.NetscapeCertType;
+import org.bouncycastle.internal.asn1.misc.NetscapeRevocationURL;
+import org.bouncycastle.internal.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.RFC4519Style;
diff --git a/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java b/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
index 2af978a7ad..5fdbde7496 100644
--- a/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
+++ b/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
@@ -16,7 +16,7 @@
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
diff --git a/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java b/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
index 580150495f..59226537fd 100644
--- a/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
+++ b/prov/src/main/jdk1.11/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
@@ -8,7 +8,7 @@
import java.security.spec.ECGenParameterSpec;
import java.security.spec.NamedParameterSpec;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
diff --git a/prov/src/main/jdk1.15/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java b/prov/src/main/jdk1.15/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
index 5b4916d2b4..f67a553fb7 100644
--- a/prov/src/main/jdk1.15/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
+++ b/prov/src/main/jdk1.15/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
@@ -16,7 +16,7 @@
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
diff --git a/prov/src/main/jdk1.15/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java b/prov/src/main/jdk1.15/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
index 0a5ceaeabe..68f81687d4 100644
--- a/prov/src/main/jdk1.15/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
+++ b/prov/src/main/jdk1.15/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
@@ -8,7 +8,7 @@
import java.security.spec.ECGenParameterSpec;
import java.security.spec.NamedParameterSpec;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java
index bc28e5e34a..527be010bf 100644
--- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java
+++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java
@@ -41,10 +41,10 @@
import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.misc.NetscapeCertType;
-import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
-import org.bouncycastle.asn1.misc.VerisignCzagExtension;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.NetscapeCertType;
+import org.bouncycastle.internal.asn1.misc.NetscapeRevocationURL;
+import org.bouncycastle.internal.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.RFC4519Style;
diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
index 50dbe4c9e6..925ccc3206 100644
--- a/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
+++ b/prov/src/main/jdk1.3/org/bouncycastle/jcajce/provider/asymmetric/x509/X509SignatureUtil.java
@@ -19,7 +19,7 @@
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERNull;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.RSASSAPSSparams;
diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java b/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
index 209e993e25..9a60c755c3 100644
--- a/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
+++ b/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/JDKAlgorithmParameters.java
@@ -13,14 +13,13 @@
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetString;
-import org.bouncycastle.asn1.ASN1OutputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1OutputStream;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.misc.CAST5CBCParameters;
+import org.bouncycastle.internal.asn1.misc.CAST5CBCParameters;
import org.bouncycastle.asn1.pkcs.PKCS12PBEParams;
import org.bouncycastle.asn1.pkcs.RC2CBCParameter;
import org.bouncycastle.jce.spec.IESParameterSpec;
diff --git a/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CertificateObject.java b/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CertificateObject.java
index a8f179e07c..21bae59d99 100644
--- a/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CertificateObject.java
+++ b/prov/src/main/jdk1.3/org/bouncycastle/jce/provider/X509CertificateObject.java
@@ -42,10 +42,10 @@
import org.bouncycastle.asn1.DERIA5String;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.misc.NetscapeCertType;
-import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
-import org.bouncycastle.asn1.misc.VerisignCzagExtension;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.NetscapeCertType;
+import org.bouncycastle.internal.asn1.misc.NetscapeRevocationURL;
+import org.bouncycastle.internal.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.RFC4519Style;
diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/CompositePrivateKey.java b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/CompositePrivateKey.java
index bfefbef0fb..e7ae707d2d 100644
--- a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/CompositePrivateKey.java
+++ b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/CompositePrivateKey.java
@@ -9,7 +9,7 @@
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/CompositePublicKey.java b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/CompositePublicKey.java
index c5d56d19a4..7f7bf702d8 100644
--- a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/CompositePublicKey.java
+++ b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/CompositePublicKey.java
@@ -9,7 +9,7 @@
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ECGOST.java b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ECGOST.java
index eb07ca664a..8b29e857e1 100644
--- a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ECGOST.java
+++ b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/ECGOST.java
@@ -1,7 +1,7 @@
package org.bouncycastle.jcajce.provider.asymmetric;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.ecgost.KeyFactorySpi;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
index 239dc0be88..4ac56c876e 100644
--- a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
+++ b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java
@@ -16,7 +16,7 @@
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DEROctetString;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
index 0278bc2ea3..05a8382128 100644
--- a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
+++ b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java
@@ -6,7 +6,7 @@
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
diff --git a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
index d2db7db4ae..d6d85fd853 100644
--- a/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
+++ b/prov/src/main/jdk1.4/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java
@@ -58,8 +58,8 @@
import org.bouncycastle.asn1.bc.PbkdMacIntegrityCheck;
import org.bouncycastle.asn1.bc.SecretKeyData;
import org.bouncycastle.internal.asn1.cms.CCMParameters;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.misc.ScryptParams;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.ScryptParams;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
diff --git a/prov/src/main/jdk1.9/module-info.java b/prov/src/main/jdk1.9/module-info.java
index 8b5d40d169..e6e3a34ee0 100644
--- a/prov/src/main/jdk1.9/module-info.java
+++ b/prov/src/main/jdk1.9/module-info.java
@@ -15,14 +15,10 @@
exports org.bouncycastle.asn1.anssi;
exports org.bouncycastle.asn1.bc;
exports org.bouncycastle.asn1.cryptopro;
- exports org.bouncycastle.asn1.edec;
exports org.bouncycastle.asn1.gm;
- exports org.bouncycastle.asn1.misc;
exports org.bouncycastle.asn1.nist;
- exports org.bouncycastle.asn1.nsri;
exports org.bouncycastle.asn1.ocsp;
exports org.bouncycastle.asn1.pkcs;
- exports org.bouncycastle.asn1.rosstandart;
exports org.bouncycastle.asn1.sec;
exports org.bouncycastle.asn1.teletrust;
exports org.bouncycastle.asn1.ua;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/ARIATest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/ARIATest.java
index c49691e7ec..e366aeae6d 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/ARIATest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/ARIATest.java
@@ -14,8 +14,8 @@
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
-import org.bouncycastle.asn1.nsri.NSRIObjectIdentifiers;
import org.bouncycastle.crypto.prng.FixedSecureRandom;
+import org.bouncycastle.internal.asn1.nsri.NSRIObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java
index febb1de386..3f4d0c57cb 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java
@@ -33,8 +33,6 @@
import org.bouncycastle.asn1.bc.ObjectStore;
import org.bouncycastle.asn1.bc.ObjectStoreIntegrityCheck;
import org.bouncycastle.asn1.bc.PbkdMacIntegrityCheck;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.misc.ScryptParams;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PBES2Parameters;
import org.bouncycastle.asn1.pkcs.PBKDF2Params;
@@ -47,6 +45,8 @@
import org.bouncycastle.crypto.util.PBKDF2Config;
import org.bouncycastle.crypto.util.PBKDFConfig;
import org.bouncycastle.crypto.util.ScryptConfig;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.ScryptParams;
import org.bouncycastle.jcajce.BCFKSLoadStoreParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java
index 1989c5f2e3..896158e7c6 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java
@@ -66,10 +66,6 @@
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-import org.bouncycastle.asn1.misc.NetscapeCertType;
-import org.bouncycastle.asn1.misc.NetscapeRevocationURL;
-import org.bouncycastle.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.style.RFC4519Style;
@@ -80,6 +76,10 @@
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x509.Time;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.NetscapeCertType;
+import org.bouncycastle.internal.asn1.misc.NetscapeRevocationURL;
+import org.bouncycastle.internal.asn1.misc.VerisignCzagExtension;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Integers;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/DigestTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/DigestTest.java
index b466f35f49..d97132766b 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/DigestTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/DigestTest.java
@@ -3,12 +3,12 @@
import java.security.MessageDigest;
import java.security.Security;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.ua.UAObjectIdentifiers;
import org.bouncycastle.internal.asn1.iso.ISOIECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java
index f9cab0e513..630024287b 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java
@@ -33,9 +33,9 @@
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.Certificate;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.jcajce.interfaces.EdDSAPrivateKey;
import org.bouncycastle.jcajce.spec.DHUParameterSpec;
import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java
index 8e2a0be2d9..c22deda20d 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java
@@ -22,7 +22,6 @@
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.crypto.CipherParameters;
@@ -30,6 +29,7 @@
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.ECGOST3410Signer;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.jce.interfaces.ECPrivateKey;
import org.bouncycastle.jce.interfaces.ECPublicKey;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java
index a86bfd3b9f..49dab95ba7 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/HMacTest.java
@@ -16,9 +16,9 @@
import org.bouncycastle.asn1.gm.GMObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.ua.UAObjectIdentifiers;
import org.bouncycastle.internal.asn1.iana.IANAObjectIdentifiers;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
index 07e342157b..9ab48d1177 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
@@ -31,7 +31,6 @@
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DLSequenceParser;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.ContentInfo;
import org.bouncycastle.asn1.pkcs.EncryptedData;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
@@ -44,6 +43,7 @@
import org.bouncycastle.asn1.x500.style.BCStyle;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.KeyPurposeId;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.PKCS12StoreParameter;
import org.bouncycastle.jce.PKCS12Util;
import org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier;
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/TestCertificateGen.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/TestCertificateGen.java
index 7c99ebade8..1758e27387 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/TestCertificateGen.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/TestCertificateGen.java
@@ -25,7 +25,6 @@
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -49,6 +48,7 @@
import org.bouncycastle.asn1.x509.V2TBSCertListGenerator;
import org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
public class TestCertificateGen
{
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java
index dfb9c606a9..ce58460f31 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/TestUtils.java
@@ -32,7 +32,6 @@
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
@@ -56,6 +55,7 @@
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.digests.SHA1Digest;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
/**
* Test Utils
diff --git a/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/EdECTest.java b/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/EdECTest.java
index b943f4eb42..820db84f9f 100644
--- a/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/EdECTest.java
+++ b/prov/src/test/jdk1.4/org/bouncycastle/jce/provider/test/EdECTest.java
@@ -31,7 +31,7 @@
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
import org.bouncycastle.asn1.x509.Certificate;
import org.bouncycastle.jcajce.spec.DHUParameterSpec;
import org.bouncycastle.jcajce.spec.EdDSAParameterSpec;
diff --git a/core/src/main/java/org/bouncycastle/asn1/edec/EdECObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/edec/EdECObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/edec/EdECObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/edec/EdECObjectIdentifiers.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java b/util/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java
rename to util/src/main/java/org/bouncycastle/asn1/misc/CAST5CBCParameters.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java b/util/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java
rename to util/src/main/java/org/bouncycastle/asn1/misc/IDEACBCPar.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java b/util/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java
rename to util/src/main/java/org/bouncycastle/asn1/misc/NetscapeCertType.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java b/util/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
rename to util/src/main/java/org/bouncycastle/asn1/misc/NetscapeRevocationURL.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/ScryptParams.java b/util/src/main/java/org/bouncycastle/asn1/misc/ScryptParams.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/misc/ScryptParams.java
rename to util/src/main/java/org/bouncycastle/asn1/misc/ScryptParams.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java b/util/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
rename to util/src/main/java/org/bouncycastle/asn1/misc/VerisignCzagExtension.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/rosstandart/RosstandartObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/rosstandart/RosstandartObjectIdentifiers.java
similarity index 100%
rename from core/src/main/java/org/bouncycastle/asn1/rosstandart/RosstandartObjectIdentifiers.java
rename to util/src/main/java/org/bouncycastle/asn1/rosstandart/RosstandartObjectIdentifiers.java
diff --git a/util/src/main/jdk1.9/module-info.java b/util/src/main/jdk1.9/module-info.java
index 3522889a05..cbeb391b31 100644
--- a/util/src/main/jdk1.9/module-info.java
+++ b/util/src/main/jdk1.9/module-info.java
@@ -11,6 +11,7 @@
exports org.bouncycastle.asn1.cryptlib;
exports org.bouncycastle.asn1.dvcs;
exports org.bouncycastle.asn1.eac;
+ exports org.bouncycastle.asn1.edec;
exports org.bouncycastle.asn1.esf;
exports org.bouncycastle.asn1.ess;
exports org.bouncycastle.asn1.est;
@@ -24,9 +25,12 @@
exports org.bouncycastle.asn1.iso;
exports org.bouncycastle.asn1.kisa;
exports org.bouncycastle.asn1.microsoft;
+ exports org.bouncycastle.asn1.misc;
exports org.bouncycastle.asn1.mozilla;
+ exports org.bouncycastle.asn1.nsri;
exports org.bouncycastle.asn1.ntt;
exports org.bouncycastle.asn1.oiw;
+ exports org.bouncycastle.asn1.rosstandart;
exports org.bouncycastle.asn1.smime;
exports org.bouncycastle.asn1.tsp;
exports org.bouncycastle.oer;
diff --git a/util/src/test/java/org/bouncycastle/asn1/util/test/AllTests.java b/util/src/test/java/org/bouncycastle/asn1/util/test/AllTests.java
index 637d40b206..e6f4793325 100644
--- a/util/src/test/java/org/bouncycastle/asn1/util/test/AllTests.java
+++ b/util/src/test/java/org/bouncycastle/asn1/util/test/AllTests.java
@@ -6,7 +6,7 @@
import junit.framework.TestSuite;
import org.bouncycastle.asn1.cms.test.OctetStringTest;
import org.bouncycastle.asn1.cms.test.ParseTest;
-import org.bouncycastle.asn1.misc.test.GetInstanceTest;
+import org.bouncycastle.internal.asn1.misc.test.GetInstanceTest;
import org.bouncycastle.test.PrintTestResult;
import org.bouncycastle.util.test.SimpleTestResult;
diff --git a/util/src/test/java/org/bouncycastle/asn1/misc/test/CMPUpdates16Test.java b/util/src/test/java/org/bouncycastle/internal/asn1/misc/test/CMPUpdates16Test.java
similarity index 98%
rename from util/src/test/java/org/bouncycastle/asn1/misc/test/CMPUpdates16Test.java
rename to util/src/test/java/org/bouncycastle/internal/asn1/misc/test/CMPUpdates16Test.java
index 4e760e1792..2831421ccc 100644
--- a/util/src/test/java/org/bouncycastle/asn1/misc/test/CMPUpdates16Test.java
+++ b/util/src/test/java/org/bouncycastle/internal/asn1/misc/test/CMPUpdates16Test.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.asn1.misc.test;
+package org.bouncycastle.internal.asn1.misc.test;
import junit.framework.TestCase;
import org.bouncycastle.asn1.ASN1Encodable;
diff --git a/util/src/test/java/org/bouncycastle/asn1/misc/test/GetInstanceTest.java b/util/src/test/java/org/bouncycastle/internal/asn1/misc/test/GetInstanceTest.java
similarity index 99%
rename from util/src/test/java/org/bouncycastle/asn1/misc/test/GetInstanceTest.java
rename to util/src/test/java/org/bouncycastle/internal/asn1/misc/test/GetInstanceTest.java
index fd6fa88765..4612f6206c 100644
--- a/util/src/test/java/org/bouncycastle/asn1/misc/test/GetInstanceTest.java
+++ b/util/src/test/java/org/bouncycastle/internal/asn1/misc/test/GetInstanceTest.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.asn1.misc.test;
+package org.bouncycastle.internal.asn1.misc.test;
import java.lang.reflect.Method;
import java.math.BigInteger;
@@ -6,7 +6,6 @@
import java.util.Vector;
import junit.framework.TestCase;
-
import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1Choice;
import org.bouncycastle.asn1.ASN1Encodable;
@@ -182,8 +181,6 @@
import org.bouncycastle.asn1.isismtt.x509.ProcurationSyntax;
import org.bouncycastle.asn1.isismtt.x509.ProfessionInfo;
import org.bouncycastle.asn1.isismtt.x509.Restriction;
-import org.bouncycastle.asn1.misc.CAST5CBCParameters;
-import org.bouncycastle.asn1.misc.IDEACBCPar;
import org.bouncycastle.asn1.mozilla.PublicKeyAndChallenge;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
@@ -297,6 +294,8 @@
import org.bouncycastle.asn1.x9.DHValidationParms;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.internal.asn1.misc.CAST5CBCParameters;
+import org.bouncycastle.internal.asn1.misc.IDEACBCPar;
import org.bouncycastle.util.Integers;
import org.bouncycastle.util.encoders.Base64;
From b093c24687f353e20db6e28917bc34e2d2cdd769 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Fri, 8 Mar 2024 19:27:23 +0700
Subject: [PATCH 0149/1846] Add ASN1RelativeOID cache
---
.../java/org/bouncycastle/asn1/ASN1InputStream.java | 3 ++-
.../org/bouncycastle/asn1/ASN1ObjectIdentifier.java | 8 ++++----
.../java/org/bouncycastle/asn1/ASN1RelativeOID.java | 11 +++++++++++
3 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java b/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
index ff7e3e09d1..5b1fb12343 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
@@ -553,7 +553,8 @@ static ASN1Primitive createPrimitiveDERObject(
case PRINTABLE_STRING:
return ASN1PrintableString.createPrimitive(defIn.toByteArray());
case RELATIVE_OID:
- return ASN1RelativeOID.createPrimitive(defIn.toByteArray(), false);
+ // TODO Ideally only clone if we used a buffer
+ return ASN1RelativeOID.createPrimitive(getBuffer(defIn, tmpBuffers), true);
case T61_STRING:
return ASN1T61String.createPrimitive(defIn.toByteArray());
case UNIVERSAL_STRING:
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
index 9f14c472d8..b3029d48bb 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
@@ -421,7 +421,7 @@ public ASN1ObjectIdentifier intern()
return oid;
}
- private static class OidHandle
+ static class OidHandle
{
private final int key;
private final byte[] contents;
@@ -452,10 +452,10 @@ static ASN1ObjectIdentifier createPrimitive(byte[] contents, boolean clone)
{
final OidHandle hdl = new OidHandle(contents);
ASN1ObjectIdentifier oid = pool.get(hdl);
- if (oid == null)
+ if (oid != null)
{
- return new ASN1ObjectIdentifier(contents, clone);
+ return oid;
}
- return oid;
+ return new ASN1ObjectIdentifier(contents, clone);
}
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java b/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java
index 4d2dee72dd..1814e179cd 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java
@@ -3,6 +3,8 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigInteger;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.bouncycastle.util.Arrays;
@@ -78,6 +80,9 @@ public static ASN1RelativeOID tryFromID(String identifier)
private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7F;
+ private static final ConcurrentMap pool =
+ new ConcurrentHashMap();
+
private final byte[] contents;
private String identifier;
@@ -180,6 +185,12 @@ boolean encodeConstructed()
static ASN1RelativeOID createPrimitive(byte[] contents, boolean clone)
{
+ final ASN1ObjectIdentifier.OidHandle hdl = new ASN1ObjectIdentifier.OidHandle(contents);
+ ASN1RelativeOID oid = pool.get(hdl);
+ if (oid != null)
+ {
+ return oid;
+ }
return new ASN1RelativeOID(contents, clone);
}
From acacac26a7b49ad45a00ad93c90495e2ae149bb7 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 11 Mar 2024 13:16:16 +1100
Subject: [PATCH 0150/1846] correct suppressions.xml for Windows
---
config/nohttp/suppressions.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/nohttp/suppressions.xml b/config/nohttp/suppressions.xml
index 6110921148..903c0fe04d 100644
--- a/config/nohttp/suppressions.xml
+++ b/config/nohttp/suppressions.xml
@@ -21,5 +21,5 @@
-
+
From 7068177941c601be56e83c47480de9c069596db2 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 11 Mar 2024 13:26:10 +1100
Subject: [PATCH 0151/1846] correct suppressions.xml for Windows/Linux
---
config/nohttp/suppressions.xml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/config/nohttp/suppressions.xml b/config/nohttp/suppressions.xml
index 903c0fe04d..2e7f160b17 100644
--- a/config/nohttp/suppressions.xml
+++ b/config/nohttp/suppressions.xml
@@ -21,5 +21,5 @@
-
+
From 3021ab89fc4004dca813ad0835a458efb93f2737 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 11 Mar 2024 14:12:04 +1100
Subject: [PATCH 0152/1846] moved to platform independent path seperator
---
jmail/build.gradle | 2 +-
mail/build.gradle | 2 +-
pkix/build.gradle | 2 +-
tls/build.gradle | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/jmail/build.gradle b/jmail/build.gradle
index 62333c7649..0780850ed1 100644
--- a/jmail/build.gradle
+++ b/jmail/build.gradle
@@ -67,7 +67,7 @@ compileJava9Java {
sourceCompatibility = 9
targetCompatibility = 9
options.compilerArgs += [
- '--module-path', "$bc_prov:$bc_util:$bc_pkix:${rootProject.projectDir}/libs/jakarta.mail-2.0.1.jar:${rootProject.projectDir}/libs/jakarta.activation-api-2.0.0.jar"
+ '--module-path', "$bc_prov${File.pathSeparator}$bc_util${File.pathSeparator}$bc_pkix${File.pathSeparator}${rootProject.projectDir}/libs/jakarta.mail-2.0.1.jar${File.pathSeparator}${rootProject.projectDir}/libs/jakarta.activation-api-2.0.0.jar"
]
options.sourcepath = files(['build/src/main/java', 'src/main/jdk1.9'])
diff --git a/mail/build.gradle b/mail/build.gradle
index 96e8135121..000015a37d 100644
--- a/mail/build.gradle
+++ b/mail/build.gradle
@@ -47,7 +47,7 @@ compileJava9Java {
sourceCompatibility = 9
targetCompatibility = 9
options.compilerArgs += [
- '--module-path', "${bc_prov}:${bc_util}:${bc_pkix}"
+ '--module-path', "${bc_prov}${File.pathSeparator}${bc_util}${File.pathSeparator}${bc_pkix}"
]
options.sourcepath = files(['src/main/java', 'src/main/jdk1.9'])
diff --git a/pkix/build.gradle b/pkix/build.gradle
index 337ebceaf8..8022cc5096 100644
--- a/pkix/build.gradle
+++ b/pkix/build.gradle
@@ -48,7 +48,7 @@ compileJava9Java {
sourceCompatibility = 9
targetCompatibility = 9
options.compilerArgs += [
- '--module-path', "${bc_prov}:${bc_util}"
+ '--module-path', "${bc_prov}${File.pathSeparator}${bc_util}"
]
options.sourcepath = files(['src/main/java', 'src/main/jdk1.9'])
diff --git a/tls/build.gradle b/tls/build.gradle
index f19dbc8858..4b663f8952 100644
--- a/tls/build.gradle
+++ b/tls/build.gradle
@@ -95,7 +95,7 @@ compileJava9Java {
sourceCompatibility = 9
targetCompatibility = 9
options.compilerArgs += [
- '--module-path', "${bc_prov}:${bc_util}:${bc_pkix}"
+ '--module-path', "${bc_prov}${File.pathSeparator}${bc_util}${File.pathSeparator}${bc_pkix}"
]
options.sourcepath = files(['src/main/java', 'src/main/jdk1.9'])
From 1c8f2377096d6da3a1bbb3bec183efb225a20ee3 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 11 Mar 2024 14:12:46 +1100
Subject: [PATCH 0153/1846] moved to platform independent path seperator
---
mls/build.gradle | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mls/build.gradle b/mls/build.gradle
index 573aa1c0e1..e277ce4c70 100644
--- a/mls/build.gradle
+++ b/mls/build.gradle
@@ -94,7 +94,7 @@ compileJava9Java {
sourceCompatibility = 9
targetCompatibility = 9
options.compilerArgs += [
- '--module-path', "${bc_prov}:${bc_util}:${bc_pkix}"
+ '--module-path', "${bc_prov}${File.pathSeparator}${bc_util}${File.pathSeparator}${bc_pkix}"
]
options.sourcepath = files(['src/main/java', 'src/main/jdk1.9'])
From dbd24fe8e7caa3574a7ccdfac74d4f037afa462d Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 11 Mar 2024 14:35:51 +1100
Subject: [PATCH 0154/1846] further windows tweaks
---
mail/build.gradle | 6 +++---
mls/build.gradle | 7 +++----
2 files changed, 6 insertions(+), 7 deletions(-)
diff --git a/mail/build.gradle b/mail/build.gradle
index 000015a37d..16f9edd11b 100644
--- a/mail/build.gradle
+++ b/mail/build.gradle
@@ -23,9 +23,9 @@ dependencies {
implementation files("$bc_pkix")
implementation project(path: ':core')
- java9Implementation files(":prov")
- java9Implementation files(":util")
- java9Implementation files(":pkix")
+ java9Implementation files("$bc_prov")
+ java9Implementation files("$bc_util")
+ java9Implementation files("$bc_pkix")
java9Implementation files(sourceSets.main.output.classesDirs) {
builtBy compileJava
}
diff --git a/mls/build.gradle b/mls/build.gradle
index e277ce4c70..a816a087af 100644
--- a/mls/build.gradle
+++ b/mls/build.gradle
@@ -61,10 +61,9 @@ dependencies {
// runtimeOnly "io.grpc:grpc-netty-shaded:${grpcVersion}"
// implementation "com.google.protobuf:protobuf-java-util:${protocVersion}"
- java9Implementation project(':core')
- java9Implementation project(':prov')
- java9Implementation project(':util')
- java9Implementation project(':pkix')
+ java9Implementation files("$bc_prov")
+ java9Implementation files("$bc_util")
+ java9Implementation files("$bc_pkix")
java9Implementation files(sourceSets.main.output.classesDirs) {
builtBy compileJava
}
From 3790993df5d28f661a64439a8664343437ed3865 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Tue, 12 Mar 2024 00:24:18 +0700
Subject: [PATCH 0155/1846] ASN.1: Limit OID contents to 4096 bytes
---
.../bouncycastle/asn1/ASN1InputStream.java | 6 +
.../asn1/ASN1ObjectIdentifier.java | 110 +++++++++++-------
.../bouncycastle/asn1/ASN1RelativeOID.java | 99 ++++++++++------
3 files changed, 142 insertions(+), 73 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java b/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
index 5b1fb12343..9dc4a45826 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ASN1InputStream.java
@@ -546,15 +546,21 @@ static ASN1Primitive createPrimitiveDERObject(
case OBJECT_DESCRIPTOR:
return ASN1ObjectDescriptor.createPrimitive(defIn.toByteArray());
case OBJECT_IDENTIFIER:
+ {
+ ASN1ObjectIdentifier.checkContentsLength(defIn.getRemaining());
// TODO Ideally only clone if we used a buffer
return ASN1ObjectIdentifier.createPrimitive(getBuffer(defIn, tmpBuffers), true);
+ }
case OCTET_STRING:
return ASN1OctetString.createPrimitive(defIn.toByteArray());
case PRINTABLE_STRING:
return ASN1PrintableString.createPrimitive(defIn.toByteArray());
case RELATIVE_OID:
+ {
+ ASN1RelativeOID.checkContentsLength(defIn.getRemaining());
// TODO Ideally only clone if we used a buffer
return ASN1RelativeOID.createPrimitive(getBuffer(defIn, tmpBuffers), true);
+ }
case T61_STRING:
return ASN1T61String.createPrimitive(defIn.toByteArray());
case UNIVERSAL_STRING:
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
index b3029d48bb..03f43333a4 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ASN1ObjectIdentifier.java
@@ -22,6 +22,17 @@ ASN1Primitive fromImplicitPrimitive(DEROctetString octetString)
}
};
+ /**
+ * Implementation limit on the length of the contents octets for an Object Identifier.
+ *
+ * We adopt the same value used by OpenJDK. In theory there is no limit on the length of the contents, or
+ * the number of subidentifiers, or the length of individual subidentifiers. In practice, supporting
+ * arbitrary lengths can lead to issues, e.g. denial-of-service attacks when attempting to convert a
+ * parsed value to its (decimal) string form.
+ */
+ private static final int MAX_CONTENTS_LENGTH = 4096;
+ private static final int MAX_IDENTIFIER_LENGTH = MAX_CONTENTS_LENGTH * 4 + 1;
+
public static ASN1ObjectIdentifier fromContents(byte[] contents)
{
if (contents == null)
@@ -103,12 +114,16 @@ public static ASN1ObjectIdentifier tryFromID(String identifier)
{
throw new NullPointerException("'identifier' cannot be null");
}
- if (!isValidIdentifier(identifier))
+ if (identifier.length() <= MAX_IDENTIFIER_LENGTH && isValidIdentifier(identifier))
{
- return null;
+ byte[] contents = parseIdentifier(identifier);
+ if (contents.length <= MAX_CONTENTS_LENGTH)
+ {
+ return new ASN1ObjectIdentifier(contents, identifier);
+ }
}
- return new ASN1ObjectIdentifier(parseIdentifier(identifier), identifier);
+ return null;
}
private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7F;
@@ -126,28 +141,13 @@ public static ASN1ObjectIdentifier tryFromID(String identifier)
*/
public ASN1ObjectIdentifier(String identifier)
{
- if (identifier == null)
- {
- throw new NullPointerException("'identifier' cannot be null");
- }
- if (!isValidIdentifier(identifier))
- {
- throw new IllegalArgumentException("string " + identifier + " not an OID");
- }
+ checkIdentifier(identifier);
- this.contents = parseIdentifier(identifier);
- this.identifier = identifier;
- }
+ byte[] contents = parseIdentifier(identifier);
+ checkContentsLength(contents.length);
- private ASN1ObjectIdentifier(byte[] contents, boolean clone)
- {
- if (!ASN1RelativeOID.isValidContents(contents))
- {
- throw new IllegalArgumentException("invalid OID contents");
- }
-
- this.contents = clone ? Arrays.clone(contents) : contents;
- this.identifier = null;
+ this.contents = contents;
+ this.identifier = identifier;
}
private ASN1ObjectIdentifier(byte[] contents, String identifier)
@@ -164,12 +164,12 @@ private ASN1ObjectIdentifier(byte[] contents, String identifier)
*/
public ASN1ObjectIdentifier branch(String branchID)
{
- if (!ASN1RelativeOID.isValidIdentifier(branchID, 0))
- {
- throw new IllegalArgumentException("string " + branchID + " not a valid OID branch");
- }
+ ASN1RelativeOID.checkIdentifier(branchID);
- byte[] contents = Arrays.concatenate(this.contents, ASN1RelativeOID.parseIdentifier(branchID));
+ byte[] branchContents = ASN1RelativeOID.parseIdentifier(branchID);
+ checkContentsLength(this.contents.length + branchContents.length);
+
+ byte[] contents = Arrays.concatenate(this.contents, branchContents);
String identifier = getId() + "." + branchID;
return new ASN1ObjectIdentifier(contents, identifier);
@@ -246,6 +246,49 @@ public String toString()
return getId();
}
+ static void checkContentsLength(int contentsLength)
+ {
+ if (contentsLength > MAX_CONTENTS_LENGTH)
+ {
+ throw new IllegalArgumentException("exceeded OID contents length limit");
+ }
+ }
+
+ static void checkIdentifier(String identifier)
+ {
+ if (identifier == null)
+ {
+ throw new NullPointerException("'identifier' cannot be null");
+ }
+ if (identifier.length() > MAX_IDENTIFIER_LENGTH)
+ {
+ throw new IllegalArgumentException("exceeded OID contents length limit");
+ }
+ if (!isValidIdentifier(identifier))
+ {
+ throw new IllegalArgumentException("string " + identifier + " not a valid OID");
+ }
+ }
+
+ static ASN1ObjectIdentifier createPrimitive(byte[] contents, boolean clone)
+ {
+ checkContentsLength(contents.length);
+
+ final OidHandle hdl = new OidHandle(contents);
+ ASN1ObjectIdentifier oid = pool.get(hdl);
+ if (oid != null)
+ {
+ return oid;
+ }
+
+ if (!ASN1RelativeOID.isValidContents(contents))
+ {
+ throw new IllegalArgumentException("invalid OID contents");
+ }
+
+ return new ASN1ObjectIdentifier(clone ? Arrays.clone(contents) : contents, null);
+ }
+
private static boolean isValidIdentifier(String identifier)
{
if (identifier.length() < 3 || identifier.charAt(1) != '.')
@@ -447,15 +490,4 @@ public boolean equals(Object o)
return false;
}
}
-
- static ASN1ObjectIdentifier createPrimitive(byte[] contents, boolean clone)
- {
- final OidHandle hdl = new OidHandle(contents);
- ASN1ObjectIdentifier oid = pool.get(hdl);
- if (oid != null)
- {
- return oid;
- }
- return new ASN1ObjectIdentifier(contents, clone);
- }
}
diff --git a/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java b/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java
index 1814e179cd..ef494b4846 100644
--- a/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java
+++ b/core/src/main/java/org/bouncycastle/asn1/ASN1RelativeOID.java
@@ -19,6 +19,17 @@ ASN1Primitive fromImplicitPrimitive(DEROctetString octetString)
}
};
+ /**
+ * Implementation limit on the length of the contents octets for a Relative OID.
+ *
+ * We adopt the same value used by OpenJDK for Object Identifier. In theory there is no limit on the
+ * length of the contents, or the number of subidentifiers, or the length of individual subidentifiers. In
+ * practice, supporting arbitrary lengths can lead to issues, e.g. denial-of-service attacks when
+ * attempting to convert a parsed value to its (decimal) string form.
+ */
+ private static final int MAX_CONTENTS_LENGTH = 4096;
+ private static final int MAX_IDENTIFIER_LENGTH = MAX_CONTENTS_LENGTH * 4 - 1;
+
public static ASN1RelativeOID fromContents(byte[] contents)
{
if (contents == null)
@@ -70,12 +81,16 @@ public static ASN1RelativeOID tryFromID(String identifier)
{
throw new NullPointerException("'identifier' cannot be null");
}
- if (!isValidIdentifier(identifier, 0))
+ if (identifier.length() <= MAX_IDENTIFIER_LENGTH && isValidIdentifier(identifier, 0))
{
- return null;
+ byte[] contents = parseIdentifier(identifier);
+ if (contents.length <= MAX_CONTENTS_LENGTH)
+ {
+ return new ASN1RelativeOID(contents, identifier);
+ }
}
- return new ASN1RelativeOID(parseIdentifier(identifier), identifier);
+ return null;
}
private static final long LONG_LIMIT = (Long.MAX_VALUE >> 7) - 0x7F;
@@ -88,37 +103,13 @@ public static ASN1RelativeOID tryFromID(String identifier)
public ASN1RelativeOID(String identifier)
{
- if (identifier == null)
- {
- throw new NullPointerException("'identifier' cannot be null");
- }
- if (!isValidIdentifier(identifier, 0))
- {
- throw new IllegalArgumentException("string " + identifier + " not a relative OID");
- }
-
- this.contents = parseIdentifier(identifier);
- this.identifier = identifier;
- }
-
- private ASN1RelativeOID(ASN1RelativeOID oid, String branchID)
- {
- if (!isValidIdentifier(branchID, 0))
- {
- throw new IllegalArgumentException("string " + branchID + " not a valid relative OID branch");
- }
+ checkIdentifier(identifier);
- this.contents = Arrays.concatenate(oid.contents, parseIdentifier(branchID));
- this.identifier = oid.getId() + "." + branchID;
- }
+ byte[] contents = parseIdentifier(identifier);
+ checkContentsLength(contents.length);
- private ASN1RelativeOID(byte[] contents, boolean clone)
- {
- if (!isValidContents(contents))
- throw new IllegalArgumentException("invalid relative OID contents");
-
- this.contents = clone ? Arrays.clone(contents) : contents;
- this.identifier = null;
+ this.contents = contents;
+ this.identifier = identifier;
}
private ASN1RelativeOID(byte[] contents, String identifier)
@@ -129,7 +120,15 @@ private ASN1RelativeOID(byte[] contents, String identifier)
public ASN1RelativeOID branch(String branchID)
{
- return new ASN1RelativeOID(this, branchID);
+ checkIdentifier(branchID);
+
+ byte[] branchContents = parseIdentifier(branchID);
+ checkContentsLength(this.contents.length + branchContents.length);
+
+ byte[] contents = Arrays.concatenate(this.contents, branchContents);
+ String identifier = getId() + "." + branchID;
+
+ return new ASN1RelativeOID(contents, identifier);
}
public synchronized String getId()
@@ -183,15 +182,47 @@ boolean encodeConstructed()
return false;
}
+ static void checkContentsLength(int contentsLength)
+ {
+ if (contentsLength > MAX_CONTENTS_LENGTH)
+ {
+ throw new IllegalArgumentException("exceeded relative OID contents length limit");
+ }
+ }
+
+ static void checkIdentifier(String identifier)
+ {
+ if (identifier == null)
+ {
+ throw new NullPointerException("'identifier' cannot be null");
+ }
+ if (identifier.length() > MAX_IDENTIFIER_LENGTH)
+ {
+ throw new IllegalArgumentException("exceeded relative OID contents length limit");
+ }
+ if (!isValidIdentifier(identifier, 0))
+ {
+ throw new IllegalArgumentException("string " + identifier + " not a valid relative OID");
+ }
+ }
+
static ASN1RelativeOID createPrimitive(byte[] contents, boolean clone)
{
+ checkContentsLength(contents.length);
+
final ASN1ObjectIdentifier.OidHandle hdl = new ASN1ObjectIdentifier.OidHandle(contents);
ASN1RelativeOID oid = pool.get(hdl);
if (oid != null)
{
return oid;
}
- return new ASN1RelativeOID(contents, clone);
+
+ if (!isValidContents(contents))
+ {
+ throw new IllegalArgumentException("invalid relative OID contents");
+ }
+
+ return new ASN1RelativeOID(clone ? Arrays.clone(contents) : contents, null);
}
static boolean isValidContents(byte[] contents)
From 6dc716dd41d1ac85f5f6dbd073245f00878a7a63 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Tue, 12 Mar 2024 15:53:27 +0700
Subject: [PATCH 0156/1846] Use tryFromID to check for OID string
---
.../asn1/x500/style/IETFUtils.java | 20 +++++++++---------
.../org/bouncycastle/asn1/x509/X509Name.java | 21 ++++++++++---------
2 files changed, 21 insertions(+), 20 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java b/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
index 03d5b738d6..958de0c2ad 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x500/style/IETFUtils.java
@@ -272,26 +272,26 @@ public static String[] findAttrNamesForOID(
return aliases;
}
- public static ASN1ObjectIdentifier decodeAttrName(
- String name,
- Hashtable lookUp)
+ public static ASN1ObjectIdentifier decodeAttrName(String name, Hashtable lookUp)
{
- if (Strings.toUpperCase(name).startsWith("OID."))
+ if (name.regionMatches(true, 0, "OID.", 0, 4))
{
return new ASN1ObjectIdentifier(name.substring(4));
}
- else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
+
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.tryFromID(name);
+ if (oid != null)
{
- return new ASN1ObjectIdentifier(name);
+ return oid;
}
- ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
- if (oid == null)
+ oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
+ if (oid != null)
{
- throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+ return oid;
}
- return oid;
+ throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
}
public static ASN1Encodable valueFromHexString(
diff --git a/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java b/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
index d9dadec113..cfa317790f 100644
--- a/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
+++ b/core/src/main/java/org/bouncycastle/asn1/x509/X509Name.java
@@ -660,27 +660,28 @@ public X509Name(
this(reverse, lookUp, dirName, new X509DefaultEntryConverter());
}
- private ASN1ObjectIdentifier decodeOID(
- String name,
- Hashtable lookUp)
+ private ASN1ObjectIdentifier decodeOID(String name, Hashtable lookUp)
{
name = name.trim();
- if (Strings.toUpperCase(name).startsWith("OID."))
+
+ if (name.regionMatches(true, 0, "OID.", 0, 4))
{
return new ASN1ObjectIdentifier(name.substring(4));
}
- else if (name.charAt(0) >= '0' && name.charAt(0) <= '9')
+
+ ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.tryFromID(name);
+ if (oid != null)
{
- return new ASN1ObjectIdentifier(name);
+ return oid;
}
- ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
- if (oid == null)
+ oid = (ASN1ObjectIdentifier)lookUp.get(Strings.toLowerCase(name));
+ if (oid != null)
{
- throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
+ return oid;
}
- return oid;
+ throw new IllegalArgumentException("Unknown object id - " + name + " - passed to distinguished name");
}
private String unescape(String elt)
From 9c165791b68a204678b48ec11e4e579754c2ea49 Mon Sep 17 00:00:00 2001
From: Alexander Scheel
Date: Wed, 13 Mar 2024 15:15:58 -0400
Subject: [PATCH 0157/1846] Fix for EdDSA verification infinite loop
Resolves: https://github.com/bcgit/bc-java/issues/1599
Signed-off-by: Alexander Scheel
---
.../math/ec/rfc8032/Scalar25519.java | 5 +-
.../math/ec/rfc8032/Scalar448.java | 5 +-
.../math/ec/rfc8032/ScalarUtil.java | 208 +++++++++++++-----
3 files changed, 164 insertions(+), 54 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java
index 8018ad4f1c..a760625798 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java
@@ -306,6 +306,7 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1)
int[] Nu = new int[16]; System.arraycopy(LSq, 0, Nu, 0, 16);
int[] Nv = new int[16]; Nat256.square(k, Nv); ++Nv[0];
int[] p = new int[16]; Nat256.mul(L, k, p);
+ int[] t = new int[16]; // temp array
int[] u0 = new int[4]; System.arraycopy(L, 0, u0, 0, 4);
int[] u1 = new int[4];
int[] v0 = new int[4]; System.arraycopy(k, 0, v0, 0, 4);
@@ -322,12 +323,12 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1)
if (p[last] < 0)
{
- ScalarUtil.addShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtil.addShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtil.addShifted_UV(3, s, u0, u1, v0, v1);
}
else
{
- ScalarUtil.subShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtil.subShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtil.subShifted_UV(3, s, u0, u1, v0, v1);
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java
index 5272e4eba2..edac5c02da 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java
@@ -571,6 +571,7 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1)
int[] Nu = new int[28]; System.arraycopy(LSq, 0, Nu, 0, 28);
int[] Nv = new int[28]; Nat448.square(k, Nv); ++Nv[0];
int[] p = new int[28]; Nat448.mul(L, k, p);
+ int[] t = new int[28]; // temp array
int[] u0 = new int[8]; System.arraycopy(L, 0, u0, 0, 8);
int[] u1 = new int[8];
int[] v0 = new int[8]; System.arraycopy(k, 0, v0, 0, 8);
@@ -587,12 +588,12 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1)
if (p[last] < 0)
{
- ScalarUtil.addShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtil.addShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtil.addShifted_UV(7, s, u0, u1, v0, v1);
}
else
{
- ScalarUtil.subShifted_NP(last, s, Nu, Nv, p);
+ ScalarUtil.subShifted_NP(last, s, Nu, Nv, p, t);
ScalarUtil.subShifted_UV(7, s, u0, u1, v0, v1);
}
diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java
index 81d8fd9638..100fd485e7 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java
@@ -6,57 +6,111 @@ abstract class ScalarUtil
{
private static final long M = 0xFFFFFFFFL;
- static void addShifted_NP(int last, int s, int[] Nu, int[] Nv, int[] _p)
+ static void addShifted_NP(int last, int s, int[] Nu, int[] Nv, int[] p, int[] t)
{
- int sWords = s >>> 5, sBits = s & 31;
-
- long cc__p = 0L;
+ long cc_p = 0L;
long cc_Nu = 0L;
- if (sBits == 0)
+ if (s == 0)
{
- for (int i = sWords; i <= last; ++i)
+ for (int i = 0; i <= last; ++i)
{
+ int p_i = p[i];
+
cc_Nu += Nu[i] & M;
- cc_Nu += _p[i - sWords] & M;
+ cc_Nu += p_i & M;
- cc__p += _p[i] & M;
- cc__p += Nv[i - sWords] & M;
- _p[i] = (int)cc__p; cc__p >>>= 32;
+ cc_p += p_i & M;
+ cc_p += Nv[i] & M;
+ p_i = (int)cc_p; cc_p >>= 32;
+ p[i] = p_i;
- cc_Nu += _p[i - sWords] & M;
- Nu[i] = (int)cc_Nu; cc_Nu >>>= 32;
+ cc_Nu += p_i & M;
+ Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
}
}
- else
+ else if (s < 32)
{
int prev_p = 0;
int prev_q = 0;
int prev_v = 0;
- for (int i = sWords; i <= last; ++i)
+ for (int i = 0; i <= last; ++i)
{
- int next_p = _p[i - sWords];
- int p_s = (next_p << sBits) | (prev_p >>> -sBits);
- prev_p = next_p;
+ int p_i = p[i];
+ int p_s = (p_i << s) | (prev_p >>> -s);
+ prev_p = p_i;
cc_Nu += Nu[i] & M;
cc_Nu += p_s & M;
- int next_v = Nv[i - sWords];
- int v_s = (next_v << sBits) | (prev_v >>> -sBits);
+ int next_v = Nv[i];
+ int v_s = (next_v << s) | (prev_v >>> -s);
prev_v = next_v;
- cc__p += _p[i] & M;
- cc__p += v_s & M;
- _p[i] = (int)cc__p; cc__p >>>= 32;
+ cc_p += p_i & M;
+ cc_p += v_s & M;
+ p_i = (int)cc_p; cc_p >>= 32;
+ p[i] = p_i;
- int next_q = _p[i - sWords];
- int q_s = (next_q << sBits) | (prev_q >>> -sBits);
- prev_q = next_q;
+ int q_s = (p_i << s) | (prev_q >>> -s);
+ prev_q =p_i;
cc_Nu += q_s & M;
- Nu[i] = (int)cc_Nu; cc_Nu >>>= 32;
+ Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
+ }
+ }
+ else
+ {
+ // Keep the original value of p in t.
+ System.arraycopy(p, 0, t, 0, p.length);
+
+ int sWords = s >>> 5; int sBits = s & 31;
+ if (sBits == 0)
+ {
+ for (int i = sWords; i <= last; ++i)
+ {
+ cc_Nu += Nu[i] & M;
+ cc_Nu += t[i - sWords] & M;
+
+ cc_p += p[i] & M;
+ cc_p += Nv[i - sWords] & M;
+ p[i] = (int)cc_p; cc_p >>= 32;
+
+ cc_Nu += p[i - sWords] & M;
+ Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
+ }
+ }
+ else
+ {
+ int prev_t = 0;
+ int prev_q = 0;
+ int prev_v = 0;
+
+ for (int i = sWords; i <= last; ++i)
+ {
+ int next_t = t[i - sWords];
+ int t_s = (next_t << sBits) | (prev_t >>> -sBits);
+ prev_t = next_t;
+
+ cc_Nu += Nu[i] & M;
+ cc_Nu += t_s & M;
+
+ int next_v = Nv[i - sWords];
+ int v_s = (next_v << sBits) | (prev_v >>> -sBits);
+ prev_v = next_v;
+
+ cc_p += p[i] & M;
+ cc_p += v_s & M;
+ p[i] = (int)cc_p; cc_p >>= 32;
+
+ int next_q = p[i - sWords];
+ int q_s = (next_q << sBits) | (prev_q >>> -sBits);
+ prev_q = next_q;
+
+ cc_Nu += q_s & M;
+ Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
+ }
}
}
}
@@ -141,59 +195,113 @@ static boolean lessThan(int last, int[] x, int[] y)
return false;
}
- static void subShifted_NP(int last, int s, int[] Nu, int[] Nv, int[] _p)
+ static void subShifted_NP(int last, int s, int[] Nu, int[] Nv, int[] p, int[] t)
{
- int sWords = s >>> 5, sBits = s & 31;
-
- long cc__p = 0L;
+ long cc_p = 0L;
long cc_Nu = 0L;
- if (sBits == 0)
+ if (s == 0)
{
- for (int i = sWords; i <= last; ++i)
+ for (int i = 0; i <= last; ++i)
{
+ int p_i = p[i];
+
cc_Nu += Nu[i] & M;
- cc_Nu -= _p[i - sWords] & M;
+ cc_Nu -= p_i & M;
- cc__p += _p[i] & M;
- cc__p -= Nv[i - sWords] & M;
- _p[i] = (int)cc__p; cc__p >>= 32;
+ cc_p += p_i & M;
+ cc_p -= Nv[i] & M;
+ p_i = (int)cc_p; cc_p >>= 32;
+ p[i] = p_i;
- cc_Nu -= _p[i - sWords] & M;
+ cc_Nu -= p_i & M;
Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
}
}
- else
+ else if (s < 32)
{
int prev_p = 0;
int prev_q = 0;
int prev_v = 0;
- for (int i = sWords; i <= last; ++i)
+ for (int i = 0; i <= last; ++i)
{
- int next_p = _p[i - sWords];
- int p_s = (next_p << sBits) | (prev_p >>> -sBits);
- prev_p = next_p;
+ int p_i = p[i];
+ int p_s = (p_i << s) | (prev_p >>> -s);
+ prev_p = p_i;
cc_Nu += Nu[i] & M;
cc_Nu -= p_s & M;
- int next_v = Nv[i - sWords];
- int v_s = (next_v << sBits) | (prev_v >>> -sBits);
+ int next_v = Nv[i];
+ int v_s = (next_v << s) | (prev_v >>> -s);
prev_v = next_v;
- cc__p += _p[i] & M;
- cc__p -= v_s & M;
- _p[i] = (int)cc__p; cc__p >>= 32;
+ cc_p += p_i & M;
+ cc_p -= v_s & M;
+ p_i = (int)cc_p; cc_p >>= 32;
+ p[i] = p_i;
- int next_q = _p[i - sWords];
- int q_s = (next_q << sBits) | (prev_q >>> -sBits);
- prev_q = next_q;
+ int q_s = (p_i << s) | (prev_q >>> -s);
+ prev_q = p_i;
cc_Nu -= q_s & M;
Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
}
}
+ else
+ {
+ // Keep the original value of p in t.
+ System.arraycopy(p, 0, t, 0, p.length);
+
+ int sWords = s >>> 5; int sBits = s & 31;
+ if (sBits == 0)
+ {
+ for (int i = sWords; i <= last; ++i)
+ {
+ cc_Nu += Nu[i] & M;
+ cc_Nu -= t[i - sWords] & M;
+
+ cc_p += p[i] & M;
+ cc_p -= Nv[i - sWords] & M;
+ p[i] = (int)cc_p; cc_p >>= 32;
+
+ cc_Nu -= p[i - sWords] & M;
+ Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
+ }
+ }
+ else
+ {
+ int prev_t = 0;
+ int prev_q = 0;
+ int prev_v = 0;
+
+ for (int i = sWords; i <= last; ++i)
+ {
+ int next_t = t[i - sWords];
+ int t_s = (next_t << sBits) | (prev_t >>> -sBits);
+ prev_t = next_t;
+
+ cc_Nu += Nu[i] & M;
+ cc_Nu -= t_s & M;
+
+ int next_v = Nv[i - sWords];
+ int v_s = (next_v << sBits) | (prev_v >>> -sBits);
+ prev_v = next_v;
+
+ cc_p += p[i] & M;
+ cc_p -= v_s & M;
+ p[i] = (int)cc_p; cc_p >>= 32;
+
+ int next_q = p[i - sWords];
+ int q_s = (next_q << sBits) | (prev_q >>> -sBits);
+ prev_q = next_q;
+
+ cc_Nu -= q_s & M;
+ Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
+ }
+ }
+ }
}
static void subShifted_UV(int last, int s, int[] u0, int[] u1, int[] v0, int[] v1)
From 02f1fb441b6b72826ea892aea4a741403d9562f3 Mon Sep 17 00:00:00 2001
From: Alexander Scheel
Date: Fri, 15 Mar 2024 11:52:17 -0400
Subject: [PATCH 0158/1846] Add regression tests for Ed25519 loop
This adds regression tests for the Ed25519 loop bug, generated using an
instrumented build. Vectors were found by adapting affected functions
(addShifted_NP, subShifted_NP, and reduceBasisVar) to account for
different parameters (last and s in the first two or number of loop
iterations in the latter), to ensure correct behavior and sufficient
coverage. Vectors were then cross-verified with an alternative
implementation, though signature generation was not impacted, only
verification.
Signed-off-by: Alexander Scheel
---
.../bouncycastle/crypto/test/Ed25519Test.java | 688 ++++++++++++++++++
1 file changed, 688 insertions(+)
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java b/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java
index 1633d54b0b..993200cf3a 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java
@@ -13,6 +13,7 @@
import org.bouncycastle.crypto.signers.Ed25519phSigner;
import org.bouncycastle.math.ec.rfc8032.Ed25519;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -43,6 +44,7 @@ public void performTest() throws Exception
}
basicSigTest();
+ testRegressionInfiniteLoop();
}
private void basicSigTest()
@@ -155,4 +157,690 @@ private void testConsistency(int algorithm, byte[] context) throws Exception
}
}
}
+
+ private void testRegressionInfiniteLoop() throws Exception
+ {
+ String[] testCases = new String[]{
+ "pub=MCowBQYDK2VwAyEA3/3evB5w/U2/UClcztEy9jyUhCYb4lsYC/Uc0Y3XU2A= priv=MC4CAQAwBQYDK2VwBCIEIPqycfmKBOt+r71r9rPfm/qHloKw1mi0u7EtapwiyLFq msg=XffXN58qcNEDB9bG0Bi4+rJx+YoE636vvWv2s9+b+oeWgrDWaLS7sS1qnCLIsWogbfSKviAwbnT17l1hipS+Qw== sig=ygsIhBS66Bh6JYI+7NS7WX/KXIIqjMX4zlgqbH8euNCg1mkdj1E9gTZ1fxSfws8ZywBfLY1Sy+7ldggN2tLIDQ== e=found 57 iterations",
+ "pub=MCowBQYDK2VwAyEAHE6pGleQ6FLeLw37qqETXGJ7ypORl7ipr8mhKsuwGaE= priv=MC4CAQAwBQYDK2VwBCIEIOOZeFAaz2ab5MpacOllrYaslZc5GniKpptk6wBxJXIf msg=5uTZqblhMeTvsI2p6090Pjkkdqd+8GZQMN1Mnv/WvVFmnJN5IBDOjahUTJnfhTxs6EmeXSYeO4WrevJor16ETg== sig=s8aJ/GKWfb2dz7ll7Ne+CrCdjHI1K3Y/7gLDOIZavFpxHcH8giHrrQ59TIWU3T4Fhe/we9EPcW/KzNcU4CUXAQ== e=found 58 iterations",
+ "pub=MCowBQYDK2VwAyEAJHkMcEbTWYrCDb+3JciGTTTwiTHHOGt/H0oWdCF7KjQ= priv=MC4CAQAwBQYDK2VwBCIEIGazYWgWo6F/+K0HNs1V1/N9LQm6T32nqJJ87pH5FSWb msg=yBv8Q3VCicgj+eBdgBrcdnp8uNO+LfgSVGazYWgWo6F/+K0HNs1V1/N9LQm6T32nqJJ87pH5FSWbXmXIcTEWeQ== sig=o4KkE0Fe5PQXZ66mfG7tnh/k2/5EaPqXAOmgo0ji+apD2iiaQcb+1skazsJWbwoubWSDFiWUlJdh+eY/x0f+BA== e=found 59 iterations",
+ "pub=MCowBQYDK2VwAyEAQ0jwSazJght+xwc61Oot3UmMdefnvHBOvi3VsQ+X4qk= priv=MC4CAQAwBQYDK2VwBCIEICD2bl/Zm5YSPMftEm00BM0MUe6j+nlZXqztAkE0xrky msg=fADFP9wG2ltHE+pIErYCjodSbK5U/wnHzBHhx/vHJjhUxQv7uWx27zjvEYKLTJeJJvD3J2fH+afqfAJv7KmAPg== sig=dFQffK66bpOuv/CVySTNuuVvZ9vneh8N2gVYmEDjwEeYKVxDXOWR7Lz9VL4VREnMKmY1ABZqFGat42mtDhT7BQ== e=found 60 iterations",
+ "pub=MCowBQYDK2VwAyEAw9qjlWaWApPsYJoi1urhuZRPJ0HwKmcxSH+d+UrulFY= priv=MC4CAQAwBQYDK2VwBCIEIEChvJXCKYlzD95RdByx424MtBDDuNH+RUkdGOrFje93 msg=cpZ5pNbNxLTwIKyTGTCUpDNSOQZAobyVwimJcw/eUXQcseNuDLQQw7jR/kVJHRjqxY3vd9/B1yDiHPqJPl1weQ== sig=fQZ9FXypim4TXvs5XmLyfHlnl+H5dxsDruEXBRChZBPpYI+RU/DAN4/KJfxf3jWsr8EknjmVgPncDftqBtGeCA== e=found 61 iterations",
+ "pub=MCowBQYDK2VwAyEAHVoqu90LAbDc9tY/24I85V3Iddy9IaYaqC6QnztbIWw= priv=MC4CAQAwBQYDK2VwBCIEIC5EY5KGGA9Vz+RXn+Jb3C2P3vLngGox1x/VMq/xgQ/c msg=4g0xLkRjkoYYD1XP5Fef4lvcLY/e8ueAajHXH9Uyr/GBD9xDLCrQyr7DAX37FiM6XMXXdImapHyrKxjZ4hljwA== sig=goY0VKd7aQHUnHkfIX2ZUbE36lbJeOIT2949NsG77LmDn1don59tvyxfC1XaXVRiVx5lz6FbRQprvDqK8ltFDA== e=found 62 iterations",
+ "pub=MCowBQYDK2VwAyEAO2X9m9WY0jkQ3rsWHgB07rKXKSowZijSwNcats/rxls= priv=MC4CAQAwBQYDK2VwBCIEIHpGklIDOOxGzlBBJx8Z8q+uNYC7qwAT7Io3moNwpdNx msg=qY16RpJSAzjsRs5QQScfGfKvrjWAu6sAE+yKN5qDcKXTcU8uPgLQEoR22vXmN0ZL1IjapYbh8IuG5X8o5C+9bQ== sig=ENLBlvemjb580cnBqSE9an761T3sVD7A/WYM9GZIspeOj8u2eyjMSrzOcu+hvL3sFNxZvuIkv0WNBZSfNre8Bw== e=found 63 iterations",
+ "pub=MCowBQYDK2VwAyEAgU4uXIkXFTLtmF3rLM4rUbpMQqJAJKFAzKJm7T1CpiA= priv=MC4CAQAwBQYDK2VwBCIEIFjsWgCM7VfazSZBCZ1VOijO1YGF1keRqw9HVh5VRQxB msg=OijO1YGF1keRqw9HVh5VRQxBSbw4babQ5wmgtR4LVClBV2VEHtuBTsPAqisBJNocB9h+LWJu+DejyjmHpcz9WQ== sig=jSRxppkrB+yUOs668HXOMy4Jjj4H9MP+cmXMwzEqsVl8wc6fp7EQj5+TrQKMxmE7wssKqEMiKkdBjDhtwjH5CQ== e=found 64 iterations",
+ "pub=MCowBQYDK2VwAyEAtouD0lJ0YQHbkEaX8gO3r9S0ChGHc+yTSaoCIvapPwE= priv=MC4CAQAwBQYDK2VwBCIEINjDs+pGo0ltBaFttGeFJCf9Mxx1HtKQTfDM+RvYsv5o msg=QnVUUQt6Oc4jVIN5s9jDs+pGo0ltBaFttGeFJCf9Mxx1HtKQTfDM+RvYsv5o1RebMvFrjIccGemNKesf2D1Dqg== sig=uRWDxSUqrlhZugfNof0M9ChCSAyXRwxPQj4BFMs1hPeN2OZOs9zwwX9A/txWOvjFFrxzZv2RfxYDsbBw361fCw== e=found 65 iterations",
+ "pub=MCowBQYDK2VwAyEA7gJi5r5MaxpTqo6RUdDKnQ6dBI7F8nLQEKyBeHXIY8Q= priv=MC4CAQAwBQYDK2VwBCIEIPpWOkkMNiGqG3fvJKZmCmk4wkMlU/9pANei/BX3Mmxl msg=0p4n7fEf9tz7VFfwSUwQ6DD6VjpJDDYhqht37ySmZgppOMJDJVP/aQDXovwV9zJsZa09HhhSgN28xezygc6rxQ== sig=EinE0Nh/AIUdB6L4m93Y9/k0EHM9gXgGfBk5w3yJ4DyBTzwmfcvKpMM4biqeeGkLp/o178h99qo7VKHy4iu/CA== e=found 66 iterations",
+ "pub=MCowBQYDK2VwAyEAQ8fC52l1Ap4uBSm1UBbMGhUVYxQh3hrrwpO34TuwsMo= priv=MC4CAQAwBQYDK2VwBCIEIMCByifE3xspIRrcWScSuaPmd3teD9OAusym1ko2SHHN msg=LGrH8cQFin0saRCHUg32Uvl6W9CwSOI8sQKyw61UPe7AgconxN8bKSEa3FknErmj5nd7Xg/TgLrMptZKNkhxzQ== sig=xuBEeHak/xpR0JWm3zIgMZBdNoAu4nBeYT4ZCMWWWIAp+N8WLRLEwqZc5ATRxFSIAyroeqqwfM+HCd57CYfJDQ== e=found 67 iterations",
+ "pub=MCowBQYDK2VwAyEALz5ECUSoAyj++sngkV9x579Rn9gIv60EhWM/Mo04qYI= priv=MC4CAQAwBQYDK2VwBCIEIAj/Likh1ESWhlieUj3NJsJYiyEaAb+NJGo0mJQlSFsI msg=Likh1ESWhlieUj3NJsJYiyEaAb+NJGo0mJQlSFsISkKXYllc3AFZLfIxEJhlg7kkSPRoSjsywIKkQMKz0nTqmQ== sig=wyrojflpY11TM7qOQID9w2MuNEiBUe5djMdOd592gBtG3rC34bCM+e4YACZLRokN4+fIAEYkVBj9IsmqPa7DAw== e=found 68 iterations",
+ "pub=MCowBQYDK2VwAyEA3v9XVY2xwD7nD5NUZl3lvzlX7Vl+sSNQ39gDfBVy6Y4= priv=MC4CAQAwBQYDK2VwBCIEIHUSb1VM6d2XAr/tGjaihT4lwDrhS6m+jQD4ss+BuWHP msg=f8Cm7q424+L+dRJvVUzp3ZcCv+0aNqKFPiXAOuFLqb6NAPiyz4G5Yc9djz1ZDGoobooR+E9P8LPdcnl3VW9XDg== sig=ArQBwnYbRe/TC/9mHVu9DpK2tUXh4QuikFZl7uKo4zaozZcR8T141Exm/c1gpEVZTVkzgej8LUsRD4bcO5L3Dw== e=found 69 iterations",
+ "pub=MCowBQYDK2VwAyEAcOsf+gEhq9BSSqzZ/qxCn/c4soTZuAQ2OIUmZbxOpo8= priv=MC4CAQAwBQYDK2VwBCIEIJjji9eyxdpYzxuxWfMJBunPDOVmBRMj4BVVP65o2Hlg msg=u4VP6f9VElsVCcWHrLH+6l138t4veA+LuUmOhVIzd8tg5ACs6fABUxYLd9WS5lixkY6lHSwtYnpxdTjw4W/xfw== sig=95we7zTeiWqIUgYq6ITdhOuY+wVeT52vFLxJ9lIHfbOvQIoUG/jIJ4tN8aO+E8+0ogKw6hbMe5kI8BDcolD1BQ== e=found 70 iterations",
+ "pub=MCowBQYDK2VwAyEA5N2A+KytH1SUeGrALPa4exr9T7ilFqY4mP263N/dpoA= priv=MC4CAQAwBQYDK2VwBCIEIPW2m9QjkRRPOvH8+G9UzZawwLHeAvpb776Kbjy++FDm msg=GKb1tpvUI5EUTzrx/PhvVM2WsMCx3gL6W+++im48vvhQ5tHN4ZL4Npk59iwd+Xt3q244B0J4TrBjQTCJNOe1gA== sig=xBAT3nWrOK3BmthFVhjzQmRyuc//xEXnht058kFn7iMiK9qTawfPYrh/0GtMT+D8T+ywSHs8dheT2u6IMpGvCw== e=found 71 iterations",
+ "pub=MCowBQYDK2VwAyEAck4cyMfKmNjVvsYCniBLPGufQHdhsYkHxwN/yLRkFqI= priv=MC4CAQAwBQYDK2VwBCIEIOnPLabQHydXPuXSFvVoefv5gGDw7g/hjwlkaYXvfkU2 msg=pTdX5+nPLabQHydXPuXSFvVoefv5gGDw7g/hjwlkaYXvfkU2eKdkOblsgfjKiunbgZSTPS+CsOJz3/C1qkuwoQ== sig=BBauQZjlkp/KGMQralAlgGOASATf4FTVr7pQJjRI+Z+ZRgWHdqwfwc2f+bskbFzdk/dMfX1+/adjpNqnQx++Aw== e=found 72 iterations",
+ "pub=MCowBQYDK2VwAyEACvojkSBSZ7VCiwZ3xXoU2ATVM0WICTajOKL9lE4p+/8= priv=MC4CAQAwBQYDK2VwBCIEIEGLCxghINDDsZ2KD5pbvtezu48inGVtJDkhGJTNlExL msg=0MOxnYoPmlu+17O7jyKcZW0kOSEYlM2UTEsyjeEVoSB1oWw43IbtQsU1aXjEAbsGR37fjN2CJUSIIjbjWobglA== sig=tazDpJk/+ksUjyROEq7CQeYG3JWvSuo/a7n4i27dTtLnBZdJKI2Ss/CFgoUaFR7MghXmuFTgjRNkFTyIRH5kAQ== e=found 73 iterations",
+ "pub=MCowBQYDK2VwAyEAcyMeLZ2B6y+bumyenoAPjsVS3hYttEc65namio44OfY= priv=MC4CAQAwBQYDK2VwBCIEIMGtgiHjjye6/sD0KGQsl3yMeglzwgUcLfr6kvZv1tLi msg=448nuv7A9ChkLJd8jHoJc8IFHC36+pL2b9bS4tSUHiMdMbHfGNxLoKVyQWmwZI25RV3tb6uCZjShyeyAQxf5qQ== sig=rleDJhVQLfwwW/8BeJzQ0faH8exOaLOj2mZ7Pl22xb26SO/kJTNjwRwuJIa1ikE3VUYyin+Z8l1AKIsB1bUUDw== e=found 74 iterations",
+ "pub=MCowBQYDK2VwAyEAVbTtelb7fdEllJU4Isl/qQBVfpCwf/FS98Qo+39Juts= priv=MC4CAQAwBQYDK2VwBCIEIGR4+PJZWiLYLvY7K7QjxgEDc6wJNEP5FZVceJcYQFLd msg=XHiXGEBS3ebu2T5Ysp26sqATj5AgBZ5lUMXuFKDyRu7aKqKSj7IA7A6kqAHTKRgApzYkHFebiEYN4OYbnwL5yw== sig=DJyEPFFWYsBLXZhuAbeAuGFGX6d1uGdOyMQWfZUxb0VRUHtOqSqnkqxD6MFQCqrCRK99csxWM/sjzu/ElUEGBA== e=found 75 iterations",
+ "pub=MCowBQYDK2VwAyEADpJZkPbMGm3OJGBNebqCWuhtKM9K7GYoummru/XeKmU= priv=MC4CAQAwBQYDK2VwBCIEIPcAlXkRpRVYcwmciwCGfXpZMhocJ4Su/l8r2kfil4AM msg=tyoG4LBmsMzwLstDhgGON++RjqIxe27QojpSXRLFBU3b2Ipl0a/3f9hpdA/20eNxNcO6RXOcZApNwXfcGwr+wg== sig=1sTcSr9s6K0vpvLL8r2ha7hf8zLez3rF6EIWZHkktuaJoguKzcfzc27lIl4INnJcDIhalsi2DROCaYTfDKhNCg== e=found 76 iterations",
+ "pub=MCowBQYDK2VwAyEAVF/N5oJKWCGWHfiAslb8VdiCxx5JO7JZZRK4jqeNpr8= priv=MC4CAQAwBQYDK2VwBCIEIIGsfXvUljv/gjBtQYZGb4AuQrkdiYfR3auP3wEq1HE+ msg=gax9e9SWO/+CMG1BhkZvgC5CuR2Jh9Hdq4/fASrUcT6+uYYI9C8+sjoyKDeM2x4RFSmY6SnAhg5qTxeEoxxNbA== sig=AJBypRL1pNBImpqiZF7G6eXNvxWHlAbxwjT+MV1H2gFBsAG2Ym3CcsyHPd0QsqXkU2NdenmPGcDcUBjFgXLrBg== e=found 77 iterations",
+ "pub=MCowBQYDK2VwAyEA+ia1bvX/7K8dvgMawIcr+MTySXi/AgVAL2drXfvqBPM= priv=MC4CAQAwBQYDK2VwBCIEICrDfb37zqLPR/skhQQmsGhTmw/zHOfbjmAjGPEW/8oV msg=vE8KZwJ6YtP/+WyzyJWretDzt0ubvZgUtNBIuEcpELCMWfbtTVe23JPMKmjDlCTdnAtrwDbLqb5FIVEiqOXzcw== sig=20vXY9u8jczxgmmBTTWT8GypkISPYyeudzcBBRW8DhFN/469gCsM7ORIFj+kpdcS36sKeBqR7Nb+668rdvKJCA== e=found 78 iterations",
+ "pub=MCowBQYDK2VwAyEATbYfEv8ed/G/fVWIK6UmJnEo4r1CbWTRGqZLw+HITp8= priv=MC4CAQAwBQYDK2VwBCIEIEYmeASKShp0E4i7tcQubwJKh7FXMoQ+AVVgIInCCQv7 msg=JngEikoadBOIu7XELm8CSoexVzKEPgFVYCCJwgkL+07AFp7AzE5dUJa2m57x2Vgya5fJJM0A8xDx8ycIfCsXdw== sig=kF8val6rPSkqlKCE2LQMY4TOtcuBr+TXHBikJLnaOrJaN3UpdIuENMRZ5PcpQQPaUpbV2H7U7d2Tp4QVCTm+DQ== e=found 79 iterations",
+ "pub=MCowBQYDK2VwAyEAbHE4FALgveWrQGocE8gnBau1q5PpS0okUZSNHY06U+s= priv=MC4CAQAwBQYDK2VwBCIEIJT/Ds6W00gFY7t5Orz8jUbrLO7WXT/XQ8wk41xVeaaT msg=lP8OzpbTSAVju3k6vPyNRuss7tZdP9dDzCTjXFV5ppOAfhGgM/MxuyzejSkeA0JkR/b+9HQh8gOgaA601guxAg== sig=tG3nio6FoZZR9Czx6K25m5qLxIuTpSwBABkek65zya2t/eEVA4117dwB2OQpDssGbzthvpWcyj4tI551PgncDQ== e=found 80 iterations",
+ "pub=MCowBQYDK2VwAyEAlT/tfiwUqJmUvhwfGT3SZzp3fE2AIH40b7r3eXvWmus= priv=MC4CAQAwBQYDK2VwBCIEIHjr+VxWtvNNPJxbyiqBPEig906yvaR3UkhisWnyyaoE msg=+VxWtvNNPJxbyiqBPEig906yvaR3UkhisWnyyaoEaq+wmzpfZ7h77z7awiRrvzpHhexuwmR0kBG+32cuoG2FIw== sig=pqy9Bjqk89dM5Vqi9sXWps7gj0K5VZ4TSbE54/bmzz0dQlmrBB3BoLr9jR3lYmQSHGeUAiOEMF/IFqiUtVAsDw== e=found 81 iterations",
+ "pub=MCowBQYDK2VwAyEALI9zvH2ox89t5vAQ3rgcUXiudRR0qqHXSTtqfSrWtR0= priv=MC4CAQAwBQYDK2VwBCIEIABqFXbYOdPeA7tNMv+mOgMwMULjSEF/ILV7jHyvmmsH msg=SEF/ILV7jHyvmmsH/yenViLDIDsUMZ2+O5OClYh62MfqPvmJfnm5xS0936u+EITgSGoFAM01tTz+FhDT3cFZcw== sig=UMMD7kAPsI+lg6IRL/fVfAfTuPuUkuKUHu+zHn4GyDel0SeHm4qeCkDoGIYcqAKUXodTCe8HFgGXO6B/LOaFCw== e=found 82 iterations",
+ "pub=MCowBQYDK2VwAyEAaluPrsdE7hJvsRlYQxKlJpLCErJVA7oJ+6VBP6ZpBK8= priv=MC4CAQAwBQYDK2VwBCIEIJdiqV/cVG3IhVWka+6RJcg5/Euw+MOb2nvvugLRXZsa msg=VG3IhVWka+6RJcg5/Euw+MOb2nvvugLRXZsag4W/k17xGzCj01czIctEQ2Ghi3mkNlAy0xSx1iI8w5oKxoyYTA== sig=TCG2PI2fhSxKFFdbR6LYTZjQcUl08fphHg8Extx55xT6akJGPSA394JGfXTQ5EmRwpmSrOc3ctWNg0W8LkzYDw== e=found 83 iterations",
+ "pub=MCowBQYDK2VwAyEAgVFBME0lxzYhAT3mMzcN4vBD14XvUE3T7WvkCz/Hi6A= priv=MC4CAQAwBQYDK2VwBCIEIGxbsvPeQP5alHZwIFpJ/zE0VCeDg4UVZNAULW9Gz6Rn msg=bFuy895A/lqUdnAgWkn/MTRUJ4ODhRVk0BQtb0bPpGeSamrYBUN5isjpmzmEyT+PNLDnDVltWRZlast6wHKCiQ== sig=o0bihdMu3Nbu37kOilhK605/skxlRzmuqckuws2sQsXU1vektNygzTVGplO0YhzaqVRiaEQ25XyX0E5WInjYBg== e=found 84 iterations",
+ "pub=MCowBQYDK2VwAyEADswLfYaCgPTNDo6VABvIVVBL2RYzGsZwRGxD8U8sBmI= priv=MC4CAQAwBQYDK2VwBCIEIF+8551mbELCuqvXE8qIYSdQY3xcyUcAJbIBk4E/b1bJ msg=551mbELCuqvXE8qIYSdQY3xcyUcAJbIBk4E/b1bJRqeo4ZJpgVjI+9VWvsp+KgIO3PHMeP2/MR352QtwkV8Jjg== sig=OK2GAlZ8ktI0sc8DZUWTen91ZodncG4F2GEAiRWT7BMG171Kt4TmpOONC7zxg/CZATbpQsYjeJbYChOHzD2YAw== e=found 85 iterations",
+ "pub=MCowBQYDK2VwAyEAmf8knio0TlExv5yjOXhS3To0t1zTwjqM6WkFCqcgm2Y= priv=MC4CAQAwBQYDK2VwBCIEIAcdGU61Dl6Qm09qZYD8o0Ijd4TstKtRsEnSC1wKseoJ msg=Bx0ZTrUOXpCbT2plgPyjQiN3hOy0q1GwSdILXAqx6glr7GkcJj+5i7A8plIVzfqdVqcAhIotNFj7urMLHIaNEQ== sig=Fap/Bkr09J2hZmS7MFQiAdQlGdRIxd5UUyf+2j9NCVH1UDW73cCHrYhgQzIYqLLKRDm4g68XQkDKVip99A9MCg== e=found 86 iterations",
+ "pub=MCowBQYDK2VwAyEAZmMMrMIw9N+GEaZ+MlNEJhp02NBmJ0ff5oMAar+DoOc= priv=MC4CAQAwBQYDK2VwBCIEIIDlRkWRmt+LuJ46+mCurmpzSgoMK+giRrLrOoFPfwMC msg=kZrfi7ieOvpgrq5qc0oKDCvoIkay6zqBT38DAhcD3/vxzbq5F211Rh73Lgjt2kIBQ2AKCE/kZhH4zmhwaO8DRw== sig=FoDjiSWwscc8094p0SEuBLw58VABp1KdO2v7DTxJF8sFJgLBCMQwoKaJh/IWvErAs01xNO+j5xTzuA535f+KAw== e=found 87 iterations",
+ "pub=MCowBQYDK2VwAyEAlFfIiS9RuWVB2EEt89Vwxbkp0qtkxysWH59GajLVnDQ= priv=MC4CAQAwBQYDK2VwBCIEILJ7yOj2x6u8927a68u22Mn9/jt85RLzZx7aL5wLWjkV msg=snvI6PbHq7z3btrry7bYyf3+O3zlEvNnHtovnAtaORX+s2PwQjBdgbxjPaPwfSLgxFmnWk4Y5QSONrkg8nSzOQ== sig=yHkgcBJ1q/8SHJQS1mfFicAnez3hLoO9wxTwC320MQVBUbstibJ5dZWQKPQTxZc3nUKngOfljHWyQTZmhWQ7Dw== e=found 88 iterations",
+ "pub=MCowBQYDK2VwAyEAntmlfS2c/Iy1zr6sZyb0qyDK7WqUWdtsaa1I7CJe7gM= priv=MC4CAQAwBQYDK2VwBCIEIKC9jpiEaaU9gYJXUt2ZCypHSydp5iOV5U56nFeqaxAf msg=oL2OmIRppT2BgldS3ZkLKkdLJ2nmI5XlTnqcV6prEB+7hLJTfgylcRN+Ng2MBDU2IjIquzE4oRirt+Anagx9ew== sig=AlKASNgsDM3hZq+yVGgrP9Cs6ut1sqbly9q6V613jrszQxs8G0hr+uEzZlIUMmRPQsx1MeUWOwVMKjruSIqpCg== e=found 89 iterations",
+ "pub=MCowBQYDK2VwAyEAe3onup6XeBxGwdWuV15GuBBgWPMYHypWmNksVjY9T3A= priv=MC4CAQAwBQYDK2VwBCIEIIx4VqqMrh+55Tlhbz04Eu0OSSRkIVBFwuED7hCn48KE msg=eFaqjK4fueU5YW89OBLtDkkkZCFQRcLhA+4Qp+PChHChKuKYO4nuCRoyK/OgE1ixwj7du0TazPZ9vqIX/gxkxA== sig=ZV57Xncn3MBEOzPF0z5O4VNPIJe9NYz8DGjC8MFZAeCdEWPzl2RclqtHzT9wG6fxfXyk2trOYO0UGLYprAEKDA== e=found 90 iterations",
+ "pub=MCowBQYDK2VwAyEAMSHRc9b0uFPLiF7PoiOtz3nF9ONP833g/8lGRaeKsEM= priv=MC4CAQAwBQYDK2VwBCIEIISX12XJ3repK7/2EMbAzZJQXdU4tNKM9xhehI0aTUJK msg=hJfXZcnet6krv/YQxsDNklBd1Ti00oz3GF6EjRpNQko4draNLxRGDGAcxlGKY7LEJiyFaGCoPptQaKQdg5sKoQ== sig=J5+N17b5XRRe7jYPFKyfgzAJAu7xfkRoY1hMbbqdct5NgjFdgcE+vqB7ygS7OPFnhj8MemHIWEvoseEgIfL4Aw== e=found 91 iterations",
+ "pub=MCowBQYDK2VwAyEA4Qs8/gmbNddoDAJF26eotJ7vXz0eB1kY5fUNdgazKUE= priv=MC4CAQAwBQYDK2VwBCIEIHUOUwvhq7F/oqKzRoQ5/5JGwmAdqD1Nagjul/xu2Ubx msg=dQ5TC+GrsX+iorNGhDn/kkbCYB2oPU1qCO6X/G7ZRvFpN/T3drIdx9JHySmFqzxs6ozOrPIl8Z7N7z7TexoCdQ== sig=D0P0GHtEGXw2U4ufZTGQ9nw0u/3KVi6uKeEg9iZug8A4cW3IWEpaTDgsDQiIbQV1G4walipOoGwOEaYgcov7BQ== e=found 92 iterations",
+ "pub=MCowBQYDK2VwAyEAaFcWF7so4FDMjXe7rx0Sc8SJhQUiPgiP8+rZnEQqRIc= priv=MC4CAQAwBQYDK2VwBCIEIClbAlg50Y8EgrYktJUhlhagflkXEd3nQTL9sEGFKndr msg=KVsCWDnRjwSCtiS0lSGWFqB+WRcR3edBMv2wQYUqd2u3Y86Iza/ftJtSL37uc7+jxbk2an9WFUgKxr3TE0ZJ1w== sig=Lm6fLEspvqzSHUDYTGqOpkyGkH/MExrYPTaKTJFGwfc1rlgmltD/FZX/3QuDFz2RC3R+61/w4NOBt+5SXY07Cw== e=found 93 iterations",
+ "pub=MCowBQYDK2VwAyEAvPN/2oNoXurS+vDYHCbjYuPfXgbe0itAbFhEijxJeow= priv=MC4CAQAwBQYDK2VwBCIEIPOrXDYpgo4GV50wKFxBZ2gzLjjSwGoYU+OLIjrY2jDB msg=go4GV50wKFxBZ2gzLjjSwGoYU+OLIjrY2jDBghVSp/ug4Cd9SfNbTsQNlNfvv49897siFoRH0wL7kEMobwLqTQ== sig=j+FR8fXWQBoTg7udoMiaB2fYii5+0fQHGbfRN5ZdTAnBPjLOIu/60CevpLQZ3wU4xQFMMQdMR/sYKa/bGKGQAg== e=found 94 iterations",
+ "pub=MCowBQYDK2VwAyEARwQK6+aqwEQkHuqHNt4KD2YOfvzd4EDIg3MtE14qHYo= priv=MC4CAQAwBQYDK2VwBCIEIB1VShb8viJS0hvqhAXO+ApFu77HOXbJ4V+k/c1JCuRF msg=HVVKFvy+IlLSG+qEBc74CkW7vsc5dsnhX6T9zUkK5EVmsJSbifLY7dXV2dqt3IJcWmrjjzzyxvo/cxScb+/mLg== sig=+GKFVPRIFUZXl/UVEA7Ew7dJpIIktgJc47TjCz+Xn7d73e7HdYk+SzNO3CAHf1rXsn+6g6aq14xJ40+sm5YeCA== e=found 95 iterations",
+ "pub=MCowBQYDK2VwAyEAsA0JXns6Fdx3PWAPV1YMlyzuZGiTGDAdGVy0R4kfAJg= priv=MC4CAQAwBQYDK2VwBCIEINg1tiot0KrcoQz5LAWPQi8VUq40bEHOlJIZgrNL1Bf2 msg=2DW2Ki3QqtyhDPksBY9CLxVSrjRsQc6UkhmCs0vUF/Zu03kar5GVOIPS9hcPPiMPalsG94tTfOcd6K489mSgWQ== sig=5DISt2qCS/TEyxsrBNEcmT0WmftDgXLU3fGZGliQ13qkdcbGfbBBgn5ZynWYjkZs+vWgY/aUFJqR1xdrT/jmDg== e=found 96 iterations",
+ "pub=MCowBQYDK2VwAyEAyXjgbLtOOWNQTI2yHWwu6wraCx7+SpA+l+MorxAuyC4= priv=MC4CAQAwBQYDK2VwBCIEIJQCZBRpNVYNKJT2RglfyiZBHqgQNT7p643mWANtMs93 msg=lAJkFGk1Vg0olPZGCV/KJkEeqBA1PunrjeZYA20yz3fjvqNAj4OYV5woBHgFBoBzBMYNMrQFXi15k7pnan5nQQ== sig=2rVSgYmxPpK5rxcfOJ9KQ8vwzampF6wLOi3bLpeBuWZkrM3c3/00WhgLzxkKT293YP9M9vQWJ7PAaHw0kujmBA== e=found 97 iterations",
+ "pub=MCowBQYDK2VwAyEAln54NhyJ/X/2jquXbp76ah/LB6oDIDr4Kd2WuzG67Hw= priv=MC4CAQAwBQYDK2VwBCIEIPM6tBV/BMq/nT0sGnR1UdDKFHYAEcsWbzbOT7qGHsM+ msg=8zq0FX8Eyr+dPSwadHVR0MoUdgARyxZvNs5PuoYewz7cZ1HatzjU17kcntHRNKlYBD4S4oYNemfMlI6F6ph2iA== sig=KIoQvdBfc9mxQ0/v4voWTAexNlAUyd/oUqMZWWHIIS/tCMO4n/+d7vkKbseaCKjIjlDSNDLTDkiGlTvlXC+nAQ== e=found 98 iterations",
+ "pub=MCowBQYDK2VwAyEAS6N91+jeeXJEbYbxEBlxjvrFy9hoJzyPWytHVP/CUno= priv=MC4CAQAwBQYDK2VwBCIEIOnlWtKs7cO6oDUYZdDRupL+rcoDOrnGBNF4DahV3pb2 msg=6eVa0qztw7qgNRhl0NG6kv6tygM6ucYE0XgNqFXelvYg8JqZNeSllXXMjUnmDLs3kZ49fXJuEtwju+fN2bV/LA== sig=OLNQWDDTXk6Y20N4L0ExI4tVAghBdEMtMDh61O6s8qo38gBqN6Z9+z9fB7pT75qJ3TS/cr2gpkgsMJCN408ADQ== e=found 99 iterations",
+ "pub=MCowBQYDK2VwAyEAep3fxNQ3AZVdrzzQQh2r6Q6HG72z04tRbF4Y3MaVfpk= priv=MC4CAQAwBQYDK2VwBCIEIAO05+oHAN0iDVfxh6PrV23NHSAG39ic3oI6j7q2zVU2 msg=A7Tn6gcA3SINV/GHo+tXbc0dIAbf2JzegjqPurbNVTZnffJIGIVWmda1asLPawPKBm6d7wom9x1aTvC75D1zqw== sig=OwfEYNcZkywink/oki2yQdSStICDGNGDMzBkiwzMT48JZdfFAAJv1MpE2PAltUQ7AKR6d8ayNAnaB+j2fcehAA== e=found 100 iterations",
+ "pub=MCowBQYDK2VwAyEAtmWPpI2qjU8+cuDxey/OeGxfI0HI8YKpTCNph83eQbM= priv=MC4CAQAwBQYDK2VwBCIEILNmVpfQEeXqAgU3AT/wzVfZKLch2JCKQVo1twgU7Vcx msg=l9AR5eoCBTcBP/DNV9kotyHYkIpBWjW3CBTtVzE8BX9m6gpvPXySqSXM+2EZSOHdWrqOuAjFl3f9/D5SV51Y3w== sig=Xcvf0aMYrUHrFl++l0AIF4gTFL3+CAAw6JdS2VgGz7kvmgFtI8kY9h0PZ134Zu+8nNVCvDxW/8nBRdFGPlJoCQ== e=found 101 iterations",
+ "pub=MCowBQYDK2VwAyEAxB4rpEdE6bQs2h2EWS5czrD7/EOiLjphE08wOAKyr+g= priv=MC4CAQAwBQYDK2VwBCIEIJ3civsLgKDYpvKpfXq/VjIlqV84wyWMPQPoG/Z2bPUd msg=ndyK+wuAoNim8ql9er9WMiWpXzjDJYw9A+gb9nZs9R197YzifOxRBzP2IDK6iEV8GH0Zc00L+TSum1AyL/HIuw== sig=PQFAHZE8iojkwYYpdditN/P40LRB+6JRB5aMWaXS2ZBl8giA/WaN7z+QmvusGZzspIPqcU3IYxLkpxqiC+1GBw== e=found 102 iterations",
+ "pub=MCowBQYDK2VwAyEADb2Wja4KaAI9S3FDjyz27HMJmRiXFM5bW8Um80DuVzs= priv=MC4CAQAwBQYDK2VwBCIEILOzZ+v4C9bwHglFkhU8BpQTwPi7gXgptY+BRBf1mFso msg=s7Nn6/gL1vAeCUWSFTwGlBPA+LuBeCm1j4FEF/WYWyjP5l49E+h39fGv22Us0XQq3ZzCi5PXuHHWE7aqzCalyQ== sig=gw+6zaHeASQU1vzZzAMDo0WBWRDKwvYir+Epb3CHCzjCptBbRbkyTezKV04zgjCC8v6pnTW+PV/JswFnEyahBw== e=found 103 iterations",
+ "pub=MCowBQYDK2VwAyEAY+kkohAG8v6XX/g5ehc3qm6uAe2wiPp2JD667ZTUwZs= priv=MC4CAQAwBQYDK2VwBCIEINGNGzJsI60cXv4kQAXN9lPtkrCAuIOf75woW7D0JOL+ msg=0Y0bMmwjrRxe/iRABc32U+2SsIC4g5/vnChbsPQk4v4Pc8sVc0KgHGRXTam3wqe2+z89MWV3CwrFlI1WgFepRQ== sig=8oO1Dk3MEb7ci90HGiLr9IIH3I2r3ot706oDagqFB9WMjXiz8/VOrk671sEsAmkEqx9Wi6BR+TToNfrVwaVGDw== e=found 104 iterations",
+ "pub=MCowBQYDK2VwAyEAV+eerrwAURGpcHcK0JeGobQoqRoNFwG3iyMszmcpr9s= priv=MC4CAQAwBQYDK2VwBCIEIF+GlnmbaoCNTb9Dp0bB1oThaqV9wLsK7ZZX/WH7Su8+ msg=X4aWeZtqgI1Nv0OnRsHWhOFqpX3Auwrtllf9YftK7z6LF7MaQ/zv/YrcFHLgNh+tO8pNZNdxTaGHJqF4pQi29A== sig=lvsqZuf9cjMwTfU3UTWpm4F+vdGQfRpB2Vr8821in7KCya+SU9L7O28etc7K6jAehVh1WhwM89bkI4KhQBOxAA== e=found 105 iterations",
+ "pub=MCowBQYDK2VwAyEACVSLzN/JMMBQKViu1fIlHn2OcvUdHLMrIxVYRcik2wY= priv=MC4CAQAwBQYDK2VwBCIEIPGVBkBRaQ5VRcjtx9GYH1QvA6ByaLj8l/OdLmQwN4f4 msg=8ZUGQFFpDlVFyO3H0ZgfVC8DoHJouPyX850uZDA3h/iMs107I9zrBTcO84NbjmV2B4pyrgbM0xQDjYrulY2xMg== sig=9KLcuiDjbHlLiTSpHLUux+xeRyUHcwx7xmLjbdoPr/3KloJDSVcJyS/AFxijLi/oCGiCk0d+IGNSsjBgYWahCg== e=found 106 iterations",
+ "pub=MCowBQYDK2VwAyEAjvV5DVaAbsrgVhzuIG2U3kRsGwZKX6PHjZpw/kBSNbg= priv=MC4CAQAwBQYDK2VwBCIEIAysY9jJSOqH6zsbLOoZhmm4dgoW8F+WaD0tjiPaiWHh msg=2MlI6ofrOxss6hmGabh2ChbwX5ZoPS2OI9qJYeGbELTDkeTTuBIxJkgMmto8J4ZZj1COP1fl42RuDoD1KErE/Q== sig=C7hZ34BoCJM5URpDRyN6sAJubjX6KGj2SPhdcSzHK+fgQViJLuUqn1JXmP3XpHYH/Po3O1CluRT4ywIjVh3DCQ== e=found 107 iterations",
+ "pub=MCowBQYDK2VwAyEAVOUySxyz79hRissjZEL+quwGOxc+AdwFas7VrRgsgSc= priv=MC4CAQAwBQYDK2VwBCIEIKxd3M5fRFsBy3Fz1cOuUV799FcJ/UvCkGY6KjdhK+0n msg=XdzOX0RbActxc9XDrlFe/fRXCf1LwpBmOio3YSvtJ5MaW3Lb+tdIdsynqxMne1zOt6B+kZIISyidVbf60bMFeg== sig=YmZA7rBj45Zli4gmwHsEa20sEhwSWXrKomj1juUhGfNujwyRxnYKoSt4QjNvlvl5AVInnhXQl0dA7hkPm9JIBQ== e=found 108 iterations",
+ "pub=MCowBQYDK2VwAyEAZlIDdXJgAnnhHVoNMQWO+OE+VcMAlQHhlQ+x8Hi/7uk= priv=MC4CAQAwBQYDK2VwBCIEIL4S80IGx2KYQQE1zxQj06ZYpCp2LDr5U3ZzuSrLpSXZ msg=KnYsOvlTdnO5KsulJdmDAYwRIWvfaIlUWSSFTSm2MAdqK5rcTcs5ACqRp8lZVlB2FZYBoOJ8yfNvzvqQLKgo9A== sig=Akz2lxK2ijLs+y30Qsf0Q6DfQuvlXAQ64zqjcpBZEsHclHzi0AdsNZw4GXaYqwSoCrPVzQVl+0Ni/mUaXmjSCA== e=found 109 iterations",
+ "pub=MCowBQYDK2VwAyEA50i4BEW6p4B1yBk0iCrFGUM0YRzz1A7zbw4v25dhg5M= priv=MC4CAQAwBQYDK2VwBCIEIEa77POdeLW7Yu5ob0jgT9jgrKS9JSxysD9FSAEhlcO7 msg=4E/Y4KykvSUscrA/RUgBIZXDuzm6v+E6kdQxEC0ip+Ka0CE1Z0A11Y+gv57xvMdb4eW0Iz3ggJtY8nfVO353SA== sig=It7Wf+Av1hSsJXU4X9cy2lJs5Hd8xblaAIxkETy8y2AEPoCnkwBF//GtB2HZH1AFzO61OadpkiiZPYrwKhm0Cg== e=found 110 iterations",
+ "pub=MCowBQYDK2VwAyEANkftEt72NPdPk87PrASjacXTl6PavTzAwx+JnyZKRJ4= priv=MC4CAQAwBQYDK2VwBCIEINgCmCrO9vmG172MlaQL14QlI0h7rOhTrAJ/bIL59Bn2 msg=laQL14QlI0h7rOhTrAJ/bIL59Bn2LlnYtukvEZDmGNPGCwbOjNrxSz5xh8R4ktueccMEdqLsymc7VqrhfRFL1Q== sig=ekz8oTUmcj8E/7JkKmz3jGPn4A/Vzo6IXs1Br8a40f81PezLt4fg4AET8yKnflXPLnIxsvWMFf75kcS/MZQ9BQ== e=found 111 iterations",
+ "pub=MCowBQYDK2VwAyEA/4riYc3bZpCPbqWr/xhgHMI+qLvApmqe5oxKC8HAcps= priv=MC4CAQAwBQYDK2VwBCIEIBlCc9I42RFdUSpapkLcZRXZmS3IQkbjs0eD4TIwofO+ msg=LchCRuOzR4PhMjCh8755nw/BOYJpgXD0ylEIsBZZ62eq+tgCglyZYIpN/94ClwRS/9xi3A5NYNPNz5/mj/TKNg== sig=/Ybq0ft2t16ji2KqGfEnE6nDP71VToLc9X7V2HHnq0CVW+hcJPM7TSmsTPFu7N96jCwajpZnyK+69JaKcOhVCg== e=found 112 iterations",
+ "pub=MCowBQYDK2VwAyEAF4l0xsXs4JpegvWBwtYSvMAW8cxQ6wtoVHKj/ljLk3A= priv=MC4CAQAwBQYDK2VwBCIEICKG9KtMFNm+NY01HdZo9vfocfFG8z6+ZIbVWIDGRr7E msg=hvSrTBTZvjWNNR3WaPb36HHxRvM+vmSG1ViAxka+xDHPNQm/wQmlAw0Tm4W5baDGnRVWshIoFi9lIYISeU6hDg== sig=xk3MjjaQ8aWi+pYS7iztra/l/Jie1/FrCXMP5J4FtQ3Zplm0BNJ8xxOK3GbsajAWIrtJT39r/N+IQUh+ZJRsBQ== e=found 113 iterations",
+ "pub=MCowBQYDK2VwAyEAkzgho5/z+HviQDIY9bkPHqyXMQCiXRrIiQCgXRkwqzw= priv=MC4CAQAwBQYDK2VwBCIEIOlUfDbMqvNWdgLVt7XbebmEeAUpE0iaBTNiwdaqIkF5 msg=fDbMqvNWdgLVt7XbebmEeAUpE0iaBTNiwdaqIkF5jlsgNDGyTJmnvIELx0AitTL/hcFhNVwVY/vnstmHvfYkew== sig=TziR8PAa2Xnuk6XixgTSX2arI/9Tq3wt1rjc+5hUI/iVtAkQHRCpv6CYZlICBMuT6kgh8gaPIvHgjP6yPW5HBA== e=found 114 iterations",
+ "pub=MCowBQYDK2VwAyEApI1F6sU7qwmXHxGL7dtf9tu1XyzAzwi3ssF37Jf0dSM= priv=MC4CAQAwBQYDK2VwBCIEIIw6ZKX5nzKL5PZv1q6cTsfa7eV/yP/CLCmyxIklP/wd msg=1q6cTsfa7eV/yP/CLCmyxIklP/wdT1sYiSq89jwR3b0hxERp6yU/itMNA7rC78lZjgQ9jOaZcoWiWkJE+5k5AQ== sig=DD17y3VKQVgikhAPgFWMZC7Hyx/tKg069CvoRYfXOfdR23Vq236SH6A2JcJPuXD0eNnKWVLit0J6HPh5eFgGBw== e=found 115 iterations",
+ "pub=MCowBQYDK2VwAyEAjlAWDsH7LRj0ZAUIVliBHNtrsOtTzA3vcvvaYpf2d+I= priv=MC4CAQAwBQYDK2VwBCIEIEc2T1fCXGz6QwLmlxyUzobRp0ScJTBIvn9nyV/dnsua msg=eXtSnxApDQM4oGuHDCKDnWHClGqMYRdM47wRgdiagdeHuIGmgqTCs2HbGJ9iQ3xzDKz0bA28/ZUKuECC3v7VIQ== sig=J1aBRj5B+Vkd3Fns7HjKvLiROS6Pykf1NXogsGfzqYEG55wrsq84J9WTNxPrAI67XHl3V0XQJhrcaQ6vTVYIAA== e=found 116 iterations",
+ "pub=MCowBQYDK2VwAyEAx/J338CWREzgr3VDj+SYEoRkufWma184TOstM64JIvw= priv=MC4CAQAwBQYDK2VwBCIEIOwyhIb6cQvGuXavoAP2bNZIMrkDGJqpkz/rwLkwqYE5 msg=k5jbL+4bGuCPkwlCPujRhoAMsLTVgDXLBR82linwu81mMkF//K7mjshaBUf/6RjwM1ahvsMeUrqYsA9N8ExVBg== sig=7eWOr0C48A0FSRz6ERZGV8BoAV77aIH0vLErlozjehYaOqzB2xBN343ak337DncVCQFmj1O+zOXc+oE5kH1AAw== e=found 117 iterations",
+ "pub=MCowBQYDK2VwAyEAsV3ow8DVlcbtSwNq02ifJ95G4MdPUJ7r1FmAbhTeX9o= priv=MC4CAQAwBQYDK2VwBCIEIEDOhJN72N9SVZZEvhDoRNif1ggDElqVYpusx+rA+Twc msg=vX1KKcCsAHuzAyNwmLQbj1hHdu0xYvraHvhhUtLdwLjYriq8oGpktEsXe0R6Urrba4/dgoiJrg3ZswQ811Q6vg== sig=zsaQwF1jX0g+1zqOE2UqKFGIalFWTITFycgcSPy0RrJkSwrtheMTxbKAQ0LzDTkJihqLBfCXu0wfO1Je+ixeBg== e=found 118 iterations",
+ "pub=MCowBQYDK2VwAyEA7dZmMFlNTWPWPZgCgWX+GMEIwweha45WyeuaJEScQEY= priv=MC4CAQAwBQYDK2VwBCIEIFJXyspLbXKewnvs3oEa9c62lm+8n9Dmtx4KxQ+Ohnfz msg=2U0jfWaZXC71/PiaxinTygfhDkjwCnVIcFfwiTnfm317zs+awCOx/0wvlH3AEJHOl+fwTLaOd3DupZ2LiIQ7/A== sig=rxa1s40iO/DgWBYElFPWzOT1/vRWKu92h7a9LlOthgAlPBoeOdZKJCI6uIJegVlW0vgkCcHXf4rRc7VomPuvDw== e=found 119 iterations",
+ "pub=MCowBQYDK2VwAyEAcKGYlao5G64KfCrn0rxhttE0nbyj9bmXNNHIpmt8Fgw= priv=MC4CAQAwBQYDK2VwBCIEIE6pRyNDgBX1xzVpC5QXW8I8Y+AQHBx31V1TieBCwZ0q msg=cD4WTqlHI0OAFfXHNWkLlBdbwjxj4BAcHHfVXVOJ4ELBnSpWhuYSQwkKA3QTldz8H8IVK2J0k0qtv8JDBa2sjg== sig=gyd+gBQhXu57ixVnwzgt7Ar4rC51pduSmd6EdLLZgPBN/zXwxsLY92KjALsXoiy5I2BKNHbKaLaA7E7eWz5hCQ== e=found 120 iterations",
+ "pub=MCowBQYDK2VwAyEAiOHKTeVVFdSn1Cb5GaOujy/ZiKKK5JTx1rOoyH2hZS4= priv=MC4CAQAwBQYDK2VwBCIEIPr6hfTbh24/qN2LTEBmsoO+O7LXSGOEnhccKGkQ9xao msg=HAZszQIBEZX3T956a6X2qPnpL18/UrgMqG36+oX024duP6jdi0xAZrKDvjuy10hjhJ4XHChpEPcWqLr3EgEh3Q== sig=XK/tnbhmjUuP2zShxHthiNTDdMpnxZDBVV3DCSoth8CoFJpm9j7l1m8RP2DkNBOk7N3C1eQuYX7Xtmg5Dqv7Dg== e=found 121 iterations",
+ "pub=MCowBQYDK2VwAyEA2fYktkj1ov74JQ3ziXQGIEBu69ZyNK9HJXcwOjORB4I= priv=MC4CAQAwBQYDK2VwBCIEIAXENRxhQHqF2NsgH+Yo2M4j2gz7T6CE8Ti5gc4lwGmz msg=s36EjclDkM5ovsjWHnTbQgpRzBcOToob27OFXDMvthJ/Wkiuujtl9lBpQ6BS+LcHAN8A+1Tdg2cAEM4kf78FVA== sig=5HL+dmVc4FnY5fxYQYh1G3EQ6mDvVmnTvO+0VrAGKT0IbpO1rzfE6s59tRIOlwegK1two489j5luttd2kpw2Ag== e=found 122 iterations",
+ "pub=MCowBQYDK2VwAyEAxgIbd+1KO+EwLcNYV0viNHISlJ/yMr6ejj9o6bZZaQg= priv=MC4CAQAwBQYDK2VwBCIEIIcxnu/B3ye5/U+gErU8IEiNJ6hKwrZyIXHAxl+IetKa msg=iHrSmjW3+YWb0eieg2VzaEwvLYfQ74WpmNx/9zzojVyyDEmzxba1RvJELvN1g1tiGRS04X7tMR3V2zC7JL+O4w== sig=NC5YeGcd9z/2A82B1c8a+8/gzFURMBr/5wDhFWgFy+dAOE9o+9JplsxTKgEtYkB20na0X89fyiuU0i7/TSo5Bw== e=found 123 iterations",
+ "pub=MCowBQYDK2VwAyEAn328lpY3CdJ7a83KonTKMTHTaUZOoVVow2eDGvLQXU8= priv=MC4CAQAwBQYDK2VwBCIEIHvvqFTxw/O9Y81plNuGexhSqOUCAJX4wKy5G/RSYE6S msg=QTALCo3mn6sfHr1J2wA6E+KSSBY0jgnO96RGVWsbAPmge++oVPHD871jzWmU24Z7GFKo5QIAlfjArLkb9FJgTg== sig=GyNNRaiV6jBM/Un1moAf6+9HoG1doryo8EH9ozNAoIIKhzOzBcXL8K1Yyxw1ikzjhB/cthvad5nIqCnFy/s/Ag== e=found 124 iterations",
+ "pub=MCowBQYDK2VwAyEAODcrDW4/Tiw57u4yH0GaqlbMP/CNb5xYJBtWSPUlkhY= priv=MC4CAQAwBQYDK2VwBCIEIBWmfL19HXVaNb/V9YjvUD4HlTXbAOGJymU43nYSzYbC msg=xNF0lcWH0tr2cZmfb86bqLDM4sFtpf/j6DIOCZw+rPR0vXBz3opqS9QqBoZrqxu/HnINC3vMzbBcfVeA1fJapA== sig=CWdE2P+RAySVsX5RBZRFMdPMVzW6Ll2OqMMrbxY1uAbXPBrPhmCTKzyXpkMQYse8p6PQL8Q8Nisk9rpRG9JcAQ== e=found 125 iterations",
+ "pub=MCowBQYDK2VwAyEAeMRPfeY1/Ej07VytXhsMqcknQhs1D4ybys8KoGdEcl8= priv=MC4CAQAwBQYDK2VwBCIEIAeBzvUPjV8+3MvxZy6vb9+fCBnLp1OKntl4jx6/M4iY msg=zC2R+O/dtgeBzvUPjV8+3MvxZy6vb9+fCBnLp1OKntl4jx6/M4iYj/zoYHQFKjVp1BhJc2ilT61DqWc67lf2+Q== sig=ZwHxu+72a0T2XCU6ofoZYytanTGxubKpzE7Nv9sdZHmJr866/Mp3z9NT53XbdokbyR7aoKWwUk+MxQPD7BGUDA== e=found 126 iterations",
+ "pub=MCowBQYDK2VwAyEAmIMQFNgNIqtEFnAL7UUKNaVkR4pq/U1oqd5hGru+A4E= priv=MC4CAQAwBQYDK2VwBCIEIEjc4Yp+7SviDjcpVR6F5uRGECy5PD9LIQO51zhba696 msg=NylVHoXm5EYQLLk8P0shA7nXOFtrr3pbRCAQOXYem+Reei9u7svzNxid0mYSww21HFI61av2xcnLVtAj74vCQA== sig=qWIwPgXSyQC4gvQ3EA59Kc2lolXXX/CJQ3m05SqhXUVCVxMR/QZbHuSEOJdNS6sOVAU6HhQxCsOKlJn17EHOAQ== e=found 127 iterations",
+ "pub=MCowBQYDK2VwAyEAYdHTU+z+QY9yPjN+5AL1GQueMSCy1rx3M1d806OLX30= priv=MC4CAQAwBQYDK2VwBCIEIDrZHcmldayL2KAfqJbBoNH5bUiU2V/LQZac6W/q8LKu msg=bjfcDqqNdm3usjrZHcmldayL2KAfqJbBoNH5bUiU2V/LQZac6W/q8LKu27+Lp9HyICeAqccrC8CwhFWgmJcEYA== sig=OCPtS11eq67EU+Y2ZicrzgqTovsqq5Lb5uG7Tk7mpAQbAxyb02Cm8vFIJ4cnSfMdC0PsgdhPORgf9irGdS7/AQ== e=found 128 iterations",
+ "pub=MCowBQYDK2VwAyEAUyRbp4YiA0rm50jzBL33lwnOjARoaHdEXNn40NK0P/o= priv=MC4CAQAwBQYDK2VwBCIEIHyDIlRjqb+Sb6qLHx2L3Hy5suUruXKJ+tNB4gnnZBTB msg=fIMiVGOpv5JvqosfHYvcfLmy5Su5con600HiCedkFMF37opZtphHd9PZKZD8BKu8dBoCxA5QvuASqYFeAI1heg== sig=uGHxzBRY5tN2as7RjVjRQEq1iEs0wB7Vqhb4hdj40T065HA2rh6ce2atRq5pUi1cMXEmVkIszxozWcMfHUIsCQ== e=found 129 iterations",
+ "pub=MCowBQYDK2VwAyEANKGfP0zeLPFc6hEt1VvkjxTJchfDMXRzU2YKz3P4zBg= priv=MC4CAQAwBQYDK2VwBCIEIAepORePNseu2WAOKT27U51DbmCfCNm/uUAOAvPUHcjv msg=ovhoXmGlzVfukw0cFSDcFjyyH3wusPP63+MHqTkXjzbHrtlgDik9u1OdQ25gnwjZv7lADgLz1B3I7wSr9+aY6Q== sig=XSeK/GK7VjgXQaEAJZMQxhLho/Vk6GrqhNzjlNGRoA3n90TESPaB7jgETupaMPc/7tW3ajHMes0brN/gowmkAg== e=found 130 iterations",
+ "pub=MCowBQYDK2VwAyEAEQzJXljPO6he8KgNb3GstmtJf2KAt5rvSS/pg8s/+18= priv=MC4CAQAwBQYDK2VwBCIEIDauwah1wGBxy4j86YjZa69dfNrzpAy1tH4xFx3PszT4 msg=wGBxy4j86YjZa69dfNrzpAy1tH4xFx3PszT4w7BFTMFYjJ9js0kgcNW8txOfCHatw9dtMNKHpxwUqkLI45l+iA== sig=HnIqSJ8Kec5S9ByX4VJfpeDJpToLJ6Q4kHns/2ClxL6gG7eN6wyXueIgMIIcEKccToIsJNTcbJ+qkSyEk+0VBQ== e=found 131 iterations",
+ "pub=MCowBQYDK2VwAyEALusS6fp6G/FtPYCNWOTFq1ISq8V3TA0DSmN5ju6a2+w= priv=MC4CAQAwBQYDK2VwBCIEIHB/Hep4WznYrotW1sfMtxR+uOGbP15iJ3NchMKlxRT2 msg=w/D0I957dumGHAI4tvnK4HPDn60VcH8d6nhbOdiui1bWx8y3FH644Zs/XmInc1yEwqXFFPZ0C7b4faU3iXLzmw== sig=8IDG4SVEnUOEWGA5mwEBJKFapSbplFOSgpCzONUVsQr/XicA1pIxVZJhd9dB8m1g2qKHBBI3xBICbff7Ja/XBA== e=found 132 iterations",
+ "pub=MCowBQYDK2VwAyEAxfj1xPSyPSoQ0snOT1ez6MpkaD06hzSFubwh4H46Kz8= priv=MC4CAQAwBQYDK2VwBCIEIJz7YoGp7tZssgpFv4KVWgCoN2QNjjZMQiz3oHQfXfXU msg=wXiQXg+Ul950ZJPaMWBHz9TenPtiganu1myyCkW/gpVaAKg3ZA2ONkxCLPegdB9d9dTbNJRHD0FccCMylNgtLQ== sig=2FHnSc+maLipWVXC8THY8D3WAbYAdnJa/ZDe9Z0uoqscna7g/1MaC8hOYgbngB9NcsPhELKnh7MfahboI2ZtCQ== e=found 133 iterations",
+ "pub=MCowBQYDK2VwAyEAN3sM/Rxz1hYmLZL76OsjkTn6xZw3Y2imuoIWfxONklo= priv=MC4CAQAwBQYDK2VwBCIEIGy19HsQGbzOdOqudIr42F7VQyPcSdJseqhdWZUJUsLE msg=x02f55Gj0W2wffYS6eqhS4ft2wZ+1Ps+Nz89SkhZK95vXF+wWOD7aa67J5rxvTPnRKT9L4IWi4GH2mviIjNfag== sig=6wjgs9WuiPEKBYL6AUoP5c6z1m8iyMH/5gXeCwjYyXy9WJvLIlWaDno+cax1aUPNZbz+pt1G/G4MeYOJBP5YBQ== e=found 134 iterations",
+ "pub=MCowBQYDK2VwAyEASNbA63RlnLdSyuyBF+WFNohFKJ9+F4wi/FY4l9JcVKw= priv=MC4CAQAwBQYDK2VwBCIEIBxK5DAmCzNQ7Iy1GhiyCqgPE7swenOzB5iu7vsQ5YvA msg=SdlbWypKKps5ujzrT4Ioaj1O5KKHWDgv/RNSDP1MMdlGuxCxwidgH8hqkv3D541+SD7NUbF38hBaHWKwEi4xTA== sig=F6o/H61xcySsNdqmF3r+p+HF0E/vajX7Rk377h0Qr09fQeOlqPLNf6KPy7akyyvdplM37QyI8IEJIBbjtQkYCA== e=found 136 iterations",
+ "pub=MCowBQYDK2VwAyEAtK2N4hAzgo8jxf70zrdyhXjBNIDmQrQveJTceGOuawY= priv=MC4CAQAwBQYDK2VwBCIEIJlsnKHDv4soVPN5eKAzD8HjsUvkZBo7G6rLraONtxgO msg=eXigMw/B47FL5GQaOxuqy62jjbcYDkNI9YvOPNlpxiTM4zPw7CrKpunaVdCx9to7mMmJUNFUhdYclMbTTB9qVg== sig=5acadnBTsnNcpS8qE/OAORmo6ww5PMa7puoaC4a39TcAIKx04Mz1hJLDAzK3Yt4l4080ZE5ivIKyQ5BY+tesAA== e=found last=7 s=0 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAA0KPeFKAEZc5+A6xLb7/06poKa9xhKKXpabhhSxh7zo= priv=MC4CAQAwBQYDK2VwBCIEID5GgFmIxxd8E30MYAAAqhto5RY9QQpvOmZINZcTUsJ2 msg=PkaAWYjHF3wTfQxgAACqG2jlFj1BCm86Zkg1lxNSwnZGIwnDSSdBpU6qWcefuwNGgKpOHtHO6Smviq7hnpzXiQ== sig=7sx8YX78+QYt9eXmP0XRcOkrlHLa0FkveOOBwdMll0mcgcJEIu8sMuRZa4BcJsfvLmaSdLQ2BkZPLTPP2/Z4Bg== e=found last=8 s=0 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmnIcJ/4T5M/31gQnujbv5h/T4ccJOW9YSJwUBYw7ses= priv=MC4CAQAwBQYDK2VwBCIEICsx3yGMG5FHTtNynjHRd4D6PvunCas3DU39ZxjPupnd msg=KzHfIYwbkUdO03KeMdF3gPo++6cJqzcNTf1nGM+6md0UiT8yZeWQQLtF70i8CU99Ty2NgAemjkIYgDzdi5Wm6Q== sig=y0HnMN953kniqWlt1yLE6eJG3YuKCRPCQmYD/uuXkGieJoSLmfkrUn+o9bPCJKAftKbWbj0B+MC06CqICXBsAA== e=found last=8 s=1 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAuxOmF36g51Vn21r7uWj8Eg7j79UhHmaZ2EhkJ3GFYds= priv=MC4CAQAwBQYDK2VwBCIEIJkQm0JsPdi4V3NJ+uxYAPi6IBnvxnfBMAGNy8ofxreV msg=mRCbQmw92LhXc0n67FgA+LogGe/Gd8EwAY3Lyh/Gt5XvUX/5+BDScGWCHGfgp2pHNLmWi92CIBJ9YABT26j1xg== sig=3cndiSbcEmKDPfC/8ExTtmbZfwPp8OlzeL9zqhlUP59++HkvxabP0lnsI41r5mve2Dlpbl8D4kOw1OmkPwOyCA== e=found last=8 s=2 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAZf0og+I/2mW153yMsTAsX/I8qATJsbYgL3uCIp/EiDI= priv=MC4CAQAwBQYDK2VwBCIEIKc3ng3JGh9fSnc97IthMq69vrYaDjzAa1wDlf5lSKBm msg=pzeeDckaH19Kdz3si2Eyrr2+thoOPMBrXAOV/mVIoGZX9zRYHmYvYB2TdK6EbZlEt3MWRe4ij1Ly+5XsJR5CzA== sig=S30dCRLlVJIJl2YLDOJ1gu5i2sErbS0ufQ/18l9SwLnO1V7cTjHO0z7+rxlS2sn2YVtRReRk2/N33fmYy9cNAQ== e=found last=8 s=3 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhDv5qOwezFXaBQQ0dn/UoHaKsQWQ1FArc4Gv7hdyE8A= priv=MC4CAQAwBQYDK2VwBCIEIGfv99hGFwhBJ7XaFOJGzINufKOcSQvLqYjd1LLYjeCH msg=Z+/32EYXCEEntdoU4kbMg258o5xJC8upiN3UstiN4Icu20Bcw0EJ3VAxUx8dkp1dW84+HgKjLKWlJWIfi90uLw== sig=PAoMCOC5QaSwIwYUJ+cLJbRZIh7nF5D6Q5f1LRJ0QtqhBs8uanPU1XF3ueevYQGIq7imZafTzylSzuonEpy5Ag== e=found last=8 s=4 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhn0RQrj2+s3kdX/Wjop/hJA+e+rGB+WAqiA7HiCIp9k= priv=MC4CAQAwBQYDK2VwBCIEIJJ+gl9Z6QoYG8BjDe0YQWFNnUnVpjQ6+8ftbl/YBxxE msg=kn6CX1npChgbwGMN7RhBYU2dSdWmNDr7x+1uX9gHHEQ/1aU9jUBPOSoInnYaj8uOwB5dQsm4IUENw9VTcGMaqQ== sig=XtnSZFQI4EfWsz+HzmoOUda2lgXy2kiayo8uI7x6Ry+nF+SQOk72+I44hLvkzoxDLXhpuUWSTvAJ0c/JkNOHCw== e=found last=8 s=5 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/xPic7Gv+VybpXpXcDvnLY8O1GURIS+XYCNI+ZcHEgs= priv=MC4CAQAwBQYDK2VwBCIEIDEv8hQTnEzM9jDBe/mKfTUpa83oBRyYjHXjJEYLXIY7 msg=MS/yFBOcTMz2MMF7+Yp9NSlrzegFHJiMdeMkRgtchjt3YFbSfSFGFgwPt6/8IMeRci1VklvlqwouDk9UQGCL4Q== sig=XOfZWpLcy/j5W4kd1fTjyDww4oZo+Ma/H+Ev313I+a0gH8iX0cNclElGZkyGgcArgNczVR57+FS1t6Fh+MY3AQ== e=found last=8 s=6 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAGYtOEebYKoq40cwB7mQ25w+hmRojT9v/3OzuS4ByWwM= priv=MC4CAQAwBQYDK2VwBCIEIKxEm8cUl/ymjrRiHW8TLDkUnZFy1OLhnjWniQ+sEvoe msg=rESbxxSX/KaOtGIdbxMsORSdkXLU4uGeNaeJD6wS+h5WHuD5Ho/2zH9NkWfpRaLEnn7SRFvKZSD1U6+Nfnyjew== sig=2e0GLWlKwrI8l6qRvrlUQ2awsfftHGO0WwwyxMK0dWU1MG8NfPIZ64qs8T3GR4kxFJiXWsjH4DnMpgC1DOMeCg== e=found last=8 s=7 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA9M2wf7buDQGPqLWIDX596fvR+hvbWOU9NUTd/WsAXig= priv=MC4CAQAwBQYDK2VwBCIEIDbjwhJmzMto0RDL75xJChRXE1QIj2/q7xbIr9HmrHak msg=zMto0RDL75xJChRXE1QIj2/q7xbIr9HmrHakMsRzr9P/p5iH3pV3XndY2cecDcvpxRcnGa/36zm1Q4Vc2fjyLA== sig=ozhXIpDtjoWMb3y3gXpMF3EoO0brOkNFqlh39UvXGKh6DGCsEZkP0laoOa9CmSNsudW7AWHFpuDGb6h9TD+BCg== e=found last=8 s=8 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAnQlX1byz9yXLVplcKH3Q5BVWiEr3/ciL4UTJMh05vME= priv=MC4CAQAwBQYDK2VwBCIEII0XSb2W/olx0iwraXP6BIHxSpJ6ppd6zAb3pxbo7Vcw msg=iXHSLCtpc/oEgfFKknqml3rMBvenFujtVzDd0l80J1BRzbc+g3sAClERq1i9W6Lf6p5Q4EKXrhHo4jDpdO1t/g== sig=D32gwLV4Ct9RTKHshmhyOdAqUq980il27KJiIVpEIbzCCN4Tu/Ot14CmqD3DrMWhySCE92mE/OEM/JEIim97Aw== e=found last=8 s=9 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3lj7c1xVRL9GifpF0vbVzJhA2W8DM6llkQ5pQm37ICU= priv=MC4CAQAwBQYDK2VwBCIEIJ+CGWFDgWBD8aHfwm4G3j3S3oc7cOoloSA92c4y0m93 msg=2c4y0m93SRjJAxs/lcmXCFEh+lA8iBT6cwMOPCM9aom7Lj4g4wfaK/EJzl3ihLZUCsfTGb2FVqN7HKI7QjpzTA== sig=Y1oBzCgNMgOWCDCJCtofjPdG+MJlxiovz3dewzZlEyD8CgU3Veg4PjnZf0/XTyqqbtyjZpe6H4xe2LPuNFRzDw== e=found last=8 s=10 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA7e+dmJxL+hA8MSGvJmWeXY5QO36yH48Ej3D1qXAB9hE= priv=MC4CAQAwBQYDK2VwBCIEIGTSzmUPggVaGDOeBRYH+HUAxmUCd7oNOf6EZIQIArqX msg=ZIQIArqXIWigmeFdfQlOczuahBjTmQpZlCRflabFX8a/5SkXuQsr2j0RneE+gJsfQwmlR03ypvA8hee7vbgvhA== sig=Z6JzeB+7R0rZUIFBMrlVRKdZHnZNWe35zDnDvUaI5oTfMqotoODBYv9nVs8fhhGNWoI7ER581271kq0uaf7CBw== e=found last=8 s=11 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAWbBZIPRGne8NoLilzqGt8t5gIwN+aDV3dtwXlsavt/U= priv=MC4CAQAwBQYDK2VwBCIEIEzZNwhT/2z272OB953mXMqvSATvi+QgOEyUtfnz0Tb/ msg=m1c7O4i6RapRT/4r8a8paR/D+Y2Mwd5MEfd4+JMcKIeNSAgT8m8bL9xdKLREQ47U2RHjJ1DIsQcjmcsAuChn0Q== sig=5mbvX2i2thc3177yXObrD+o1Azy/+nAA7zugs2UBgT4Qe+rrPW5bnYm6PA5le7+dR8x2AX2QlAo9ay4qciK9AA== e=found last=8 s=12 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAXNaMG6/QO8MW7JXygKXAC1wTiqdZFEMJm6VSppHEYzQ= priv=MC4CAQAwBQYDK2VwBCIEIBCXYtkB5I2zPtAEgbtSuOod2OBTbl8lqonm0uEd/Vsw msg=zQ77IZHxLLtgdfzpej4P5z+ZyWfO7vtQvgKOYbO22M/RnnWPu9aQNYVIc6ceUpnIUNW0SBEBBbUD5k2rjJ8erw== sig=twCxzMDHJLDyD55Emi8GhdHQGBmMw1yc23DhTVQLVFvw82Cd7c3LxhtywMmtrjOHkiF4tJnlXvf0MvWaRXlGAA== e=found last=8 s=13 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAeXVWB9eA9kvLwcseA7WgPni/V3Ju8suZrgVA5ny5DZg= priv=MC4CAQAwBQYDK2VwBCIEIOK2CDCISOXlLazxVdFz009cXMHhMZoySakzjEDeojjs msg=M96mO8n+Tlu/bMKVR2unmeK2CDCISOXlLazxVdFz009cXMHhMZoySakzjEDeojjsgsSO4WHhDl9aYS48VaZjAA== sig=qOFKE+ETWR/Ji6oZBsFFFy/wSss8QuWvuyp2C4PiDS+IShrikZeOycQnYJa1AvuiEwAX8+52GiRcucgq3BIUCg== e=found last=8 s=14 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAqjlMWK/99AfUyCCN5nf6y1j1VbTSfCW2N2tDO5u1YA4= priv=MC4CAQAwBQYDK2VwBCIEIOcsjKsviaKhOp9DnkvWydUDgvdaVc3gKduAIoi+yP4d msg=S9bJ1QOC91pVzeAp24AiiL7I/h1OQL/3vosVSt4pzTB3Vhezar+q00i/KEuG54xdkouoVBITo5mwITdut8198A== sig=j/oMGa4uQKe+esk9qT4UgVtC0i6H6MkKg+etalg+nkJtplcyxH/G37LLZt8BjgiKmTB0c+MbpFy4+DuZhl/rAg== e=found last=8 s=15 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAWWmXyvXKwlqbgc2YwPfCnjFTInMvfCMe4oscv+e7Qrg= priv=MC4CAQAwBQYDK2VwBCIEIOnbl4xnhiJKS8LxEiXgMUXP3PeM1sRx8LWPkfqoWrg0 msg=mh+ELRgCFk8vQAVSGQWzCk/GRUK+HXIFdgf6vwle+6xDALtcN+n3QuOdUIuvdDpTdXxA+oxQCUgehjCveNPTTQ== sig=ftdXyEV9fAzdHJJwkPS9e2OgD3Q0oidFj+2lb2juIn7F0rn19bEAY8aX+2cbBl6wOJdUAdBibHbDLEpmnz1fBA== e=found last=8 s=16 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAkYwNXxIjO07/jOzUKfwqa5in9Npxv1Nq/AxM1iFy20w= priv=MC4CAQAwBQYDK2VwBCIEILwQkUC1RzqHYKebQPibHkCWT/TJDlEMV5sRZIeiSQYx msg=vBCRQLVHOodgp5tA+JseQJZP9MkOUQxXmxFkh6JJBjGixD1uOTGaZWI/wng1YS70HNsLXLh+iJ+1Rdq+x1nm+w== sig=hpFMkzvbCEsH1gU+5kh0UgX4aZhZaGJaWb9p0UwlMo0Xu14VdFlG7B3Ep//KKmnBKJF9vQNrbq1Usz17w6QHBg== e=found last=9 s=0 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAV02+cCQrM8L4JKFopwC2Irk/r8IvdTHPFsSpIk28BqU= priv=MC4CAQAwBQYDK2VwBCIEIB0WJu1FrVCAK6qDO7TeQ6XwTnrE+v8o5icfZc5B+LPa msg=HRYm7UWtUIArqoM7tN5DpfBOesT6/yjmJx9lzkH4s9rCrJ9F08XlZpiw9qaxJyXkkWZy9NjB2FgQuuYLfLKjvg== sig=2Wk/i9ez9AHXNU0nRxONp4cXSTE/bvGLuz+7r/wvMeSuV6giEcOI96dj5dlhkZDOMVo5eGV4lRm2NwEgpscEBw== e=found last=9 s=1 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAa4KfKBqr6aYogm4cGelwOKZXt5IoLmg2LkgOZ6MC2dk= priv=MC4CAQAwBQYDK2VwBCIEIO3itNpDAh3vqm+3KL+XYL4JEGxKrnbtTLQA9jxLkB3N msg=7eK02kMCHe+qb7cov5dgvgkQbEqudu1MtAD2PEuQHc3mk3frDhDe792tXRKhsa9c7AGoLmCdN1TXkeBYMhZ97Q== sig=lASYRIYV4FWbqWpPskbBOuqNYxAGXEDp60ZqAopAOo5dO/A9SluLLC2X6BSJmLgjRdlr0/ycE+XxkocXlIhuBw== e=found last=9 s=2 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA9pByVlq/HxICKK8qchUErWL/krcCSX+9IJkicy6iG8Y= priv=MC4CAQAwBQYDK2VwBCIEIBgPTZtMsMfSrpPCS/TfBxB/JdEfk/ykwO3/Pu+zFnjU msg=GA9Nm0ywx9Kuk8JL9N8HEH8l0R+T/KTA7f8+77MWeNTeYlaLDNEmVq5adGbq+VbkvFbQK+sBIAGCKIeESrNulQ== sig=2olUmwUJ54cnHlXg6GNOJ1ZTToPjJCdx46EbgntQCniZ0+OPctPWLtDyB7cxGdAcRwXUctz9Ti926TR4SkMkAw== e=found last=9 s=3 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAANnfxxbj6gQfyUeFK4zVpbVWqS+NkZiErRjKAwqTeZc= priv=MC4CAQAwBQYDK2VwBCIEIDX4Pc7iA5sFwdbq11pHy4oUpswqrzmfsOdIrKZgQOjx msg=Nfg9zuIDmwXB1urXWkfLihSmzCqvOZ+w50ispmBA6PFZNNyNk9OTDE5dCK+d0zYeo0lZLkLBhcWrZfx2m7Oscw== sig=d7YAPky2medLciKt0p0T8t0vYdPRWnEg5Op+Qt/Ec8BMwxLVazignMi0q0pJtqv0OgK/Jo0PnAOIDe3N0GA/Cw== e=found last=9 s=4 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAPTYLTlgIw05E8u3QroDWVXI3ZMCSCPHbFROLNgqlDlE= priv=MC4CAQAwBQYDK2VwBCIEICkg3bbZvhWoOJXHGQvhSSlW99dNvxsC37HDlDAR7exD msg=KSDdttm+Fag4lccZC+FJKVb3102/GwLfscOUMBHt7EONvGCsFc+aNaXKKE5BWcEqKq/PbL9CkRtIVi+KdFP3vw== sig=NfExkMHj4/Pp4PPTBtnK3cu/pvCSfcBfl4daGYp/k0R7rWO5Kndcg9glv3LLmmnXhAwyQo6s2q7k0bsC3vh9BA== e=found last=9 s=5 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAtmT+YSWOXfl+r+ZOFS8+GZrfxFyk0F17rgqck9uJd84= priv=MC4CAQAwBQYDK2VwBCIEIApJRMTJ3VGYFnZBeMOiSKUuJP5cloneLu6iDmRIbOHb msg=CklExMndUZgWdkF4w6JIpS4k/lyWid4u7qIOZEhs4dtH0nACdz53tW/8M/CS01fUPVecHIV8BTxGmNH1m4CoHA== sig=0oYGnwIENxqAL2KS6p180hAAxYgDzalNQPTeTn5IOU+8J7X8gS7l1OS+CT6gXEhxMT7QfAof+tZ/yGb8QT1FBQ== e=found last=9 s=6 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA0uZpdCaB41K752gkuJ/yCS+GSqbzbUCrZJIZFCHYpwA= priv=MC4CAQAwBQYDK2VwBCIEIJBsyZOs1AyRoESIwj8q0rGAbE2wKt6mhNHnZa60Y880 msg=kGzJk6zUDJGgRIjCPyrSsYBsTbAq3qaE0edlrrRjzzQpBr9hwq+ON+Zh1buD5QVi3f+YVNb9i4Cxtq2jrGnciA== sig=EFZ+ptOmdiVI0wreL9QoVBHk3ODW8md4F60rbKxK7PF5cxDURE5XZXP0Rm86Opo4aU8jAe+a1XjKCPj9FAwSDQ== e=found last=9 s=7 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAqiGoAZp3DWqruj+Fp/+XYlZGodqEGafsW+dhyK++RE4= priv=MC4CAQAwBQYDK2VwBCIEIIiCxByaJP/yUxt+BXsS70bzbe8iJkgmRhqGoG8Znydv msg=iILEHJok//JTG34FexLvRvNt7yImSCZGGoagbxmfJ2/NGe6/3JvE2VV0aJILU+RR1KW+KqbAIJ3R7oXl6ynS3g== sig=y0DY/wQ2zyppos1ixORCPwYakPY1n9lYvzs84Miuka1SUoGqxGQnnKUwvSEAiD9/4QSNmEZKreO3DIqYfF5eDA== e=found last=9 s=8 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAG0DkU9Cw0kKK6y4L7ge8OlQ3vgX37/qpa1dXy0ZW3Dk= priv=MC4CAQAwBQYDK2VwBCIEIOUGERxLBkusITTcRfJjBLueOIYAMYvC/O1O0IRvz5Hx msg=SwZLrCE03EXyYwS7njiGADGLwvztTtCEb8+R8QXqBFDQjqrQUHIv1h902+dfVM0oON1UH9xJ+yPFQcgnJbrvzg== sig=1G/9BCxaO7LUkc1PUeun4WJeg0E+sQ7c+HtWdA065FMtHApi1jSyeLAghMYD7nAJ8XWH1ZeL79tAv50mQcvIBA== e=found last=9 s=9 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA7MnHuT6tt/lCl+TIT5pnyCYU5XFDcSNWNQJMBZPpGEI= priv=MC4CAQAwBQYDK2VwBCIEID3YdiSenH94I9G1Owqrijo4Phmbau6wIu7Hjq8GR54U msg=Owqrijo4Phmbau6wIu7Hjq8GR54U3zhDfkfTkkvy2FfQ67Dirf3bYg7X5DH3EeyjqJ7nVqSv0WRfd11+ALrnLw== sig=cEGpmtKuNKCVE+S/zz726cGCVsi57RqkSfavuouzKR1vZiztiDI2KG7c4aWEe9Ner8XiTLRhG1dXksFNMrCPDw== e=found last=9 s=10 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA7wA0xL4EtGwZiaCkEyKW3LjalBDRpL0foWdiriRydbU= priv=MC4CAQAwBQYDK2VwBCIEIBUWjC7M0ncKM5bWoz04QWLaGjeq3+1TeG9V6JaZlOei msg=sX1K6e4C7icuNDL0p8CGrgNYa51G5NRVMqNLaml5sXh/KcEB1ysB1Lhj4Xl64K/EBqBEYgOlazNtEXzBR0Yfww== sig=6712YpTl/NP+N+7Ugx31lAuon01yIU16cWx1+Nb3YPSJWFmHefVRS/p/iU5bAR2LTZaM+IOfNEzrnNgFwwZvDQ== e=found last=9 s=11 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/PUSpUlNlkmMJL6V/wu1YM9i1QrjEdZ7AB18OWZrdD0= priv=MC4CAQAwBQYDK2VwBCIEIF9kxqbFR/bP8cPX9xLs/p+utd9zs711Z54OI33KOTGc msg=X2TGpsVH9s/xw9f3Euz+n66133OzvXVnng4jfco5MZzRGyWLlaVPkC4zIlfgwoRj/klcUSG2r2qm1IkCkgt63Q== sig=k4oTptQNnSQAaM9XTRRdKKqJM08Uh0sLjyVwXpdXMhLVskbkhOO5WH8jq8uNNPJhWPy4BXSQ8oU9zELC0C4ODA== e=found last=9 s=12 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAzDxv6JewiIIhyMvN51dFnqL2iNVcZlSbXZXc6Mdiaqk= priv=MC4CAQAwBQYDK2VwBCIEINsb+bZLSge5sDCWmZSxXTSQGT9zyVFfMASt3X/unDSz msg=NJAZP3PJUV8wBK3df+6cNLPe/XPjhD60FN8yrb0RrZDr4ZtkSAUVbdmAVnxePeL0h2VRaf1er5JOYcLwf8gNUg== sig=okXEnDcP9+a/ayCrbP5fuE/GgqyHPXTXzYcckPYIjRphsCCXM26jJYZJee1j8GZ9iGGa4NfY3dBHUrAUCQ+8BA== e=found last=9 s=13 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAjvYiTOSSJMsUtS4N9vDcHYChbjQrZ1ojbpUN/kOzm18= priv=MC4CAQAwBQYDK2VwBCIEIF0jbm4I3fMCh1KqsOW2JF7Ji9epRhX2JWf7vpnOYgzJ msg=yYvXqUYV9iVn+76ZzmIMyT0Q/18/7WiceC1ipvFW+MCoPMWgf2k3GC7eYSqgOcG74QqS74ZyUQgY5wxAwBktHg== sig=k15nJEzbeysp6a3hzly1tAGYjTgNuN2bh3JTIUdfY4pxSb6Rq7aI2+p1TKfs3I7WxMzOv0v7iixLuhIU9X5OBw== e=found last=9 s=14 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmcNAEiexHNXUoCvWg508hPzmO8yJYdjJumnSNv2ycTs= priv=MC4CAQAwBQYDK2VwBCIEIOViP5P1lT7CgNfAGlbQw77Z2ssolKf0y5rl1gCcxKIJ msg=gNfAGlbQw77Z2ssolKf0y5rl1gCcxKIJVz12vKOZVj2yto6hSEfy4xa8f4275UQfubdg/rfvYjp6MscUcrl9ag== sig=xKMlGqDwTD2Y7AhghforyjtVkj5mDpg6KQZ/BPWNiAXbDZkzGFPqLxQn+RO3ODZaLE/BOZZawRtKkC4IJeu1DA== e=found last=9 s=15 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA5WH5O8LU2VuNmJawr40b1s1VlvN80HxbqRlUaASCHs4= priv=MC4CAQAwBQYDK2VwBCIEIH/UIR0thAsHZJKnDtjiuK37WpRE3bNFL0vDXfa2NYDr msg=shC6+xGvSAlng9Rxivs6nxjUjo7eSHdo2VOSglzKS48BtXax6vs/wy+SMlogaW+yuRbnvmzXN6AVLvxUl/3abg== sig=N82jX5T2xTUx71eX+pw1/ZGk2lW5mXwJPytuUtGz6UZHij05/EMVr/dO83BnC+LoXj9B9lURl+JGHGFiHDHcAg== e=found last=9 s=16 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAcK0asppfJji2L05PctFMUNDnCls5vUiAJS9Hfz9lHLI= priv=MC4CAQAwBQYDK2VwBCIEIP3p2HiLW/JoWRmvGnbbNA0+bvcFYqyVZR5TnJ/Ep1tf msg=nNhQn5P9Nsd14TO1DinQUHdo8WcW4nCTeLNgjK8C+JnDq04SFdYFEQIHZkzns1+GPd751YZq1OaTHKLvxPcGqg== sig=yG3UygI3hYRSGo+9JImcjzTyZfqd0TWgZq5Hy0HuwiTwHBONPplQMo2a/XEVFQ1o6lcmaV8VbqOGi/llhqfwAQ== e=found last=9 s=17 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAY/zIG6Jfs5QSmhzkbhjR+3n3KX40SlneOrSomd6Mbuo= priv=MC4CAQAwBQYDK2VwBCIEIFuvqYK/ObcLTRooeSdPpb1MdVkR3MSnK4YUYih1KRpz msg=TRooeSdPpb1MdVkR3MSnK4YUYih1KRpzXxvFIujSDuuXnwx4ryuy+VpNvO1RWnhb4bKrWz5K3fVjwM3N4Xz0nw== sig=pXs8vQuYjpl/3kouKfoHGL+3NK2cobLi/kdp3SIXpkrEhD7z0m1Ly9Tu0jE/OQ3onYUPxMbkKBv1iePqMsUkCQ== e=found last=9 s=18 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAAgtEREehKgJzyElLZdQRDekKQHRsQYliNTM4b/4yyos= priv=MC4CAQAwBQYDK2VwBCIEILtvd1N2uiUQxu7QIdhOZku1kW5lixXgn8HgNv/UAAPJ msg=d1N2uiUQxu7QIdhOZku1kW5lixXgn8HgNv/UAAPJ0FP1xwL2KN6xHHaQvudejJYDAAQRfbFzKWhMDam9Z3wzGA== sig=NLQx/T8mKzkO5kXIDoDPg3sJvS7jyrGE4/vu1x5nZ1hYqrhmCHgkYW+keB1iylplin+shWJCqRabGOwkxJjDCw== e=found last=9 s=19 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAZJFyOeWROi4E9BnEiIAaAt0AMMj54bxhymyJ2cHmLaE= priv=MC4CAQAwBQYDK2VwBCIEIF5c0l1a1epb0vy1p8fnWUiuP7mAJlKN0CzWE/qmjIXN msg=67z7TPrx7YTHyNV2jm+JyQbqNjEmhvQPE5ZFzvkkSYu/WLg4uiOWnpyOVFoHMsjC3vgKOO5gvB5ZXlzSXVrV6g== sig=is22m/5APwQTBKqiO326H5dOVKncnV+NcwcS5qV7GzK3pvQns3gpHBJiIeMo+ws2YFT+kYjbZ1KVwjjs1D7BBw== e=found last=9 s=20 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAD5+SD9ck55fh0YXAnJ01UpxamLnT0cj4nxL0gIoay1E= priv=MC4CAQAwBQYDK2VwBCIEIMcoYeZci52NrQneWZ/w9KXIuAUlx9brTR4P23vM8rOf msg=600eD9t7zPKznxtsqEoAefvhHq8vVetMa3HhStvd75SVSc4VCWJTEGcWj/uFYn+GPSAs8uYzZFI2YGQ65bQlQQ== sig=KufNow3WBbWH6dv71lzxT0laWZ1RI8y9S5N8v56OWiy51Ql7k6kvE0POIa0hN4HsHxoSTg/jN0JRgKfJcDI1AQ== e=found last=9 s=21 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAoAYZa1Nt0e+7DsDzYVRU7lz5NUYV4L+ziGWGjYe9sBc= priv=MC4CAQAwBQYDK2VwBCIEIBUWPxM7whavZBNoBs1HMk1f37OxVxgHvjCMmqtBPjFw msg=GllQHAyjfOskgeglz77OOMOF4YgvWJdN3KntGV8m425ZYO64pNz9O6NM0zZMQ3dylPMbO5PGHr0npBB509Dkrw== sig=NGdbuHsDSnAtad+VZrtKmvq5RKuE/hkleVnFQgOebNIWJbXz4HWWd8I15fQORnMrtcmylkpUVmDpkm8WktjOAg== e=found last=9 s=22 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAipKryMwM/0tYkWGKeuWQ2BrLD3eZhoplGBx2pUXuoYY= priv=MC4CAQAwBQYDK2VwBCIEINofJjfOZbLD0vBp2YvJ2VO2r1cK3hVXSVgasDBrDhYA msg=4TIn+/vaxTWHcDMY9JtioMLg3eL58mc71vn3fCphyc7UAVpIQqzBppdN1NofJjfOZbLD0vBp2YvJ2VO2r1cK3g== sig=8GYXZR0fCaRcfYfPjFoYBLqWPpf667gW5j3LCm633VwppYseQl9llSme5HZ4HxpGjUpwWa0LBHm3pu79qP7CBw== e=found last=9 s=23 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA0+r9hsqiTjCjFDcVZJUQ/WnpzKlMPAFIC9gr0UWXsfI= priv=MC4CAQAwBQYDK2VwBCIEIL3hgcrDSSwEc5mPDHKsilZwVpo1+am7bDKxxNRp4W/q msg=Xlw1fpWAd8bMdBiP8lR+UqkUQ6zKSsIh8pEsdlzkQnIGN0BjP+bho+rBymms793O2pQtPRSAv2ZqSsGYSVdv4A== sig=KrWy0pedC2y0kGnGHMrRKwcqNCKqJrSJChmDIp6/kr9hiWevv9SzOtkBz7dyqz54kQKkV7aiipl38eVWpTU8DQ== e=found last=9 s=24 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAqJNqsVH7WHQqzDWzuBBkpUZ3jo97OAFJwwsYpXmNkqQ= priv=MC4CAQAwBQYDK2VwBCIEINuYcHj/RYcsDZo2xow9O4LUvC9svVIczDzfwfBg6ZwR msg=zj62QbXbmHB4/0WHLA2aNsaMPTuC1LwvbL1SHMw838HwYOmcEdMgHRUVbLlmielkrgnMB1TTh7j1/LE0yXi4QA== sig=M7ncAHELwXMVNgmr79fhUYJJz5njUCRp6C3lPCopgRBAQVQ74ZNp7wU96M6TtJqNqqgjmnWXZdY9+VEEkF2YCg== e=found last=9 s=25 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAlSB6wk24gl8uMIYOftnOXlAS10f0QZhgW9DtRUD0VGE= priv=MC4CAQAwBQYDK2VwBCIEILVArKqBMcxgyHED4D0JekGFOoiGR9mU/VuSj8jfZi3B msg=M9yKYgzvBrGVb0qCfgbDrHd09kSe4GxbcsqgxB2QswTg7ASw3FshhmVc4rVArKqBMcxgyHED4D0JekGFOoiGRw== sig=y1FaqnbV3A22fYhfPap8p3RSPi8q9mm2ODkwlVPiYPOVmHmQ/XQWG9Te0qQxlu4IkzmdN84dLGhqjgl7W0z9AA== e=found last=9 s=26 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3m0trGWzujesZ5wBv93uI9jJr8g28SH8s2dAMFUhZ24= priv=MC4CAQAwBQYDK2VwBCIEIH1h8TSXkvgzu356h7PWV69yPPM89jEolWmVUtSQuL2g msg=6KrNoCQDEWn6eJgxfWHxNJeS+DO7fnqHs9ZXr3I88zz2MSiVaZVS1JC4vaCqSoHu3PMR9qWlPJfANvll5c2IRw== sig=2skkVrGw7D6+NxD/+6rKR4QZq6O/JFw6Cyoc/yEKEfqS2S6fh1xFntGgzSuKkV1NI70NBPrGG0hS7TLuEHglAw== e=found last=9 s=27 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEABmnUosH9Lwbl/jpp1HWPNERP3dVm9NuObFysF9nkajo= priv=MC4CAQAwBQYDK2VwBCIEINuEYV1lE8tgKaA5fblH0iclSJBP1quiVgSnvcK9lkfG msg=R9InJUiQT9arolYEp73CvZZHxuNIwb+QZEqOdfERwmv5S3Q8oUp58NBqH1RKKHkZw+0b4+ZONP9/gAo3q624Kg== sig=oXpXy2gJwiL+JqWM/bWGyvqlOdhdzrmF1KZpWCSGuOteqme67OJLJw20DQyw/T0ad/ZbxsZpSzxOAcBOQ/d5DA== e=found last=9 s=28 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAPha2E/NsKWms+kDeMREZw2096/jH3Qg2hVCNTZK2pmE= priv=MC4CAQAwBQYDK2VwBCIEIOdOB6Uhu2oOn/m/RTIfQGVjHfn3vUy4gyQGok9kBJJt msg=LYYP9iKova7ayzxv9v2IBVbf2sA+bHKdJwfDk3FaXv+McuJfAYZBPrbM7NqOzhmcjEOtJbge8mN3FbGX2QzZ2A== sig=tVXz4p3SeVj5Wu1F7cOVTD6wo3EMfMhzsMQL7DK+w8F42GEupnfRA31XKQ6nbGCunABSSp+7XWfrQ1O564K8Ag== e=found last=9 s=29 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAIDJrbhcKpHNDeU2And5vrjTfoFnrfVq5bNOBa5ciA7g= priv=MC4CAQAwBQYDK2VwBCIEIDnSKvmbcaK1ndX8PAHq/XK7uGtXE109p9bKVPVuGPs9 msg=GcGC8+7ZATrixeIByMfGrWIGl9hzTzPQzWqZ8mzGgv850ir5m3GitZ3V/DwB6v1yu7hrVxNdPafWylT1bhj7PQ== sig=oooEOxSLirwLOvrHLUPA7lwSu0FMO82pgfVc0aWNWuJSkX1sOgKa/SA/Q+YNeoskf2YykxmqjpQUfRQiQ16qCQ== e=found last=9 s=30 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEASdXGBZFDSTHhwH0LVGVdKIr9jip2rcA3khhER4OqAHU= priv=MC4CAQAwBQYDK2VwBCIEIMYtC7NIDMqmG1Zx7nDsU8qznfPYoebif1tlhARFdc8i msg=DMqmG1Zx7nDsU8qznfPYoebif1tlhARFdc8itk3hViPL1v5zgMkM4Q+1gdOjPkxCP5kKX//T2uPB7Og+EmlIPg== sig=1ZHDDRw4DmXlzzyY3YvGPrvQocFM4NDpp++DDUsvnRRiR6EI+9P4m45A7UiLIlQIuEt32XBklicKK3JrX3PHCQ== e=found last=9 s=31 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAVlb0HkE69Gu8hMjjVZClUj32j3S1TvMJzdNvea7bLqU= priv=MC4CAQAwBQYDK2VwBCIEILT7hBeRhO6SdBNPGp5zITWWZPxeEYHjcUgzoaUNLGvh msg=tPuEF5GE7pJ0E08annMhNZZk/F4RgeNxSDOhpQ0sa+HnrBZW1//ktsWgKOs/lVhYQYtmDI+aZJQkr23NmU75ZA== sig=0Imh+/3HzkReLITQj14y2dOrsF7pN7/r/hzD0Mb0ES+RpYUALuoSuOZR/M+ibXbRItfDXpInXqZjaNyEJJIZCA== e=found last=10 s=0 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAEyGSb7hg3v3jaRD1coUoO0v1QUAL6avu+wnGLhS2GkQ= priv=MC4CAQAwBQYDK2VwBCIEIKUXz9TfYiR6pkR0np9usl6VsRw2dsfTi9YesskbKz6B msg=pRfP1N9iJHqmRHSen26yXpWxHDZ2x9OL1h6yyRsrPoG+Zq3/bulDuUN+GP4DezuGBh8FYWmh+GSiK0ZU6zuC9Q== sig=vZGqSpuz2j1Q4wK5f6dfAD6xh7zbV/A6pit1tdD/h7ouFRCO5+4WNod4QeEXn3X45Kifd1yzKjhiUq1ntMBKDw== e=found last=10 s=1 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/LTQ6dWJsf0x8r4xflrzGu5ob5jomD9Xz5eZudZBP4I= priv=MC4CAQAwBQYDK2VwBCIEIPW0vIq8LUQaYknhv396XMiXvG3HPrl3Av4rK2/U5FgE msg=9bS8irwtRBpiSeG/f3pcyJe8bcc+uXcC/isrb9TkWARRa//azQy0mojFq3oU4IL0EQMWIbcMo4otwarf6ugGCA== sig=4XAJOZD5EPWQQlOaEuE84GkqygJVC/44gxANqLF+Bw6tmqHJ11cj7W93osV26Q8sErnutn+UOZYWLHXTpxq2AQ== e=found last=10 s=2 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhjx1zduYLyPpAm1AFkcZSUn5B71Xdoo/8fORQlIXMNU= priv=MC4CAQAwBQYDK2VwBCIEILjaLTCMl77XJ3kQ0iQLzEOZW7anp2iOPB2IAWCzVUd0 msg=uNotMIyXvtcneRDSJAvMQ5lbtqenaI48HYgBYLNVR3Rqd8DW3DrII3u/FRgcvnqzgqg0H3nIQ/pl5+pbJIF6GA== sig=/f1hI2xcSZhG2KD99ULeeo3BmtKbd7eGCbaEdzK4XeSbMn2ahLsRI+p520FPT1I4CXwLg/o/Huj0Ng3IG9sbBg== e=found last=10 s=3 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAb74RfkAN9uRYgqq9epXLudL2eTv7ZYv4iwZU3OjfdyU= priv=MC4CAQAwBQYDK2VwBCIEIH0SNr0d7xZPBqtZqI2LHH7O36ltE+xAjsgcWpBSggh8 msg=fRI2vR3vFk8Gq1mojYscfs7fqW0T7ECOyBxakFKCCHx/gcR9Np2rftkeEfvMLUedxd5OnsnvoB/sYqksRdn+Ww== sig=p+9T2O/LUd5A3xUaGpx+CAphKAkMA+RBuh/8JyO4UxJGDzMNGOnFenK3sliJFO8LFZUd0uWDAXW2pDWVM5bkDQ== e=found last=10 s=4 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEACwJo6J60IffgxcwJuzJKcM2W5Mfm73pxiwKY5ueMTaU= priv=MC4CAQAwBQYDK2VwBCIEIBpf4YFV8PyjuTT7iBv4WEIDsLeUHH9yqvbrGkozKTap msg=Gl/hgVXw/KO5NPuIG/hYQgOwt5Qcf3Kq9usaSjMpNqmI2Mx2Fv300kvTSRHPX2xBYVQA3V/1mhumc/l0BsKcRQ== sig=mV5ptzJgqw4Il0LYbPpDuSUXRih4Gj8ZL3LymD3j/dzNerJcpkoc8Q+rFAM/AE0PoH4DRsiBtw5UK4iorrNKDA== e=found last=10 s=5 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAcN71iSHVJjl3V//79Z4bN6WLMqIZBKcSYEJYoVYSaLo= priv=MC4CAQAwBQYDK2VwBCIEIDKHweTUgYfC9tPsHntGddFL+uWNg0Gr83x0dJeGCmkB msg=MofB5NSBh8L20+wee0Z10Uv65Y2DQavzfHR0l4YKaQG6AZF/9O220wMP+rlN800BUJIyLGMzJHCczw0wrgsUhA== sig=PXOl/Srjj25XUaIx74i8jzMgGzB0ZasYA1oKgTN8zrrCUAfhjXmFUQgUEX5U097ue2nljNY5bF9hYpwYNudzBA== e=found last=10 s=6 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAuyAA2Re4VIzhYipYG6ShThl6gA2hMIpZXnq3Lzit2yU= priv=MC4CAQAwBQYDK2VwBCIEICf7I7MjMcy8kaj5rgh09BkNdp2hm4MrGF54Sdiim30W msg=J/sjsyMxzLyRqPmuCHT0GQ12naGbgysYXnhJ2KKbfRbY0cGlxpRRGmgWPDu/FNcnrAZmIsjfvpJky+VDP+103g== sig=cYipUjeEX6FkjqYgb6kNVDS5j/cN8y4sF0fmqUfRQk9wGB/BogIlCDgjgTL7QJAFFBEZkG90FuMAED5O4VIJDg== e=found last=10 s=7 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEARCMeILoMCOou6KDO2Ek5Mmag4SqAK2zx6g1Cqhp7WJ4= priv=MC4CAQAwBQYDK2VwBCIEIHxbQJcE5IqzmV9KSX3XkaB1/3FuqcMPiMU2GJR5uKml msg=fFtAlwTkirOZX0pJfdeRoHX/cW6pww+IxTYYlHm4qaWmDvL9w8w+luvuYjUiXqPiO+GOVDoEq11c9pNkD/9Tlg== sig=HMMJdYuPXSX6rb250uKgA7aqiyxa+V91Z29wF3/nEs+FIhq7TpDETubb3H4J5qFoDo8KUH6XBEQOP7eUY+HFAA== e=found last=10 s=8 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAqPNOyJi+N031E1E4biSAutBdEREnfQG5j6uOAsxpr3k= priv=MC4CAQAwBQYDK2VwBCIEIHNstdLNN2PJA5aT2xTuOXxxIScfy6hmNlLZ2Pqn+gaB msg=bLXSzTdjyQOWk9sU7jl8cSEnH8uoZjZS2dj6p/oGgc0JE/T/zeo37llQFkCSx/3aRbC8/pUASP1at7T9rO9h9Q== sig=GPawjStneD3u9xDQ21zztsDLh0IldbCQxkMy7/RXyXpbXnydkUHkjHgNMU3NkLwYJYeAI4vjIsyk7jyaB7nQDA== e=found last=10 s=9 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA4Z35dH8/CcN2LRm65u+z6/GXI6TRYxiEGcpEeLi2aXs= priv=MC4CAQAwBQYDK2VwBCIEIExKZwli/QlK0APOGNrtuBTqJ8fzUECrsxlJeCNrSRyf msg=TEpnCWL9CUrQA84Y2u24FOonx/NQQKuzGUl4I2tJHJ8W9qxEbtrisez8Y/mkFjnEcupXFlJ8j2qTGS9XZzB9SQ== sig=wIr6xHZSwi3ZSzQa2mDx3e68YwvlnehAIATZOI189w2YR1ZEgZxe9FvOido7qoRCPiOIp5qHvf7VTUjivPQ5BQ== e=found last=10 s=10 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAFSY+d6OU8g1lOHw57XHLafiIlpEUAmGpGBVOiS3rLvA= priv=MC4CAQAwBQYDK2VwBCIEIJRt/rBnUz1pXGVTCs0+UFeKL/h0PutEnRf6wzQAWuNN msg=/rBnUz1pXGVTCs0+UFeKL/h0PutEnRf6wzQAWuNNIZkh1NgxaUQLACQVftEUyk/6Gl6p4KF3SSgTOmm/FEEVoA== sig=8T4CEiItW7hHr5AtV04qHa6eP8VCwbJjZe9ABr6PRf7bQ+npCGuGeifqUPWLhbj9ctOXQLJqtoOOat5jZQfZAQ== e=found last=10 s=11 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAV7uL+/xqgXThMWDfHPPFYoIW0Gfa7oWBq9PzCMUu+Jc= priv=MC4CAQAwBQYDK2VwBCIEIJtNGKIeKjiVbofOWpvinLPZxEy7EWt3TVeoel080KPo msg=HNytJfxnrbV4fPC0wCtRUKTDkyzJj6JYLdhNQtdE4ARAd7keEF/iR8NXLEF4Jcf5irCYintWcfe36xVw/xrSEQ== sig=j/4rq7SGZ3cPq74N/YXDlG73qRXcHDljiAy3HNi/peSoSlLirM7iZFEm84HI6CNvOk6fpfakyhVnkKDFLs8QCQ== e=found last=10 s=12 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAWMZBMZHJxDr76or2k5Dkz5l1ISaBfX1uuSu9XyTRWvQ= priv=MC4CAQAwBQYDK2VwBCIEIBFLFb9Ccam98kur2cf8M61x9mgBS70PJuwLJYBsecPI msg=v0Jxqb3yS6vZx/wzrXH2aAFLvQ8m7AslgGx5w8jhwJUpjCjce3hVfuAV+7FLVBRNcOGmMJ0kfxKXaASxTUl7aA== sig=NQhphVoFN7ruP/SGwMB/11C7gD+EE//LmzG5PSWCVcFPz68z0drfhYUQpNxqbvUpSdh7Ejr9ucIsPVjNf/KYAQ== e=found last=10 s=13 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAMRcHnGvbdcg5hoYKyCKhQdbKPcmixfmbhEAZV1qN3I0= priv=MC4CAQAwBQYDK2VwBCIEICylxlnaUW1l63aNDHpMRukSUlmEkPWooFb0ibZb1Xlp msg=gJbulyePFp5MbZrYypQCrpQV9i2X7mXkPqBx/QxS+i2yxRWXjHNNFl6QzoqtBPl9z8IYC+Eux6UNjwFSmWcwng== sig=1ZN0KvQ1QU388vnTcsb5zKd6BgCWZ+S6Q+ddCk55eQ/6Mw4V7GuPmWBrbBimMUq6uc0SsLnMSMblK/X93EqDAQ== e=found last=10 s=14 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEATXo8KJbJlqPzvfXmSPDSY/XKi/1yGVbR+RXyvE3rSQI= priv=MC4CAQAwBQYDK2VwBCIEIEJMFXpB+27KcaoZ1sLTWfq4za+3LnMfuBeNZHqyeYjD msg=Hj83HhWVXaHKGd/BCXyquCXAnFWvUtljaieNV3oEAy0cHyqqu0MIsQKi3Oa8iAmIJDOAc1TIhOm0VTNBJ6ziIw== sig=6LUk2SJ1pV4Qrr/TS3+HVtuBFIhHyPoFnFqO9wZOZIylHVlK1Y5j15V+UVdi/k7xrsVlY39C+mt93Am5t4c7AQ== e=found last=10 s=15 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAwYjjGuOAEJKSrZUN3uM7n9jQTpaIzZlOlo5k4HgacyA= priv=MC4CAQAwBQYDK2VwBCIEIEo3olAw56nD3Jamgby0MAwGxRUt/xrl2HQvlTz7NG33 msg=kA6eRBB3+b8n7NnBwSF59WuBzD23NbqzcfDJGJcbsfKMSebDLmhg36GyDf++xDVYfyqyAF2FjnZjRYOk0Z8HMQ== sig=4P9rKPx4S0lAMeq+nULE6cph3rAsZvthRRVWIb5WeXFZ+8r3Zn1AfLjJiUXzeoL9Z5UneXxpRNlsDH/39ocoAQ== e=found last=10 s=16 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEABMJYQbNPi6qVtn9bV//RwD2mQ3D8/jTxiV7oXdAj6V4= priv=MC4CAQAwBQYDK2VwBCIEIHG38dnVo7GPjumQox3tTMlg+5FyO5ut+kuXkfScG9rH msg=zu3Ia4/WRT8wVZIaBZ40felwTg5LkJlJLO6JCzDbcaZbqNBVGLu87X1QdVXXjk0T31eRv4vWrPQE3eZ9cFlkEw== sig=bKeLxhg/6MQszu4Iv5fqZ1CEl+xqdqxOUrDcZ4JEtNQGVFre+GZEipA0AOA08GUe50BmlusCXfB31tAilcmADA== e=found last=10 s=17 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAqQSEbqatOY5e/ntBb77xqoekEwyieWxIu5hj8G8qrGs= priv=MC4CAQAwBQYDK2VwBCIEIPbmbBobF/PIKeeJCm7wp+mmEjSa7ilsc5ZRxJ8EvxU5 msg=LVlmCar25mwaGxfzyCnniQpu8KfpphI0mu4pbHOWUcSfBL8VOSFei6Q0XOsh0zIH1sarOizq7bQQjo5CzZtupQ== sig=ltEZw/l/O3s9r2NCcwdypi8X98ZAUgDkV8imfRqVWTgmyBoPQYXOsv8FDdfEKJhbwvDbja9sDvHAaS6Yh+PgAQ== e=found last=10 s=18 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAqpB1OA8D+a7IaM/L7Qm5zcp8Dw7jDbSeH8jHKQa1kmU= priv=MC4CAQAwBQYDK2VwBCIEIANjMFRGqjv4rnHLEIEXxlCfdhQZGA93m5DgDtjJTp7S msg=sevxozGLEYZ83MZlgRru9G2fIe2ImRiBxmc9YM80j2vUmACaB6xpsRj/kO3N3+ra+MmNHy63eO/DtALK6/nZYg== sig=9dw7rj/Gapr2G40i1W/5Vgv8YwJA2v79IzODttfJMnf+SIgshZU6Flz0jIv9iGkvpL5AaUAsdpkGTvAK1/cODA== e=found last=10 s=19 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAS4S4ii20i/mBlz5SulqFvxfw51R072Ng+G0pUifnmmI= priv=MC4CAQAwBQYDK2VwBCIEIBq7Kjo7DQGGhGRjGu0HKU2u+LD1KvX3SzckOmA2ALRl msg=+LD1KvX3SzckOmA2ALRla+RBw8SmZtsgLOMUsI2T3E4QWFUuQlqSPXEOQXNuQFxKBBpVRFx2p4us7WufxwHbNg== sig=Tm+Q+KyZXMfdB9ci1tjEvtR0CHfT0IiSRWEh6MJ7T538GnaHq/2OMsDEyREmWy4oi6sbFJnuDz1MALmOlaSeDg== e=found last=10 s=20 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA8r8zd+TXo3/AcvzsLSz6QalHsr/WnsX3YFJRS87P3lk= priv=MC4CAQAwBQYDK2VwBCIEID93XYwPYWRCK1Ez61moO6V29kemhvuJmmsycQXn8RhS msg=wOhj7z93XYwPYWRCK1Ez61moO6V29kemhvuJmmsycQXn8RhSEnAa4lBG3fGlhOn7XUpBBPWokO76Zqlm1V1p3Q== sig=R4GTvyLRt5SaFIryG6kpWEsc/kW9at9LkKilDND0fcjcg27olpnqVNCzpgeeFRGGiMRyc3UgDra9UfuwXKgRCQ== e=found last=10 s=21 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA4zUc3dKw2Bo1IwG+G66aUUpsKHihDr4KqRP63u60j3o= priv=MC4CAQAwBQYDK2VwBCIEINsJudM4W0AO8AWudVWZSF4KwYm2+OembJswyCnxelHo msg=AFjvIonAhEVdA0uqtMLaswvbCbnTOFtADvAFrnVVmUheCsGJtvjnpmybMMgp8XpR6NMI2SNQI24YycNNSiyUDQ== sig=WPEAtMZO1TFIwl6lThmzCLJqugzI6aBcWm2EALM8cK+fZY4S/dAUAOOO2mxp/Pl4LXyrSVLgE6E6yGjanaSPBw== e=found last=10 s=22 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAkdQkNm2GGT3obDqrf/HGqEm+72Yir9MaLWcPWeiOdnA= priv=MC4CAQAwBQYDK2VwBCIEIMC21Eyuf7BirEkh2e/dX7AlKRI5gh/pIDC765pkWUUl msg=dGAay9vdIjwzvmhvblcduY5dn3WSVMbpKnuIbTVo1WH5i12dAIQsNpsdsBJSREyuZNF++F4aDEN/S9vHTvtyHw== sig=D6d3yPXemyF+87iayBOBNUdErt+4bwmZJOeoNaIwDfY+Lkc3ne3sCcYTeS9yk3ormHlUF64R4i8OBd9SA7aFBQ== e=found last=10 s=23 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEACZXeoWc7+Uz/p8YbCbZl6KdrhWROE2+75lgAFz/Vjwk= priv=MC4CAQAwBQYDK2VwBCIEIMwnyOrv3mwWcAyEjtz6Z2XXVoneHaU08fIE80QO806+ msg=Br69k9FDWZpNrbg1JIsuCZ9FvoTmzciTChrlAAbn4BKRmhvwJVK3TBW3wwlTUswnyOrv3mwWcAyEjtz6Z2XXVg== sig=f3N+VPiv5fshu50pazT8FHapZYgi8YQUiLvxElw3sSsibUgtCAaqqnn4iM8wp8P0VGxwOE8KUfdiGiVB4MhnAw== e=found last=10 s=24 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAbxVtq8KC4xo4OZvKpF0/ZCPBKrtSYTAPWx5hrj4Pl0g= priv=MC4CAQAwBQYDK2VwBCIEIOkKLYsfS7Ql6jK7LNtilHq6ZgtOcyqBeM0sWNukksqX msg=I/TpCi2LH0u0JeoyuyzbYpR6umYLTnMqgXjNLFjbpJLKl8rT8S7gTNV4/ZJLePM5bIAlaURyD/IDZKD5WUc1xA== sig=OHAvOqnuQpKmka16etSSBQbwsjZkxgQqR2jKT0emwtUBkJ+uJTbIZt56EXpp9JtCJcZSS5C42Jr3V6cvOq82DQ== e=found last=10 s=25 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA50prt5SC2k5D9pTAIyyRW36S+Ti0I7S71n46e0VYwbo= priv=MC4CAQAwBQYDK2VwBCIEIBa9gJJXvvZBMS+RHLyQiYUxjB8C0ZtEVL3olCkwCjK9 msg=jIIgOgAtkjG9Ip9bXhyzI9i6VYGn3HiqksTbBWdU4NoUbg0WvYCSV772QTEvkRy8kImFMYwfAtGbRFS96JQpMA== sig=gkzykG06/C35xXUrX1C2hDwCgZusIQ1/1zn6ELHCDgBlEs0QQt56ZpaohnJZfsCSwYumb894xgCe+HlkhgYgDQ== e=found last=10 s=26 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAnc66hJZtPTUtCbOpDJM46whnhWV1rMza5DeN4Dk6g9A= priv=MC4CAQAwBQYDK2VwBCIEIF6R51kFPvUBoFQ9JR27yZi0C0ph3NsQV5S12xoRNcWi msg=yq5pSls4gRmfPAUXARU58qekyW5MnhMN0yx9L/ielQAv6Qtl2b+ayH6+1RkVX5N9u3GfjLMa85rMUt5xTpKIdg== sig=lS8azKVMOpogMBOkxDNGDARCDzuMpH52bQ5PD4nEUpWWMe5Jq5qCLCHsKUrKycdGrcoEaHRr25s9YAD1yXdiBg== e=found last=10 s=27 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA9ZKsRgfPpFfwlU9xjHLnGlTRNL1Pser1aYIWNTfMxjU= priv=MC4CAQAwBQYDK2VwBCIEIOFkozS/JK4EUrxeOHbw/Ip+22ql2EE6sHOV/8a28m8E msg=4vt9ncFtozirIg0ah48/maPhZKM0vySuBFK8Xjh28PyKfttqpdhBOrBzlf/GtvJvBO+mfw7W3F67FOWjN3qf5Q== sig=MnbhVIzMyuxhtZRK8oPY6ydSLr2SetxHVdkqUcorNDvNm4G0GbVFYGwhDXHB+HgxJo9JwMBnvovFVNcRoaN+Cg== e=found last=10 s=28 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAdnEYGyTkdvXlN4olxeZHHFpwyT7bFEr9oEc7HDj54fk= priv=MC4CAQAwBQYDK2VwBCIEIPaDt6jiNXdd/TStZO7Gt1NXACLEn42mIJUeWSSNbAH0 msg=t1NXACLEn42mIJUeWSSNbAH0tM+zPzkCiNGjuE1yWUlJWW54AaWm3JGSAg8a7/41Oc8uRCnmImGE/rmadkHJEg== sig=Gjm6iNbb456h9S+d0GDLOBmO/3JNiXaYmxHcsq1cWMr37pF8SxuLK06DtMkXjYWJlTGsCe7+r5IFl81GKx7PCw== e=found last=10 s=29 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAJC9DNWFv5HpWMhpRzHs18/rbvBx1npoYhAvL3hOJugM= priv=MC4CAQAwBQYDK2VwBCIEIECTblrzuON08UsQOjxvLkgCThpu0XZL2EU7Xf+Tlsn3 msg=WNPX6ECTblrzuON08UsQOjxvLkgCThpu0XZL2EU7Xf+Tlsn3cwACDY4WqOoOMzgnRmNnXcIdw4x7iOdyjbf4Dg== sig=VwGI9kIX0rhu0UdmpCs5RwPJocPHOkINuN2GrKEl9nO2XRfgdexuegl7lrdhsU4nIdB1y/WP0FIgHjdnyv2RAw== e=found last=10 s=30 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAoNrzyvd6JA4U1lJPv57gJ7h+MCP8MsqBFYKSQwPqYCY= priv=MC4CAQAwBQYDK2VwBCIEIDb4nYWmjDa11jn5TIR+reqlYn+nT7UtEyYThPKx/F83 msg=f6dPtS0TJhOE8rH8XzdK/jFBDfoIMQUW/kl2PMGF1iAN2Wu+31+gbAZPEHtadhO+6GchWnp4SfJCyAH4G4Cv/w== sig=BPRs7WWFQtsjNtEHaed7HiaADlSg0l+PKRFXOwj36plse3F/30dgXowjB6/VgcrIZ2OdEnbKt4d22dwHQY59DQ== e=found last=10 s=31 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAKU/2jLBnlWBLDa+1+5TCXJqHiIZyY1OGftYVBR5eN1o= priv=MC4CAQAwBQYDK2VwBCIEIFiz4GkbPmQhS23yuHc2qL1FzkLgOtkZCVrzHhJ2gW98 msg=u+VxJp5H0JPMIHWhgHhE27LCy+Yi9Zhz6NPYm+mb6HdzoskWICXPiac4XjbvBdtP7E1CGiIb5MaK1JWaQwf67A== sig=z8Qz11FHsKSjqI0wA3YlPqZnIR4wVRHBOmMF/pdy9yLr31xipzrJJSqHF7uuin6uVyWk4ygHdOoz4b+hJgDYDg== e=found last=10 s=32 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAMfWtTtz4JLILkUh8UhHW/86GrGeg02k/wL1fq0Yl9Qk= priv=MC4CAQAwBQYDK2VwBCIEIBSCZ3huUUH8ccjilK5MUo7HwUso79RLmBQ0nJCJ5d7V msg=rrAEc+tOw4dklgT7RCuJY0Yf1yYa13BpSbZTNwTREoTQ2a0j3FGPa2rcyNUYBmw7MUgNu1jY/vdS7rAUgmd4bg== sig=i7TAIFtrQnpTdI+4p1ikjvPjrgYwk1THr505niN9DSYY423YhY+r9NAarbAf3m+NYP8d9HjopzOQ4638zt6/AA== e=found last=10 s=33 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAH67SSmFE2UoeCllSBXENGKWgr8UhxEtMSicavvc7iz8= priv=MC4CAQAwBQYDK2VwBCIEIEXRHvPKOKunEplY2SlS5Ot1TQp9o/Qx/cG2jzwpLhIP msg=RdEe88o4q6cSmVjZKVLk63VNCn2j9DH9wbaPPCkuEg9JWERFb9rJIzqNhzZX9BpX18895TmFP4wjAFK1xLbrWA== sig=gLUZNaZQP7V5yyaQDDiph9UH/Lld0yuPyYihJv6c0QXXdhleOuJ2Z6x+S6Y5hqWDWESgoJjVKTMeWn33TFLxCg== e=found last=11 s=0 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAu5/OicpI/dl3JKhXW4/qHe3zyJCv36g+YdMxevtRoac= priv=MC4CAQAwBQYDK2VwBCIEIG3rShHEhyW/7wK90qhoeatkKD9y6Spih/9vPJyyWs+p msg=betKEcSHJb/vAr3SqGh5q2QoP3LpKmKH/288nLJaz6lpki53PluycjHivsbNs3oNbqHYYZWPEkIOuZVX7lQbCg== sig=CBW5muCujXDu0izreGTdqNB+7POtAu+DlfMS4DnzQDYtlgxigHW9AMoZRgbXRb8Hx7IieL8lNtXREBSSWB/WBw== e=found last=11 s=1 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAJNy7tOGnvPNxR+w2xU5j7Ff9H+9dabmFhMFIvFYc2qM= priv=MC4CAQAwBQYDK2VwBCIEIL3e6NSAIC7j5FkEUWg3LsXgk1LXHnv0shJVGGPfZnqZ msg=vd7o1IAgLuPkWQRRaDcuxeCTUtcee/SyElUYY99mepmZ54VwEJi0ntlvcvJhikf/SId/eRRng2e1uTuPPmJdAA== sig=xMnEhmn+J3Xf+qqAAna4zQ58b3/MJac3k9qjrtU92B5S9w/HwPTK586KqEyG+iZgJY4ZgQj6iKRxHKQNWR0JDw== e=found last=11 s=2 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhveHcTGTusRrwHInOckptycpDK2nZdK3wr/so/FHtoM= priv=MC4CAQAwBQYDK2VwBCIEIISGSQ5tjwT9CHAF7ddg9cLLFoTey//xs4JtfQOai9Re msg=hIZJDm2PBP0IcAXt12D1wssWhN7L//Gzgm19A5qL1F44iBNr6rHtK/Gn6NMx4lLM66J2KdX9Eug2M3vE4TzXfA== sig=VInzg4YsPsXdfY04N/z1ZISqePfIsYF66WIvK/GIoSwh7nyIBjnI63zJ8nIZv23yL74ZYp9UA9GlBn2yIm50CA== e=found last=11 s=3 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAr25VJ0Nl8pOwup3LDTv0r8EX2MRFOunoHs6EroA1qCo= priv=MC4CAQAwBQYDK2VwBCIEIM6OoUlxc0zsds3cO9WlbtG2Q7NgLSSGRP3II3XhxaAn msg=zo6hSXFzTOx2zdw71aVu0bZDs2AtJIZE/cgjdeHFoCeV0kLg8ZlHHwxuUsrbfaeaWvoZBkMZZVFjIUShJLLn9A== sig=nsMqFs0WUYoDxi/p6sJCbESzwdtqnMNzseWeIMRsNo8FBDJ6SC7Fart2tPo3b/nW6HZmunMxR/yQI0JTuKFvAQ== e=found last=11 s=4 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAIFzDlBSlMAyII7GkwYCmvCEHdOHzLV1Ar2hnQCYt7VQ= priv=MC4CAQAwBQYDK2VwBCIEIFmyCNCTE7aBDI+GhcDWxu5r5I/+SwW4o7RxxiQjzkAh msg=WbII0JMTtoEMj4aFwNbG7mvkj/5LBbijtHHGJCPOQCFDm+Up4/yjD1+uUTc7hFXXev6CLS3BcxW3UWb9zI1OFA== sig=uuGz6SA+raR32Nt+AkTvFElAytDC+zVcvScd+w1c+4wi6HqsLXc3KHeJDFY1cEmoosML3cLno1PHngsai55hAA== e=found last=11 s=5 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAPkvPcRmCirNxX3716nKRaiNXbeM6XmSYAXCE9WjDwHI= priv=MC4CAQAwBQYDK2VwBCIEIHkkjPBbn2dlOmQDq0ANs5W8o/oRhJNjKKNOq12QmYBf msg=eSSM8FufZ2U6ZAOrQA2zlbyj+hGEk2Moo06rXZCZgF+0qprXj+WrnmQr7sc9vwcFtSzfnz/yLFFZeCJ3FEXKPA== sig=diDsW286QNlKwB2pfRiFydq3JkAwD34hPjWNJ/Z73fGLOVuJ+OqdpRs7SgNGbT5y/IRRUbxt6Y3K27upV2KqCA== e=found last=11 s=6 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAKO6JRIkJeYzB6x/cJqQTKnHiUgPWTlxI+G+FP08bOuE= priv=MC4CAQAwBQYDK2VwBCIEIA+YF4XsQiyJA4poxuKSBAqMOOeqLCi4l1vieHL1T8js msg=D5gXhexCLIkDimjG4pIECow456osKLiXW+J4cvVPyOwSbKg+8JAfE0yylUcCiS00YHROutOHMMftU0XgzC55ow== sig=SkyBy4MgE/KUzB1+UU4sEwIz6/xzO8Up5Jy9pj8j+LLN7xYLSShg0de3E81U8f9zp3y0MlLg46JS2YqC5UavCA== e=found last=11 s=7 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAI/9xOLfZwT4OhWPuEMmAyfS17KxKNyyaSWhUQOedDQs= priv=MC4CAQAwBQYDK2VwBCIEIEktvOGcSC57HhkT4tCoM3cNQDrDssUX1MGYfeivwVno msg=SS284ZxILnseGRPi0Kgzdw1AOsOyxRfUwZh96K/BWeimiQptm8+D0PgYoWK5S/VwMGAAJRc2ZWOi13ngyAdmYQ== sig=+WQ2XEQ1bEWPH4KPqqtJ3ZJYoC1wLE/L/GR3GrxGo15i2hOKADowbq9dQCujCswlbOs45XmEvR8glxdLfBWADQ== e=found last=11 s=8 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAH3pupeRM+ImzqeXLRZ3KiBEeGJSixQLTn3HwJELBjpw= priv=MC4CAQAwBQYDK2VwBCIEICjT/cTsZKT114yKU69XFquI0Z0Dzo4I3stF1idrr2Gt msg=/cTsZKT114yKU69XFquI0Z0Dzo4I3stF1idrr2GthwRqvQLwzJy82LcQToQFSSZ7/Awrm2pam3rm338R684iNw== sig=dfhrEjDsXrfr9Xnvx/y4F0E10RFdrnlw12Ab5Hv9ZLNyTZGj7MeoHDXDiE+CbmU+ChqXjO2mlyGQJpdLC+WDDA== e=found last=11 s=9 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAc1lTNNekCBSQgBHSWKNSsCigq3niuuEwl302agk8q2E= priv=MC4CAQAwBQYDK2VwBCIEIM4rllaaHYXgHpngGLE4siGc5CjkQrjL5YiDCF/6ChXe msg=ziuWVpodheAemeAYsTiyIZzkKORCuMvliIMIX/oKFd4cJE0joNoVJzm7tJBIiV6wgqwpCF3DQvD/KLm153s8HQ== sig=8dh0R4fSgyai+gMaqtqn1s0IOZ2NwUgyhqk+HgGPN+GwU+Pa8zTLEpEk6U5C4MFnifD3pGheNuTHFV+Uoz9QBw== e=found last=11 s=10 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAa9JM+bSVNb1HGtugdGUMFvaNheU4s4qILCbQOHsYWM4= priv=MC4CAQAwBQYDK2VwBCIEIDzng9n2X0ZS4OUh4mObO+D/V69V4fdcVRBJkVqdIeWf msg=54PZ9l9GUuDlIeJjmzvg/1evVeH3XFUQSZFanSHln9txvxtqC8ve4bvnkqx5/kAsvO3SN4s+1BaO8h/SskY1Eg== sig=zcb3cvMbGkfWmBsvPsD1Kij7tB9SCzeYtAV+nv38epl/16Uw+I9mnF99AJ9lQeI/bbH58cB/ky73snArv+lMBQ== e=found last=11 s=11 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAFf7CWcNudycFYYLUxzoxK/eL49YfUfwf8SSPZhgJmhw= priv=MC4CAQAwBQYDK2VwBCIEIOqbiByWozm8sTlavmtfCeMPEPQCtZ/F78x1RFA4ZrbC msg=m4gclqM5vLE5Wr5rXwnjDxD0ArWfxe/MdURQOGa2wogAVidgOfekO3a3Uo0NFYut7E7FDQeWdPlCCFC2dPdJ5A== sig=+DEgL2lID7/Aar46WfIH9VmS8rXj30jHCau8oIJO85FZLBI8lUeZkIF9Ryk110q//nE2Pz4xbD8jYziOU7TyCg== e=found last=11 s=12 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3usUzG1o6zXMXIioxcnkIE8Sv8+q8tnhPTOQoWl1zwM= priv=MC4CAQAwBQYDK2VwBCIEIH60m/gied7HNipFIyKQga0UIum65G13ivIdgYDFco3S msg=InnexzYqRSMikIGtFCLpuuRtd4ryHYGAxXKN0uEPonimdv5MeZu9eAvNAtxhJTndWlGsNIT55ORIA04aWofp8g== sig=M3jb679zGQrz9CjMb98spOevNoU4NurvQp8Yg/huSolc18+KXWPxhc4lKC/ne91oCk20wAQx2PEd8iSKu53pDg== e=found last=11 s=13 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3aktVCM10MLyCN6qPw0jpH16edO7bw6dRXE8RLtym4Y= priv=MC4CAQAwBQYDK2VwBCIEIGmcWwMp6Hg29CCkpRPRjcIR02HYYKvDzYVc93n6WjlX msg=lPzLeAFFj03UdUuhPhGIi4vqKZj0rDeXYr/WXD5AWQxZvdfgq6glA9/yY9sj0xgZXq4UOQ2QjkNQqMpjnaPBPQ== sig=4o6jr5G8tRdT791yhVTLLoTuxdM02ij0wobQ3tcEJNrsdYw0u7Gljy3wMkqKCIwUsQc1VxTEsIU2pBDihYtMCQ== e=found last=11 s=14 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA2xsG709fe6bm0YpBA4zFyLSPnFCDGv3gKLkwXZiZrK0= priv=MC4CAQAwBQYDK2VwBCIEIOhf6ZkMh9muvv0af/JgYcjjh+K6STn5/lbKIEspf62W msg=d4yVHg3rokgAPMagYLoGPQHlfzDB8fmKw9+CAyWBUaQTapJhUsg2eGFLsyd9e5L3723nbKIN6l6YhrMCU/si/A== sig=W+GWFQQcBX/JC0FvpCPViBD78ZszJMijxRKcXtRnpViCdP39olXgiccICN3Og/ahoUmKTklL0Xni+0287i4wCw== e=found last=11 s=15 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAB7jTjiu6AluKWhPcbMJFxoAi24wtHKNfMU9C1PniXSM= priv=MC4CAQAwBQYDK2VwBCIEIO0ZoqvZg5pH2i2txjGUfOVOLZhWbRTaS/HkjFhhXMpp msg=B1jtFojanqkiRmMRMBcHoXrq10HWTMQGucvBd5JOg9r18Sn7GQ62tH/365AZ9UcPR5L6SI45gkRyeRH0GtfG4A== sig=3QDiyWD2EzAYzHcu9oemchtN+nJHrqsfs+VUP4Gnx1CPEAAhV3Yrb73pk5uj5ZNDuL7N/wKGV/j+hsoj/FOaBw== e=found last=11 s=16 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAD9bVrh7QvLnO/2vh5Ssv1pMOKjVKCIOUeBZVxPANJ5A= priv=MC4CAQAwBQYDK2VwBCIEIDaRkc8G43z4YX46iKJWbtML0Gd1jeB5kaYHAhsV4boj msg=9Nm1ZwF9OHaO+6c8byxT7DA4WcWmRqNbsY6DcgwAqp6POSpz9GTijG37hrjxNUa8u+e514XeU6brDx2OuM3HFg== sig=AMm+NxaFB2ERAG+C5Js6YH0LuLfxdXaGjgUB4l4BypQuAIPFRWECPDUPiKFtkkLd8m22smwXWzbBeBQmHz4aCQ== e=found last=11 s=17 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAwPxVooOYPATcnM4+VVuRFH6F211N1I94pjL9FQ/qaVs= priv=MC4CAQAwBQYDK2VwBCIEIJgyFhII36qr5iVvqnS4v4dyUnhfsf1mZo/zv0XW3XY2 msg=q90lajF+u0nS3GSLKARwD9aM09QA28S/HLsAiLB7joHyAEJfFY6ys+McToGXMbHuAyKAUXhgY8J3pCKuJGH4xQ== sig=9VWMtuCUJnWwuyGKqfL5oVMc7aoGuhtQmRsMsI22UCInlv+CwozmbZ5f+JszP2oHVW2x+oACsuSkn/m3TAasBg== e=found last=11 s=18 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAtty5UzHE5OjNM0dV+Un73nWCEpEX9SXAOtdVvnKOano= priv=MC4CAQAwBQYDK2VwBCIEIOuJCXjVfdEpSxB40cmWOEHuN33Vs7XEgKnzXyVQuuus msg=fdEpSxB40cmWOEHuN33Vs7XEgKnzXyVQuuusU2CLaD8AYY+2HbObQnvSNxavay7NAVLA5wcjtlsRbhBfjdqeLw== sig=1QCLxLtalY+yUP0xWuMOhdpl73+Kbkb6OSUlLBhRudgl+EwWbeODq8sefed87M5/eU4bGXJZ1AQbYlJTUrxLBw== e=found last=11 s=19 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEABIzpHZ/q2FRYIVolgXSty0IIV78SbNgeixUAK4dHqYc= priv=MC4CAQAwBQYDK2VwBCIEIESfQP8ltDEK09sdBeuBdJCWCrZ6lzRnV+vJDeqj3zFX msg=r+Dl/d7mrsmd+1hMVv90ptjpWxd1bQQoITnm9bZHuvNaoTHpOAlhUU4wImOkWcWDeDm8Pgbw8swYJX7AxVwNpQ== sig=9iILIdx1HiCpfk9eOEhb7OA1CJzb7qhBfgc8PXX5H4H0x1ekMC+zgNDRxmbg28BiHq5Z5HWJxQ3fDhFZyscUAQ== e=found last=11 s=20 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA943BWCrqddCPqWxp4I8Mr6jC/QSvDw46c5LdHjiBuNM= priv=MC4CAQAwBQYDK2VwBCIEINSb9/HJM6D6V6RJ236xkdOc+UKQz5s+/2KqNXL/KeS/ msg=msRXIJwIyDJrD9orpYMn5gLAXT5jswp1DeryqWxnK9teF7Z9O+fH3Uu8WI3Um/fxyTOg+lekSdt+sZHTnPlCkA== sig=snNCOoUvGWavs3R2ZqFg6Mf9Whs3lBTPx6200KKCReRpuM9vKu9q5U6dt0bhSGdr/K+gPmIwQYAya1OsHcbACQ== e=found last=11 s=21 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEArvDvmY+Xw9YQcMFLZfkV/vhO4dx0V/y498nZZzw9EPQ= priv=MC4CAQAwBQYDK2VwBCIEII8C4L9oKpu19vBJefVwskXJhfV2AKEgo+cVJnSd9kCI msg=gdAv56cM6JMyIP2txs0MPQjS5qNtJ0E00Bc3ba7ya2qvZvl6kCEqb9JYCyXglwWFFuYsnfRHwUgsZb9B71w6iw== sig=2OUWoOnrcUHb6IKYJWC+/gKiMojX2JQ4n1RamPgYKDgbb2zdSxDE6vu2n9DBcvi6Rd9Ys//OSw5lYWAFnqSXBg== e=found last=11 s=22 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAjZ9fo188feZ3Ek39EpFAX6OC1rE7PRUBZIm2Eyj5qCM= priv=MC4CAQAwBQYDK2VwBCIEIPwXJLdsjJEJ3Q6q84asxlWJKFZylGNaeUpjndCVgEXf msg=eUpjndCVgEXf6n9kNyIydJRiGK16gGo0+8QJ8MzV3vKLzBBsbrBQTL7KIzrKXtoIlH4oro/dDaa97VU+iycDVA== sig=gURlNzID2Em5zuQpxi21CP4huCT97DJfKVJNtJKiYRidUJr0M5Xg2ffM0ySoeaHaw7yna+Bp0uyFIn3jg3idBg== e=found last=11 s=23 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAOff3r56/XDlzQpcmQXsAaGPUJXoTaMxWT4JB3QR6ApQ= priv=MC4CAQAwBQYDK2VwBCIEIAT1wftFaY+xSWt5vRqkwKReGc69fDuyaB4+EHlDEED7 msg=irBUnXl7Wt+f+6eAK8skK8L8jZne5GTTo2KTuPofbTdWhzy/aDVHCwT1wftFaY+xSWt5vRqkwKReGc69fDuyaA== sig=S7+EnEEp21tm3fGPMJ1j5RFX/lCLU5OEiCqfZWzb3TrJQqlPdoIsOQ9DX2xC+QuYbM0rcXmGb8/cjenqLs2bBA== e=found last=11 s=24 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAS8n5JxAl5aXpOc6IumYPgzaq+EGhl5gCjv5/SYteKxw= priv=MC4CAQAwBQYDK2VwBCIEIGacq7r9Dvz0HrcROukmNgn70AtSBbcFgMuNhTmKnBJY msg=TsW39+nqc7muxR8fEoh5da7fERd48uVnbCwLB00TagB5w/c7z17VwlPT02acq7r9Dvz0HrcROukmNgn70AtSBQ== sig=o5Bg/3GLULzpO0rEJVFA0pCBDvYt9qv19jDxq5kSG90nKpe2TZaXBbgsu73rXb4nxZGPYJb4cCKafprI1fC+Cg== e=found last=11 s=25 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA8AacbY1mAXw6ibYvCdT0i7rKvzyX8f7UXcUjXjcdYIw= priv=MC4CAQAwBQYDK2VwBCIEIHEQL9at1ZdynBSsKcUXHmvfuPD25T7Axsd74VFV4fqW msg=Xg/2qyCC/85dy0DK9JqfHHEQL9at1ZdynBSsKcUXHmvfuPD25T7Axsd74VFV4fqWZOKu+oF4v69YU80WKyj5Dg== sig=GFMcZKo9UlyW7lc8UPohXh6ER7YPaOILejFp+aunfuojT4mFwSavoe0GLYM0K541jL2KWfeHYOtOTTbRWCiwCg== e=found last=11 s=26 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAX1TNuehcLRMwcmoD52UpA+7dO4dM9ip4BO6ukXMbJxg= priv=MC4CAQAwBQYDK2VwBCIEIK5wAdf7UrMleZOEcaesrsQpd+LL+YjBSVolCkHoACi8 msg=TkSuKdge6nb2Ehjk5q5wAdf7UrMleZOEcaesrsQpd+LL+YjBSVolCkHoACi8t/KfS7UqhywLQLaJ93aWNsmLig== sig=LW9CVbobw19sk7FCapc+KVxDDb3800c2YqDkddE1lVpYsW0lcv4DxtpjsSBOnVwQ6DKuyYUxYk10Lh15SoSdCw== e=found last=11 s=27 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAHE4LmYF4PNv4lxODWJuxi0A0j6Pj8PSwmz+Y9ZtPdDc= priv=MC4CAQAwBQYDK2VwBCIEIC6uLj4tMpwKL5fDGE7AcY2ooEwIs4LZpWBCJWoouWA6 msg=t5xHPUo1BHNEnxd6aMzS2oqWinNSh07fTC6uLj4tMpwKL5fDGE7AcY2ooEwIs4LZpWBCJWoouWA6rA/t+ob7EQ== sig=su0Mw63Dnu5GVTV8O4q/5Pa+d2aFe0z6PP/mMgHimh36YMwWGhEbQLjPbw3Cm4dW9i4Z2bZ+ogHXsPjSTcUMAA== e=found last=11 s=28 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA779LBUMedNNSCjX7XaLV/Md8xwycxhVbc+YNqJCcqXw= priv=MC4CAQAwBQYDK2VwBCIEIOW/k5MyjvrrfTAoSRVTjhp9URY1kQDUUJReEy/sHPPO msg=ANRQlF4TL+wc887mZDCtz3hcxVDaP9pMrI7H6toaFmlQUJQSz3xcyo5V6lYaGOPmtHtBPpY2ZwI5aLtIcj62rw== sig=4hkPA+RDygUJoJGkvdHSqx4UTAP3o3bxEEInC318NIzM6HDvhiAWGBtRSiuMmQ+O8AOwOO+F9XIENUrc0VeAAA== e=found last=11 s=29 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgMnMT/vNMyNUnUKj5xdwUp+/m1cVN4KWKM3A/5HU16Q= priv=MC4CAQAwBQYDK2VwBCIEIFdLUd2yZoLmyA2/dDyQlwySeWeZ//PW0bw72XNqoz/U msg=9ZdUu4BL6c+GvVIpp1aDN/Sqj4cKJqhOmz4sxPPj9ZySNTtGuHHLHlNM5U1B/lZDvYq9fI72zndmFITt7q6uwQ== sig=J51qu/skXQLXLwPlCs6ewjUBX4SyDzMIjwJ0i/SQKUSD4FZbtF7oHsgB1edbaXFZcW5TWONwVVPdiRDW/xBZBQ== e=found last=11 s=30 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3guKyasUs1kozD8zvM0VirHC/VvewiVDnd/LiAy4JaM= priv=MC4CAQAwBQYDK2VwBCIEIF4cs/YxaRQLBsJDD6R0kFwhYSm/USQU7DiBzeSSUTgQ msg=Sn84dQ7/d9AFVW7Ti2rvhhyMMp6j4AEg/Qvz7eBJBAkDMTEJl2ZZOpqRGq8rJT5uZlqH2qkMTqN+99AFNuOtkQ== sig=U3/i6yeIoSfTWUBiowAZKvdm+EpgYHuAcUGKd1yacBcp2XlVcRfrhqW9SvV7ajOzfMJ3pqSuNisQY8jz7LoZCw== e=found last=11 s=31 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA1EQS/jv1XrsTnfSmdX8gfigRaWC1ijFu58tWErTW65c= priv=MC4CAQAwBQYDK2VwBCIEIJCV35SkiqOXeuk5neoQqoaJe9vRx3CyCyHsMRTOZ6uT msg=xyOc2VeC9hIbFA5PyRLA+8EpkFeampswlQztLvvhYvFXmoKbyXzh13x2fjboH7yeTecXVnYtFMPe/zIeqm2HcQ== sig=vBbWaI0YnV539dv6Rp9lI2uhTLODgkdfWfD+ygbRzTiJtjvzHLxyZqmpVWZCjOzk8dQKrCn85S5hm76AzXHnAw== e=found last=11 s=32 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAQm8JYWxnvtOOnXzqq59esG9rOsStg28BD41SN9cJ8wc= priv=MC4CAQAwBQYDK2VwBCIEIPXKA/f8wAoOvr+TrSrm2FQYl2ZHGWzhbLLeH2HH2w07 msg=bOFsst4fYcfbDTsy3+LB4QyGTWocVGLCcCf4MgOkNfs/Yn2IL+6W8yvBYyyl1l2bE3xS3YgwLu6Ro2Xyl5sMeQ== sig=JMxekAUV0af5UqMlzOrtZYw4sGOmQzdNDN+PYimZlassiRyj1OG73kn3QnPQ/llCXSPrSHMXbZNFVUoDxpCxBg== e=found last=11 s=33 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmU/ljaiwso42qg+bTDFhnMeZFySmeJT5v/YEBkiRD78= priv=MC4CAQAwBQYDK2VwBCIEIPaZLvV/lQOMVNjxxSy3B7FoQxbcrY3/OpKBOBpW2Fe8 msg=oMnEI71JUEBpXB4uEFIkYmVr/Om1Rf4Qvwf3E1dd1DHYlGK/brEJ116MS/XuWqCkZ5n2mS71f5UDjFTY8cUstw== sig=CTe1opltJKHcucc3in4z2ECuTAAXsWGMCNZKm5XSYYZorSEStRaAyhB8q4Z9hSME/Xu12pI/mcbXKb+opkbiAg== e=found last=11 s=34 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAW83IcFI5yOFvbEWOEBVCCQj1yJ5vB9NIKJvx3GIkJmE= priv=MC4CAQAwBQYDK2VwBCIEICy/9Ak59X8S+T9ewx3tb+MW3C6IgxEBfHSIYjpLJBLx msg=LL/0CTn1fxL5P17DHe1v4xbcLoiDEQF8dIhiOkskEvHlU34MeNgRu0cpgfu/vkEdtXcXkhZiinDP9f36sbUf+w== sig=NVD/+BRF3SbF64JUoMdjkMfa9JAstToqnAFRjKFjaN21jU9HpJyOdU9XN+f+WLD9XM5R5pGN35zt/q45cYdHAA== e=found last=12 s=0 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAEm+9ZGyK3v1OBkrllTnZfa2yWaFEX3qi6r+J64kSvS0= priv=MC4CAQAwBQYDK2VwBCIEIN1pCRQZKbQ8xVDd66JoBvdnMTOo2oY8ArqjUKXI+x0w msg=3WkJFBkptDzFUN3romgG92cxM6jahjwCuqNQpcj7HTCM1uAUjADKqaPRumnYJBgxbrfTPf/E9YyHK3CvrEsB8w== sig=TmreIp/joleEZZ/opU4I6PtJRBnJXdRYSDJF0wUeupIH0GwhIrti8kwtG8d+rNcRwiA+ar3c1hm32bcVu7LRAw== e=found last=12 s=1 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAFJeeUQg6+lZPMn+zMjq36V467RsPidke9a78aRS1uu8= priv=MC4CAQAwBQYDK2VwBCIEIK1akVONTOBoIMqRQ63fgUYyj1o7DeNdsKrC/Lgcxbfm msg=rVqRU41M4GggypFDrd+BRjKPWjsN412wqsL8uBzFt+YE01vYgpe5xg9yFRAIOWrLrm3bSottKXGqj3P0gPMQ/A== sig=5xQ2b0uRRudIlO5LFq0sAbtHcndGyrPzdpKpPGJikm9IjtNLQ8K7UU+uukA2sowTw1Dpl9+080EBdzd1rKVGDQ== e=found last=12 s=2 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAOSK27uFAUHEz+iej3U7ise+To+dgXlZj7qdGIc0pBk8= priv=MC4CAQAwBQYDK2VwBCIEIFsjV9xhZODpsNePXOBpgpvJIfbymUV3BmP42IJrE8sF msg=WyNX3GFk4Omw149c4GmCm8kh9vKZRXcGY/jYgmsTywVU152GWVKE7CnCs0MRGBqvgIMkt48An0F1EdfEYlQUKA== sig=J8gHAPaOT1C1szZVLg8ZyHDVnmBgiov461c12M4AadegzaJNW1BzfzKRiHh5zKTUkbKoseb9fL1DDMdI2VyfAA== e=found last=12 s=3 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAFTSYYcPJ9QmYXPbA7v6C6hhnHpqDL/xUzYUX4DnIvIA= priv=MC4CAQAwBQYDK2VwBCIEIJ7nDv0NCDAiv9NyFJSIqxvDmP5lncPm+lbmgPF5Wdaj msg=nucO/Q0IMCK/03IUlIirG8OY/mWdw+b6VuaA8XlZ1qOHmhVULN1J+hL7AHJGAmNP2ZLk+XrHZb9Hp12Fgs3TFQ== sig=csuWC+zoLp8FvnYDf/8xq4bWUmGYn+SGMStgYBgAFrOasBNptsPpaN+x0BcDBnJjNz5MSO83XkSAQOCXvGkhBQ== e=found last=12 s=4 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAtivgcUIUUJhkhbDl1vFfz7Mwp+HbetVfxSeuGZr6rus= priv=MC4CAQAwBQYDK2VwBCIEIDg7N0fOrlK2drBjkm005gAM+awo73mzXp40X5CZvk0c msg=ODs3R86uUrZ2sGOSbTTmAAz5rCjvebNenjRfkJm+TRwi69iX71pfV9gLVCh0f+nZRIsLCbyUWGuP2ifKiwtX3A== sig=uf2UKrhJryRYbIXF1aEyxyHUKw9nG1fU+K50rNudXNKPftgH+pS0u+IO74TPS7Z1NZMRa17G3JbwLuGj0aPTBw== e=found last=12 s=5 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmzojeuftrTUqKbXSsvym3Av9JMkY0KtljAKjwNfQ0BU= priv=MC4CAQAwBQYDK2VwBCIEIPkUAa8PUdZ224AYbJqmvjbW8+sqWcCplJxNlNpK91ul msg=+RQBrw9R1nbbgBhsmqa+Ntbz6ypZwKmUnE2U2kr3W6W3mDs8Lkp+C+deHO2msPKMarqW+gDL0C0nLAzClVARRQ== sig=wwtxSI4FQ6Q8t6hvv1Puws91thvXs40WnBvyTq4/9MZla0l5dMiHUc12akkBZpZuPAMMTQzfjjEwp03eqqp/AA== e=found last=12 s=6 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAequiZMG1y6AaLfMFdLm4Wbf4AIJv49lRhxdoRq4cGGc= priv=MC4CAQAwBQYDK2VwBCIEIGtSt5c58QbHsuU6GzR1s68bJLWxeArMajBfmMnv0fE1 msg=a1K3lznxBsey5TobNHWzrxsktbF4CsxqMF+Yye/R8TXvQQ0N4euyI2e2aXObt3x38ZNMgqX2qq5KoI0KmOdtQw== sig=qlK7CB0SBHNzEyUnrQMQcRkUGBGk9E/lBb/oqD9UF4xf+FLyFrMQIqzrWe0X7zM+q3ctjba1n57OHCQmgqQuCg== e=found last=12 s=7 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/ULn6wzVVVQq6kGbfA0+E6TuBtDbS63UeWDmPLZc0hA= priv=MC4CAQAwBQYDK2VwBCIEIP/1OwI1xl+dz4QwU0I97vMjjXmoeVnIEJDNH1eznu+9 msg=//U7AjXGX53PhDBTQj3u8yONeah5WcgQkM0fV7Oe770O0j/ZDrFplGEMqnOXJldC+kfBoZAVt1joyh6YHvnvkw== sig=FfbMX4SEZM9ydqCtMPJwoeKjW+AaET+BkkJ0m0J9Piv+Oad9Pcjw8DnsU4zShVN/ZVuvu6rrPavbToSSMVODCg== e=found last=12 s=8 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmhP6v7V5ugQBoAtgf4d20a5KBD8VyQhL/CL+hGd2vdU= priv=MC4CAQAwBQYDK2VwBCIEIBgyzg9CuNIZQm7+1IV4iL9pSK1sinOwyDIJ0k5UNS/0 msg=Ms4PQrjSGUJu/tSFeIi/aUitbIpzsMgyCdJOVDUv9Fj+z+hVCe9D69Ptn3pJqux78REOUb5xzgpIbt2tOFKF3Q== sig=UlGDokcJHqpd6cEUx7akEsYUXF5/rLz25e5MhR/t5SRLv7ufFkFPyGG6r94RlPvtgeG6xMtpW2rBioGMMOFoDA== e=found last=12 s=9 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAepAtZIq+a6CM+1vDB51EVo8EwtoDmWXdgFWq3qigo60= priv=MC4CAQAwBQYDK2VwBCIEIMwtOfx1KBQfSItOIP+zlIClskqD3BIIBCLUWDiWMmMk msg=FB9Ii04g/7OUgKWySoPcEggEItRYOJYyYyTw15PeuxBl8wt7V+S5Z4vbfjsIF8nS4MHqWbYVHNewk5i6gMvaTg== sig=MZpuu8Iredwb9MhlYcABX5K3rTsorsYaEywclDfKmSFEWDiTev8jYnvz2bAmKOoRacCUHHB0zDRvt8DeM39tBg== e=found last=12 s=10 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA69Ilg5U3k9/aNFsWzWUyePGvlJKy3YQo7j0OziyLmsA= priv=MC4CAQAwBQYDK2VwBCIEIDA8TW4d3UT0SHVEkpIuQJ26Ypq9czE5V2dPosi9n3rh msg=RPRIdUSSki5Anbpimr1zMTlXZ0+iyL2feuGJlvvx1ZOft2R1NsIgUyY0d7e23xRkip8eKv2C2S1fbcVODaKUJQ== sig=0YoG2ZEEIrzSJsKxx0UetO2rZnL8TtiSRbJivGfqksdhusGOrks6cHvQuvMB0gixdydBzUDowwqXm+vB/qtSAQ== e=found last=12 s=11 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAJst4paVQsxtSI1xhRPvNW7gg8B6aAGwmIrl3tqpv1jA= priv=MC4CAQAwBQYDK2VwBCIEIMEFKNc+VI4o9kJ919b7xnmRoQffnODUS3A9HlGuFsdC msg=wQUo1z5Ujij2Qn3X1vvGeZGhB9+c4NRLcD0eUa4Wx0KC9oAgrfoBHeYnjS8cJxdOhZRZqPAeEG/BxX2RgfJWwA== sig=TTTycy9qze/aY5Vwx93WEYClLWYLnFL4TncJ937fVVILRwI+2V8yBS01LYlwj0ID8lDd+HxDTvhOId5NcnU1AA== e=found last=12 s=12 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAo9fwcEHKuH11H/JsQDk11kQVxtot2R4rxMTF19TUabA= priv=MC4CAQAwBQYDK2VwBCIEIOloRnMarNksIRe7EJnvv3pkg/yxneqP9nG+NwU/KWx/ msg=X5OdrbYcf6fFvEsdY35n92oy7ygmxXJF3axPP3GHlKKLqlpUlJ+Ah68pKkFHf2pbupCSCdpxPUQxBHJEbkAYkA== sig=98LPk1Qe3lcnNlwXX+DiKDK+d+PDR9TBFf3n1f+f+W7YVsRe/NlYSj2VHzgXS9gqygXpk6q88HiWKyDeO1/jBQ== e=found last=12 s=13 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAZPbYTPjv7DY4oZGhMDQKETWh3yPc+HeTl5eZFwTI8rY= priv=MC4CAQAwBQYDK2VwBCIEIDAZ7t0fFxVb30Qn/HhzzFdQxOA8f5NGWpGLXfe9cQjp msg=QLKbwsAYAJjAPnVDhgZgVlGKAOTm5v/5+ZYwy8hhclFbAfbpdClikuw1/DL9R9EPcuPKlPtQvNYoDD7MGqVI6A== sig=CozqDl5GV7dD88twWjB/0bgvuPM5wWI3a4HQoOwyR33NLisM1XdVnrYiIXP2s4Qc/vdTnVsFh6/CcLZAsmxHDw== e=found last=12 s=14 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/Kck1CUJbr1/3T5cr7kLrdcBMkk+FPEvYBFuIF1SHqo= priv=MC4CAQAwBQYDK2VwBCIEINHyisn61/t+tWBse5UEP/xNO2QcvhCKZ9kku7djemZH msg=e5UEP/xNO2QcvhCKZ9kku7djemZHaEYu1RyXEdSQ6ttS7KeBqUv5c+K4p8NtN4xOMmShW8t+6jbcaIsEYndzYA== sig=5H3GweaUrPFECqwsKJCkH47Y0/WGRzlJM4I/MLpdn0lV32j37NYEnMq32+P+bG16vJjCSfp2/ktvNRz6rgKxAQ== e=found last=12 s=15 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA1dxOtQWuKls4NylCfsLcgvtLSynhui7Awz882Eqhmbg= priv=MC4CAQAwBQYDK2VwBCIEIBDbu4zBmrY++EJ2DhcMk+6ypPfT4BTBamJnQs7ysqZS msg=mrY++EJ2DhcMk+6ypPfT4BTBamJnQs7ysqZS1THQPXP/8CYJqKCaiQtyeKub7mxOO39C0aLD3YG1BcILR5WESg== sig=8Kh9qxOfD/gDqYZwHI572L/9ofvdPnwV6n1xulNhuqYCDYMPuy3GvuA9b6RXKOBlYbBqxmqfwwC7RodoY+q2AQ== e=found last=12 s=16 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEATJMDnSuY3FTuoIs54vbRLSgqd5rnd007B7bc+K6sJcU= priv=MC4CAQAwBQYDK2VwBCIEIAD2g7JPRKF3+zDLSZn75cGesg7l5for7yVOCS6y3/tx msg=5eX6K+8lTgkust/7cYKUxa6mcvt+dRmCOVwsP4Cn09E8QbE5TCH57TN2kcAkWvUIMbGHdtb32qToyObyIfTuSQ== sig=R/rkvbOp+Ce4e3fr224ir98dupq6jQLFowMv1xMCbLvz+r6QDcNRw7Cxet+7JQC8co/P5qhBUwUyZiNl8qX2BA== e=found last=12 s=17 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAHGMP3MXWwAVS/kaf79qjrTKpe2hVwpUtkuSRfKUTxp8= priv=MC4CAQAwBQYDK2VwBCIEIE41vi4rwsZ7xnn59DSpySOLBJF/0MNKGniVzThv0Hbs msg=p6ifOZ1/BNOnjoErAcPgQaZTuxaqvA/gZmcGrcu+jYqrlCMapCITN3ToX7OpqxPr53Fk0VSxQWgACEegc0hSCw== sig=boTwhqxV08H/7Bi3c2QfPmGC4b8bXE9URd8E5Okqo0fdjPfJN7qPqwxTjQTLqRQUZXfJnD6tb9/ejsr3gKIyAQ== e=found last=12 s=18 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAQtkg0iGRNyPYVE2/sY3S6efT3ZXB6RhbBviGtS6GnyA= priv=MC4CAQAwBQYDK2VwBCIEIJMux46hEtVkqt243pAFevumK7wxtyYJ8zYRj/oOAlNz msg=1WSq3bjekAV6+6YrvDG3JgnzNhGP+g4CU3Oq4tHjrMgeAIsHWXciHLrIPi6UKjlX/1dXS3ydzoTfbP/ZeRGbfA== sig=lydECVEyiqE/w8JoFnxQzDS7Xt1eHQT4u9fTCMDRcXG8U42b2E3Yq5OFACmQKn/oU59N7jrf71tHSjqdv9NyAw== e=found last=12 s=19 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/OmFLvu0O0a2ON8O4TS40VGn0vJZSW42Gg2lm2Erly0= priv=MC4CAQAwBQYDK2VwBCIEIMg/+wMPwvQ0/+qTKt1AqcoFid/0yAuvQ9AQrn92J+Vi msg=Pi9r1cHjxVXVFs7EShcESjWNjRHFTfGYV9mBnCK2GjV2EETY4j40mqxrrj3VX3raJ8ClLPBFJCGX7JE4QpENig== sig=bxO56ImQg+BRwxkUHGaP9HliKV1DCBOljlZQD7srPCxY37mDVsmJoCzOxadANNjnaw3XgWnH4Uycabxv8El/Cg== e=found last=12 s=20 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAIzAZNck1AFc1c4RErSpah+vayo3L+hscNcjO+HhEzWE= priv=MC4CAQAwBQYDK2VwBCIEIOLO6dcp9C8jwKOQ7tbZx57AyuuJZ3T0zF0igVQToX2K msg=ajkRb03guHR56eLO6dcp9C8jwKOQ7tbZx57AyuuJZ3T0zF0igVQToX2KJ+a9at5Zh/Ju7bKqyzl1VsHnZpre6g== sig=eMYCzL1cHPGkilCJUZl4mLuPbUYEBzeMIQcILs63O+Wg6rmmZmaXNVReCBjEPyE/62PKiTro+5+jq05UBRQcCw== e=found last=12 s=21 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAPOnmSUAOJw3LEsxnAbTvJ1Jda3NKn2IzfA/ERwhA6eE= priv=MC4CAQAwBQYDK2VwBCIEIMONbT7N14FeoYPtftKu2kVubr0y0dr/s9bDndTCXjR7 msg=fYmjOCcg+1Z88UphGoc/lgy6r4Ve/WKNXdqjXSy8viUSLVXQR6EB1oZ5cSwU1NUufpYEjb83s0xIzQAgU80Erw== sig=tDi8YGJp2Hhzh8iGNp5ydO+wLyIxRevqHBhizRPHjEhgjLuHmBBZPVBodtCkCGRxZX6LEqcWWL0jLTEIHXTACQ== e=found last=12 s=22 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAfKd4tnhN6rsfQxQZiDLNIIN5GlVWVwHjNY4kAt6S4fo= priv=MC4CAQAwBQYDK2VwBCIEIOcJBImbALp3mbS9SanBcc6l7kaUV5P58ZDFWMco/jfV msg=m+oFP6Xtbx2WmuvkkbCtE8P8kUOOw1+cKN8UGI44C6hW2VJA+b8icAq4rQlu5wkEiZsAuneZtL1JqcFxzqXuRg== sig=T0ufCo9+um3cjh732hy/kAzWCxpXsJSwG1w5ZbC4cVP4ZygxlRWecxA/5WsMVwW3qMbYjU7yF9Gg8bOdyhTVDQ== e=found last=12 s=23 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAvUYdF8RPPcFhFqquCn29vCjVFdvlNJ57DmxsQX692rI= priv=MC4CAQAwBQYDK2VwBCIEIFWmvj6WfNlrspGPgOVyO6FdS7hSki5D/S38xvGZRUSM msg=ri0YKU60+V60OpnFLMlY8dUsE8qGmxkeirNPGtnVqNWLp2gNFHIjzwWq3QkpAOVAA7lwR85HvnDtpYjc1hTFoA== sig=A0jtHx1jXDMApfw8i30L1GmI5dmjNjhYz8uGZVw7LHO6ocPitho0l8a0ogFkPmGm0Fh/xSdYPEcDn+g/vZBhCQ== e=found last=12 s=24 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA7n6N0aLdB/G6ul/WCLDBlIfxmOixL235mJoyaDfBONQ= priv=MC4CAQAwBQYDK2VwBCIEILbXQExs2T1ZP+KQt2fHapAMZNewXwhHtFmpQuDtm2ne msg=YMszv0bGihq210BMbNk9WT/ikLdnx2qQDGTXsF8IR7RZqULg7Ztp3hn1csqGxNciPHHKT0aqzvnJeoz1MaHu/w== sig=SkQ1zvLWEct2dHYH3yAFwSOROOdrX4ycY4eEOoH6TY+9sAO374/dvj0RdxghlGArYmdH9wrIrkDJ9NsE7UIYDw== e=found last=12 s=25 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAlpjggGfj+IvKfrHJVT4sr8jHfMKeAzOsKugzlSUg2hQ= priv=MC4CAQAwBQYDK2VwBCIEIAASQWVl9/QdtNLQdNNkmHCsb6y11nzoD0/h6RDcYd+A msg=mTs4+1HFdIJZj3zDRFicO5M3XRJzNT876agDrvkAMabJS0LQbAASQWVl9/QdtNLQdNNkmHCsb6y11nzoD0/h6Q== sig=+GUcXpmgIMXjHukGMMQO25H6AmGlxygHQw++YmPsUIpbTzYZ78X3lNSrUSp1cSVaC6AdXpzOg4EeVGsWNQv6CA== e=found last=12 s=26 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEASlyElqW7pbtb/30iG639z99G/kTt2xZ05jreOMI1vME= priv=MC4CAQAwBQYDK2VwBCIEIAbY9YnfF0JC+Oo8+qCIC35kK5FG7AdPZQ75MdRx5c+z msg=IkI1IekmAnndmThaZ+ySER6H+Hzdn9eS+dUIE/tJGjFDKpZfZxKK/5eEkEXW7yBJmp+UScrRb0va+SHbBcXgsQ== sig=JF2QMjpcTnMz8UPQ7cJbNbNsiQb/e+0ZzQYZm/9ZOfXxPxLoifQz2cYoXOFQKeJnVwnMeWpmBMnW8OOrC5R5AQ== e=found last=12 s=27 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAoG1e1et824NdcyVNIYzoZKkyFzRREizJ1EcWS7Y9XEw= priv=MC4CAQAwBQYDK2VwBCIEILOYDXNWuaws5z72uuCq+cMUvDIEQQ/7v6DNPcLth4xc msg=APsJZgnIYOF5hhlwMBMzfp05MkyUM9sAvdrdgZWzmA1zVrmsLOc+9rrgqvnDFLwyBEEP+7+gzT3C7YeMXDW/0w== sig=2MRqHwLn1U58A7uICCcAG3Oqp4KschHhCGQ2MKTENgIV7vXCQUwdHaxTsZtPnBEbg7wXXASFepkyF7e+bqUWBA== e=found last=12 s=28 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAuyNaLKSQcDYRFUSfOmkdM8LrXpbZTBweTftg/AJjlhs= priv=MC4CAQAwBQYDK2VwBCIEIBH0Jr7nVxxvqERti3jHUuYIGqAZ1rpjqQL7rP/uX8bi msg=vpTYKheGk+qz8aaiSn+RsZYM0cAsuqtiEjP+Y17niYlh4d1QEfQmvudXHG+oRG2LeMdS5ggaoBnWumOpAvus/w== sig=3LDCKVlRmNGpKuvH1Fx2RzbvHhYKFwNrLkNZIOiXozPqzZzuiQQIm2A9gmdynniH5PRR/rVM3zANySf6AGtLCA== e=found last=12 s=29 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAGieV9F7tI0EbSSdPYENA0m1Ev5ARTu0eRYGqdpln0Pk= priv=MC4CAQAwBQYDK2VwBCIEIJVIgzzDEbosyqseFzZ7QJFxjQiUMe7qgLcgTV3dCma+ msg=cY0IlDHu6oC3IE1d3QpmvnDQL8muUBxj3XSOll+0tsWRbbtvZ5IIKXR3in7CNzdZJWrpnEzZ0QyOb1bPZWJIsw== sig=FXdlfVNjpAJbLBuJmpaWbLUfgpRS9Fvo4V5/chb7JNXIySGcrDYguF7WiMc6Zjh42IAy95Ho1IQY2up8fv+oBA== e=found last=12 s=30 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAEb5rFpjJbMqC7ARi3LG2WE0inazxeULil6RuWr8zilY= priv=MC4CAQAwBQYDK2VwBCIEIPbCxtrfJJmQfskKZTLuE51/GTWKONfusAoTkyg6zioB msg=TcYRfGbWk9X3iCuR8w2Up8rLfUyMYEj2wsba3ySZkH7JCmUy7hOdfxk1ijjX7rAKE5MoOs4qAd6NHwPVwqpwDw== sig=fJ30iTh92YlAKdkdFKjoNfYiNcxj4hHg24zra04P/dQI1Ddjd7dyWfcZ9xDX+Z07A3DHgJQtzEDGvVMfbJWPDw== e=found last=12 s=31 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAyRBlz467LY6UINeA2Dtofbj7W++8xhuhoLtX0NtyriQ= priv=MC4CAQAwBQYDK2VwBCIEIGaX7x4PDTZS8tAzllGR3KSHccJhxtzjCFgrviQvTbKt msg=dUU2xq82I/cXXRbNegr8Gwb9vOgU06Mn50oYB040xBcA5WaX7x4PDTZS8tAzllGR3KSHccJhxtzjCFgrviQvTQ== sig=uF+xokfQPW2EeKqVt6xs9K1xa51HwCjlOGPFv9Jk8Qh9mO2RBuaOSSN+SwWrr3eVOyYMOop4EIZnlfyXtt5HCQ== e=found last=12 s=32 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAcI757lYVXr3vD+c6uVDQtYUMxAeJzbK8ZEYjznz7XGk= priv=MC4CAQAwBQYDK2VwBCIEIM0O33PpBppcHdqMKKi9IHyGPmpMp9dc3VDPBs7CESjq msg=KOoMYUIo+R/Qj1n/J9oCxL54Zgtu+3gMg6ga4vSeeNraFXWJDwQT0yiOsEr0R/mIfUjoYu0Nm6OfOr+FMgz1YA== sig=PD4btTeGE9rO/48lTQ3ajKOvP6zCKiGLVT9nnYRaOC9yXNUNlXPtZY1fFLCyPOcSSD5xrTOx0Bckx7NQ9TpqAg== e=found last=12 s=33 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAPJjaIfpDLOspifabH6D2aDwg7TpH25/VzHGSbtVvDSU= priv=MC4CAQAwBQYDK2VwBCIEIOnr4YF59sc/nZrkhBQB4Am4ENC2H8bpDDlsDeYja+KV msg=iyW6xe/p6+GBefbHP52a5IQUAeAJuBDQth/G6Qw5bA3mI2vilQmDn0qF2CY8/g6QkzVxXu+f/vfastRhJjrYng== sig=qLhDBZ6PhheR36GoZg+yDljuvMg3SzJRfEiv3qo9hzuCPStyKVkVx2iz/e56o7r4c5NmN36z9KrSmf0RzsddBw== e=found last=12 s=34 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA0aF0QLsxlvFFASEPI+6gV3SmPkkr/iZmxmBrNXZCkz8= priv=MC4CAQAwBQYDK2VwBCIEIONNP2HD9Ou4XI/Bnrspd0k6vfLflkWQG7b1gJHMEW1A msg=vw1PPX5U0/JkTyWUUZfxfVs2vW1pObKc+gpbHSozrb9KH2vnc5PmNYl6tkT7YVudp9e/VMEtD5192IlPZgH4GA== sig=t1jj+Lz1pMmtKZq6QLWUQrT+7qJKmoxLAmee0GfViTq6rzv8hKW4aUJu6391DDnEdglctvIm7brb26+tu+yDCw== e=found last=12 s=35 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEADpZMbzPavsucERbuRFdHH3+6JBMz2XTTZ2jIesLl4cI= priv=MC4CAQAwBQYDK2VwBCIEILWt5ixReJZYe4f2XstytJPmTR8y8ZrRZHcZHPUm0NJH msg=XI/HQWkU+bdJA0/tpg6XhEtMsBW4pxfN3GsUn3lUM3rUkCwduAWm90l4uZBFl5c+RsR81Ca3yiaeStoBvo3utQ== sig=C0bitsFOyYAha0A6Vkom/DsQyxZ51abNay9B09xnSAzZncpDbPRmMvDk5cjPiuiUOfcB0u/ZpGoeTbxxxoifCg== e=found last=12 s=38 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAkmn6//0jrnVpn8ogZoIbMOsAeDnZXMA236IoPAeT4b8= priv=MC4CAQAwBQYDK2VwBCIEIMsq116JYX61g8C8OB9OCZasVnThds7p2iZhKPZzfhDQ msg=pvJekBSTmWn5BduyVE2IZDrSMnyyXok3uDq92niROMJMiKl05dmMlCzgoZZ4Xd/SBXx4f8mowqjwMwyxrKAByQ== sig=sbidO+fLkeEQctgZkgNqEvGBxxN+KP/7BuD+AmXFplixpmkgmu+bmqkICf+uhoZxIPixFq4WYaO8DVMyd0wpCw== e=found last=12 s=39 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAG64VYGT6s9NGenUTjjYPHU195IyeihSrCuERKNoRnAI= priv=MC4CAQAwBQYDK2VwBCIEICe71DJWcXWoOp+bfiEuHFUMqUo3UcZGjkNflThdz81g msg=J7vUMlZxdag6n5t+IS4cVQypSjdRxkaOQ1+VOF3PzWAQxItjFNWhWkams4pqdq4L/r6iGvrX8XR7NVBn3xfPtQ== sig=eO2lLJs6Zwk+Qos80FbKQzgbRXL5ZenSyUKdr+iXAy7YBM1lrQhabg6l+ZYbsSSdwXT2ys5uMfCdrOAUMYz8Bw== e=found last=13 s=0 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAlhhN4dsZYSmQiYmbgc36PNa1osuDEmg3VmaOC/ekrHs= priv=MC4CAQAwBQYDK2VwBCIEIFzg66vWe96qbgRK5G0PeTofkgtIHbN9yJOinYNYbSLG msg=XODrq9Z73qpuBErkbQ95Oh+SC0gds33Ik6Kdg1htIsbbd0RKzWoS3OckzdQYSbWfqvHy7cQxYbfOl+j2+75A4Q== sig=pIR2HzA3Z9pVNoSAYKA5cxr1x05y92yJc0XlRPFnNUGLLA78RLP6H0/Yl7wyXIoM7xciCHF8BUJm7p+EjKWhDg== e=found last=13 s=1 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAFsiQ5P1JWvVonc68/C+8cySEt3gJ6R7b9WBqpFaNIws= priv=MC4CAQAwBQYDK2VwBCIEIKNHp5drcjffIf6d4Ya4mJl5i7b7LsoiKalOpSYD27OM msg=o0enl2tyN98h/p3hhriYmXmLtvsuyiIpqU6lJgPbs4xPVuNCKbQdG2uUpvhv5CM7kX9kW/A4CyI8+szm691dFA== sig=YSIJYOb1MXLDSLBitnSBJHyXLGjso+WHY2qGQtnzxEcaSrjoszlOsX7wDK41EqqxEh1QxEzzAERwFCoz9ZrCBg== e=found last=13 s=2 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA97gOtAmQSeK7ARsCH91Mq/7LfN+m2s3VtZ71xbtCzRI= priv=MC4CAQAwBQYDK2VwBCIEIPipiHDZXv+TKgIz5HMkPjoMnEbnCbxGT/jPZvbwomNa msg=+KmIcNle/5MqAjPkcyQ+OgycRucJvEZP+M9m9vCiY1pnPjeDEbX19ZhZpXnnkdVdmqtKw6C43hF6jXBeSrGMhg== sig=2nTzMWeWuMu9hdq4KJ6HCk+/ojosFi7ESqtmoM2ghKG5OXHkw0RGz58jeiSjsfqGXhP1fzH6ju2sLowN9VL2Bg== e=found last=13 s=3 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgCymeYN0uEwxuIpSaupcY9+Zf7fERcPtL2FQ+EuZZsQ= priv=MC4CAQAwBQYDK2VwBCIEIGRa9bCJTLKrtUkTHsJZur9Z6YngbXsYMK0Oi4zb6hD+ msg=ZFr1sIlMsqu1SRMewlm6v1npieBtexgwrQ6LjNvqEP67P1jXrkb6C1EkC9wd+/mvH5Hmiz3T8Og5leSCJtPXdw== sig=cW1VLAeoaRH8s0zJlF0vQ9bZbo01fc7fOr4N0IrvzmD61dqmhp728hCHld5/6V0IBZ/asMsFse5P89cfjdX7Cg== e=found last=13 s=4 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAsvdPAxLAT8bEiLqTr0Yxy/21h7KV4VrLgbVe8darptE= priv=MC4CAQAwBQYDK2VwBCIEIP59ecmxOTf71CS7nc+ExobtRb9eeHYjGffMwhEXs2Ef msg=/n15ybE5N/vUJLudz4TGhu1Fv154diMZ98zCERezYR+Sifx0NKL3tLixYFWRjL3O10jtyhzYxiATbsyrqOnhPg== sig=v0Ys2hpGUV3Fh7QApNxavPoqC0TgItbKDprJb38VbNXFSQBXxq9CQ9sLiEELgEcG0o+0TFxeX+JEZdhCsTS2CQ== e=found last=13 s=5 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAdIABRVuoo1UQCYokC3CX8sANT6ws0RjFEz7sNirtKAU= priv=MC4CAQAwBQYDK2VwBCIEIEnDb80n3jNdAyd/AiCBZa2wc8t9U/AUFLO2nkeXB874 msg=ScNvzSfeM10DJ38CIIFlrbBzy31T8BQUs7aeR5cHzvgrFVgktZCh62C9iGPoSfCd7GGJoJh+MQzJPEUR6Gzr+g== sig=7TQcpPHVoKNDwKtCaXXnLBre8K9u6hbJDcUOA/HhUtnhldAwx2TO01EWHHNu/0VasqMD98WtHVXWGr5+ACx0AQ== e=found last=13 s=6 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAh8CPfDa9KaNy9LxLwLIakynEgNSwr4kFAYvrg+vRyo8= priv=MC4CAQAwBQYDK2VwBCIEIBpe5GIP4bFF00tL5et4rHhLFssxLj8ivJy2F+t4IF3i msg=Gl7kYg/hsUXTS0vl63iseEsWyzEuPyK8nLYX63ggXeL9aFLawzwKWsaoZy24FhEZ+xY/41NZdsr+5Mp0i7VdrA== sig=QjWXXiosKt8Q8bqgUe6q5mnp2NlVNCStQc/MYUHssNuNMrmEuqoreBx8tFBDlXkpAH/rWFmEPbZN8F/5ZTzeAA== e=found last=13 s=7 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3/1d+ZjhAKuFdijcaryEfNNhjpYEqtbCQDeAwCfiug4= priv=MC4CAQAwBQYDK2VwBCIEIM19w9f/HbxiiqH+gZ4Xnpa47h7HxE4sBbwLqm2s+PEr msg=zX3D1/8dvGKKof6BnheelrjuHsfETiwFvAuqbaz48SsMOuWE7ZJJ0X36AOIGlcv+48QSGEvNFIcnXOZju4Edcw== sig=JzpFAcAWo6RGenAfpcKyLDyF/luaR6+x2I3wkIWY3/wzY0QQKq73STCTQ/rB4fYp14TLtJ9EToSZ9M0cFlDFCw== e=found last=13 s=8 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA+OUjgNQFXn5upYUIdJZwWRN6J2PkwiBGag9t7il8Zkw= priv=MC4CAQAwBQYDK2VwBCIEIBVwJm95j+PaBINhIh0pODbdHt81xtAwLoN4lo66zlyI msg=FXAmb3mP49oEg2EiHSk4Nt0e3zXG0DAug3iWjrrOXIiuGmv1+Px6ugIGJwzcwJ8QAOCthorNWmPIo34mZn8W8w== sig=8D+LS1dUKz3oC07wZv/M9TH4QmSmi/IwsPWW8F2I8Q/rjCnFe4DJuribZlsK7/Otqoe7B55nd3WHLV7hhU7TAw== e=found last=13 s=9 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgIPQalfnDN8siJ/xF/40xZfWI8ITus3QYv5Hu5F89hs= priv=MC4CAQAwBQYDK2VwBCIEIMEwVk8jifyN9oUKrtJCLZwn37985MhpOQ5ceRDVD5EP msg=wTBWTyOJ/I32hQqu0kItnCffv3zkyGk5Dlx5ENUPkQ+tiqcgkT5Dzkxu0oortVlcuE81sli+sScNlQ9XxdRKRg== sig=F7UfmBGyYna63JP8anFuiltralSo/1LtBZVK0UsocxsniI3/M9ha+rpXvvDOZNsNQ9SERU9mjdpxpO+bUpBCCw== e=found last=13 s=10 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAIMWO2oYT+4d8dndcvx7VItYE3jq8sH67tXKyjKSuYJQ= priv=MC4CAQAwBQYDK2VwBCIEIP+ua6gsobhQVMAx8z99QGlPgnAZaq+65ZIR54MstXLi msg=/65rqCyhuFBUwDHzP31AaU+CcBlqr7rlkhHngyy1cuLBntgxtLSWIv9upeCHEp+ubJWzVlQzouwSod6JXZueFw== sig=dPyfIMCYvCpf6TxQ0IPkjT6zz2R3Q1Orfy66aVTOQ0SxEtqtwbJsqvNxBPgzaaCI88Bw+C4q4mWnIQWc+jLgCA== e=found last=13 s=11 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAAG6JI49VyxH55EHbPaSYO/hQ71fiQPd8tY/J/chSoYE= priv=MC4CAQAwBQYDK2VwBCIEIDS5SSOfeGkTkJLXMoKwMhkyZzeiVuTWlndHxoqLTO3h msg=NLlJI594aROQktcygrAyGTJnN6JW5NaWd0fGiotM7eGf+9O6A3v36QIAG6sCShhmmhIVKBRfamU+yuqnMfN4pA== sig=p3wKfXjQvx9+cz5pUa/huKeGnlMxyGrjyfQt0/w7RcVVSQAwsRW92wlUNBTgO0m8uHY+lWXjQmkyGl+zDQPjCg== e=found last=13 s=12 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAXYXLxRI5OE+1t/JndjW29EWlzs5HKCNSZb6u+AtRKto= priv=MC4CAQAwBQYDK2VwBCIEIJ3/2ikjdDdhU5MBQiNmFK2MiJ/vKbY500OQXmdCQ/OH msg=MXV2ry/9xnrlNu4zEfvCkHVKmqfqp3QZI66Ty9IktpkFNc3XwVqCpiC3CHW2puEXtr2S3iiKoLgl2GjB87ao3A== sig=WDs2IbSLd3o+SQWbMJaNVtcuX460Ar0comq62eAjZleDFRFUQmpdFufm+kIKz9qsvEjeYfV+BXlO9X180vbtBA== e=found last=13 s=13 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAGE+PjOmZNpcVIfYnWzt/0ViwqGTJhVeWMu0ya2XKK9M= priv=MC4CAQAwBQYDK2VwBCIEINxvwwkL5rWwoAI6426Su3Tzsqrr/ANPuxhZkh3kriOR msg=wuLwGI+qWSeMjtutH+olth+X44f3jiR94sX1hu/BepN05QkSbpMZy5hCcnXBN85VHgaXp/DrphwjRk2kT2vLUA== sig=1/9HCstHrQCF1bVP7kYfHPQXeBZcfOzIzMxtaZz3gEQmnEo7EanHwaNLx4npbIR4ZFyRcDVOtOV+yim7Mu5pDA== e=found last=13 s=14 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAf9n1Li5LZZbcWaTde5yNdlHb8WcUugboX/coNMVz2E4= priv=MC4CAQAwBQYDK2VwBCIEIBZMs/NQGtORzp11s5cRjI/RXl9sHRWDkcChB5e7yuLG msg=X2wdFYORwKEHl7vK4sa+ylqIK6HtOECV9UZSvAUJMjF6T2qTEwgzN/bAmbolMgou3V6AVnzWOagbBYAPALjqIQ== sig=TxzPRJoYt8iGwNiCI6KQTBHERHBEUrISMqdx5fHJTI7G7+3KhaSktOtk4WEI7zxGfH+NWmbGBa2lwxN0icqOAQ== e=found last=13 s=15 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAvKqMoL7VgmA5dWDZw189/4HRBCYvoiLYLuU3KeWY01o= priv=MC4CAQAwBQYDK2VwBCIEIAxCo/oQ0Yih58oBUtCgWmLMZDYdftmAt7x4b7dPuzcC msg=T7s3As7GTzTYcnHjC7fSra22lR7vls0jWX2FrTdJGmnFlVPKp6IfmfWoEUVUHHnOk+Eu3ELstp+y6LVsvWWoAg== sig=xXsUuN3RH20+Uqol/AVtGs28KoMNM7KQFJKTL0hIx38KqYyKUxV3kz43uFrmV4PcNuAGOU0DymwzTUAH7lv+BA== e=found last=13 s=16 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAelYJJyFx7IdoZs6z1g7CBCpHPruui4xwo2P0h8w4q+U= priv=MC4CAQAwBQYDK2VwBCIEIPUSjXiMV7ypdqen34XYZL3HJfmZQtrqbPnad9tqHjiR msg=V7ypdqen34XYZL3HJfmZQtrqbPnad9tqHjiRGivOzugCgMftLtcK9J091ANOQLKn2/2X7O4vAHFJ/oBZ5+WvCg== sig=zJnZpedFD6fiKciaKKoYjEpDw55JDv2MYD+l1J0Bty6D/7o/b6w9M2WDxOt+UoHWwgwrfxYz2Zpu0U24VTPPAQ== e=found last=13 s=17 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgw1dL+jmUmbWzTu+hjKmsCyuIFdLFyvV9GMeCIKnZKc= priv=MC4CAQAwBQYDK2VwBCIEIDA7SvJbOrra7xFAfcKPAsJ2B2QpH8FVZklgdzteYNzZ msg=kBo/byfAHl5EKDkKPArZF7CuzeZIxAIPmrRK/0WPeQEgXUiharWnho753I/O6AJ3v+6Asc/ehV+rZqZK6dtpzQ== sig=eGuGh8b5yMliq2ZxzlVZ7fbf3MmQ0B4nLe7mnwC1wAYdwmg/EFy2fl10ZbpwiyawtivRV23OHe+uBUaUobzgAA== e=found last=13 s=18 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAtELrXeG+8yIDXQqT8gYKcGQ8nGgLZ6WUfLULbJfook8= priv=MC4CAQAwBQYDK2VwBCIEIIDxLx0NlcbF4i9+rGRqek5gQQ2akdmYRiYCaHFZkLV3 msg=HowidYDxLx0NlcbF4i9+rGRqek5gQQ2akdmYRiYCaHFZkLV3wqFawjue+g1Ucj9QbOcthxLgDL2O+OUzudrT8Q== sig=f3J6DB4OP5e7MYFGqmvJCFRsqB7X7cfTkpduhrQW4vKh6OsCT+EtCWx+0T7Wa3kyNoZa0arXZKOD8RXKwgWlCQ== e=found last=13 s=19 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEALbvXaM/R5Qszs43CaDIvxW6gTLjJipmYuR3ZI1ATxoo= priv=MC4CAQAwBQYDK2VwBCIEIKjGknu7GikB0t5vJ54I8m4Gt9TsKcHxTcgUmSYzz7Rf msg=e5UVsPuQpCw48QI1Sa/Lf3rlxG14xy1dsYaEejYnNYrIGmJYwg6CZ17I7mEe2dw1PXPjA9hF2kbFt1SvbWEEwg== sig=WBiGl68XXNcXSbNsM9QSNqrU7j7FAdiVHJ8zVb7U+s57q2EJDAwT1j+oFffmaT614THjNMptjxovf7e6m+S1AA== e=found last=13 s=20 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAw0hV/197yK/mSBkPwPVOajiSpEHayoiVdiBcXP0//hc= priv=MC4CAQAwBQYDK2VwBCIEIGpQaCKO3rzM+xcdmf3eQSnULylhi3AMvm6k4PqPGDEO msg=5kEjqQSMIvL16zwogjq03GAazRdjTuW0VDBBOKHQAuOIhmpQaCKO3rzM+xcdmf3eQSnULylhi3AMvm6k4PqPGA== sig=OBJpdrJdlHqSc0nmGFh8AzYhKIZKtho242HrYVPB9NxFydsig6qAj/6i6e+yxOYCPToeyGBJzFhtV5s1dVkEAg== e=found last=13 s=21 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEACOK/7lb0Zpwt/RSRH8/i9xI/nnNwL0mIenvddV9B5vA= priv=MC4CAQAwBQYDK2VwBCIEIIdJ3yFgW9Glm9OTJTcw1rypoXhLf5Omfb5kPbNW4SM0 msg=OmKlhwOSNoi36f/hDvfVnkHR/f9+lpNx1H85Q/58xKLFLb1Y7f58vxPN9f01sUbDj928O0lRomQ07UOHSd8hYA== sig=dCBBs5NdCwCW225/tgGbWWJYMoOmWduxV10Wel2SlY1uwpp7ySZz/PAUWYwlb8m2AT5eloY6l8o5Y5KjnaGkDg== e=found last=13 s=22 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/O3ERGwF1QdI22iyEuFEI4rTbnynGD+eI5Sb8z2Op5g= priv=MC4CAQAwBQYDK2VwBCIEIFmc0dVevA71VwnjKcl9RQbh+/vaCoNHKurJSge0L6hq msg=4OPYnEzR4v9ULeqilGtaMBUmmytGeQi52KI8v3fpmSqdlA+wzK2dKWCMlLicmQOVCWNZnNHVXrwO9VcJ4ynJfQ== sig=6NBO4S248jZ6IHxjwX5gxPuZBCgaWZ2yaglYtA9ORvVReBN8agDEYPQ4baY0M2xY9Hr6AxiaKgRJnfGm4o0sAw== e=found last=13 s=23 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAbfgmWlzR8hJhtLucXm7Aa4fNG02hmvTQ1kXc5lx94XM= priv=MC4CAQAwBQYDK2VwBCIEIF+jF470RRp8/yn5JSP9T3hFX/CES9/yGMXjdJ33PEhS msg=P/8CBiylpO4FpRLlxmPFSOs/XFHtcbDuvS+yZux0PxnxY4j2iRARSc05f0VyOCtLWB/Day/+shEStYVdeb+QnA== sig=atxFL4cX698JSvqEsutaojBYbV/YY7dOnCXwt+zjiATqchsdviRHiO6Jgh7e0BuLptz5IvgqdYXd/mtdSPdLCQ== e=found last=13 s=24 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAGeNi5dOxYEGPTTTy7wabn83cgmMYlSgEOUTk4Q3N8T4= priv=MC4CAQAwBQYDK2VwBCIEIHuYQxkLhTwilCkA0SlIfhUGI8lGOrPBfjfH0vg77Er7 msg=WewkUaAkYsd8tAvJZ2e5sL7Bt+zucb1uRNiMktnljVYqzUiM/S5ZJuKqfYLIheMbg/0lKuI77Uy9FTXc2wlwzg== sig=xZxagOmPMVTgGfTRXXkgEP7UwXWaUtlFkqGvidmSpJ4O6jTKx1b7UZ4qsBEgVS/P9mVWUmVRutAo1FYpmwzRAg== e=found last=13 s=25 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEARs00IZjxLwFg0HfKBEC9E2qVNl425Fm2TRn84g2h8Gg= priv=MC4CAQAwBQYDK2VwBCIEIGr+2HjNcx/9A0wPKlkbYNF3GQXNvMO4TJsLsIfNj26n msg=1Bk+TKrcbjI8z8cf2vExTMRgEGxNZCqmzBsb0JnHKvs6690dVEsZRPUFSfODrMueHHg6F8fYXxQnubhN/CS5Fg== sig=Vqkdjo3nLmX1SX5a7Remo2IpUGj2gGghLsTNTHTUGcn2MlULWXdNQOnZL7E8100jgJk3tw0kR4gXJK/fAPZzAQ== e=found last=13 s=26 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAsPJq6G+NNb3QmK35iGLssZaz9nGDex3rJA5bDUKvbd0= priv=MC4CAQAwBQYDK2VwBCIEIIftC28enEVteoyBpv7I0Ok/lkS8mKrzF+qIKxiz47ie msg=U0m3i5weOB1op/8WAU3fPIrrcvWBswCrziHZiwtkZc7h4PwEk39BrBim9iMOSaQz5kZRqq2FdFFquaL/Iq9gtw== sig=GK2BAgWhJP2zGG7fROhV875MDp1kDb9P1f+LE9jTq6oLjGGdua6HUf2A91ezsZNr6LJBY9g92gQ2puzLYdp6Cg== e=found last=13 s=27 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAdQC+chlYOHlElYKovixji/6AvIM5ftwOUYDlQkkvRyE= priv=MC4CAQAwBQYDK2VwBCIEIJZ5oBTdbL9KJzsUtJnD9+9C2sZEp2r4FmNQI18TTS5R msg=lIKWLmYU/5UoajP4Pge/x5oA8Uty1LFeN+7jBgReo96s6x8Dpy46YlgS6IKvRiS40vNpEFL8W3A9eTt4Ao5WVA== sig=EihlZKkNNOSqWpM+NxU4lcULHXa3dhd4ODJ8slNawm0fzfGPjwzssdqBFQ5hZxjhnXWSqug2W5Y5zIFXjAjcCQ== e=found last=13 s=28 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAx1dhb+ZgWE9O08L66WeOuwo0oZrS5y5skiH+CJXeCD8= priv=MC4CAQAwBQYDK2VwBCIEIGHNhfdFIYrMmGadzZD8gb/IByGtd7/ZoHtgbnadVT8a msg=K+mvYc2F90UhisyYZp3NkPyBv8gHIa13v9mge2Budp1VPxpK2jBlpiygrs49bCBMn7acsIyhw+POmbaIWCNZGA== sig=DjKdQwGEy0LhEp0kmSz36WKnC/yM7Kr5uVpHG89yDug5XWK1ojomXeHSKulB6z081UFcr6fZLlExLoNTphOGDw== e=found last=13 s=29 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgDofkq0/5UZIe7ZuGeUAevwMDP9rnemCmBPuDVz/Ze4= priv=MC4CAQAwBQYDK2VwBCIEIFLUzoYodONr4E9m/0YDjtiL0+Qe6XKksz/cLXKlUQoe msg=ViZvK1zby/g5NgXGJ5BsffUkz3BKCpvxUAA8LVLUzoYodONr4E9m/0YDjtiL0+Qe6XKksz/cLXKlUQoeE+l+SQ== sig=jeSuMXq6j7rmCXRrgSGoQkhokMME2Cfk4RQnocxoaJufYJ9th6vZeT+d1Jtyg8S4FY/jgjAoIICKQxjVfdxDDA== e=found last=13 s=30 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAKzRc+zT6RqQc5JpT6h86fryHv2+mZllEdrsnwQsUtIE= priv=MC4CAQAwBQYDK2VwBCIEIKm5UZRZXuN8EZXDwhsESptkGNZ8Hs7lh59p7eO6d6UB msg=BEqbZBjWfB7O5Yefae3junelAascYAIaue4TzLeyQYHvaUc9akhXpwL/0kMErGYWWJ2tJipXnJQzMHhaE6EHCg== sig=WwRz+nQ/SNUN1rjU7tt/AmfjnQRnRMNns1drxDGEbJcUBoIDHxJZxZaxvP5xBBpOzEqe+M+Ga7MRu3ePOMO9BA== e=found last=13 s=31 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmZlleu/HD5HbPDf/cmpOLe0aiDY+3hksDgjeSgfvg6s= priv=MC4CAQAwBQYDK2VwBCIEIJXmL1p+KueyAWLyJ3DkXjAEyKps3I+SHBuuD4WwWhJZ msg=5sgIrM4cdQR4iHvCz/qerrKpcQZ8HiWS9YdOItHHHsdHt9ZH+QK6MLUVN7NgegGl/1MRVlPZ9oDvVzzcuZbnAQ== sig=v26b6Lj7k38MwRqchaT+Me5DGrUL4RpWq3PEbUDwePxGxCZmmpCk8mUXu+Bbf8Q3o9ic+Wb72noT1Q4VgnXdAA== e=found last=13 s=32 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAm+TQGrX9GHO4UnbOictk3C9r57tMuHii5sM2a8GMTbs= priv=MC4CAQAwBQYDK2VwBCIEICEN4iLrQutrk57jfvU4uGSQH5xk+JNJLuPh5Sbia2jq msg=O/chDeIi60Lra5Oe4371OLhkkB+cZPiTSS7j4eUm4mto6r2lFSBu53Y1+2VSExXmYZFFdiFMGew3a3jK+PuaIQ== sig=yhc26/4dO35PcDvYMugZcvgpM0TAaIRYBS0b+74w8hJg1+mbcle90jEJnQMnpSaj0vrR/PJLMC4NGFURzQEJAQ== e=found last=13 s=33 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAMoc0i4PsjIzyqVYllo1fXwq9faVjPUefA8dO7C7uvIE= priv=MC4CAQAwBQYDK2VwBCIEIBmIc/owUTm06JxF7vdKvNyIRWQmzbGGJICb5KPodlnw msg=mc1aJBZCEmE0muzPEu9DOeAsPuel2oR0p/Z74w3TIiZJDnyShbYZiHP6MFE5tOicRe73SrzciEVkJs2xhiSAmw== sig=6YQ0+PDqEbUD/tdOwb59+3M/gLgZu+jwkKzaPNA7tqvVks7lpO+YswQ5xIglHVrQaMUf7P9FUhIb/UOXZTu6Cw== e=found last=13 s=34 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3XQkOCwf+RFkk5TZQ8lXjZ8LetYJsXbnjAR/G8MLiCg= priv=MC4CAQAwBQYDK2VwBCIEID/tKLfi6zsRa/XRzz2yrrFS1Kcm7EtaBioS2twKdcGl msg=OxFr9dHPPbKusVLUpybsS1oGKhLa3Ap1waXqQHcRquJ4NXYJs2CkDaDeUnKE8DOdL5kPKWIA6W3Zt+sDHwMoVA== sig=eMEJ5WY11ZFxocGWO8RWrB/dbDuNETQZu5FHo07gabwJaHPhpZAGlNHnKHsAf44JkN1lk40WWSQ7CvcBiOY9AA== e=found last=13 s=35 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgnfTT9aJFS3dz0Cm8fly3o29BWt2TV8SX7k1LH/7NT8= priv=MC4CAQAwBQYDK2VwBCIEILEQKV3r/aoFgwbP+C1D4U0CGZBcZZgFLnqtGtbddyQk msg=oO+5nG+6/NdXYA+gmHUqV0rA9KqB/kW3lOUAo5TQCozTIQk2PKwN/XuJqgpFhbaafR2AaVHyX0A0NmqJSrEQKQ== sig=xS25TyZDfmXBWrlqhxsTD424IhOKHO8tB0emR8io1Y2Xim6+OAptyFzyzfgw5GSJKi7up5/fadBdVfgTCDqhBA== e=found last=13 s=36 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAalhMTR5GewKzwQp093RnjkT7XeC8P2IhnknFUf+iaiA= priv=MC4CAQAwBQYDK2VwBCIEIDRZqPVUjRhlEl/2BsQJzhw3ux1XiuWLq8iZoUgW+CRx msg=NFmo9VSNGGUSX/YGxAnOHDe7HVeK5YuryJmhSBb4JHGHXCMb9x//rVjJNiud2hmLU87E0n5Xj/MCSoZVtzDhGg== sig=cTAbOor6j22tvjPFSyhnqp7HcYFuIBGCN6w3xNwX0fsnFeff92J1Wp0QkhJJ5OcbuwKGU9rVVXUM+cHFqtVOCw== e=found last=14 s=0 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAjCVWw4bKywgqnomHshS1UdJ5eU5LsqWWsle5yGcJ4+w= priv=MC4CAQAwBQYDK2VwBCIEIBlGwMotRjviah8DTaCMHDMhaKpaOceFSR+QMoLsyDIV msg=GUbAyi1GO+JqHwNNoIwcMyFoqlo5x4VJH5AyguzIMhVErJyBmKqSDlK4Di+ObTwTKZbU+dFVFLylfBbUT3FdZw== sig=oS5/BDgfKqkpX7RZkfclOYwGW+vaW2bioYrAqBC3lUeOFj8Yx53DQgU+IuPMJFiem7/ykJzJgYYZVGZ1Wr8fDw== e=found last=14 s=1 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAnIP97EdvWheZX/nFOt1iIJAk/dWCU8ihy9IPGS1X8bs= priv=MC4CAQAwBQYDK2VwBCIEIFU+O4btlEJ7INidQ8izFw3Wx4HUL20mRCGMJUXK5QTC msg=VT47hu2UQnsg2J1DyLMXDdbHgdQvbSZEIYwlRcrlBMIXZtfGQPBUYVXeanKcfMQzsrP7XkJ46itO2ZlNHkRY7w== sig=UV4omuE5t6KBSDq5aW6s1mwbS9R9nwU6lC0MonGFIhvNxB0crCZgnRAGWch3gxea8mx69eKANPP9u4AxUbXXCg== e=found last=14 s=2 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA1pzjLLlKW+nbf3BXU1U8EdFFv4qRTRquEiQhlm51uBk= priv=MC4CAQAwBQYDK2VwBCIEIM+4YC5hXxoyWQay2JKFuBJTy/CwWBfkuvEipq8BSGRh msg=z7hgLmFfGjJZBrLYkoW4ElPL8LBYF+S68SKmrwFIZGF3mKwswmZmqBZvz9r1fZY4xEMjOSFDyczgbjKrdwTRZw== sig=LvPmMkFLojV3UztPRK51eB3ITxFVN+72sz3hCJg4d/KWXr6necqo+mQtWienp1tr4KI/i4Kqjz2NoTLTzORkAA== e=found last=14 s=3 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAy4Kh6AIXHgbT02itCtoGIibK0VqaJNt7gob1UUsa/xE= priv=MC4CAQAwBQYDK2VwBCIEIGP1a46tZYpU9lq+kja/U/4IrgQxQ4nm7SJH2XRNiwf1 msg=Y/Vrjq1lilT2Wr6SNr9T/giuBDFDiebtIkfZdE2LB/WbIpuSfgcy/Sjcs8sXH+oBmcSFNrSOMvaaLdyKKQyuyg== sig=8xSLthxKmijCuUjE1OyYuT+DizMc5Wa6CQ703WTJzwAVeOC5KQfrmkeCRhlsQD/YlOQShjM9bX2ZG006SoysAg== e=found last=14 s=4 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAktQJcODwixp4d8x4i0sazV4aDhtlppP5uN1sxxi9j8s= priv=MC4CAQAwBQYDK2VwBCIEIOA5k2zVtBu5PhSeIySC7gDZK47qn5dbT6uDN5Nsi5Hv msg=4DmTbNW0G7k+FJ4jJILuANkrjuqfl1tPq4M3k2yLke/F0Rr2Wq6Orq3DSnoJe5vp7QeyyYEh14V4aFnvnd79CQ== sig=sLZUdKya5+LGTi/UskPkKLU/h+Pfe9UPvmHkpIA/3OOmunU8/gpJwRcxaWT7bvNyoTGTF4D5rHqBsIUklpA0BQ== e=found last=14 s=5 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA8Vu1Whv1H8woMRamRy8S2bMS0H7ab9l7c77LRVKW2FI= priv=MC4CAQAwBQYDK2VwBCIEILZEAxIf/9PsCK8iQGZoOAEZjuWpffhOWBI48Xk61O4f msg=tkQDEh//0+wIryJAZmg4ARmO5al9+E5YEjjxeTrU7h9WAmhQRh1daV00AAICqdS4G1LOLPEOv5hIVimwBXI3KQ== sig=2XiMk+Sadk6PP+6nJaLpr5006I77MYkV1hOAMaYsOwQk5TTVQxxQ6pNrSXwDo4TOT+DZsPTBwSI29o6YrRsMDg== e=found last=14 s=6 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAtevlqRpPeJU0ULvlPna30uIFJrrMLAma1Ml7TjjooK8= priv=MC4CAQAwBQYDK2VwBCIEIKOuM8evEFyRHee+Zb2KzPhOcXCzKcblamDvSKjWEfDn msg=o64zx68QXJEd575lvYrM+E5xcLMpxuVqYO9IqNYR8OeJ2u6HE2FOmlfL5A+F48EDujrqq45U7ef0dkfyArHGIw== sig=kkPUnjn79VlBZny3K2r4OgtCuR9CEGOibzshLd0GOftgWSFJEWH36Wh1zAqBYYrrLdbDWkSUDH8b3CtBFj6QCA== e=found last=14 s=7 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAdCLm/vIJOXdiutrv1EfsGPAGBHlvH4NdfVkXTPk1+dA= priv=MC4CAQAwBQYDK2VwBCIEIMjoHwuJA5eIOdRmS+ghh/IZj3B7D3PO7ryfV1b/xHSE msg=yOgfC4kDl4g51GZL6CGH8hmPcHsPc87uvJ9XVv/EdISpq45RsgpASeEYHIbuKYNg7YyhUOjbqDB5GDx6lfnyIg== sig=MbW/0EtXK++PRVvftPsTJfPa25AA3D8dY214/wIVHbYjjOWApr7JrFxyQSScOPjFPSewpUHGjVsys9tnXgefCw== e=found last=14 s=8 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAkVW2PfKqa5QbPDma5xWYnqRH7sJjp/SZlObfjeIHM94= priv=MC4CAQAwBQYDK2VwBCIEIC93EXIzoEtBYPV1x5ZTzaV1M3LDdh8QXmRfT4urIjBS msg=EXIzoEtBYPV1x5ZTzaV1M3LDdh8QXmRfT4urIjBSXYKGP/IPx4UxZN4kv/7lvU1y2ROKNlz7BfRD4cpc0kKgSw== sig=symhm4eves/ND9On+/PT7ziE37KAbLGb78d6N6flPIH3Nrtv497SotY3Asa0K06V3TFXxVb82trK1d2+cQ9NAQ== e=found last=14 s=9 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAYRzqTQ5Ea/GQkKfvwhvVABs5zZnYFGqmyEQkiWwf/Uw= priv=MC4CAQAwBQYDK2VwBCIEINghi4zLHbG0exb4BCAIHc/285OUOZjXwJj2CNB4fm/u msg=yx2xtHsW+AQgCB3P9vOTlDmY18CY9gjQeH5v7gWThbGlfvBwmwmDrSgXjeAfZkEkAQt3eg2uRcw4yoZAjDuf0w== sig=IUduEcVrXxlC2GMiImscHsTTfWoxt67WIMjzxCWW+u0kYG9MV8jYUzysGsyxHfYPelfQhsolMyRgkiqfqIZQAQ== e=found last=14 s=10 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEARGLw7ytONHmcHBhAn59IuZwdV3tEGX/bWl96qxCBMcU= priv=MC4CAQAwBQYDK2VwBCIEIC9DEp5jNVWk7OH8QbzCMs4cmCnZwqmjg4z1GGvtfTTV msg=L0MSnmM1VaTs4fxBvMIyzhyYKdnCqaODjPUYa+19NNW+P5B259sevNkrtAzuEZZo3fZ4REjZYcR5zuCs1DXRdA== sig=EWxmX686sWuB6I6wSj6OBUoizNIYtpcN9lIVR5AKzcXTH8+tVhxobOZP2E3URA9dSVbiRVkNesPbujv+urJDCw== e=found last=14 s=11 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAGaavvJQkYApJqFCo1SpwyzbvPlEI04RWalQpUki29sM= priv=MC4CAQAwBQYDK2VwBCIEIBNdcwVj7ibtrNYyKo/LjOHWixM4ZEUp+DgdIE/xgq7C msg=4tNBWCmYbiI9BHhRDc9Z2Ee5jgejIhyzc2eQmtEj7r82M1MW9jeaAt17yDTd4TozLuucq97VrUnMZMHomSlg0w== sig=6sTRa4ly2OJVdAYbCFZKKg7NPBxWT7CmVhpcql/EQTXy+F2Ob2dwtAdItoH9QsnaaODWz4BzqTusM03IxLxECg== e=found last=14 s=12 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/BtX8y6TtfB6J16osePQ2goWNS73D1aZgYe0dIu0Pw4= priv=MC4CAQAwBQYDK2VwBCIEII5ma4tvCG6gwyyRDvQx7OLcl8BklEV5+q5J6N4/672L msg=NlQVO3xzdbXc093G7tiM8zzT53ePXlmSMTy3BivJP8hk0g1WkuGNNSkdiDxQ3VvE9YhjxIvTfqInp6SHl8FJNg== sig=Yd9xwMRGfljaeriA34F92A4Gz/Xx9gZrmbr8+7WAhX7yFwX8vVBikX87UvFbsWhRxUyqSNSTFCy13XOrsJ18Aw== e=found last=14 s=13 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA62CWMSh/Z/rQLG4tG8Cuw8JmdGXW+N5CgFawuiOSNGc= priv=MC4CAQAwBQYDK2VwBCIEIIhjk45YAKiO1zFUlM2InBE4UFit5WD0bVvl9NJuvuHC msg=zYicEThQWK3lYPRtW+X00m6+4cLZcIJxXionNlwzJdvLwRXfW7VO0Z4nimq3laalBsL0VMXU9wmXZDe2F2nhEA== sig=YPVDKuhjy6PmI36JY06cTnvEomcpqaoXszzr+5OYJ0diXvRUcPyRMc3sEalWiQrIUnbn1GzVyQA7l37vg642Cw== e=found last=14 s=14 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA2uM9enIkR/oM/YXF+BnAvvIoRXCQ4pPOpc2dz08tV3s= priv=MC4CAQAwBQYDK2VwBCIEIG5eVKErc+1sU+fHxzRL0odQG0eNjE28tpgS0UzSlJZp msg=bl5UoStz7WxT58fHNEvSh1AbR42MTby2mBLRTNKUlmllABvDcFvBOis989kT5UJbIaVRQoqIGoahtnOVdDbEYw== sig=WdNSg/M/ROmyIowfwS9jXxUVRmgyy7ClhrPL0XlXV0zUAzoYoiJfS3pBcwAr4nx8OXBi479KOHIF7OYPG8A7Cg== e=found last=14 s=15 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA6EvDdnb0llwlZ9QOdMbb2Bq9+LMZ6oD3CScnuJU1JRw= priv=MC4CAQAwBQYDK2VwBCIEINaQylwvc24EXS4GjXAhzSpJ3YIHDCME1dzbVg/4ylaZ msg=hsh5xDQ+jD4TtbaOsbYa+NKQDYEv7TMTlx11ogo90DVIxk0FFtadRX1ILcgx/8lMp2T2IWicj5h2gv7GLW/XIg== sig=MukIYeEO6/P6zJrvECkCK9mC+lAKiNU9gIv1U975EoWcGvLagRAnsGUu75quWu9kz5krlnLEYGTKjW7/5T3bCw== e=found last=14 s=16 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAaZb4qleF87VuKdIWpniXxqYx/ClnngejZQgecqkGFj4= priv=MC4CAQAwBQYDK2VwBCIEIA1q/26f313uDNOo04cFTOHIDUnIxuBEB5VkRa/fAZET msg=FeaQpCWPiI0Nav9un99d7gzTqNOHBUzhyA1JyMbgRAeVZEWv3wGREyzEPZ3SQcHL+w1CSMk2L29s4DajHlEigA== sig=QwwL+szv/IfJ1I0iOf5XRqG37y25Y7e0xPawD7PNKauFaFnDOeRP4RH62wUt8seWPa/5ZTmZdOOg6vVJed3zBg== e=found last=14 s=17 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAaIVChkJbndXOtPuW4X01DSV4zyfYDlGiXjXj7sBBlQQ= priv=MC4CAQAwBQYDK2VwBCIEIIIPFnXjEAGVKUqJ5CzWs174DcPJ+xX4Vh+ulyDYi7pj msg=xhvkgg8WdeMQAZUpSonkLNazXvgNw8n7FfhWH66XINiLumPY1UyLVMVnL8UmfB/NBhj3Gjv73ORLZHiPqnQrMA== sig=gjl0P5BykGQtidaVXZ4OapR2kxIV+hjM35xMqxvKEV0XOjje7SB1b50DOYZDdHSYbzwHMOuDKzP1bVYCcnjECA== e=found last=14 s=18 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmeiFD21Ehm8mxZJzqOfprFvVc1NA1Wga4DwE8QzWkZw= priv=MC4CAQAwBQYDK2VwBCIEILBkQAvrXdn3NW9FvPByDgpDTLfVbw77Z4qXFAnXGlxX msg=QDDuUCGPsXhXevhN3Fxvk1dvTGTLs7d+9uwLwPwUfQdU5W3j49DTbCXUhRjXiLfKgUawklCjkPoB9LLHS2/vWQ== sig=ABDsl3kDVlM1lE8pRlphHP8kY/rvrLRC8YTOyHF+s/3ngCOWQi5i3qhoGMChwAfhmQwfB2R/IV/RaSo8NfeoDA== e=found last=14 s=19 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAkia57Z/UB7qW/coLTgwWZduZVVAVBWApP5V3rOwgPZc= priv=MC4CAQAwBQYDK2VwBCIEINmYIaCAqh/1kYU+9ilg9HKvrmhdD4u40BE1GtmIMoRn msg=OZp/hXcmkKPucKrD9gBgI4eCXfktUclWBKz13UpRvQvaNDo2htqZxz26Bm7zhsqXoODhpc/lFIVRW5vWzTTngw== sig=ygj+kP09VML+z4+1aiasdLzZcJoCXlVeq9pN0qLqNoyvpIt58WXj8+pvGQ6y0fS4QD8sdsQFBE/gYwmuqbv4Dg== e=found last=14 s=20 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmTB+coZ2J+Mu74e/HyX+JmHGrvzKHqce0YfkLjOyZzU= priv=MC4CAQAwBQYDK2VwBCIEIFHEz1/X7QrMX3t6Amhq0wi9w+pVzLFeCY77pam6tOd+ msg=2aSjhX2Q5yVBcSZsmU2UEDySzOmzphMuDVwAcIg27jdRxM9f1+0KzF97egJoatMIvcPqVcyxXgmO+6WpurTnfg== sig=ByEyfMNXU+golEoLQWSxqo5xFJb8mSM5RVYtIVoT9OV0kZo2ryAxCDrISlKnvfy8uTWfwzXLIw30jBhmSWHDBg== e=found last=14 s=21 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAOAtVakSIZMTFWkuW1qcE3QDUUjzNQRPCB8MK+PenZhI= priv=MC4CAQAwBQYDK2VwBCIEIEexwQuuiENLEJSZ+bm53rhkk88zYN35tw9DiBb6rzAS msg=tw9DiBb6rzASYE6kl3SK+m+QKAvKO/D0d+LhzGNFgRMd1tKOieUE0TlCEhfTNyowguWAM2Pc0p2R6IsWmuNv4Q== sig=e9+DgxlR46Nczm+prDRUavvENbC2sStK6tx6MQ9/KIRUT9STmFDdVRr4/XQ+69ZOVYLdJI6WRfY+ZciqqS4KDg== e=found last=14 s=22 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAU8RzwoVIfNwRVX9X9OSnvQBCbHeFf+t4N6DanMJHnaw= priv=MC4CAQAwBQYDK2VwBCIEIC71kdEkIIUG08HFAqSak1O5WtR0n229yh5ZU36OUC3G msg=wbWmuB/9iPwI+iIc4wteif97dodMulWC2lEK2fOrY0tOa7o5mc0UczDNHZbXWIj9LvWR0SQghQbTwcUCpJqTUw== sig=x/ppbpEbvUjz+uCmIWl5lIOitlZxrGvRN4ZlPst87a/dBMcN7XYuxHkXZKbpmTsmdhnFBy2r00r02fGFSpfFDQ== e=found last=14 s=23 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEACnDDfo0cBXw82tDq5HPCHd1lDgavvbmz4v1VzhZcmlM= priv=MC4CAQAwBQYDK2VwBCIEIAQOBniYtRl/lJe/tBc9iLAgm/h3Y4OaxHuZ1/1rZHsP msg=uFbaGVdVirsoS3e9sEMjaaN1Y48w9qc5APPf6PmvG+Hnz1oitR1K8KgOIVxNwKbyeawSahx/GmJd0sQyZ/uMbw== sig=TkhZ+wSGathHomqYR/+QdRO6Bb2PaB2qOBF4WrHYOdprOhvYmC7svOagH24lxpnUWIYANk4EpyVIlP+TiA/ECQ== e=found last=14 s=24 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAa2MRGNSORs9mAmccujEEr5I4piY0yevnoqilf0uPAbI= priv=MC4CAQAwBQYDK2VwBCIEIOFeIxD1N8e0yJ/h981CSjOEmbueZx4cut/VuP7daCIp msg=J1dNGjn1pz74R6VkDeC21HcaatwWpeEW2UndWdkli8OXCjjfYwj9rhskGcdre+3U9q3SFQE8mR2G4IaRabCQSg== sig=8c4BLWoMzLMxUTJZTQfKuFKU8kw/SI9bJrvlDnmOMngAKxZK2R0FwzoF/jmcG1XZIQXsOFBDv4MXR/QhsIRBBA== e=found last=14 s=25 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/TVTG7WQt1XIDLlNyl4yAhbveXq/mPT23OK2p671Vm0= priv=MC4CAQAwBQYDK2VwBCIEIOew8YuwBrvvDDH0bIRq7+TMEEByVFVhuVQ2O7rh9t6g msg=0cu8hzH+Uel1+2Zqm3utnP3eDuew8YuwBrvvDDH0bIRq7+TMEEByVFVhuVQ2O7rh9t6gfRtq4VzdyB+flp7pJQ== sig=Gk6aJHFW7x/3tAr19Q5TYH/nUCR6H/tHFxeTluH7MueOCP02lanuRPi2r3SbNJL3Nbop8XKAze4qe8WfYS6JBA== e=found last=14 s=26 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEATnkhKuQcz6CTCkmUmxBbqJ5CxcAiSvXXVncT49Nvk18= priv=MC4CAQAwBQYDK2VwBCIEIDWj/k1VYQMSkN2xhrLtLH8bi2uvVQJ6wWNlBS6Hq0Bn msg=EFUjdTWj/k1VYQMSkN2xhrLtLH8bi2uvVQJ6wWNlBS6Hq0Bn949u9uGvqrA7ivtOhw4l65by7M9PVpX2gGZfCg== sig=y7BJPBTBm5NodkBWVo3XLvdGRWeD9l0tO83bg2rku7rzr6uYaE//e+9tDP1pWmQT8wS3WjMB2OlMsNCHh51+CA== e=found last=14 s=27 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA8JZb30nb0g1x14OfW1W/nukoX2z5PE8kwdoOlPsRXzM= priv=MC4CAQAwBQYDK2VwBCIEIFiVw01jLqdl42ltnw+B0J92oF95nW1dqWME9EVEd4YK msg=w01jLqdl42ltnw+B0J92oF95nW1dqWME9EVEd4YKi8vfN5VL0Qcmhs/wv2VnLE25udC87J94pvFhbnOxvnTzaQ== sig=B8iXl/lYGVuoNcvdSaAYH9Ny1zsw9y0+/v5IwZ/9l4EYyAFe7gOLVieaUxGr6oTexk1d8ESdvJCYCFnR8B1tBA== e=found last=14 s=28 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAqdqwhlD0Ao0FOs/k+aaCmzMbTsuhp1evabO80hBleQY= priv=MC4CAQAwBQYDK2VwBCIEIAMv3Bo3hUdpOTdQZjUoAFVhh+UjgVR4QBMJRNx3xJDl msg=L9waN4VHaTk3UGY1KABVYYflI4FUeEATCUTcd8SQ5Vyi3nxmJas8TeRhOiVb1y2GayEZ/zL7B6HL8zvOecUGlg== sig=wr99uHFzM3PXphB9TVHlCm3tf2kaYJ1OBxFdHAfMGYZ1X87hWNCBzA6iCYuGnL10r8QCzgWBo/lebtcVJ+fyAQ== e=found last=14 s=29 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAF51jeLxl1rYM1rBSJ5gLJMXHxD8CFZUBK3BB1JW5DSU= priv=MC4CAQAwBQYDK2VwBCIEIHky5Np8wUdkBuei3Pt9rdADXrLPxmaewdB7FSkPUYGj msg=p3ky5Np8wUdkBuei3Pt9rdADXrLPxmaewdB7FSkPUYGjATtqqE9LM03m7rqK2f+Rig+kbHFxYJlAkIMmnT73gw== sig=kvqehogHT00vPmv/ghO/nS8i20h1iXoItb0WSeGwjZkNiQW3F27mnfV02WszvM6SwxeBtLHbUHAb+NNufPF8BA== e=found last=14 s=30 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAdO7JFnLdvf8zH0rs1SpdiypIv5TAY3d9qhoq5o27X7E= priv=MC4CAQAwBQYDK2VwBCIEIIu7AWSTwPgMQQb9SVF0nxWoTvwgAe7NGxnTBERgzbyL msg=xIR6xVrXPxdx0cgCWwbgREYRi7sBZJPA+AxBBv1JUXSfFahO/CAB7s0bGdMERGDNvIv4s+2YzydMZvgfm4ivww== sig=KJLXT9FnCK7seLb4x0boJROG68b9BHTYNBeVe8IoSFPW9sSIzQPcq7Q/GiBtKpxCl9MgCl98U2DaEsnWLqgfBA== e=found last=14 s=31 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAZ07XJoey2kjQ2hjQed9aDBb0Q7fmwRWq+QnPusXhans= priv=MC4CAQAwBQYDK2VwBCIEIMRxbLSLpINPpCfBjJFESwHvCIHIVBhyeaOwgWNafo9h msg=EI2cR9RRjYdqYZrVzQa3Oe2c71Tzfu1/5V2K6Z3uMxPkRFhTj4oGucRxbLSLpINPpCfBjJFESwHvCIHIVBhyeQ== sig=VDmoiUFjMUj8zoJDK9NBDlWBqsRRsI04rFpNcyShP2cJ1/LgsBUj/8/etNHTVl8EUFXCq5VxfinioBl+rRaMAQ== e=found last=14 s=32 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3qX8W/FO8WgHq6GQsLFCwWFpEZh9+oY4dqSFRYc0PFQ= priv=MC4CAQAwBQYDK2VwBCIEII4KLBvrrluOTkiaFQC6SN9femr4iAtF6iKg+qJzkABe msg=khcD7Bym2d1PLe/HQ2sM7+IEjgosG+uuW45OSJoVALpI3196aviIC0XqIqD6onOQAF4TmWMmaKllHDvAoLRG7g== sig=5bFiD1Q7+lhkr0GXjOWTr2Qi4Hh4X3XQYQglMHQ9BEEGQD2EToHy1KC9thcRiPFA71BR9gJhwsDCftzh+/FLCw== e=found last=14 s=33 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA+b0dlNC+xjKtPyJ68RTL2LORfDM8m11+ERIdpCL3G50= priv=MC4CAQAwBQYDK2VwBCIEIDSb5VHQznWyyQABhaP3UoYNPaHMuD7714zmIpxmcMhk msg=hZ6gnRnv2IggMQRNof7DnqhWxmrTIRLRr4Y0m+VR0M51sskAAYWj91KGDT2hzLg++9eM5iKcZnDIZBWzWFDDkA== sig=U4+L0Qe42Owgqstyb8Im8XNvD6BxkcpbgQTdmQWdpphKssAxIX5t/8W4S2sjf0njHGxWnhwOXWgk45numzmyDw== e=found last=14 s=34 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAdrkpLk8EZ6zrrF+K7ejlPkv6ZWMKkbM9PFh/dKKkHIA= priv=MC4CAQAwBQYDK2VwBCIEIDnxg9OEsKzD7ua96A35VD7nclFpUqI39ShNuGnR1KN+ msg=k4BP15XQB+8yfxEMC2csIPQvrC09vV2RyLc58YPThLCsw+7mvegN+VQ+53JRaVKiN/UoTbhp0dSjftx+cuXIoA== sig=2LXBbdBtV80y26jIkHcOOXq7r/pSN40Shu4f7mFvWwMjpDnTXXxTkRkck8a/hpuMtOWqckgrf+AHA8+JQcEKCQ== e=found last=14 s=36 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAsxFcwDcLojXUEiyyLdu0obw8GrQrJuH49phvSUswKOE= priv=MC4CAQAwBQYDK2VwBCIEIKKiYMz+tmr/m4rR/+kZ0NjgOqhqJb+AXXs8KDkEb3VP msg=V53rmEee1A/bQLG8OwX1ajQ0Y871pOjlODMuDMsCPVTWGJ4xEaVSv7rMaS9i3c+0Zo2iomDM/rZq/5uK0f/pGQ== sig=tpan+EcrcfGTSNsUEWu0h1Dc4YxwNiX3Haxofdo7Gr7B104Xb1NbF8M+E5a8FTdE0+PEPTIDqmdYMIqAsmuUAA== e=found last=14 s=42 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAWNPmakqyrHHejUO7H27qbFzcylW5bEr+OPSqus1vPIs= priv=MC4CAQAwBQYDK2VwBCIEIBCvTw6Hoyn5JsxHYSdNnXElw85SI82dSaxqtcNo9HAs msg=EK9PDoejKfkmzEdhJ02dcSXDzlIjzZ1JrGq1w2j0cCxSCb4SS8M9sJjvKJLG2mhjl9EWuTkMH09B+E/Y9LklOw== sig=DooigK1dWSZplUqtfll0eJfvf/iEzY35snfb00ejoaCO1Rv+YVbAMJwDXCF1TPUeEqNaiegP5a6afqiaXK7/Bg== e=found last=15 s=0 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAcRgbHN9sPEoAeBLd8TYxQQoE5nzCtjqReIWZHTkseRM= priv=MC4CAQAwBQYDK2VwBCIEIEG5uYTnQfGD+DIKGTVYEBzEz1s51v4iV6JzNqXYt2DO msg=Qbm5hOdB8YP4MgoZNVgQHMTPWznW/iJXonM2pdi3YM4vgB+3rUaJ5ku8qRCzR4O+aMYnX3OrtoLi9oCpDgWE6A== sig=eVpayQhFcfEnDAEitsHTEOVOTW6rLxnlgbOm/xteUGekfpeCufPCq1Wq5rDvV3PTNY+V0Er0brHy1WvxY7REDQ== e=found last=15 s=1 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAbuMmAO6GnYEZLiZM4HNHBkCNiszgm9BOCFTdYiseA2s= priv=MC4CAQAwBQYDK2VwBCIEIIRh+MIVXOT4HRrlILID8LMJjNmdH7AfqU2leELfJqsq msg=hGH4whVc5PgdGuUgsgPwswmM2Z0fsB+pTaV4Qt8mqyr7oMPe29ZH4+R8aPgl7M3o4jFO1NO5PgQL3MIFRRixFA== sig=V0f5iy+cfx5oKnY5CwZ4eP5/IHZqVQiqPsK22kJy0aBBQfzU0zAlyl6h5G+c/97ZL+Z505Xuzgnx00IYZScLCQ== e=found last=15 s=2 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAe7yI4bJRIweGtomYKBmCNHQm1x08weTktgojd7uUjfk= priv=MC4CAQAwBQYDK2VwBCIEIDHahbBLqbjLMKZuhCDFJsqaroa0KPVgiuVvtatVp/ak msg=MdqFsEupuMswpm6EIMUmypquhrQo9WCK5W+1q1Wn9qT3m/n2f71WgLtuBad8ttL0A7TLI1BxdS+GZs720dAYTA== sig=74QERXzquku/Otp7j5ALUxVT8+1vsqIo1/Rog/Hp/aOFX2w4qm+MFLXNogGwJhyW8PHv3uLzA9BN1Wtno0vNAw== e=found last=15 s=3 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEADaA0iFmpirfLRE/jdjuybbNk4u/+VukP0weiCurZN+k= priv=MC4CAQAwBQYDK2VwBCIEIDFiSUuUIpeCvaVL5AQyAalY3EFcfofaSzE0eYv4O48U msg=MWJJS5Qil4K9pUvkBDIBqVjcQVx+h9pLMTR5i/g7jxQJZjgUGAbYXq26rukea6w5K3tAZ7WylOXsygJOGb6ZFQ== sig=dD9kDLaNt378wcxjCP4kcHM4wUBprZjT9nMxowKElnLweTsTxtmJeHFvI0IHNfAK9wYNpu1ycBL3bYqkS2hgDA== e=found last=15 s=4 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAXtNr3apyDyAkNEeLUXTahcfAGIR4LJbjbi+e0HsKxZs= priv=MC4CAQAwBQYDK2VwBCIEIFWBu5LbX5JtxZGAG5FckyMyiPnwLPiztNNhaF4ZTX9e msg=VYG7kttfkm3FkYAbkVyTIzKI+fAs+LO002FoXhlNf17knsuY8UhJEMZ5lPYstvTltnU1TuyJhB0WJqPM/vpzLw== sig=S6/9rLrfIJ41UZPYp9LHt/4RTtrwy4EkgKafgPqL74idsdJ500gNCAoVk0NufJH0VPQJzMUFbM35z+D5fsJDAg== e=found last=15 s=5 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAqgCSVaGc4AudoMr4//2/fTsLJz+CGEXjqI3NgOQbvGA= priv=MC4CAQAwBQYDK2VwBCIEIAZlNwFjEAXWysmihFNSnQLnYphx+7VomcRw+8RfBMQq msg=BmU3AWMQBdbKyaKEU1KdAudimHH7tWiZxHD7xF8ExCpIsviVBLX0z2Djerysfw+OYrwKN7Lf12u4C6J295SAVg== sig=rFC0mcAF6HN9JF4tFY7jT4x93gNWMrr24WIZ72tnMdVq9Ik/5uG2cNeQDtx/YvEgQBhLfSVfZBhtS29hLl9JAA== e=found last=15 s=6 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhDm3Lvb6tsQAwcAjpP78gSULPEQzD3Ko+GT1peMOp/c= priv=MC4CAQAwBQYDK2VwBCIEILVVqCmAqJ9H9W54OxKMcP0ytDIRwqu5QpUPfiurjxRp msg=tVWoKYCon0f1bng7Eoxw/TK0MhHCq7lClQ9+K6uPFGkIdjHcsbfsdsoxdl6UEPHY5A+Tt8yH5MPgcXLkOkQCzA== sig=eLAZwBbNhI30Sv6LfnQSIPqapc78/OXfkX2V25TKf4ZbefAAs1Gq3UT5NAOMOBD2FQHltefNGQrPHqAE2OxbBg== e=found last=15 s=7 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAn/9yv5NyZdRp+/1NavuVSy7tVGOJ4sMI/HwhzPPe7gc= priv=MC4CAQAwBQYDK2VwBCIEIGwS1kDyBWuk1FA0gk/inYZsbXSOU56fIn6zU7+vCcGT msg=bBLWQPIFa6TUUDSCT+KdhmxtdI5Tnp8ifrNTv68JwZM/XLTdGVTpf2eX+54PuaWY9Xs6fNfmPEJQt3hb0vLuhw== sig=uPgjbNZ+iK+rD+qtYQmdkcNClrFbDPwF7XqI++ho5K2nmh1xu0L9blIZHhddfxpPZNI2nc6RZ7K38s1dMKjUAw== e=found last=15 s=8 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAVVB9a2cdMffP3NZnFctw9iG3DpzewzI5KEMG1V0K8pI= priv=MC4CAQAwBQYDK2VwBCIEILH66tKKUf+0eETnw7Jlfim9JKG7QNsxazANvEBNacMv msg=sfrq0opR/7R4ROfDsmV+Kb0kobtA2zFrMA28QE1pwy97W2475s4C5bOeW9AuwZjhMe+aCvqM0KujPaHz4y8KvA== sig=TSmVhUJsxXGxDZ1bf7CF/h1dN/na48d7xMOzUNvKsc01ZpDfiGY2YvtvUUoI1nuYyMz3D4tp+o+gd+HaIXdIDw== e=found last=15 s=9 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAAwUQIo4M1qy6efc4w7fy9w4794IQSas/9qFl05h1WcA= priv=MC4CAQAwBQYDK2VwBCIEIMhJq6xLjtXELk9aEoHE01rNCH+j38K0YQEamjssRqAD msg=xNNazQh/o9/CtGEBGpo7LEagA4uswFEWy1FNgkQx+d2yIwgRx5lDhirsnnFS8141Ru1fJWXeQA4cGsIvEE3GPA== sig=EKpMVwjdFq2c9aVShr9h+NqX36uT2KPSQxlP1hz7cHy2qXdflf50xUB7g72y6e/Etiu84OOOkbzfupFPvcTOBg== e=found last=15 s=10 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAg0uXLg26eJhHIP2EuV5VMwkZ9M0EqBGbSnMBLj8qU4k= priv=MC4CAQAwBQYDK2VwBCIEICiFe2OSiR1uRxEu55Chsy5N8GtdWh4Kue+aUS8ugOGw msg=KIV7Y5KJHW5HES7nkKGzLk3wa11aHgq575pRLy6A4bCQygddkX6sMQdBRxzB7kHolECRDF2IuzF4G0TygASbGA== sig=5zb5O/zUnoa3oBOZYg9aHHHszbrW3zt7UAj4HhU6D/qRR6Th0wVRbTWfZdIz9OmcRbbVEuS54qEtNgctCrtDBA== e=found last=15 s=11 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhDqAxB5WzgL9lnfCzHk+G8xaoCvKE4FR7nd97r2SwUk= priv=MC4CAQAwBQYDK2VwBCIEIMCr4lM25BDZ6Ewzbw6y1HQjwwEmozSLdJ8ZnAw/+loR msg=dCPDASajNIt0nxmcDD/6WhHulqT9yepiHLDh0IkC6lUYxYEO47oDUNdiKuP52ZkcH6kFLWxvLU3qonrewaS7Vw== sig=y06d8b2CCfZHU+VG9sgIbi3B2kikJIsuRdHIKv3zMwIaHLkAYolQhA9xOy/7Vijz7fWvG1z7BZ221b8KCHLQDg== e=found last=15 s=12 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAJ/YL1hsAQpPFOn526Cl0U1aIoCmFM3MJmxCmng7Ecto= priv=MC4CAQAwBQYDK2VwBCIEIJztITaSsxFJFxSSQI/lStdfomadpDVBc7OQYIPTcO7A msg=nO0hNpKzEUkXFJJAj+VK11+iZp2kNUFzs5Bgg9Nw7sCkOcOwWeJQmy0PtifUqK2ijNwHoz/H/117INH42qw7ew== sig=hhsMtJwNEcV252U6tsAilLv7RkL4DQm4V22w/HllCu0EU/ehQ09YuhJBSAkucR4cKg3O1FibBrFmmQYDcVV4Aw== e=found last=15 s=13 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/RGUcow7+t89TEYW5T0C/pQTY4C+uXUMnM8TCJM46l0= priv=MC4CAQAwBQYDK2VwBCIEIGbtJhEiX09W6FfESZ+FWWKV+Yb5q69Z11eH8d0f50sQ msg=lWBRMcKQfzg4ItoVY8s02Xzca5imvow3wMkf7AVexf2mvxgAJDYpjGbYvQAJ14yLfnQi6sSCbxHJo5OrbfP1Sw== sig=vSdP08bMaY6apW1QfrXU8q20WyCUPou9zkRjlVF+CwMLrsft3HStpMpDtRFqIRwRwj3nSVKeBlC1hKsG9RTqAg== e=found last=15 s=14 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAXZRDI0Xz98qFIoZWMUf4uYej+4Y3sLx+2fQ+61/Ip0k= priv=MC4CAQAwBQYDK2VwBCIEIC4ycR/Pg+EvlWb9nofu/SEoGphxh5FQ1ydVzKTeEv2f msg=zKTeEv2fDpXsItQ4NX63x5O5JbLUJAS77Y2mpHzqb1vpqR1++wCuJo7tVC+sNvVZ9j3/6z4pmkrl5+38NHEUyQ== sig=kmuV3W9aMiRSnhtqQSfIOsGjUcGKmcSa0apr3cBSSI/V20YYZTMO3UTgv6DG9DAIvxHiX+GKt5bM5RZC5dPTBw== e=found last=15 s=15 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAR9DKim6AFz9D0L+oEVfTARHniLVxGhpQQk6OK/6UjpA= priv=MC4CAQAwBQYDK2VwBCIEID6nAPJIMrV5c4Q5L1ggmOEx0+dFdxW63k88jX4GF0cf msg=bHyD0n1LgF7WqM97TpmOax2QTLw/SDiqoK2BcICQUVc5/U+Att/y10LtigLxBBHH/NeAdScpdAwGJusBO06bMw== sig=kUtn3Hux64xmPBEk7tHxKySscj7xvWA8D/FxGAFTKtA+0EoSfXi3lT/ZBdhatQJ0GOcR9gZh+qiamHPAA+qnCw== e=found last=15 s=16 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEACW4+FQWXjtCYSSMsBHdojsTuDAOmLNoAeXXi2wfeKIg= priv=MC4CAQAwBQYDK2VwBCIEIDdk/4sT0/betFtwkN6YbtI7fbFM133ioFBR260gRfpU msg=LP+f6rFEFoMHN2T/ixPT9t60W3CQ3phu0jt9sUzXfeKgUFHbrSBF+lRCgrVQ32eOH7tIOQX1V3xyXDaj7BAO1A== sig=Ysd9z55LfRXUt+BxKNM0356yjhDR2VohdIhzgdZjD9K5eSM+QjMZ818I3uCv38upJ3UI6g44x+NLXcM+5H2CCg== e=found last=15 s=17 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAWpG0npFRhbH92UGlmsdLcJ5K+Z5XCJYh36fuaHz0qhU= priv=MC4CAQAwBQYDK2VwBCIEIOAVsqAlrFCg0k+rvoz/3qSMHdCGxswj2F814wNG0jxW msg=wd8M7e33U0tdWlZFgtXI+fOWwDcgPg25PFZspsla14Tz8f4jIK2CsQrSxtZgSN+MEaCIgy3p9cRIp1afGTITxQ== sig=ZWbUkdTeJpADQLwRiGH4RX1WZwZXDPugxLYU2N1Pao+vObfViQ5BWm3NXpTnHJPjnrS7VNDGWoG7vTe4l6u8Bw== e=found last=15 s=18 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3k7BzDYQSsLY64V3S273re9BuZfZeSgdheM7l4JpXug= priv=MC4CAQAwBQYDK2VwBCIEIDdvw4Nhg+wrAOH2GLqxTtot3uPnVcbu2mX9miEmRgXp msg=miEmRgXpwsl+ns5PYUJbr6dTPYWRmlkqYjO4alal9RjcdSnwEyE+y8Hqm6CPtrJsltA+PgBHvvDHEGuW/hJGng== sig=4ChblR75A6ZM216R85mj8MZIhe1xt83qqrt2trHCsq4Lh25L6/Woi7bCVD0pVWvc3lD2BDJyjbT3QCD2+TYIBw== e=found last=15 s=19 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAlfQqLgqBFHehUOWnU4eN/gm+CKSkLmSEo2n1K+ELKx8= priv=MC4CAQAwBQYDK2VwBCIEINwW4QAMDFHX+ddkvy/A7wRycB+ahyKgLtOdQFtfaxPL msg=dDajbxZOplSoV4lyWIaQHXqHNcXXHojUYoc5lczMklv63BbhAAwMUdf512S/L8DvBHJwH5qHIqAu051AW19rEw== sig=zu2yGljWkC6D/Zawl4LUDA4XcdMguA4OAW3zb9Ui4EmhMLjfBrOZ752oGjC5PpwzPwhUOmy6gxB9mfMi4Z05Cg== e=found last=15 s=20 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAs9MlN6HWo2TsgLW0LomaSow4B3pBzPBXv8raChJ+wdM= priv=MC4CAQAwBQYDK2VwBCIEIPJ4b3lQ1l4H9WQpccfz25THdmBSSibuFNtovFUUtU4p msg=4FfucowYvTAsVRfxVHpWUTh8XcUP8JkLZ8eKTz1KW5WBFN7N3BwTatsFjgYwEVOoMOlLQ+zqIMPdzsHStkZJxw== sig=PhWrVJgl2jPJbEP+jsAJjlYhH/9ZU/akRPPC+bjZJASfGtLF81sR2dtnEJJ67IOrmrn2VrqDyCmbaJp6mPMyAg== e=found last=15 s=21 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEArqGiXTDjJCRBvXI3MlNRwyuLil3tQLSynDB3QUHSJlk= priv=MC4CAQAwBQYDK2VwBCIEIJFCgCW0JY8ueKKD/cJ4ucM0BdZtx5pZ/Dkg38uoWyL0 msg=g/3CeLnDNAXWbceaWfw5IN/LqFsi9ModeJ4fggVFU4vojDWIaq6IwmzymEwYhzDgYkvkROA5V2QagJYmC1j27Q== sig=s7dchSkDITB2wp8tjoM8uKhXm52Frej/g2pvJ4Stq0kJ+uyuiGQWTtPiub/9PXploJzdd8AdOyJsrAaPcTFiAQ== e=found last=15 s=22 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEASXFlHAHXy2RrnNrM60PBTaWA2tokGbavOK3DyMqRDL0= priv=MC4CAQAwBQYDK2VwBCIEIEJ968k9xwr745P0kFdd/0A2cPKOqXhmuIiLPYNnz/1o msg=GOBQueZP5hzvyveAeVQKkHMT1dMB3UJ968k9xwr745P0kFdd/0A2cPKOqXhmuIiLPYNnz/1ofWfYdsoDJXcTkQ== sig=eFcuG3DdOPYdBQTo79MKfDN9ZPzmq2NhVHFgs2PZPerqLsWm99Tyd7OC0qxwlwHLnPIb0jZavOT8RrD2YkP6CA== e=found last=15 s=23 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAydzyd2wztJHVVpRd7QvF1/1/O0uW+0CXI2g5/5r+6Ug= priv=MC4CAQAwBQYDK2VwBCIEIGgiz/cBNBH71WkV4DvATy+hnF/xLfxdCL6yyEiMzSpZ msg=whfAgLqpkFc8gpVfLLIjpYRMX2HYhE5IhiUZkzEuTj7J7meT+D1WJgDyxlpoIs/3ATQR+9VpFeA7wE8voZxf8Q== sig=Cein4zxKbMhz6VHuGVmj50forw8RKeBhYM9CJ6WEy3EKRuHpPivmRi9lWqGJB5EbtxMY2mU/QuRvuUD+Oq92BA== e=found last=15 s=24 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEANQPE416EO1e/YIfYZwokJzJW91j5FNWLI4swn0gjmP4= priv=MC4CAQAwBQYDK2VwBCIEIJmNgRfC4yHNaWrqxXrsWJKFIh0OWjsKmEJ5IWfsA6Nv msg=yUhk92hrerFdxOl+q6q2FjHu3iXHlfp5HJdgnfXszZ4tk5meUPBMTESdSY2eVWZnL9DULjnZihjHX5armW3lzw== sig=1k0Njd/4NDnJ9WkuvTZnFMZ1NIfG395A2P6yqhJHV5dcw4SIAY+IWxQoQEmTdxUrH+IHG1m877YwKnDuuWn2AQ== e=found last=15 s=25 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAsMWGI3+oO67hdRp2aSpGVGYBDsaWyLki7aWs6HAS6m4= priv=MC4CAQAwBQYDK2VwBCIEIHehqPYlfBfYH90FLccoweWZpMM3Evmdp+hdcWHWuJR8 msg=TMOMgHpnLgnRa5NAh3LwMx5b+r8duN4Bo9LCl49kdeQrHBLKgwRsOM1b8NzoIOsq2TNO8m9K5bpw4VlImnehqA== sig=fYLpXn9C5x19l4cN/emKTDM81tdIg4G0nN88nuAMqknvuNMdmMhPUO4KTBrGP5obyo5s39MJ1WTK+fe8L2+VCw== e=found last=15 s=26 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAkiTmVwCQkfzx6JjgC576f6dw0+Wo7PTp6xzcNFGxzRo= priv=MC4CAQAwBQYDK2VwBCIEIFgSkJrNttZPMxJC757hYtsjF1ca2kacH/i0Ku0h/mzS msg=q6riLhAv/Ypbki0gVo/QiyLt5hORyMPlof52FyoujQS09l9gA/ydd4B2QE8dLoWSRFcwKJIGHN4gpaZWZuKFqg== sig=Iv5NLvdV4kc/cJAA2bvnHgMXibj6tj6hWl97sZz5LA/Ix+Vh0VgsWHlEHEc0ccVZwGX25BqSrghL/abxVFz7Dg== e=found last=15 s=27 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEARnKigl2gKR5lHyyUuORJYruDxgUj7O0p6rNG51VmcC8= priv=MC4CAQAwBQYDK2VwBCIEIC9mp7zcDmrPd+sTwmZr/LaLlXBGvsOLxpNicHT5QgGb msg=aEVcx5Xb3s48Ip3cG98+XLEhSkJG8q+W3GEyAGodlzK9OemVEJRMat3FumovZqe83A5qz3frE8Jma/y2i5VwRg== sig=BN+ew7sg31lM0Or+YY7hhYtM29C887tHh/cEcXT9sOLW3d/5x7hQN59QyHqmQ1Hn+DpYIhZQPqEiAf3zNbbSCw== e=found last=15 s=28 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAn+8vHv2QlMeijiySod0yhElhWPghcpH8RHfY9tkT7vI= priv=MC4CAQAwBQYDK2VwBCIEII3SQkZSpQQX0mZDz/iIlHWX0KMJNIMYWraCOL8yIUfg msg=R+C0Dl7wrlYM4046xoAOnfRsh0PtUrf+QH/jvDEHWpz7yNeCHI34NQH9nZnmfy9B0LWhS0dyeK9iODjOQJG6Eg== sig=M6oJH1fCDACrWcGoLD6LkuThPgUQLUbmAT4cqz2V7O/2JS0YIqSZYM6Cpn1VZHwLEsu+oYJaMi3LVnsnLU6QAw== e=found last=15 s=29 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAIMh/nCVYBLpo9bGoFamZ6AlkjUWSFjc1hwflbTYzACU= priv=MC4CAQAwBQYDK2VwBCIEIPfQE8rpMw8Rcxk295Ltio6b2rynJAsk1wnNmIRIZbSt msg=tsDUiGmiJBMz9vfQE8rpMw8Rcxk295Ltio6b2rynJAsk1wnNmIRIZbStOkQv90OkGM9Ussrj9ZTwkyQL4A2tJQ== sig=u3/pWM8j1SLylE8+L3W5p1aETwMEmu2bmfrb/6q5lr+oq1gaTJ4rMEAyEbvA0RQ8b9oiR+LLCQBdTBqz8F6TCw== e=found last=15 s=30 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAOV6fvMN4gZSuTKffd2zbGskWB99hr7res2WhHevHuKo= priv=MC4CAQAwBQYDK2VwBCIEIP6a3wkUPLbsJbS/EMD6XGo9/yAyEslZqQ+GH/q/tyE+ msg=PLbsJbS/EMD6XGo9/yAyEslZqQ+GH/q/tyE+pPlvTFtdT/MscOwng2IuQ4WDVoumejzPuqC6Wf9pWwoGlJDb8w== sig=q1tizST7iXXD54JwMFVilPEkRvKl/M1E+WGE9tRXsjp+1fg2ETAV2rjxvWwJQjH/Yy92zPQElYF4WI136oB5BQ== e=found last=15 s=31 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAEsGGSW/Gu3HAiv7/MPHz2PswMvQM2bOJfuTXxFWqRQk= priv=MC4CAQAwBQYDK2VwBCIEIFkwoE6pPsuNV1xsq/cmcWbZVL+mL2rZT3OCFxMMQz+i msg=y4qiB5Qpz11hMHNMgKISD1kwoE6pPsuNV1xsq/cmcWbZVL+mL2rZT3OCFxMMQz+iYvuoLyjeZB6EK2LUFQFY0w== sig=8yXqIsBxr7OtWWGg67O0HP7dPWFOYv5H2GbVzNMYo280/3wRCYMmOP2Tq9MTuEfUlise5EnPOUtaDEFEK1JvBw== e=found last=15 s=32 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAFhE4dGE8o/tUm/hx/aP4lTeL+I+aTtO/z180zOJYVqI= priv=MC4CAQAwBQYDK2VwBCIEIKGfcdFXVqOXnS+XEI5thtOtaRULhGYecjjOYX4CBQPV msg=CTOPoSYin+Ap9x5x5DkEy/HxQLx0kVh2gwXDZWJK5HTJOK/ZhIFKnsI9QP9hBez2KqC4/hgni7kysfll2488pQ== sig=nti3YWNNWQXJ+17TRji0aTgToPBZ5TEx7UfYOelGNbO6DVHrplr3elQ3lOzQdk2lsIb/Vfs6GyRBEDFprwv2AQ== e=found last=15 s=33 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEA6bUz9hWfvAu6nzxcwUpONCWGks18fsDqk7AqFS7PXPE= priv=MC4CAQAwBQYDK2VwBCIEIMp7R8yHwffb0d1CQfD9mVF1k4pC500P7R3AQqAZRk6i msg=QL/CK9Mw29OWSs0hwU9alwfWKSsV1hERVwoFO1zVHnkq4tpuBlPp2rnzPNPufRbeIFnKe0fMh8H329HdQkHw/Q== sig=o2uvOo/nANVXhXTHnzHjzOpNJ+ONmE4cbXBtHxo50ck6zbLGevizJvjO5H+YkGjsRvY8+DsKhREwvcax7uJLCw== e=found last=15 s=34 in addShifted_NP",
+ "pub=MCowBQYDK2VwAyEAQOWjVLS8HFScIrUbwVVgRP5D9jTS52XeaGAuDmxYAxQ= priv=MC4CAQAwBQYDK2VwBCIEIOk2lhkb4hFslloPTx+TmYKr4NxMxUlRnD8PQ4craCtL msg=6TaWGRviEWyWWg9PH5OZgqvg3EzFSVGcPw9DhytoK0t6CFR3PZeN6edgjxrZ0dW1zVP3rgaEqleaFNd8URBEfA== sig=jtRs/UGspouo0iYaFfBd8wa91CSa0pQV6xSeLCnsZluk4AYiVNBWjFZZ9oU1HsPLzdDEGpGbmU193LnedXFZCg== e=found last=7 s=0 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAHpDsS5HdjkJb0dCYT5hhddSm166G9HQoC2k3GDMD99I= priv=MC4CAQAwBQYDK2VwBCIEINw8Y9Rsrb/5kqGsTPwV8STseqmv84Q6YKEcEv2w2ovQ msg=3Dxj1Gytv/mSoaxM/BXxJOx6qa/zhDpgoRwS/bDai9AwMttrMoZdQ4iLnemnlvC0ZTWWwwRPXcEbopP75BvxrQ== sig=3EJD6U6e9fjBO2Ju2rN8P6UK+IsJ2uyLMj4wD7fh2/AHDfwpbFJTZMXsl6EX5OqJ6/W0Yq2nBEA+fcO1zo2YAg== e=found last=8 s=0 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA6DIyqh98QypyNljYuK0Yox+RY2chi22UFMQ6mKbbvys= priv=MC4CAQAwBQYDK2VwBCIEILUJF/RnkQpvBEq73BpXpaAjBEsuCA7SojGFSm2uVZW/ msg=tQkX9GeRCm8ESrvcGleloCMESy4IDtKiMYVKba5Vlb9l9g6m23Tv9nd2XfUwCNrBRtrCpKiOZaufteVa7LXCHA== sig=WRWiex3AumHOjuLndKw7p4OdjJM8pidHgY8YzsTjSjtTtwRJvzLgbBOP1rPqxFF+aF/UqloJclS/gda7o5uEDw== e=found last=8 s=1 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAsOPphmmWs4k9ctn9dMnHIkNZXI5vuvTckkPaIrwiNz4= priv=MC4CAQAwBQYDK2VwBCIEICFqwYdweTEkVfkZ+ffquTocIx7s8ZgPGe6AJdCewL5D msg=IWrBh3B5MSRV+Rn59+q5OhwjHuzxmA8Z7oAl0J7AvkO0ne9GYj1yT4wSeunnnb1VcDxjtZ+w8qN8lBfZDzVnzw== sig=rdFSJFIg0Hqky2z7dPucCjxjrqJQPHk8bMkby0AnuRkKA/E5LLPuMt5EdPMYrCyxXPHK9vSBkwahgIjwS+jUCg== e=found last=8 s=2 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAUpNUaZcL+urJA17UAKo4Na2VoztV/aVyEyQj0SDBjIY= priv=MC4CAQAwBQYDK2VwBCIEINvxglX/8m5YI+eDzCvDM0nRlUlc+qwem9TnZuCHORda msg=2/GCVf/yblgj54PMK8MzSdGVSVz6rB6b1Odm4Ic5F1pDLTRl2QeNY9ip4/jVfe59LnUYO1ot/Mf1FOTl1ud85Q== sig=9EpPk/qHoEZURIE1CR9XJfmceZXedjBkCfvWaI+sGTawJSEqoOrT22xOwVhYbUWviC9WSK5WSZwt2PRo3IqlAg== e=found last=8 s=3 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA6MHneu2YsrotLji+Jd91XULghdgZq5xaW8kjkGADM34= priv=MC4CAQAwBQYDK2VwBCIEIBOC9gDzHHJcD2uJi6iIeysCHFwlwl6fkfW22cuoRvYm msg=E4L2APMcclwPa4mLqIh7KwIcXCXCXp+R9bbZy6hG9iY7oT7Qv8XnP5Vc4tZMvOeWDFf82LQleiHlZO0p5w881g== sig=j3k6/eCF2wO0x83LpLHD4Dmi2HCrAcd0me9QL3y8AIbRiutQJp2s/1Jcp8tRTaAyrLNY1lcPWuFEABMrzF1OBg== e=found last=8 s=4 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAJbm2aEiyqpX8lQvQ/f30pAd3anLtbpdVRcMl+qodWgk= priv=MC4CAQAwBQYDK2VwBCIEIHRcig9pYtmZZq/jVW/nfTy85QH1mbViwciYy5fCq1qR msg=dFyKD2li2Zlmr+NVb+d9PLzlAfWZtWLByJjLl8KrWpFE5ir3WAxzitYBUmfKEVFFQrS8Vazb3lE9V3X5aZnXYQ== sig=21WAOMBavwYUk2pkYkW5N4wLK5QNEhspiX9YTpV2eWciPF/nu20U1hgKRWRilqfWNjs40C1qTc8Bk0GD+EfEBw== e=found last=8 s=5 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmM3/Zggp0aOINx+uhCmCIcTsi0k3fmMSgBPTmNrSaYQ= priv=MC4CAQAwBQYDK2VwBCIEICfJ5oMNeYYIEmcbLP25t7BF78SNRPL/J85/i/uecT49 msg=J8nmgw15hggSZxss/bm3sEXvxI1E8v8nzn+L+55xPj17H0rPKN6Z1KDATr+4NliCZqqKhQZZbtiqoJOZtQsapQ== sig=2zvO7FUyWl6Owov/MOz5i8AD/Am9fE1na5lj4BJmCQiWkcPIi26RXQG7rkZ+pPWMz61g3NdwRABx4E7gASzkDQ== e=found last=8 s=6 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEADE6T1shUGBsIc3CImli1AnfE2K0u4+OGbUZjPMGgQsY= priv=MC4CAQAwBQYDK2VwBCIEIMWzWhvXzzCvC3O42bY9uM8LCEPxpQbCXxdHb160h6AX msg=WhvXzzCvC3O42bY9uM8LCEPxpQbCXxdHb160h6AXa4QHMXbIx1KTqyhmmTzTChmMIpKgj7H1Yna3dqNYJAMqcA== sig=mKKQZof5Y9VGkqFEsxwDHk7B8VEN3us8I04xqqUDYC92wGnnanHlKAwYJbgxa0n7oFqzduJk4tto+xOsnVv1AA== e=found last=8 s=7 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAzpSqMVjUK8gtPguKb5kMa8efjbfnIKsDFIHjrN7qBmg= priv=MC4CAQAwBQYDK2VwBCIEIKIlq7DD502/di/TdOJUV8vmyhS006JckoF2gVwpUwOk msg=w+dNv3Yv03TiVFfL5soUtNOiXJKBdoFcKVMDpPnqXJMPC5yetvVu42FzW3t4NOADQA8Wivsldxdui28//itMxg== sig=PhZ2Ijp8mQbM8+wHdq50wbLCxErrXPj/1HaPQ0deWK/JPMM1QAAbbvjTf+zUFUEGCPqvSj9IijwwTVPaO/5mAw== e=found last=8 s=8 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3rrp5Lk2ewftAO3z5nG36OhfbjpB7XKpr9kgzVRYROM= priv=MC4CAQAwBQYDK2VwBCIEIDxxFhXb9jxcvIFcS1TLTN4bohHnXqVajuY8TODG5dMT msg=PHEWFdv2PFy8gVxLVMtM3huiEedepVqO5jxM4Mbl0xNcqFt1yQvS22NFttzVXhiHfe4caoFf+ZQWGh3WY9SbUg== sig=/+Sgwa1h5dueYC+7h5byNCLiah0kGXxtmni6RQV9Bwc2hzurbl/QcAINduZ9WEqZNwds5EcUeRsWAGidwZN/CQ== e=found last=8 s=9 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAVnMG6RGk0i5P3WqJ2aG9UK+M2ca/55Aea6g/+l7EUww= priv=MC4CAQAwBQYDK2VwBCIEIDW2QadQ+qZPFQAX1IuQEn7B6qSL9S+YNr39YcrUqXpu msg=tkGnUPqmTxUAF9SLkBJ+weqki/UvmDa9/WHK1Kl6bt9UABaiEWsrQtfYQXfSPsiQd9yBDR5pak47uCj15RAEsQ== sig=da8aZTRvOpgUsPborKnMR64rUxpfzK0rpe+bQHStE19ycwN64UqZ6ZwTpSd61wVXf7UOmsnduyiBGxDyH/KrDw== e=found last=8 s=10 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhzR1lBSAxLgzh+GOtDL0SmEROPHyf830DoknO3rZSCg= priv=MC4CAQAwBQYDK2VwBCIEIOLG5d/aLchi6RU49063TRpIzFe0GEcGBojNcUQz0YQm msg=S7fc3vhT3HVYeueii0Kx3BCjnIkRHcf4aoMI3JkYSqBZRcTAQNtnXuzOBVbQ8BYNFEFVzk1OVlRiUoUR6P8z0Q== sig=bGDjgYraskpAMLfFreimXEEpLz3k6Y6raYj6CMe0g2PMTnXjTdlZZiAkZCxVWt2aYgR9Gi0K6ZbxP1Nqt9brBA== e=found last=8 s=11 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAvrWfI9fDJcar/1uHZc1ano51EwLz0IWUgfiq0MX3/M8= priv=MC4CAQAwBQYDK2VwBCIEIPiGUJusC4PuuuVHim7ESYTKCA+m+S0C9sPILIBphIRi msg=rAuD7rrlR4puxEmEyggPpvktAvbDyCyAaYSEYmkv5YsPb1jOtoWaSBe0SOxur/dSCZpc2JyPi4k7j6bdFdc7Xg== sig=rim4EnMXhZ+TOBWZAJqFnNiVC7PZvMSG21NHfILXtmmrUVtwGjE49RYKgXKQdS2nOtCUri3cIYlKpDx/q4mjAQ== e=found last=8 s=12 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA5aNMKVfRETU4dms585gbWhEaAZqd0vi0Ej8Ps9zmCB8= priv=MC4CAQAwBQYDK2VwBCIEIIstCfgUrcc4sLn1ZtzmathKJalmBl/IiYD7mwEALK20 msg=rcc4sLn1ZtzmathKJalmBl/IiYD7mwEALK20iBOFU0n3ttIytnsb5T/48qnXmEt8K3Imk5/5sHTV+QrtKt3Kmw== sig=JIfvFOG417/+2nB2E6wBvhEygUX0M20x+Mb/4iCFwWk7nqgx/PdBOtW2BEWNpQ4rL7pI4GDYoeyajiKH0gy3BA== e=found last=8 s=13 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAYYrBoQgHnuS3levk9v+0dHzjjgwrqbzr1md2BYet3SI= priv=MC4CAQAwBQYDK2VwBCIEIM82wQ8CANjO1CG/b1OTQaYbZ3YsHTYm+XsYep1W8GSF msg=+XjLwCOvHBXSd35Ir5r6HwxX1I572Q6fqS8Ox9m9Lr3GTYMWFmP8VBqRlB//wzVL5Hu7iILUcnUtSluICXJO8Q== sig=OTD+joRNVjBhAAkd/uWYPncrS/2W0VvMO/FYJfeHDDKkYt3lrf3N2vkeS8qz9Z/zQU1+KdtqRfvFzl3LgOhPDw== e=found last=8 s=14 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAIKBZnfaaVcEBa+FTJpmmHBcf4vcKcO4+5v/iXFHTpDA= priv=MC4CAQAwBQYDK2VwBCIEIGlMcS18gSEMcGEO0pMWxVuDjZVxdEcvojU+kcm+uKz3 msg=gSEMcGEO0pMWxVuDjZVxdEcvojU+kcm+uKz3DwyO/EHrm4tedZuam0lavgl5H9ofO8YSXRb5C2CmcNEU9clpaw== sig=RHIkpNTnWwMw6heqe4RWysE56S3KWuJ+ysaqS/ox33F8Q1BwSzdI8Ibw50hktTQh4cjJ4zo8R8M6jsz2eULaAg== e=found last=8 s=15 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAst0qEVaT9cx5EsTjMMxhbVioLL2SKylkinapAlQDZLQ= priv=MC4CAQAwBQYDK2VwBCIEIJS8U83Du3KYhZFU1epgqTPtXhg8IeZzTcPsbO2hiSe4 msg=C92G6vybK0/OB9IVLBiqs5edD3hzE59d2jKUvFPNw7tymIWRVNXqYKkz7V4YPCHmc03D7GztoYknuKwL6nT2Lw== sig=to6o3wB3LzyrSDLMlx0xtiD/n3xFvWDFhd+RcPtIWAhN0etBXzQ2/I9hMGPRIH8kiZR/EXX25iySlLjFCAe+Cw== e=found last=8 s=16 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAF9BYIgRPjgjjGcepOMo/AiqnqiVGqMSHpyHuONz3bR4= priv=MC4CAQAwBQYDK2VwBCIEIC6nATsPKaLuyByUlYebKymCbWfW68VERpxTrGuBCwlQ msg=LqcBOw8pou7IHJSVh5srKYJtZ9brxURGnFOsa4ELCVBtOlDCn7WU/PMKvzvaRXlYuePfKlexOuzBhjxWxQ4AAw== sig=ahGLVRQkrSRM9ZrBqAVqRZoBYedjDEIsvpzTbqa8KrSZsMAwt5q8OzkiyhKCyYxBcAc4XHSszkqw5inLN/pQDA== e=found last=9 s=0 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA2/2e6MYTlS/fclD5T/kdSX9oWCRGPmYsquX09bu+j4c= priv=MC4CAQAwBQYDK2VwBCIEIL+kLt0ceFxI48cdPWlA4W0TydbErsV+b4MILG+ybLc2 msg=v6Qu3Rx4XEjjxx09aUDhbRPJ1sSuxX5vgwgsb7JstzY/4lJOQ99xBJw/s/wFZEEV89wb7yzMH0qLfm/CY1k1AQ== sig=GlN+LGpJelxKsro0x4t7fXUrDmh7kmZywIo8Fts9y9+dIAHdOTnA2PA3z61VfbEEJYUej3cZa80Z+VDeNzrACA== e=found last=9 s=1 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA5LrjnzRFio/PIEWVRa/l2N9/r3k3lffCpvPId8IlBHU= priv=MC4CAQAwBQYDK2VwBCIEIFr9mVmLBHlMFusTtVzWhBG8xMK5zQmGvqiB/j1pFZHL msg=Wv2ZWYsEeUwW6xO1XNaEEbzEwrnNCYa+qIH+PWkVkctr8cmdBbMc2NuHMi9/TFAy9B/5MtpMmeQuI3phoLZn2Q== sig=9IudH4UABWyKIDvuf+Q3akxRoAvSoSs1YAcmTEysGygKIvuQeF4XPLCKVFoOwL4/znR/hFJ0AnaLdaw9xbQpBA== e=found last=9 s=2 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEALDhuzQrSuz5AEUvn/9FYng2aq00nrlvSxqyZJZs9tBI= priv=MC4CAQAwBQYDK2VwBCIEIAP0Zrcs2xicBhloCCdwgv0eP+kVkF3iW2ZyXEHgmISb msg=A/RmtyzbGJwGGWgIJ3CC/R4/6RWQXeJbZnJcQeCYhJuDhaaS5OBZrjdbJdzHqGd3LVOagaNSxkbsjz43n+mdBA== sig=3qXKA/IggPNDtIlHvjKSQl4eUwKd5f9aoqeTJ9Si9zzq/r7UGaFKCIlP7mBYcqZv7Xf33LXyaqxc3o4OBFBmDA== e=found last=9 s=3 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/4uf/6NIOriyqDAMmAlVFMXvwfTgjMOoBYjs+a5P0oc= priv=MC4CAQAwBQYDK2VwBCIEIMuA+RdrWI5yIPOBFRfO8Lst9vBakrBC9DflgiMvujKg msg=y4D5F2tYjnIg84EVF87wuy328FqSsEL0N+WCIy+6MqAhTKXQovvWKFoYCZGQl+oG9ORLylitK82LNPBNhmX/Cw== sig=LnDenkVBWLSds2Dz90TRDBnSFuYoJQXSMj4ptCMfBeynlbJUstLTYpZA9m9uZZCPHl6nfm0J0p9sGYJp/zVkAQ== e=found last=9 s=4 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAiezuTEFbeHb4ImjB9avUZ/nA8mgsXkE+jy4MZ5oJ8ME= priv=MC4CAQAwBQYDK2VwBCIEIGR2rV16B/gWo2blA20GD3M20YwIwa+CcXB6o2qLy3Rn msg=ZHatXXoH+BajZuUDbQYPczbRjAjBr4JxcHqjaovLdGf/dXxC+gbaYgEuWlaoclAOBjtRBYRWeqVdsVuewV9baQ== sig=3DQSYaBxLr+a/L2B568XGFIaXS/QM9KTEwXmKEDeD8+3zUJ4IXCJdU7yyeG1727PX8lllDKgcpUrJtEA/jYFDg== e=found last=9 s=5 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAcapOHuRQJfvaPnaOn0sxRRTW4Qmwze27fX3VYrSbu5o= priv=MC4CAQAwBQYDK2VwBCIEINRL1nbSNhRX6cAQ3jOuhd5k8G/nloedR9226gmLgUUn msg=S9Z20jYUV+nAEN4zroXeZPBv55aHnUfdtuoJi4FFJy8Lfc72pNo6cyU3j3a54NhLFW7os1REBEgiHSZeu5Xnrw== sig=6vamBUAb7DRAbYNpDhnoKYbXrX73juRu9DKEbFu9AJvsrlWH1NiXaQ/EoRjE9qt3vAAZWhO1h+InAFfP170UBw== e=found last=9 s=6 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAvlgouF9o+BIa0+bSqyjxVHv8DYz7EXiuf/Mo6IuhaBY= priv=MC4CAQAwBQYDK2VwBCIEIApbBTashDtYAboqQbj8//vRgEE3l4JLCUKNouY7qzik msg=ClsFNqyEO1gBuipBuPz/+9GAQTeXgksJQo2i5jurOKQY+su/SXwQUwt5eZWhbOuhSatG7FR6hUAbNQC1EUvjgw== sig=i5/8rX8bQlxbOZOFa2Wg3HXg4ygclmXDnZ/3H9DwBLCgrCHqCp8nO+0vgqnbFG3thCGQie2z4P1mdUGwvg9XAA== e=found last=9 s=7 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAZuTZg2F7egDErwm9ru3QUUZnr+0LAhcp4LHbZSptgts= priv=MC4CAQAwBQYDK2VwBCIEIDsPm477mNXnfkMvE96DPJBm2NmmazyBGYinLp1E8IyI msg=Ow+bjvuY1ed+Qy8T3oM8kGbY2aZrPIEZiKcunUTwjIjkO89kMLWLpt0XDPV6pDX2ZPBgTAVS/uAA1uB8j/j+JA== sig=DBfVPPdm+KzlgtxddC0L4HzVvmCk9shkVem6fBKxfQVuSCobqS5b6nVGJU9iHwy1smcWcv3bN6/4EGILmd9LBg== e=found last=9 s=8 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgQC2vVXNQTuxDzy9YGFD0MpmlTuV2ppV/h0tH9idkN0= priv=MC4CAQAwBQYDK2VwBCIEIJtoxPFBO2sScb71Hr2DbfzEkq5qTTzaWwI/g040oW43 msg=EnG+9R69g238xJKuak082lsCP4NONKFuN13bl69BcZNHGgPpPLvyXt3okmAIsuBIDdbLZKDLCVf+PK4Swpq7ug== sig=mwttA//XS/Wdm7uiw9hIceA2Wt1thjfP55u2d34QhP9abyQvrF9cEMBWpKo7IePZlYjYURHwSUoiA1bQ1nAHAA== e=found last=9 s=9 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAq16R7SY4zHqSbN1YqUCwTJGTceUfPgEw9XbGMXjZL2M= priv=MC4CAQAwBQYDK2VwBCIEIM0h61oL6U+2x1Zxp6IWztJbSnHcoVsGuLyXWwHBEIgs msg=IetaC+lPtsdWcaeiFs7SW0px3KFbBri8l1sBwRCILN7xT7qepRnWuE5triy6kjjMh2whg9oxZw+bwiembws1IA== sig=6tz5M1lAtk5H1NqEIM/Dpw6lG/Jtcf9HzDT1+LeY3fOoCIb6gVBHy25qY0SPRzQWX2HbnVYfPQq/nXmxTXrKAQ== e=found last=9 s=10 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAQB8bc9JfcTpXsHfspyQNHuVP7nYX84QNvGQMQepnXQE= priv=MC4CAQAwBQYDK2VwBCIEIHImrYbvFifg0hyWyaDVqLo2P3eRcBFhHL4t0d3ATOcu msg=UZ2K1Jg4CpmegQ7JTwzGhx5EwNBqsrNP6z1WXniKp1m3E8W7C63BG8WZ73aRVfBoSYPg9dOlG6mxcJ5cle6xCg== sig=aRepJNngISeBdgXQwp0XDK8/qPuQsIzT472Cv3lmMQOm1/flXFOObTx4ti1ypvdcjzqVtd+sUBVcxPzsSrmRCA== e=found last=9 s=11 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAl9AaTm7z4+4DiWdaAPFud+Hv6Aa5Jxs2jaOuDvF4t30= priv=MC4CAQAwBQYDK2VwBCIEIHbZctga5S0B42NKIyQqsGBOC40GI1NGB7tr3lAffJga msg=GuUtAeNjSiMkKrBgTguNBiNTRge7a95QH3yYGoUTh1cF791CXmJbyIol5NcRuzxIyDueFn5OYK3Ze7mS/mYqTg== sig=VXGhE3o6mO/Zh78K3Z3Lcs8/7fMMBCPU+CzRnteGPcXeJ2qpO6L35KIf0XDx5nY9Tkah8N3EOdcWr4d7gA57CA== e=found last=9 s=12 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAYNtC7mIFJzbH5BscQpBMRHpfBG6lawnVvH94GgMY0Qk= priv=MC4CAQAwBQYDK2VwBCIEIOLVcpGzikOrIi+ei+JlrJ/I8PkcbZ6ag2awevTNgJzz msg=yPD5HG2emoNmsHr0zYCc80k4Ie2c20n1wiX/Ki0KuBeDnxf2CkdQYzqxYh6LcZUYlk74t04VUwReiVjE2rTI1g== sig=HCrJZDl+4qRxut1p1JohrVxOiynq4c36GNEeKdMHJox3nmHbtj7i7opVwZWPS0cG3Qfgu303FiF/rEVBwY2nDQ== e=found last=9 s=13 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEArIx5QuNi8blTY8Y8nHKr3KkPyQE36qBOjFPuQpT8rVk= priv=MC4CAQAwBQYDK2VwBCIEIJ7WPauRIJmLPGEtDrBV8iXvjCsEaHenWO7QsivxwGoA msg=1j2rkSCZizxhLQ6wVfIl74wrBGh3p1ju0LIr8cBqACp5bgS/XV9ENJdisO05yEDGePDAj666zUyKyxnswwVYxA== sig=K6Xq5/z8Mg+tE8cB2hLCV8avYSzY28cfMti70nP9IYET9s5qKTDsNZ9OhobR4e5TN5EWAt3c86D8N8O3Dit8AA== e=found last=9 s=14 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAXqLF5YCe/8P3L3oDlinVgMoRXY7t22se79RPOxFWoNo= priv=MC4CAQAwBQYDK2VwBCIEIHD+hcwKq4bP2K3VjZL8BfXNNRJ+nuN5+8LRZ2s9Nr0f msg=Pal43Sb4LavCS7gzX3Ux7lkj0mscShmK2ia9qylM3AxWxwuvoH6fx1rVirBlUNxb0blT1u4Q0cGyGQimntC6MQ== sig=P/UjtY1ZuGH5fqlmyfq6XAhd2l4Og22vLf4bQ9ykQLf09LdF+o/AGA39ijjT5g+SOocffQQuNmPfBCUmmWxGCw== e=found last=9 s=15 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAOEAxBV3yl8WWPEb9pHVApWWayBfYLb5IqdYf26uWiu0= priv=MC4CAQAwBQYDK2VwBCIEIGmx55Ykg0bNw9GGMWflsjY7wjajw6giKITEpqNaHpKO msg=I9tk0/EC9Rkc1eJz2DiR5Am4Q/QgX3Gg1mOqfZ6SiQ+mkKDjhBDBIzKjk2o0hejD8zvBT0OUT+KCtF2wF0f2Bw== sig=wzqcrj2Ji+oIMZONjxK+T4PNG2e1Y7UYnjbgu2wJiI/5KLYQXR1MU9v2VLq0hB9nzSGNegbcxezdWeH4DiXPCw== e=found last=9 s=16 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAFQaUhfymR3LFT/Z9bKqO7WCbd50QQgst0lJKq9/0JeM= priv=MC4CAQAwBQYDK2VwBCIEILW+D5MYorzzwXsKfrVSV9S7ptVNwydnOku7PYBjjwjM msg=Oku7PYBjjwjMI5GMuqKjGkwOU+HWde0dC6e2dYR/yhGDIGffIWLULoGEUHAjKLNV5RsB26D6JRsg7lLiwz0Rng== sig=f5+BuLBHJIwSfKKuX6c2XrYeRCkbAp2lbpBziEXX+dRv8wT+Q2511YzpZS4dkzovW1DvFibhsnTtrQP80OebDg== e=found last=9 s=17 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAE/Z4qCZf6oeIHPVVWG+AMN/7hfF84KomkN0DPtjcu5U= priv=MC4CAQAwBQYDK2VwBCIEICpEqkRkem6SBSBDYSkw84xk3Q48gWiBi11aNw8C8P4Q msg=aIGLXVo3DwLw/hCfctR6nmBIqEo8LURISYsQm3YG2UH+CoE48HuqAJ7I+RW6BQ1PJyM9rmB/HqnpOHV755lZdQ== sig=niWBPhruKdRYBojP2RO/3idMKWzcNg8SsFvlxpnjxAF7yMtGoCqG8RGnsPQGmUtQXyCXXyG4IsXpUVxdz/XkCA== e=found last=9 s=18 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAp2itvPl+z8LZEbur+hJ0qthBmtbb0SABFfXYGei9Mt8= priv=MC4CAQAwBQYDK2VwBCIEIDtBd1vcebTMWI5jKpP4CSMbE4CMKDlN7frmxsPIsY5+ msg=t/ICSwiQdTB89r7Ybjt2TR0Vz0OLwORTUg7HsRs8WCNuj3tHuhIdb8Sl/XBuei3KRv8E+eRcyUDnyM/YFMkvFA== sig=ekG51XRwbjU+AGVBshsXoPtCuWX2RZ0OOeZ/J5yKCUwo7Px0VM9UN8j0P1/kVd1Tnf3avRzPepRkRgrKGrTxCQ== e=found last=9 s=19 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgRp52AFYgvlP1JbkHz7p9N2qgcnlwZxEnPWZ/KaI9eI= priv=MC4CAQAwBQYDK2VwBCIEICvx6H2vp3hPWxGqnyIkXh8zsAJc8Joo4na+HNL6P8ex msg=JDVF4bKKKwb98m2gTJXDRKamziYwXX0PUZOuzjitk2zqQvzGrL9b9Wf1nZ/+g5vbSy9CQtSy9nuJ7AWLILI8NQ== sig=Et5DMmrTGzxU5STwmmnVNBT3fBIsngzwnrh5QU+KChbQf2HdaVKEsgd4EvoNcBGhDfrYEwV5ycpMZ+PxE3YjCQ== e=found last=9 s=20 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAGr4yocDhLIrOL6Fih/BfAUU+KklJrIMM3TpCnVzzgWE= priv=MC4CAQAwBQYDK2VwBCIEILPGgkNbQR0X9wWDolosXqSmu/jd8bH+fPDfoDPGaLo6 msg=3jrxs8aCQ1tBHRf3BYOiWixepKa7+N3xsf588N+gM8ZoujrbvUebmYrEleAtdlOr43swy/8MYLCkNz5GQ00axg== sig=jcwfGCuTTMn98NhLnEo0lmC9tfdp1mZpn/qa+ZgESuiEcKd/W+sWMoTnBssWFPpl5cK2zzhXa42Mo+6XqQyDDw== e=found last=9 s=21 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA5f2OsBUMpgJSBiBCud6CrDgOb8fnb377tHPMUAhpku8= priv=MC4CAQAwBQYDK2VwBCIEIPutBae7XSWWEAdKXgStcba2lAxKuj3EkZHfx1/8SDgq msg=seQGx5IulYVW6f6hBKu17sh+zWZB4QPl/yrUNOT7X7hDo6luCD9L7Oy4E6McgQgxG1jGrcNW61OwUrJCZ4ZRCQ== sig=ahmRLcvhyH0cJm9pMIYk8qGyjXLYDAH/KCQ4ab/K7+/CuuIP0ToudxGrS1JZ7/XDP6sQmwZTKDAr8X1Nf1oEDA== e=found last=9 s=22 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAfxAUfihFrxF+OoD7MdELWILMrfb/AvXVQRV4/WpZpy4= priv=MC4CAQAwBQYDK2VwBCIEIGRdw1PBTNr4L0Y/ggMNyJNnzpO7S3N3jBzVE0eauyun msg=HNUTR5q7K6eXuv6GnsgsOtlH4Jpd8I6JO0Uy+gGI59l7TZFkJbFseqoU9+sUT2w6TLZD2uKoIwC70VRKHhV+Ug== sig=Hj3XVCdcgrPql96WQz1pWC9+6/zZDMguskKjnatNbbe+SRhybK4jlH9Nrt1ZhcdgTvH9lKY4TQkkoTaAf7PhDQ== e=found last=9 s=23 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAzDtAtFRvYELDx1foLwQCUkNtmnUgJoejAlAntzrtpg8= priv=MC4CAQAwBQYDK2VwBCIEIGJ2eiKZBHCxD3BDtnqhjvtKmwyD11GUlDHa5zIUCLjj msg=LPUJGWzXpoaBYnZ6IpkEcLEPcEO2eqGO+0qbDIPXUZSUMdrnMhQIuOP0sNgKvE5pPd8fIdb136sseQCTxGcqqg== sig=m41sd5J7phr0zo8sA2JwvjTXvFeqKWmkEv3iGjA7jG1doexlb8tsaybfA87q304r/MbWmhnba9x9M8SmWSwYBQ== e=found last=9 s=24 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA0qsVQTGTq74sXPS5OLIUecO1pxPwfL1ajdjUqZGai1I= priv=MC4CAQAwBQYDK2VwBCIEIH7sYVrj8OvzYSWFpgEWtDDblIQ0QsI+SamGDyV+4keL msg=i4JPUhxAxLpbIlHkDRQJW1aXhZPiSciUQHk07NMeiClz1GCxXTlcoNTrHDnLpzNRVgXgbKCmDycFc3Jrwx5NZA== sig=wmo7yOCWzACbwNcs4rZHP5EO1br77Qlj6FuYxa0yINgVbkzjSUrQHsXm3w4PmIfmIKfKUHn51d5o0tvdWcmRCA== e=found last=9 s=25 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAnPVRZZBvdMr/6Ljg7698FsUe/AKz0S2jOwnTxRcSrY8= priv=MC4CAQAwBQYDK2VwBCIEIBG0ghMCkg8xEtqJvZ3Ep6326QHMjR98csLWqfSJ5tsN msg=U7wqAnTkfLP53Xt7eMEefyXAK5ajGzaS2oqOCdhDt++kEbSCEwKSDzES2om9ncSnrfbpAcyNH3xywtap9Inm2w== sig=/pPkRkGLs5RAM9bxB58TGeYKixXg3AnPFzmrMTbecK3PmGrSMmybD8Juc3/SOMlbndGdk+NoFBWrr4ZXwxQnCg== e=found last=9 s=26 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAZcVHB0GNr1ZlO/ytpOnSDIo/Cr6Mi6wg81NlOaPnzFI= priv=MC4CAQAwBQYDK2VwBCIEIAJLzZvYPnnDp4DmQ4ZNfun+5c7VdXfOT3gBKz6/LYKP msg=IFAoxlib8/GnBwJLzZvYPnnDp4DmQ4ZNfun+5c7VdXfOT3gBKz6/LYKPIzhIHD+OnsiKHjru01CnS60kqsca6Q== sig=Rfq7a2CeEmVskDOImTW22O37171rT73zgIQuOkjmfQvGmHSF0fnspAG8K5/9+rHc/HWinOl+3UfCDrRzEm/3AA== e=found last=9 s=27 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAziXMQbqrSktGT7LW6taCzNdW7XNbuuEqNAK40Rd/NJU= priv=MC4CAQAwBQYDK2VwBCIEILKtyuK9Uy3jVcMsK6/2ImFMn/6uDa5ebKPLnFdAMfbb msg=Arm1CatqrqQKhSGQiQ+4E6u/Sx2lQmzXSkcE+9zB51+EgLmognmpO0WC+7zF65FoSPeguNQJJj1g2KGZtNKyrQ== sig=5YMzgOk5WGGx5tkVNsuy8qBm0TP/X0su5eJ649NRrASrmtakL2XsyX94xzF9HY+nCLIU19P8mx+w2pf3x8urCw== e=found last=9 s=28 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAQ1kddGvQTMAgOjWas4On5RGX6CHYKq1Fv0Wea5cymh4= priv=MC4CAQAwBQYDK2VwBCIEICgWHAFL6sul67ikjzCPUKXyIs2UbLBxenNYVIie4fmz msg=ajyHSaNuFPZhSm9YEfKe8ceURcsv2CgWHAFL6sul67ikjzCPUKXyIs2UbLBxenNYVIie4fmzFyBB5/SkK02rWA== sig=RcTjC/OLHdV2Ibo0MHIpi7zsWrX4Fm3kibDwqLi0s7DZXeIQZKCJNRC9uMs8mSJVknS2ByYMnXR9VU3OKg7VCQ== e=found last=9 s=29 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAPdyeZEgaGZBTsMHVZ/iuF2dm7YddC2G0M6aI9Xr1hyY= priv=MC4CAQAwBQYDK2VwBCIEICiSKpY+iV1iRsSI1GNfJ9qsv/R50wCvd9qmVYA0BGt+ msg=ACdgOWUd8/aF09Eoe973ptmFo/YBU0LAaVKLj3jp2qLGh3egrIdPuH06xZY4NWmGXRqIPfdo63hiARet8hbnSQ== sig=7AV50j4LsmeSTR7fu4dyVE8DQZG/o0vIJFtfxECq42twOCkBkEe33tDdA/rflGk4P5KVgSn+Ft4acSV5rjnyBw== e=found last=9 s=30 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAFwl779AGyZOuTckZiLjkFjopLrDu3RqGGGFzCwl6QoE= priv=MC4CAQAwBQYDK2VwBCIEIECssVGO8t+3rbYsVzgeRAEfoyG6pOE5qrKe5KH5Ht/P msg=PCJz+NqJFFtOtAdj/3ke50Jny9/n/4IwE9/MbzaKIbnB2aNfeeK2+vHSZdTKtLnLIODU42R2ACradiIXSHmesQ== sig=8barku2yA5fI65ciRLnY123X6bLzQ5pfjYOv4r+fNjI+PNSF8CIHGT4t60c4Sn8kzxMKqPvr8q7jHTDoO9UZDQ== e=found last=9 s=31 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAux0QdGpHw7g5xdXeEP3c5F81QNgJ5lg0sGpvRl7su6w= priv=MC4CAQAwBQYDK2VwBCIEIMBlU7/jsfYSHUZczt37mf8VplawWGvjRGRoSizYNFTC msg=wGVTv+Ox9hIdRlzO3fuZ/xWmVrBYa+NEZGhKLNg0VMIdOvqggtBkBI8FHQ8IYmWRltIjayXMiLBNUIzUyTv5pQ== sig=1EhkdxeNI+UIRnuOxjMUqWaE2e21JCTG3nMKOaHOio4MFmuEaRAUzX+Izb+SxlGhGBotSsnynt7UcUfnzzKxAQ== e=found last=10 s=0 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAWgNXkDjSowfnL60s56uX4FbZVDlgCDOSFyk9iYTKvOo= priv=MC4CAQAwBQYDK2VwBCIEIEwifddis+k/GKVBNqU2wVvZOtdupq0IJ/mc6oue+wgc msg=TCJ912Kz6T8YpUE2pTbBW9k6126mrQgn+Zzqi577CBwnBPJIIjOThqnf5OuorZJk2BtZESWT9ERTUMwjDYTF2w== sig=2ROjbB3L3zVI/DJ919UtL2OYVRrn7S/tNv10Wx47j9n2sIfoDpasMfiR0DWaJucpD+3GNBUa7GydUlfvtlUiDg== e=found last=10 s=1 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEApIBh/FC3g4vIbMbcQWqYfj51K59JqWeofLR5b46fFpo= priv=MC4CAQAwBQYDK2VwBCIEIPWksiz5hqG6d8fYPc5rB9rcJb1pPhesvP59xFGjiix/ msg=9aSyLPmGobp3x9g9zmsH2twlvWk+F6y8/n3EUaOKLH9cyMeGoO3Z6r8URiSc5D8XpH75535z58yz9yd3d4p8gQ== sig=d2+ayYh6Y+P0gpNMac4eoAozdOucvUue4xM/8uthI+wmcF2fIIHl2j6T8xxqGaXC8T/SJtv2wcUHKSnemIKBDA== e=found last=10 s=2 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEADMWR/8jaXfLeDy9DPGZZ8nA1PkER6gZ3sdsIWs2PYO0= priv=MC4CAQAwBQYDK2VwBCIEIKsXIjNDeEupOj0wfbhVBSqjr4/gvBwK2D9lifr7+Kit msg=qxciM0N4S6k6PTB9uFUFKqOvj+C8HArYP2WJ+vv4qK1SwPdOkMcEzeuUzexl7ToCFjmJ3In2OoFgVX3kBmmgUQ== sig=RtFX/iwyi2Qi5qy3oYJflVKnYfYo7CSvfuoU7B7rkAQV74mpwRKnlt00QZQY7pfPRYSeWO6xnjVnhx1CkIOeDA== e=found last=10 s=3 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmltWbwWUy9NMvrc5ToATVFcansSKjM9zhwA0L2cXbs0= priv=MC4CAQAwBQYDK2VwBCIEICDsiD0J2R2DSV4zWuruN4ShoebsIyOuCKk9a/TE9kns msg=IOyIPQnZHYNJXjNa6u43hKGh5uwjI64IqT1r9MT2Sewgw85DQNrKurEPBy/s6NKyvhyYqm/tZMeEqlkwrEFGHA== sig=YtS2X6KU/8g7T5JolSFimvm+ZfrikPci0ZpQ7n1Pmf2TJRyq8apLns3l83K6JuEYy9j5iwd1V1O3wWFRr/whDw== e=found last=10 s=4 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAxFjzJFwpBCi4vyiCldIe/wqLsdqUETPxG12bqgmFkBM= priv=MC4CAQAwBQYDK2VwBCIEIJP/WubHI4vay4+WNTEsCyQL4dfuc04ol8OrCeWALIyb msg=k/9a5scji9rLj5Y1MSwLJAvh1+5zTiiXw6sJ5YAsjJsooNj5n9Pk2Z5A1ONu6WAFSoacmqH38NQaLmrqE4+Q+w== sig=8noKM41S3mUrarvqUkJZqMEEgdD2TOy30AxT2H3Cuu8ajZI+RGZ2uLNkY0iU2uoFI9zWdB9fD4YyhCLlPOTtDg== e=found last=10 s=5 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAJNZiqeKDdEN/60h8/h5VNp5MKDiaV7SpLgWqJaVY9ZI= priv=MC4CAQAwBQYDK2VwBCIEIFZG+2ZDxTQ3ep3sjprWdi7+Zktw8wM9onUWsK82W5Dp msg=Vkb7ZkPFNDd6neyOmtZ2Lv5mS3DzAz2idRawrzZbkOn2titaNOGZoQ/DHJkx9xZymr2Iu6d8mrqyl//blHgyBw== sig=qomdS3eH8RXoTU7QdwBSve3eiPMFUyHYHDl/OH0rld8MPjwc2OR6rEZBkSWe0kJwsSgKEoiXllrLVXF0iihWCA== e=found last=10 s=6 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAY4loFosEnwKOt6nByzs7UToyZaVp95nnx/ypCsaLC7A= priv=MC4CAQAwBQYDK2VwBCIEICa6sOopZXCzd6RY8Boc2lsMljiMOCY1JXa92LXjEgh5 msg=urDqKWVws3ekWPAaHNpbDJY4jDgmNSV2vdi14xIIeWMKJzpqMngVxWu7+19eWN7hVPGup8gKFHOaMCTR2j4Fjg== sig=OBBtVEIGHkDZjJ9LcN2Vv8L1CnFAS0tcgz9MP3DqAFfrACxuk5AbBwzmEr+K7P0wxu6F45XqKEnxUCI6LOrWDg== e=found last=10 s=7 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAeK9TopfnLXAKfWAeucHPLjwuaOXBWTOrZpXne6RnlYI= priv=MC4CAQAwBQYDK2VwBCIEIClHNDhsdxEN3UXY6nGeEvhqWOzVLnrusNSs3HUKLixH msg=KUc0OGx3EQ3dRdjqcZ4S+GpY7NUueu6w1KzcdQouLEf6gSlD1mW/d2ukwkAZys2QwHGWGHWJBowJgs0zFsYUeA== sig=3YjGEsFc5P/Ml0cVptAQars21uZBZiDw4/dAiB3AMb7iagW3oWTIwfTsYMkdOmpupe84UzZiwMHRhfUMZKWrAA== e=found last=10 s=8 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAVJ0/i9GDUrDLGZ6k01UkPRG+MIGBGfgtPPqWNWHSJsQ= priv=MC4CAQAwBQYDK2VwBCIEIN+4iA4p/D8M0s4s1PNQc3bK0ld+TI+EFKOdIBmE7ajw msg=37iIDin8PwzSzizU81BzdsrSV35Mj4QUo50gGYTtqPAu+smYjGjUz9bvxAlSZH834FsmGJ8VKulF77YzwcqDSw== sig=EueCyMZ3Dyjmk34mzABhS5aLzfxMX0prekL8hHJo85AjAYyC6v+7VYIB8TnBWq0I8g387QlvOFC9Z2vjjph4CA== e=found last=10 s=9 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA5Ap0u1ciQAJyWF2Nq5AIgppaoh2tikn11CGXXov+pkI= priv=MC4CAQAwBQYDK2VwBCIEIHiE7at54NHRgiPom20p+8bRmwIj93XLHg7EDENNyTTJ msg=eITtq3ng0dGCI+ibbSn7xtGbAiP3dcseDsQMQ03JNMkhAl5a8B5Tzfm0R07U0VQDjD+4K+ZH6mAPpeVwxYffkQ== sig=abXqCrjr2zczXQMJI3X5aRnSfqNd2P8I/j1x60aoRHJ3ke1JAwkunAtuor3Pv1n2BacgudSIH5CgoPedAPNYCg== e=found last=10 s=10 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmU+M8wIAbBzseJH6AocQ5ouvmZm+N5JJFH3mVEOWSYs= priv=MC4CAQAwBQYDK2VwBCIEINO0UKcc0pYvRneIxRVIO1gucLzB8ZVrJj53YD4v3TcV msg=wfGVayY+d2A+L903FRbUQjjFUyTuTxNJZatqoNdm68ojADcXOexkmSMcNwddx5uv7ZghLUH/rs2GKR0E7+b0rw== sig=NXtNaKqzTcGRCJLtK5TlcDm5yN1NQ0eT/3xd2jLB9ihDtHZqyjDlkZAeBVH1VTmliV+ctsXU2k0mf6hZsLVYCw== e=found last=10 s=11 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEATvalBvKSZF2CLacTUV2oqZ/tQawWM6mOoX0Qt6jobiY= priv=MC4CAQAwBQYDK2VwBCIEII8QkH7RnQEur4b8vWAdQjfr4ZCtJoERHA+EKwoHKWYK msg=jxCQftGdAS6vhvy9YB1CN+vhkK0mgREcD4QrCgcpZgqho/TgUxvni1x6eIjifowfmNZIeIfmJ478nY5O4h/c3A== sig=QqXC62L/1T4H7WA1xguUVOTpZ4Z14HbMZlP0cm/hpnT4ipRUr0/gwOupDWXbFSYvRVBzSUOABs9IpLK6eyALBQ== e=found last=10 s=12 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAQuOdKX7NCjyAr2WfI6glAjTJkm6YFcQgOBwOe8Zfh14= priv=MC4CAQAwBQYDK2VwBCIEIAADNaVQ6zc6sPtTswdQ920MO+sQEMpWDqqVBUn+/J5t msg=mVwVzMHeeZIdvFIG4AAV0f3UQs3uFBVBRLv/Nz/TLHxrFJg4TClE5m27/xUx79U3dusnivZj1qw2/CG2aI6W5Q== sig=t7pulOHLxrwo2rN9/Xs7kpbPSxJ7ldIfK04/tTMbI21n8ilbl9CNihqfLSEB1fQMOYoVIrQRbkS7UXOBO62hBg== e=found last=10 s=13 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAIGB9q0TI0EjvYJE0xmnfjLMBbNvkmZc48YvfSyD5t1M= priv=MC4CAQAwBQYDK2VwBCIEID+xjwfzzAzQgy2ZMj/dohIkP91iYaPsrY8nJQ1JVPVy msg=mXeb6WDx/ffkYl+k8ZEa3OO8EC4BU1ttg5Ffzhnd9gPBnZe0nqzcZ/frnb2owS5HKGaPe2KtpPDGUyrwMyUiCA== sig=5Szy+T0AVwP3OReBLswQkRd7FZeZS9DirCuYusJAVQ/J5ST62EzslmZLGqNRC3TRWiNWnf1ZTegwoADqys4DCg== e=found last=10 s=14 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA+5SpHKz060IU7R2fKBvb/0OSSAy+B2zcfGHF3wX+pso= priv=MC4CAQAwBQYDK2VwBCIEICa70pUdmdAeYJ377Yr4QPeQ4eq15J/TYDx7FavXkoZH msg=UKabTZtnA3+pEnpKFDFhLCKsqsU29DdyRDV9nxnDdtGOA43KIWjbrnw0GVpBbGq5+LBf149BGO/FVmk3pmg1nQ== sig=1KkibqBXoDD7yPsPBIoo9OYAfehIxGSQeGJCHJN/BkaWwg8fvbssFV5Wvym/yhGiwzP51cW/mRPEHyWN3YzeAQ== e=found last=10 s=15 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEASWAUAIKMRli73hlFdS+SfYVaY2O2mvFjlP3QZyFFfU8= priv=MC4CAQAwBQYDK2VwBCIEIGL2Zq9uE6wbeU3mni4G9N/Jtdf5dllhHWxqGLKHNTVi msg=Yq15SxXMxPgFbL9Tp4BJ0g0ixG/iDYmuM428jb/inM9xkf9U3u89UTUAepDPz7hhUCsoV4PslFuFNgm8wvvdYw== sig=vPp99xy9rXvppPm53Lzwdb9a5I/dnXWCc28Amc/+2HQ8q6LSVaGaeGyoRKu3oXRkdOeLuU8Vuo11ysF0VI3WBg== e=found last=10 s=16 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAm7GTBTu59TE3ME2yYAsuizLT8wiNzbDDhq5SSQNtceQ= priv=MC4CAQAwBQYDK2VwBCIEIM+vuHEBQv1bXpNvBwKopdPRwKHtUPla1SLitwxAcoJs msg=RsmOPmrNmidRL2lxILsqaZ+D+NvVsZSDBGmDxIgKoc6mi0lPyu1jLxImnXc1XhTl4D0QQs3680MqDfA+xn/5Aw== sig=Vm4aDOpe9aeMkSzuOO1iBEA1twTVlcVG3mdnxqM75ZGTmX7ugvyhsXXZkPLEssMMR3/x/q0nX/YVZ3g1lJjaCw== e=found last=10 s=17 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAILsX8HvDmkpEa+zCRZGJb/6Z3mufU1T0kq/T6rvvL44= priv=MC4CAQAwBQYDK2VwBCIEICTGgD/dVF9jkigtqmX93KCnKC/bZ+yF0iu/KJXxetXg msg=7MtH1b6741JithAnkIOSn/Cr+kGWle0y8WSrrwFE7Kd7aaBK5e0tP/mCou8IW5lRzoXlmZScF45r18PwRybPUg== sig=C6iHWrg7vF5CsKf39n3Y62HEkDfwhBkCmU2PF7LXETNfG2rC2sQP08R1/IxMhvcP5RXF4P+j5NL6FV9zQNmnBQ== e=found last=10 s=18 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAAYj8rMcj9OIWposfLgYxo2ASZ+Xeva2HCr5eVj1VexQ= priv=MC4CAQAwBQYDK2VwBCIEIJmNwAI0GHnyxlhtJ88peaatDsI0cuF4sOjvMlAL9HnH msg=SwGcJaxLsD3Xz7IZJMeY4qDGeYRNuAXiPHuz+yvLtpzyZTz9jVKM/5nmsqA5mY3AAjQYefLGWG0nzyl5pq0Owg== sig=xVouRLawmkwNdCEe0cb1Zq1iRXe3rOaCzTt77lBjtef1ydLsBdYiSsn2qLc7YQ0P/q/nVNeQdyTfI+PEU34QDA== e=found last=10 s=19 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA+y9C++IQH6G4gsmnknCaPuW7bvE2HiYeFvgxUqPjMIQ= priv=MC4CAQAwBQYDK2VwBCIEIBAyylmXg5OeHyjvCt8VhNSRuO6++hbQznxZi0cmPf/r msg=YUSSvW7TXl8W8CGSduvvuLiHi+9un6K/RqFx/FZV9B6Fyj692+k0ZgdcY5u2xRkfEvIWDXIyIaKRm5OCygPusg== sig=oTfnazs3nxm3gp9wDnDLJFTqqoSYd5OYy4MAwEz/CRauX4E/IpRdeRgjVnDowefqwR++TSXDSh9xtzficNHLDg== e=found last=10 s=20 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEArSi3AXaNkRPHypxuLMR7jQHLyPVjFkqU41e42TTdLpY= priv=MC4CAQAwBQYDK2VwBCIEIJx7/cPhFQ29P5Qhpt9aynj25MYwztuFbcLGaRCOfPtm msg=yjbhnHv9w+EVDb0/lCGm31rKePbkxjDO24VtwsZpEI58+2amiI5O2YYh2//rJO2JaSNFcoLEq/K/d3jlxZWY2Q== sig=ucl+6aWvUtau019zFEx3g6yyJ8xnt81wx0QggiWgXZ/KIlzxDZfCmKSuBXWs2z+JMYAGAHXPmJs5010T6a1CCw== e=found last=10 s=21 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAafJfuFf3UIAdiv2wGIemUGa1RgbHghD4Coaxha7J/0o= priv=MC4CAQAwBQYDK2VwBCIEIOnFAzAMwljD1XG3VNovAsm9W32DMiT5hKjtiGPkwzxV msg=1Ya3+AE9yAe28a9BL/lnP0LUEZPHJv8Bvw8TTcLduki58wCObPpiJATUvOqeBn7hZbuvg6dADLrMLY37k5bBTg== sig=1xVefKMGve0tUbqogRtn2aNoOST84SMfHUOxVyeYWGkXoWma4jnYehum6ivhpsgtHHgWKoYed3vHnyb4rFVpCA== e=found last=10 s=22 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA+Az8lWI0foVFrMvOn405qBfHiTP4GgQY4MvcJIdFxE8= priv=MC4CAQAwBQYDK2VwBCIEIP07z8xGJCqh4O8ytzNgyWeMebo/EWAhAL/TuAKIeLXD msg=YMlnjHm6PxFgIQC/07gCiHi1w/o76AqYclCbNI2amK1gfkixbG3MdoCXkvrI6KrldQ/2L2M+2z67D4rgMCm/nw== sig=eqbczU5T5QJGm0en0NCwe8Ud4XbWAAcGr9tfrriZBDvwJANNnqH+QzXf5LijwIvr5Y3ysEh2jC7WMUSII17LCQ== e=found last=10 s=23 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEArDuubupd4tl9bmE8sQNpZgnpMeCgFoIX0J+ejVslioM= priv=MC4CAQAwBQYDK2VwBCIEIMWWMegoyquM3Aujl9kSBDwEqkNk8hR2Qf7zKFaOfsRW msg=Qf7zKFaOfsRWFFuAVm+mRQmvwmdXcehfRqE9DMrymyuvwjscTUFurqW7DeHQFU9ibxGXD0/99+EOOlG9xnfNPA== sig=dkcMZ8VCLTgqG0tcNlg20tp26BVq1trCnYlDaZ7szisl8Gb+7GeTxjim4B0h2mKo+HV0MzFmmogZjpOV7NmwAQ== e=found last=10 s=24 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEATPZMWENxy4bN3j0V5GBhe5o3vErlzODfH1DeAuDlG9g= priv=MC4CAQAwBQYDK2VwBCIEIOO992AnIt0zR6cPY0uronFjK1K6eUpX3c1COwJjnteN msg=QjXLZlFa4733YCci3TNHpw9jS6uicWMrUrp5SlfdzUI7AmOe143nUDDc0fU+n19vojba2FvpOLgQhcxvt36Icg== sig=ACitAaoDGtqPrHb3HuU4ykO/rh4IPpXenkt6SqKDd0S5Iq+Vb6d59+4/HxWnLYtbznQtREfFanrNWqn7590gCQ== e=found last=10 s=25 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAQPUhLTnXEAhkC9hKHNaJfv/Wv9nAmw24lQIjjQ5rOHE= priv=MC4CAQAwBQYDK2VwBCIEIMugafCUiNbLejpUJAImaRjpG+co6sNnRWhd4PqF1sSr msg=iNbLejpUJAImaRjpG+co6sNnRWhd4PqF1sSrj6zgs7li74WP55krBJlaGzlueRHeYMPK2yP/yiybAfCg36FCAw== sig=zhBZSogafjtmyLqWolxZzbWxp7/oeNbwNnAXRtXfn2c+c7rMhEYvLlVQIUHhgY4huRn7kGweMhYlIVYbFCahAw== e=found last=10 s=26 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAUFW09uQiOrka+tW+ryZ0aua+LXTEq6/S+sxHaMFag/g= priv=MC4CAQAwBQYDK2VwBCIEIJYiCRquNypGktBXipg/okv8tnQwyT0FjVZkonl7BiTA msg=TZeIGnsnbt1vdKGeJ9yal2ZzHdouvV9cjXeN0oXieks2LnYJ4CrzyRfigRQbWvmDtQmNMI1cKVAltQgJHPo8lg== sig=Pr97Ne8m1jBD3c7yzqT8L2v5nBXsl7wIciMd2jqhQT1errMAMrNDq/dwY7R0iSwo8m7Rxt0b8xcKg4N/XzdcCQ== e=found last=10 s=27 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAROg+MgPJHSzgoveOSestls49vCR2r/3saBkpgEn9VO8= priv=MC4CAQAwBQYDK2VwBCIEIMuo75YlxZYOKFpLY3jfu/59Tv/ARKRsa+Xfhk8hP5vA msg=hdhZxzuZSDMQRMuo75YlxZYOKFpLY3jfu/59Tv/ARKRsa+Xfhk8hP5vAAsmsiGUiQ8LC4fPJNtg/vZaGLV1Iow== sig=nQrKIMq2UnXvp2Z4lR3HdaI9qhKC9bkHKMHfjtIryv+hyh6mEhEOSaqe0KisaBJFqEYDiQ93e55WwM/kKjE8Bg== e=found last=10 s=28 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEARoNeIdkOkA9PgM54OZF3zoSQsBjotQ6V6ZOrp0VhQI4= priv=MC4CAQAwBQYDK2VwBCIEIDn/sXCnlL4K2AURqXGwLifOJwJEIj1V150UrmER3GCN msg=93Ej5uHxBKjSQ6/jf3r55vymFfKMElaEHE4M0F2kC7Lh1za1T7A7hkklQ0X9iAFLQhFu+M5Yb2Yk4biqXqI1UA== sig=RLiX4rIYT2L7LYDV4B+FvVoFZo1Tmsut9Ixk9NBgtG0AnxKThiGujxlKQTpJrZOLimR5IJgnAJIK9ZwdlBMKAg== e=found last=10 s=29 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAb7cP38jSmHuse9y2qKAN3M1jmrkt/pY5SuGY69YgHxg= priv=MC4CAQAwBQYDK2VwBCIEILyiaUbSHLA8pgo5r3K/AQtKg5ZiNkyDhfmiJnpuSp/5 msg=Ob64XUxkjpSXq/D9HiBOMkdcJKBlnp85jc5SoyI7dCrQvKJpRtIcsDymCjmvcr8BC0qDlmI2TIOF+aImem5Knw== sig=LLq9k5Mibc//xXErCIJEyIqv6yuTmjHQpU7CH140bkFgJ9azakRo6MPMmW7mamwJu8sqNso/f0+PXQjtnwLtDg== e=found last=10 s=30 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAbiDs2BlW89BCO8Rw+R8KsGUOZfbgieEgUFkx6BMnZkk= priv=MC4CAQAwBQYDK2VwBCIEIGcvApOm225JZail57JWb/ANSdEqpuX0h1vzkZpqrYI1 msg=kZpqrYI1nFYMc1viGHXR3uWZYLzsW2ZoiwcFB7wzMVV1IsSSzvAnt6BIVUlG9rrkqExGHhav6sZjzXmL1suc1w== sig=9PSCThVrW9FeZIv29OFUIbYWuGiYqBaplYHYCg3tDvaJKxlYxtHyeFt2u5RjpdfgU091nrCJIiGNgULD3QX4Cw== e=found last=10 s=31 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEACPCRdUS7vBIKCcEZFG+lyHsf0oZUzVRLmYDjnDPWxCY= priv=MC4CAQAwBQYDK2VwBCIEIFKCfS19WvmB/x1/bB0O03Ry3a4IdT7tRNtNuZ1xZMNo msg=81KCfS19WvmB/x1/bB0O03Ry3a4IdT7tRNtNuZ1xZMNo+8M/8qLjqCMAJ/tLLl3ISCjXdbov+ngnyhYJLROAsw== sig=V23UC+oUz1xFiTztfGu9tXacSe+oNnkuLOJRD9IBi9jVogBge8lNCKYZXbWfyDQpa00Ea85gkB+W9CmLd7AqCQ== e=found last=10 s=32 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAse/oyjWhBgVL+c1yfW2tgy6Mze4Od0/aj55BYZdHUN0= priv=MC4CAQAwBQYDK2VwBCIEIAMduO8bTPzENp/2pnZCkr3G9ZgK5GZtCfc6BGiQ4/+V msg=Np/2pnZCkr3G9ZgK5GZtCfc6BGiQ4/+VXFQMMsczc3iVqIe/sMlvWlDoue0vsk7Ls4wVUa42pQmEV9Hpb/8F2w== sig=6jw80bqyRFMoYbowyc0arSLGsu/8gXHUd7ULY9yATnw/R1Ezc51dcfz21OvADewl04y57MDoURAXZMzBoIIeAQ== e=found last=10 s=33 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAkwZaHK2OmEg9nDS2fEhH0jySZp4ym2ImSwA5Du59Q+w= priv=MC4CAQAwBQYDK2VwBCIEIOzUSvfCCu2NwFtpyQ+o8oDewcv3HiPS2FxYFFd4HTxq msg=FK9ibFT1TlrXNr7PMuzUSvfCCu2NwFtpyQ+o8oDewcv3HiPS2FxYFFd4HTxq6sJ1qfhfQOsyPjpVVdvCadKxcw== sig=Kyx4EdP1dAB6dcLbwasd6TF0XBKhxZ1kbVfDsRlKmnvH0T/gI+4vgF3a73kTWRuM+Qb63PANpdCzWT/P9md9AA== e=found last=10 s=34 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAwoh+TTmZ0W/vI39R4Qu5ucgQeOol40imzxxmS0dsBvg= priv=MC4CAQAwBQYDK2VwBCIEIEESo2Qmvd1bmkqbGOdmcci4XMBBAE+98K2/ej/IalT3 msg=QA5LdHgBTzAdzPotQrVWQZauvWhSY8G/qSITYAXm1UD+XdoHWEszcknMilcAc1BzSW47IEiE5Xp3u/Tigao2Fg== sig=0tD4Ik8Eeed8LKqHMyNT3wmrjNzSmraou7CcGv1B+ApSTW31j9mmY7xWcEXNBKOkwqoIajv3ikULOTr9VGjZAQ== e=found last=10 s=35 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA0MRsfPjTQ9/Qjt5bUaW1AelU8ar9S3DLhtTdb/QgFW4= priv=MC4CAQAwBQYDK2VwBCIEIKtgQUtH+w5Bmh9/mgr1FcEtS19Ln4tM2FJU0zRUwAGc msg=YS+yuwowpP/csN/nPrbVSnoqNvy5iZ/lJjkQO2pGYQ7DBh2ZPKZSOZNLn9fMoFYieHdATLoRq2BBS0f7DkGaHw== sig=h7V8/IhSHHrk2P4nsbCHdZmOUpHaRzbinVJveAlAts7sjOfXpBolKAfJW5DYaLiG3/HKpj3gWMB3XbTkxvidBQ== e=found last=10 s=36 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAdltc1m9op7NtBhD8DiUDsdCo8RGgCV4RVmcsitC46U8= priv=MC4CAQAwBQYDK2VwBCIEIKT6CD15wZvMO1muFju2iN3WSZOkyQT0D087PNtQt+BC msg=e9E2vQd22CEEukrUKlC4LKsp9oalwqjDSmCi6hnQ4Rp/sseR53uqC9Xss6T6CD15wZvMO1muFju2iN3WSZOkyQ== sig=D8pu6y/fMXMYz6+i/ZYGPrWAs40DnpqdYyDujGsfSWuG7TP8vlF8nf6GUBkL4nDO6nGF74L0hZBaQA/vyPgYDw== e=found last=10 s=37 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAdeI8N23lQz1JHFWuHlMu2GH5A+nsi1pfC4BzcoOKthE= priv=MC4CAQAwBQYDK2VwBCIEIMeqNXRbTa4jZu4sPrm62eyaOn5y5GJJqoCWEDZ9Y06E msg=NKwyR4W+NyOf/kYKN6Ki2qOyTPGZJoFsk84W0d9EFXrtKcPVlEFwB8eqNXRbTa4jZu4sPrm62eyaOn5y5GJJqg== sig=uhYo0QnNZE+cComfoBlD1WYku+2nl3GiK+OyzVinqTi4r2gXhf4QZXv6ZIROnui421LbvvC9vfK9FZeFGSlCCw== e=found last=10 s=39 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAoSq5eyTr3kNT10mvJ8S8UjQENSz6znEUUuxKhFYIwhg= priv=MC4CAQAwBQYDK2VwBCIEINsTYnADtHminjp0FIROWN3+DRDFsSwqy0R0bAYn4WSV msg=2xNicAO0eaKeOnQUhE5Y3f4NEMWxLCrLRHRsBifhZJWa+3DvRrE2LxlGeH4zJz6aBoUrM8YpuBQjmwmfIwHcng== sig=ew5TDV1D0vOTHBQ6nqzFKx5HpfS2ae5KTBShicFOpvBmJ+s1EoKPfCx/mqna5oJ2NkPIIo6O9eUuL9orKZOjAA== e=found last=11 s=0 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAG8ouSZ/7LXBd477vksld8WNz7O34o8LMfmHs6YCGlWY= priv=MC4CAQAwBQYDK2VwBCIEIAUHG39AahFE6/B2O66aj6GN+AdvQyOX0OQLuGuBjIYT msg=BQcbf0BqEUTr8HY7rpqPoY34B29DI5fQ5Au4a4GMhhNl8Jku0MC4gKtMDShA9xezAP0nYMh5ZND+BzBbNAYLaQ== sig=U01DDCVp/O+KykUarWq/AF7H7yX1vD9eE2J3Cz7t/JbY6N6qlo8qpsA30XruKsNG0jtJmPYwoO67Cx9VoN6VCw== e=found last=11 s=1 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEATVN/R772H5+b5RCqt92zoia7L8LdurZWfibBqYr8EGQ= priv=MC4CAQAwBQYDK2VwBCIEIFFudG0a4mjFJEcuam66BYt0sFfuTW+SZrQs5zxffjfK msg=UW50bRriaMUkRy5qbroFi3SwV+5Nb5JmtCznPF9+N8qLCnVwnv1SltFGMMrBmVjKyGnjdd9HlwPdgqZpF6Bn3Q== sig=l4UAUFVDlhgaEMc17gjBB0fMQyBFd4ugn4EdnJU+GgdTLx5NpczzfEElp0aCwf7EUkOuvsZIp0DyixDEISBsCg== e=found last=11 s=2 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAkXdJvwjG9+/ouQK0IPda5Hq3nyEEzOjv02ze29YslRk= priv=MC4CAQAwBQYDK2VwBCIEIPkpRkgG/W55sMwGhgwbxNsQvKv2Of4eC1bMDDKhnCrQ msg=+SlGSAb9bnmwzAaGDBvE2xC8q/Y5/h4LVswMMqGcKtA/v4CE5QK5GyPT/WSgFk7M7GZlB2kLC+jXb8VsFvJaeg== sig=zUT0b6oc3zJ7IWmLQAcZ9LpAQB2fJbu0NKrvRp1DrRKOIAi1VylDMGewRiPeROsVxb2EWP7VvoAz9aROrtiADg== e=found last=11 s=3 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAybXDhjS9ylJE4HEuNYFKNEd+7FTGiKBiPCWQV05RfFc= priv=MC4CAQAwBQYDK2VwBCIEIPAXRyRhyU9iV98v9Q428MhmJNHo81ltiSYE7/t7QHIP msg=8BdHJGHJT2JX3y/1DjbwyGYk0ejzWW2JJgTv+3tAcg9sKl0iu43U6oPFR1o3BLKSiY8ERc3dPKI6R4X195f1mQ== sig=0HFf2XBrhN8h3Ad4IVLcMa4fvAV/G/yh8fOk/b+Ut/4r2Kf5yoNMO3Yq54wcZhCHwMFn1F45g0OKgP6WvT6gBQ== e=found last=11 s=4 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAtlgoIJTiEHXEFqsCbv+4Pq7mW3dBQ5O8rGm0aLl1K5w= priv=MC4CAQAwBQYDK2VwBCIEIFwzt/Xw0htkuU5LDU3zMe0Ktdgae/YFVUn2QN+COZZt msg=XDO39fDSG2S5TksNTfMx7Qq12Bp79gVVSfZA34I5lm0OV8PPWge4GRkJxVe28psMgzylwVFdrTrwCbPUh6KGhg== sig=63o6rO0IC6ZZHk6YGuVxRNHbbBIi+NJlmFwF92EmuBVNBD2fLqgg1XiiMJNH1NIiIrozjGxEtFFKGqYWVEZXCw== e=found last=11 s=5 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEArpLBMZr27tq6N2iuzMmbwo8p6ZiyKVBmwNMkSjG6UKE= priv=MC4CAQAwBQYDK2VwBCIEICAsKvlbR6xdXkRbJpyLIc2C8QV0V+NrmbAU/GIdGD47 msg=ICwq+VtHrF1eRFsmnIshzYLxBXRX42uZsBT8Yh0YPjsYOBX5cEfHrDqxCH0q6x4Zj8+y9m3HsrIYv3k1bq7ufA== sig=y4L6Gxi5pYCHP00NPzrHzQHq1kuJ/BfBpU/Eo6wGUlYtu3HAEsRm6+UnBvpfmX5Le5dpP6uoG0j+TUhJRtQmCg== e=found last=11 s=6 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAEyNgScytZXWE3yAm1SKkQFT6oMNgu/E0XVOcQc00Ius= priv=MC4CAQAwBQYDK2VwBCIEIGaTwqRXSZeUQ/qLVdVe16CeQm54z1Df1ABcUkjewGj1 msg=ZpPCpFdJl5RD+otV1V7XoJ5CbnjPUN/UAFxSSN7AaPWh02lTBbsz+90sYhgjjMZrxRSRJ/8NmFqQddRoEx+5OA== sig=M+KIPUx+EjpECrnDU2OKdW1AQ4yDlB9qBW9ALkT7OKy3lPR2+sBbMs9zfrflYTxrsN9Qrjus2eB/awP2NSRlAA== e=found last=11 s=7 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAUiyyLDOCa6aUArMAy6TKqdJdzDYlggws+LnnlsBNrT8= priv=MC4CAQAwBQYDK2VwBCIEICz8N7IJRlVnMxTgr699zMN9Ks31VBZYUl5WcR/xyd2i msg=LPw3sglGVWczFOCvr33Mw30qzfVUFlhSXlZxH/HJ3aLnmwcUFAoWnG2X/7BNs9z21WlAItGymU3nBwXppkfj5A== sig=iGY+nwLPTugNSmXZ8V90lYpk5G0XmwIIoXPUx/JV4QzKAEBqPAd6uuKkfOC18m0uZhr39DtGKe9P7QFSaJruDA== e=found last=11 s=8 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA9h3cR6GgOeBHPwO6GhNlNt3oU4waGPj9Ozn5cBbuTos= priv=MC4CAQAwBQYDK2VwBCIEIE9mJqmbekqUYYCnej3iN3+a7W55FNVHusnUj5J5V8SK msg=SpRhgKd6PeI3f5rtbnkU1Ue6ydSPknlXxIoM8mAbtmlRSaKRSk4+ISWVnd3scr+ogvgOWczoO0cDsTqU/JX5lQ== sig=+VNdt6OVsHTK5D30g43x0THTxdGu8jRhDkV7BDcduiIWAG++OSEZHZqcrj3J3rccXxaGevgRxurrnACu8gsdDg== e=found last=11 s=9 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAekDfJ151h101IOHeVIIUsyp1nkvOiMeETLeDvjnpZGQ= priv=MC4CAQAwBQYDK2VwBCIEIMXrLC7CAqujkB+DOKI5R2J75PgYMoiBnhDd+0RtHsOg msg=6ywuwgKro5AfgziiOUdie+T4GDKIgZ4Q3ftEbR7DoAIgAN367PQG8/AANNj/zbcnMi3+o1iOggV1m4WoslFOiw== sig=GFaUx4NVaoFMcSJeq8lA7O62sej6mt17IvFeJFFu+rkHYSJiu1uIFUb8ZvUVNI9VVMwKafHN/fCPqkEuii/SBw== e=found last=11 s=10 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAh9eF8gqEt4dJhSp8C+ne2HUem0ByZ1WtNZnPhgQgHYI= priv=MC4CAQAwBQYDK2VwBCIEIAqIB+LxnWuRud3/yKYu73FccOfitzXGD424UUQcMJX9 msg=iAfi8Z1rkbnd/8imLu9xXHDn4rc1xg+NuFFEHDCV/STnirQt8nC3Zho+rzSXTPYSuuwiOHcThJJC5iHGPlwZ2w== sig=djvx16+IdOSICTW+Nhd706C/4uPQh/5RxqzRznIfQasmJgT6FrNqEpCU80g+hgi2XBvecKRV9m0IYVGA8n71BQ== e=found last=11 s=11 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAPwoBU9rvqnFRD3bketRJkhV4Rc/UGL6D1Jm4Uxubp0I= priv=MC4CAQAwBQYDK2VwBCIEIM0k4HL0tSKZvOMYAIPjvEbB8hmTGkuo83P43LLFDisM msg=9LUimbzjGACD47xGwfIZkxpLqPNz+NyyxQ4rDIx2ntyWwTzisexjYT2IaZ13MdToCEeVASM9CnJWOkvtmKxg2w== sig=ho9rVh8N2K+fwzTZT5BWWBldIWiPy4Fyd4KHSCgIzwwhd58znOcfR4bcFLBpeuEEZyYf7HiUKBjtqsKTZR9dBQ== e=found last=11 s=12 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAnUmMTktlHnLOtCHmBBAYBVQYAQJECvh/s4qZbamEMZo= priv=MC4CAQAwBQYDK2VwBCIEIDdtgt5jo+RBro+kMfnLamZNAazOdITGnCL8mC0FuLZC msg=amZNAazOdITGnCL8mC0FuLZCuFWUwQIGkWtCkUvEN+5PNqTSkEwxfNKZZr3B5h9GBYjc6nCKsNug0ceFU+UnLQ== sig=DlnNapUlYuoP2ySm566/RwLLYH6rH29ClxEpbwPrAdvpQsBhIm5Q0HKSqFf9zp6sYk7EDswvTElFf+qKtqdsBg== e=found last=11 s=13 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAzZ0wrpc1Rh/wn+bG37ljxfzOylYxVfb+mNwGvIuee0A= priv=MC4CAQAwBQYDK2VwBCIEIFoaA2LX236KL3Ab1egfNwzyRqZoEb62BjuY5evuczgh msg=1aKLUwPV4jL/EZgNumZWIj8ey7bLJksH06wR5tmyVZ6FDeO8Vguy9T3+Najr0I2fQ9OjbYrvm2bHJ//FcdkfnQ== sig=iIa1t15nICpNfljsAP43K+ATS+BLB4Nrnf2mWGeHp5dyogQHEQvVRY2G/vkoT8ci5aL/ldMey/HwmdV4HshVCg== e=found last=11 s=14 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAjVD0t5J7h05f7qpmuUtzUcRb+1ZHZkqg5NSmBJOp9es= priv=MC4CAQAwBQYDK2VwBCIEIHdPLmH/OmXzuoJKNGzQ0qoc5AsDzeUzx2ZFOLCdSfx8 msg=zcGrRrFcKhv5p/PEnl9n5RURELmch3kiPt0qRG890RhBMwJA0lj7ctd/+npycrCtNwVQBaekZIVff7gh1i37Yw== sig=z6py/Ekwei4Szwy4X2Pr4g6xeO1GFQcqWaWBCtabpCiLdex61bsGKvcRMqDEmd2axhXEBKeUSzP7VYmfl3MBBg== e=found last=11 s=15 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA+UnkRLiO6mCYkOg29FC8Y+fstbGixc1z/DEiORk1iPo= priv=MC4CAQAwBQYDK2VwBCIEIPpB7mgU5KW/g4WhYxwgRBis55SPlLzaQtr4hawkYeEn msg=dgsErb/pkob0I858BB4+u/9nKcxkYZLBv35zuewmcb+dgM5mV4JRPfYuR8Dwgw/Ju/unJXHeTaTcApuQeZs3jw== sig=TTSlRKM9GkvLKCd7vP2aISg14qpWwp1lLInkdGou8SlMsOZ5fHK5s5mjz2KKjrbp6hOqxOgv+tJNAckoTF3cBA== e=found last=11 s=16 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3O751fpTvUdJiuGzgJnHv5HbxXOzTezoNt2Zf1QaLXE= priv=MC4CAQAwBQYDK2VwBCIEIDSThXFq/T+8SRIRLXHvwTm6CFxbbw2cCLFp72/jcRkB msg=EkYObxsmAE21sR9FcUvWbbiSzLSDY2CX4Edgv1IHQR6TkRTdJbNp917t7U9u9yrOu2iVJ2gYvbRmbeOHGYqDRA== sig=1F57+WnGPg8bn/Nwdi/Aqg8yz63KprZANXNnQE/nLllq8r8ZGur5le4U2dqitTXlh8BeRSZmmGfS1AmKekKXCg== e=found last=11 s=17 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAZgPxEH2OFraGzJHQSRqrB+Z2B4DDH49WZWIvKgN1xIc= priv=MC4CAQAwBQYDK2VwBCIEIHu6hSeLgdxcOUybeWYSGP0sN6r6pNbMahEDIiwmdsQK msg=z/IVdKxi/OKt0AKnYHnutvQY3D7GPbvwEkA8qa4qxcD15AtyJCDDoJJuBOp6BWQxBIMJ9bXaJw+uJ37NQvYKYw== sig=MmIWIkV2bCaGWhziu7PAG8916RTwJZ5R56JbKs0FcOKVcdifBSpqPzLa9E2T6fGwiMVVNUtcbU/FpQVD2cdNAA== e=found last=11 s=18 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA4dAi5LjLYRviuHV/ilGciPpgDl4/farIkRc8XfOXUqU= priv=MC4CAQAwBQYDK2VwBCIEIP4F8J8OqWYQONbwAu182uM1Uv7flCDeCGihZmK4vqOA msg=/t+UIN4IaKFmYri+o4CjZm7aL3ZEMb2GN5+rw/a+bfOFA+RoObwTYpKJc0qFaax+pKs6kds36W3kO0Q+EuOrcg== sig=ScpLcq/EPOlWlxTRg8uwP6m9qjilJ+UVT8NUgGntkfwf8HuQf3h75eW8O/DBAZB3oklYQPwTEQDcY3HmrNajDA== e=found last=11 s=19 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAtnc7NRxJV6cS875kTBFdu4AVfevq+HknCH/EoyFKR8A= priv=MC4CAQAwBQYDK2VwBCIEINbjDYqnOoGt+iSJ+9vGUK0NkUJnlnO9T6HGuMZsFHm8 msg=iqc6ga36JIn728ZQrQ2RQmeWc71Poca4xmwUebzSpsWCmWOaerIoj4mpabxDuI6CLRU6gvlh8KSphkOrZ9+clA== sig=omn925A+YRgJxKTXPie5/UjOmg577a0P58+RvHF+NesBoJMNlQPf8MykYsbvOxEkS5SJP80LNi8kAiBwJAgnBQ== e=found last=11 s=20 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/bCnD2Tqy9Z3HwubsdZg0H/JtQW9w9j3nzLPIKnUDTw= priv=MC4CAQAwBQYDK2VwBCIEINlYQ5b7yYkV0eirvZGwrmnuWRwItm7SDrRTvRrGKwh6 msg=3iWqTdaOjX2Emxt7M+OCdvAUaNA+0fv+bCfqHz7Thx9oKz55FR7ZWEOW+8mJFdHoq72RsK5p7lkcCLZu0g60Uw== sig=cvEmBdhhhIAyScYJPCqqSj2kYlb24wkNsZ6pIdRdno2ip0W9L+Yy8sClU3YJ5yk19VHOLpxdqbo1yOKNw4MXCg== e=found last=11 s=21 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAWFGYwbHXRSznEe7vN16FleGLCHJbjvTlk2nRbUWnc/w= priv=MC4CAQAwBQYDK2VwBCIEIKmvzQrLIsqONgH5uDEQ4DXDSYHeB56HJCEkFBvo4yyq msg=jjYB+bgxEOA1w0mB3geehyQhJBQb6OMsqh7LQx8u69S9fCb84qsuIGxLqsFYFwA2nTDIZ2Rz5op+KOFxW7+kHQ== sig=FyiQBjc2GY9nfs7+gtG4zDQJ/hSAEO3Xnx4HUeXL8aEYCxLk2nrniv4jVbHpFEqRLTkDxBXyR1lS1xlE1EcyDw== e=found last=11 s=22 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAyNWW08XJQMJGTef4U1M2+zx2JMQdhq+xZW2C66x+IjE= priv=MC4CAQAwBQYDK2VwBCIEIHtvlg87C4BX14EeAk1qfzHo9v3a/tfN2YIrX2+aG+ah msg=XEa1ENZ6cJhCk5xgKDtQu6TEjWq/mLx9PE1pzO3IFS919CUYykR7b5YPOwuAV9eBHgJNan8x6Pb92v7XzdmCKw== sig=2p5VoCmw6ZmBudLjk0/Nw6+l1fZVby1iAYA29VADydzUIU2HLGJ5SVM7HRh2MtHPqgsP13PB2M3zEg2levddDg== e=found last=11 s=23 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhNOHVVOwBqIVamb7kpzXdegsl87Lbul5RkLE0VTDdxc= priv=MC4CAQAwBQYDK2VwBCIEIOPwNqbdQRn9DUpdePXAOW/vBuvww6t720kHiR4TG+KL msg=O8O5pYstV/sm/v9LuIeLjmhcifx2OVgplpa2JCOibPrR/CEC7F7FS3Fjr2AsgxC8iGFCrKYY6+nU1SldbwkaNg== sig=rJgoIz/UAkCya1UmmAjxdishO3wXLK5UouETTPeBJCPfkzJKDF9ie8F0mfE1EO59wZnccyV58nLDlzI90J3yBA== e=found last=11 s=24 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmSTudAe6IzmxoKH1xXihjHBowtSwV9HC6+uyHBo9MRk= priv=MC4CAQAwBQYDK2VwBCIEINCL+VZRPhDCxyJTGugiiDGmvKGD9PVS3m48kzWAJe+k msg=XqYc2NelX0+SioPpz15yQqG9n+BCFH8HVaaO3Qer9NYHNKhGC+IMDUNxOWDpBbQYMII7FKWpzaADSDF6EuowQg== sig=6oZds8eNc5hvJcygOBwedkTTExxAQyfowdCX6x1HU3saFtiz7TVQdAOZEudZtJZ/tzrCW4LV2Tles75EvWXGBA== e=found last=11 s=25 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA0amF9189i17uQrNevhFwqfefjMnHfVmC0x2WiD8QW8I= priv=MC4CAQAwBQYDK2VwBCIEIAOm+WPRCQg39hauQFciuq84e16q4R8zRqQLI2JNUL6C msg=N/YWrkBXIrqvOHtequEfM0akCyNiTVC+glrgWVGgAnaTuNruB4qmkD4aBtrJ1nq3qlX0oRTmwe7PTHHkFHhv7A== sig=YxbpDE/siX3BVJDXDHhxsHB/ndVfsDpr0dXFS8FiJXG0B+7gl8cgoQIBncRhFpQzDWLQheUnljOoCv8+uiHsAA== e=found last=11 s=26 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAaoBumcp0+MUKaNa69BT7YfHJxpc+VFl7zbnkBG3glfg= priv=MC4CAQAwBQYDK2VwBCIEIF7UKbwTT21uGsjKQzrqbCNTkBZoQggLESvu8jfQgxQH msg=0yvgsQGuzmNH+pAhubmZ5AO/nTifjRuM1YAQ7L3jG8VphI9aLiEgAwA1s2AmoRSAiS6vfqgOk53sgbt2j/g6wA== sig=FAYCAJ5XPwNvfs0UIIAfcrpkCTj9pOPVVfymtdrUnV0iwnPOAtKyogDKwBOAaHdH/a1BAw0GRBxZmKuXCEb9DQ== e=found last=11 s=27 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEANXVau7nKQI4+48qecYoOq9RWgZOA7JLhHGpQEUAbzX8= priv=MC4CAQAwBQYDK2VwBCIEIEZ6q3O+ZDn+tC0twl5RGaCPsMgsbnSMp07qwsCp1aTy msg=Bief/lQVCRNRKoB0QVgtRnqrc75kOf60LS3CXlEZoI+wyCxudIynTurCwKnVpPIcKPVSPxZhOu9NDV3H6Xc/1w== sig=+WJlMSlsHmo+i815rJh279DnNbfBX0Bj5ToCnX6mRHut+aN1+7ZLeluTnz0wzUSmlsHTRMu4Ioj0Fbov39pBCg== e=found last=11 s=28 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA6Pc8LJjYWd4oDgeDSiolugltO/sycCPKuYe39lDZYFA= priv=MC4CAQAwBQYDK2VwBCIEIC1CxoLtSxtiDed5Ex4MOkhYt27AB8Wlwdh/R3ZQaGrq msg=Gcehmvuagq6skF4CWY5fxCFIXvZy3S1cGB5Y+C4681pFVMo435FpZmAA2uh6LULGgu1LG2IN53kTHgw6SFi3bg== sig=xgBcaisQf6y6u3RUqV+GCMsvynKJjlD4NXQ71Hl+L1/pPbo5glAZPFVfpRf/RxoCBMb2mB9lPvIBtEfQaWTOAw== e=found last=11 s=29 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAbWlMb1kKZlhWEzW8Rp+7h5a2w9qZM8JJ1pozkYlM2lc= priv=MC4CAQAwBQYDK2VwBCIEIA3yeiFQ0hfcl1ucAmRW7nNP871skASyaAAw2+hp46cc msg=5Wa8dKWfwLacthSEoM3q9ypM5KcYDnNR5aVy0JM7HGu6ULsdSaH7PmXKnvAT4kRifvdFY9Etl4ROBaY3yHyo+g== sig=IrJVF+m3Swu8uSOaXBwkTU49WpQl9MdLw1krsyqntb5t+DFOCzmK7gWRz0uKcn2SB1GaoGghpGltKzSbM5tlDg== e=found last=11 s=30 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAQ6og6ibUfeDsHoCfnyxQL9VNmnwU4S/Thze+etLtW+4= priv=MC4CAQAwBQYDK2VwBCIEIBI0ZcChMzwKN8f+S/ORLCS8yePgYBNERpmtTzCXRk1u msg=4IxkZhI0ZcChMzwKN8f+S/ORLCS8yePgYBNERpmtTzCXRk1uBDhdUwk+9/xPVJ6s6wkEU+c5aA5NJa3tCC6VGw== sig=m9uJT6+TnsEBXLSmYNWl6NzpFJCeuXCfjnctEOxGCI6Tg6XzQ3Z2Ve9TL5sJ6gtMev3jecsgqbSEDw3iKy3KDg== e=found last=11 s=31 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAWgKwgnXq1RaYHW78WVP01ONNZkpt1G1hR1Wkwqh6v7w= priv=MC4CAQAwBQYDK2VwBCIEIFOOa5s72Wxs5uBYlf0y4BaK0e2bn+Ijvr6ac9YwwJtE msg=Wle5cMJ8+QFXDr5vGfzggY7QHCz+Wy7HjSF4DT27QV1tkQ8va3jJxG3Ms90l/q6RgVvLJRcTRyxp5Cdhkj+qpw== sig=OBAJNPuoo68Z4/YXoweoLBFDtOcjU0KCoFBUW9xRpNzzNmzrWWRGDJCrMOEPyeQamzvHT0oFcpq3YQFtVbvDDA== e=found last=11 s=32 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAAfV0Am0LdqRUd3ElwIvybUcZdN968wTr79eE81BDq/w= priv=MC4CAQAwBQYDK2VwBCIEIHD/DbwqxSxlGf/eP+7ivHADN9jpdMLXiIFrX5zkVDxk msg=AzfY6XTC14iBa1+c5FQ8ZByKNy+brskAXWhm1pJrIOQfHVASrO3m570fYvE0Wp2OmUCaHZ6iw0MzUc6YdLx7Rw== sig=ijvUKhNPTdWrFIGN3LV6hj/IYPSZdWJhVrMDooZ9vKzzWoex5jkChfz1OA6VdDR6mzIcclGbk0ftjIpQVZkMDA== e=found last=11 s=33 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEABJZMiHwb4kWvdvMxhIKCaz9BenCp9fvQRnQ1qc9z73M= priv=MC4CAQAwBQYDK2VwBCIEIOmk4W4hftN0z4rgPDeDq6H1MUN6l2Guv3bf5+mg+o4c msg=v3bf5+mg+o4cLWzwbOgAyrXhDGDqF7m08jxNbeR/xSHQIlkegWybgJRDY/xpiQnyBAfoOW05IFBAY3tld06cmw== sig=KMHedglAtLxRfScpqaxdSaHWECytr2gidxqK7QufI8AthDt6t3TLZylTgcPWKa9fmsXQiItiX96OtK26rXUdBw== e=found last=11 s=34 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA60FdkcuwML+kAkLJr+BaJZxK76kAkcOm4oh/hWR3RsA= priv=MC4CAQAwBQYDK2VwBCIEICwXNnW/q/bDixbXVpYWWKg+Fbs0KucdNNq6tTqP7XHk msg=K1fn5zuC3cFP2AKCE2UG2jHMAhT1FWeW/yK7VSwXNnW/q/bDixbXVpYWWKg+Fbs0KucdNNq6tTqP7XHk6sK6PA== sig=2NJj+OnHsAmsLZzhPA5UZkGMlzsxgYz6ij/5pCtnGHWKCJGEEBnYXcOI26eJT9xBnc8gddvzcGy0AxPo2VvXDw== e=found last=11 s=35 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEALLAr1oDBMARd+cii5ZLJgijoCdsXWJHVFBsv/ymgDgw= priv=MC4CAQAwBQYDK2VwBCIEIGBasUJNh8Th7XmbHyvfYD0QJvuOYtkmRpngq+FFzhPH msg=Rpngq+FFzhPHcXbGnZvFuJXxryp6h3cOl1+KRcoxDSu+84Zk537f+V7h8yG2blLjBX2t45ErAX7Bq5MKIr2+Cg== sig=dJGvqvqcxNCoGBsGQRIbxUn/dJfx8IMqSr70U7/mi549YlTWZ9YYdtxHQnZCLac877oYTWjcWi59Vnp4Rlm9Bw== e=found last=11 s=36 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAOkdW1aB9tgks54LksoKsyHAuwlVXT1GLwRS0HnyzWbc= priv=MC4CAQAwBQYDK2VwBCIEIEaTAyMV8JdL/Zks+mL7lDGeP/wlRxVlQYLcRJvhph4f msg=X+Ior7wfvZQ+RLh/StMsASaDCBPrJDeYKwtCc9sAESKGEqgrSnCHLkHYPB+qPHNnmoXQe62ZrBZXkdRSRzUG4g== sig=kFB+cBqjj/5H9BO9pc09ObKxJZdI/mnI3JgoRZtjxxIxy1Q80D5l/+mfyr+usg2AfFKiR3MCnKABW4B4+b9BCg== e=found last=11 s=37 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhBchleYYWoAyyhGIm0FKB/q9M436EBJ6BzhJrNcPM9o= priv=MC4CAQAwBQYDK2VwBCIEIIwYLRv6JMAxZV3nzenDVpvm1iOkvdYkgS/N6bpj88In msg=jBgtG/okwDFlXefN6cNWm+bWI6S91iSBL83pumPzwiei6305MYmem8cef11wBRr1V4wLlsdix7A4ohr94oILUw== sig=O78Hq5sTrpnPx8c4H0MkI1OURPHdxYJrcgt4n9ZVHXqJVq3wCet6jGvAjpIrl5TvcQvhb/NnKviLJj7yZaxmAw== e=found last=12 s=0 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAEcQrUuN0I1WbgDMUBRIBnZEoNJnYj5U4UqdwkliQtG8= priv=MC4CAQAwBQYDK2VwBCIEIHrlVodxJec3pdyUjd48lFBC5+WsK8DaBaOn+UhAR16/ msg=euVWh3El5zel3JSN3jyUUELn5awrwNoFo6f5SEBHXr9iHtb1Uz3gdfhIUXw4rvY1w9c40IbwwkFB5HIIdRVfdA== sig=kIEQN/VqhvCkty51hBsKf67PeQ+NZw0khDs22tPxQ1jd/m/KAbXyxbgK/41klKHfwgsx81szOTY+V4je8WSsBQ== e=found last=12 s=1 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAk7DIk4PsGRyTxWrPGGv7yD7ok7qKfu/WoSWo1x2WfG0= priv=MC4CAQAwBQYDK2VwBCIEIC3j4SFR1ltPozDesptNdjsEmbWKu1BE9+vTuR/MHDEK msg=LePhIVHWW0+jMN6ym012OwSZtYq7UET369O5H8wcMQpeID2KVDpeQqwT9WF1Y3me4Ok8PtoYQ3b+jMVTz426Kg== sig=wz5zdFuwGSHdOBpV26UYeiLPdiJ2wDvgb1yuU3j9JaPOb1O1kh0SRAcjME6YFHG0143JsPs3ZEphn/ItCJ05DQ== e=found last=12 s=2 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAWSYvJgbmgB/nkjElEWnl+CAOw8AyznweOjkJLTfAswc= priv=MC4CAQAwBQYDK2VwBCIEIFWcQDBPKUIWHlR+aocfPNyLuPOzIz1zNXhr+8Wp6ebi msg=VZxAME8pQhYeVH5qhx883Iu487MjPXM1eGv7xanp5uKYLd5V4IK1ClKHtGlsl5eBYClqVipzpJ5aZ6HnrJ7f3w== sig=+ekAGj3xtq5AroXAWs3mhKQqW5bML0n4AyXdEoTgPM2cuVpGp8gnqUNmZbvulqDwpl+ekAroSEfvR6M338hWCg== e=found last=12 s=3 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAOu8etn6e9uZVbSxD2EKFh0eso7NCIINBRogpm35w3DM= priv=MC4CAQAwBQYDK2VwBCIEIEbdXsWpw7wj2TA5YiG0WUJYKWf6pCO/gZBxwsw/9d8D msg=Rt1exanDvCPZMDliIbRZQlgpZ/qkI7+BkHHCzD/13wNOkJNvKTft0O/xnVVw0kxtkioATwozhKp/y7z/woNtIw== sig=9UgQ51bTPAmbKscCNLOllvQczuzQaHZp5apoDDmfx2oMbQfaGDLOktLVS984K00M1L6gXY8eZO+IS8Us89yOBg== e=found last=12 s=4 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAcqGT6+Wv/6hE+bmJC+70T3WPFqrKnE4xnvZRNUIinOw= priv=MC4CAQAwBQYDK2VwBCIEIFwVfGiBScul9fYIEzhE884aCu8tpqXKFyd8utYpg7Wc msg=XBV8aIFJy6X19ggTOETzzhoK7y2mpcoXJ3y61imDtZxxjVluNk1RO29tIagJv9xwlNBBFZwczIq08djSLaEDGg== sig=yY1OmgRf5o4wmPZ48bZz9OolfYQLGHGjzuHTa7vuD5jcWVeN1e7TP1GZqhNioCpn63zKNOamNEObg8QFnj8VBg== e=found last=12 s=5 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAy9wza62eZ4zfXZNz4vYULsHN7c9wGehzFkKFCuz/TeQ= priv=MC4CAQAwBQYDK2VwBCIEIGLHenWlkVrD/qwHU6Gfdiw351c9cYyqa/dn2htG0hS+ msg=Ysd6daWRWsP+rAdToZ92LDfnVz1xjKpr92faG0bSFL4erEkle1wOtx69icvCyh6Rpj+/kEKJ4Fq4HZ2OJrbcZQ== sig=VPBf+rC1j1B5CVysOjKaANAwbDuniG1jDpq6ySks5iiR7wg0QdltqxCAo8HVK6zwzyPe5znbXl5BcLKDTawrDA== e=found last=12 s=6 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAOwNIvU7CivMxXyYHVC7r2Gb7u/3CUwwh26GZfLGxoyY= priv=MC4CAQAwBQYDK2VwBCIEIATBJKtBM5Zuof3m/Ji52wdaEkIcH66cVjxpLeHgjgyh msg=BMEkq0Ezlm6h/eb8mLnbB1oSQhwfrpxWPGkt4eCODKFWFdJBCo6K5ac+9nKqMTCYxb7Eth30eqQn5YbYQ9hF4w== sig=8QWFQNg8/hlJS0Dw5eYYWieg7dc8EExU/6Y4N9O/7BYM5pF0IoFnN4Pl9vftvf7f+FnJa2AECqUFqPaya/NxBQ== e=found last=12 s=7 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA9TxXg58hrFBW0okBk6SM/AOSat2NVdEaCbNT4u99C2I= priv=MC4CAQAwBQYDK2VwBCIEIHUhNormCtAgBIotjC4DSIIj6A1YACzx/6aPCdthlKOT msg=dSE2iuYK0CAEii2MLgNIgiPoDVgALPH/po8J22GUo5PRP8V5sMBu6eY4NWiO6k8yhIML1BStoEPiyMF3/3wOTg== sig=+D0saXPzNR+fNhZyvp9QHK6PvGKEhMWJG1SmjyS5+s37qbyTREL0IvCz/jSYXmteMljenKOjYHGED6aAJkjSBw== e=found last=12 s=8 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAe28d69FxILp8b6KzWlBqLnFSNoSh+4+tJWS9G1gJdqk= priv=MC4CAQAwBQYDK2VwBCIEIMPYlhtun+xbK6IQKrksHm5MgBAx+diJ+Tmp+rklFt12 msg=2JYbbp/sWyuiECq5LB5uTIAQMfnYifk5qfq5JRbddtQRD1dxVRtXSKvHIOpfd4PVcubEZXIqPkIqVJ4yJ3oHew== sig=z5GqZR1OT+MqjOV5NMIKp/QJCJEJOjd5tiiO5OxyrOlTvG5vjo0wFgZRHWEnHplPXrUJv+SyVwXX6XXHqYM+DQ== e=found last=12 s=9 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAfrpt+SIgmM1Z5H5K67km6CV1dFABDmXM3msBbebGwOA= priv=MC4CAQAwBQYDK2VwBCIEIHeMBAnhleg/ZBCtC0n3cPhyA/BD3xqz7iDUoEP3C2kU msg=jAQJ4ZXoP2QQrQtJ93D4cgPwQ98as+4g1KBD9wtpFNomkINHDXGx1iKvOZqRHs/l2/ukm8OYhUl7D/d4ItXPsw== sig=nUVH2VgQsxXM74tnN3lFeT8Wo21IU8GjrvbWuKHP/0UTspeOVyojrJ7nL3xSn+Vmx35rVC3NjYnjkRGO3dVHDg== e=found last=12 s=10 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAq59eFtAit5utMnnIchLO4vkRkG9I1V+jts0cZlkftTo= priv=MC4CAQAwBQYDK2VwBCIEIIKkXym0UshKYcdg3it3GF8yw7vYSRD2ogg7xWWlbLfE msg=tFLISmHHYN4rdxhfMsO72EkQ9qIIO8VlpWy3xE/w4+DeY9jUZbcvCwRxSrZySbxHpc+PHBwJz5Zs/wwwGRzscQ== sig=XQ5kNnmC7EMpKVreNqCJUSSbmVU7zaylPt0mAzmvNb/Gh/gpOdlpp2sp6tGEJdqsUPJvaDEQWHpF1woPe7GSCw== e=found last=12 s=11 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAEgBNZg+/F7YqUiOosIiMTPbwgbmwx+VZhA2usZJpDhM= priv=MC4CAQAwBQYDK2VwBCIEIHFwkaUhkfSyj1m139gQmHQGky8GV7APk/q82yFTkwJ/ msg=72Bx3sS+7Ih7pDxZR3GuuzuOAI6O0TwmhNDuYxVPhfWgmETQaNb+h4xCoDp4pYrS9qmldO9XG8bcOe/QvwD0Sw== sig=7Tc5PNHwNu6VClY/WWIFih69Vw70I+ey2zG2LMcMkdcDW2cI/3L2RwF8pNxZ8xId9ipcoc7rMOzJKRPKCnm0Dg== e=found last=12 s=12 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAzSEhHVTBSJXVL6ndSB9FDAG1tBG+56ytwjtn/0p+vf0= priv=MC4CAQAwBQYDK2VwBCIEILro+JmIsgF6+zQYepj/EoMndRWRqIsz5boGpz3pSVBT msg=qIsz5boGpz3pSVBTeNtvJsnx5XKpoDobajj6MWCY4ryH7Miq8EpPS1IhyPQKD4S83cuMElty2S4kVQ5Oaq7ErA== sig=SpjrZbbZ3583S7CdW12BSzaeKB6hYW7ZawGoyFOevCkZuvkWwKMXt2rY2z2alk0eATZpcTfclSvnRucnokhQAg== e=found last=12 s=13 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAByp3P6JYmDM8RwYZUUkBsMPZNoWNoLx/GA2s9dY2Orw= priv=MC4CAQAwBQYDK2VwBCIEIFTkSi75F6WmBWSlhyO0gkq4WOvK8fnHtb3QdQHfQX3T msg=SE7Fz4LaIbLBRS2NaMQS88teCgS3wYhRmETMw6c44pbX0g/nQkD7BhzR0PESw5oykWLfagXEBaRIA7ZIzWb0og== sig=/s9AddtqoBd/qPBNovzYGvJzSQEFKUoW0wMRylh8Zpj/yEGHQn+0l2f/D/7BQwd1NiTZBASOhFBxS0rxkw90Bg== e=found last=12 s=14 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgzT5ODy0HNJgl8tnJ9JGy5erXVFUdZm5eEFz3TCTIDI= priv=MC4CAQAwBQYDK2VwBCIEIEeMaQ/iAkrUNVdPr9M4z2vVmySgeD+EH1zlYnsY7rLH msg=1ZskoHg/hB9c5WJ7GO6yx4R1XRbKIJnq1vN/Ag7aRw5lp47q3gjiF3PE6SmI/BUrVX5fzwwEbx3oGdER/V5+7Q== sig=D+SjvzUwbvT0TrIcFQ48rF+zJi9PBu4wh99+Y1YWiys2R6PtkO7lUsONSjKoYc0KQ2AZOEq9nvfnhNOVLcIiAg== e=found last=12 s=15 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAADR3nXG4lYkmrSL69CfCLqknoVa+1nE7UBIHsDL4Bjc= priv=MC4CAQAwBQYDK2VwBCIEILR88F4HFpv+0XmsaI6VuHCjLIoQbXE62j32hkKZz8sv msg=vdTOyGSvc+fRE/TiBtOU1jp+YqbMTZLa23hovL7dQZ/NZ7AjaxbSSgKIPhn5GaFt/r/7Xh7GwwT+g2EPEnkBSA== sig=fNXGVjY2tsTrUKDVF2CDtTyoCGyQsBv56EZEm1ygMdhZsZVvtUO5/Xs0uLJteqsRtnnjo8iMyHjFKEMPppHICg== e=found last=12 s=16 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEABEk+afzT53ubmjwwVkh6L7zfJNAJ00cdEkgQWYq2TOo= priv=MC4CAQAwBQYDK2VwBCIEIOINSYJgPpvqxiekED0J/kUhKKB7XWI0rpSccp68GjXV msg=7gtKEeOXNEalky8z2p6BqleHI5mXm7HqfDQzVqS+oOIOM1BRwodGJ7C5QMn8JeG62JZ+2JzzNlDeqbD4XIlyyw== sig=9dyEmYvZaT+iUR5AieKOlA/6186sIjIngZnkKcKoavyaWijXmx2y/ehnXUDb1ZgUIirPYQb3yfMDyLGOYAD8DA== e=found last=12 s=17 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgHPLClp52r1Cg27nDr2/nl4lIGN4YDgCQbjy8ZwjJRo= priv=MC4CAQAwBQYDK2VwBCIEIJvV4h88lZr5bAprZE9BGLw1dFJsYlSl7gX5d0eapkNv msg=pe4F+XdHmqZDb+S/2KAR37aF2Z1E4+EGGdc7S4qDrWnWsML2Vbw470uitfR5JoHvSW11ALHBjV9friJ3rR3skA== sig=VEayAgZ74Uqkb4chpPgizbwk9KmUh8HscUy32XOKR9mhwbiKROU0Wg/MbV5MhEa/f849ScA6Pz60NcHcYP6ICQ== e=found last=12 s=18 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAbcwTJkNVVVw1MqMH82GTPtdjufJimYY71qzht+5TRcs= priv=MC4CAQAwBQYDK2VwBCIEIAJTfkzWgCfLLhrL2a60QCD/jCVP42s4XlfqucSiFg/c msg=0Vav0mFrxllRRNacMq0rd6j0RMD0O0fbaGzCJHJq/h+/98zwCRV/fToJV98GRbuB3MMM0fI2YMXt9wDzaqETYg== sig=Z93qLppoai0wFBSweocO/4zrv2aqXkSp6V88pNYY/gIiYdl5BUWFdf+baH9MGARviGHzNP4uAFRpIUGLzOMMAw== e=found last=12 s=19 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAcsi5sXtYBZhgel6/z5+VBZBneP/uMl+t5oe3jNLnk/I= priv=MC4CAQAwBQYDK2VwBCIEIGTd0dyyKVXQ3OhQPVFCw3Idv9JGDvFvJWO0TAbTmo5B msg=Hiej/sMgdd0AQxiMHLP0+z85Tn9/Z6x2xMbZ1DyUR0VwvXN6gohA+YUwf5db2WMiI5mv/570yebqevVj7S24VA== sig=dTsEYo1DZCpb2I8ZhkDJR2vBqGY+2mM2WfDQkfKGhSoceyX8N4G5XcpuTJVQUCXBqJmW84onFs3VgN/z6NybDA== e=found last=12 s=20 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAPGf+KbYAETS5fKfUFQhnVqJBAq9sv0HfsGWtaaYGXTs= priv=MC4CAQAwBQYDK2VwBCIEIDFbfJVLt7WpMXf2NahwhJ7hSyMoNKQAsRC4BJ6Zbgna msg=Iyg0pACxELgEnpluCdqcT/ZqWmOJFl5L5eUV+HbSTuoRD+zMDIgH8YmmA0pT4leSQexiDHJzKM7L/jBLwL9ioA== sig=zHJjczaQAe859BkgsQ34tGtolc549PtFPxAcNyDrPczcYqw/xI+AubKDuEEWVL7fA3ut7WH2z5TEovnzDRwjBA== e=found last=12 s=21 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA1dNOEG9khJd9OZK4e3AtGdYDIRSm4p9ORxyyDQspyPM= priv=MC4CAQAwBQYDK2VwBCIEIKq8nuLOKGu1iSmnhvigTXDitUKKwCC4JGpTD7gt4RE+ msg=H9sTgaPIRmZyZgmyzIFEeyahDyAJ6soRv/ya+Gd/8gHkLNqFgH68d+qFxFS/KOKUVrcrrBax8oZeyJaIqrye4g== sig=vbRFaF/F3cjxpBK9UOoxU7CfW8myT9pOwpmowzrSW6Z4/jksLOgOhu8y3eS0wLI2sdiCcxNsRc+72wbRUNI8Bw== e=found last=12 s=22 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAvkhg/nHmcZV7j6d5d9eBb0McxMS0tyRo/LC5Br8bwas= priv=MC4CAQAwBQYDK2VwBCIEICnSKL5JeRIT51vv9BqlyFm5rvXZDrZ8BTDs2QiZ89JY msg=7+O3b2w2hQ+B7+RbhXRd9mxZ1yZ1cnu2Qs2wQ6StWdEVZIti+5wQOBItHELsTZjK4tfU+RlUzrV72wYWMYxStg== sig=fLLoIMZdM+ajRQM+8qliGs0GtLxeaEkMlGDUIHmIWJErTL16tSuVsuopKwFftI/7w4Mb5G0ArQvgqO76rN5+AA== e=found last=12 s=23 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAaTU5RBHx3Z/+eUOiDMMFSaJVJREPtEVXEUA7Ha7h4gM= priv=MC4CAQAwBQYDK2VwBCIEIGPMtAfM8KK03jWcf59KL585gAwAaXOLT1IDqNTf5tHE msg=YFVZg7grYJIa5mdYMwhjzLQHzPCitN41nH+fSi+fOYAMAGlzi09SA6jU3+bRxPVjqSzDMFFYCmrfva+/YACA7Q== sig=x6xuhCabQsn9At8pYNPfcw+dA0wxuvwgni8HtAIQ/OQhs1IFHEKd9bSMWvId9gJi5zCLae6hGAOGi1n0DcGqBg== e=found last=12 s=24 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAAhVCxVymvqjro7LfrreMrbogkrO7/+6tfLY2rKv0KV8= priv=MC4CAQAwBQYDK2VwBCIEIBmbi1tULIQsRBcN8qXOck/LiDIZ+Q9jpQtUorKQgdmL msg=V5BzvApphT+KQ11t3mBaLMhK89ycvaNO6261twxc2Tq1KgmedEFJlRZZ0iN4GZuLW1QshCxEFw3ypc5yT8uIMg== sig=plluH5rcyFIVKTmLA9fWRt9VN2Q67z5hJZM3SFM6vFTyPVmSLFYTmO4Dr7wrboB72mNj0tKSUOSWkk4xqFyWBw== e=found last=12 s=25 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAsEjQ1z4zhKB2vk7jQWqf7DG9s+hWBewTeVR9N1Xl6NY= priv=MC4CAQAwBQYDK2VwBCIEIAAGmJ/Ut4OPNydMp2yjuxG33fJV1ExBr1m8duKHrWJr msg=Qa9ZvHbih61ia8dE+tiVDZyJ12rRWB/LRfTOySyPzxFCAB7Kx2zxgMS50YPTWmwvFk/rb+NLWrsnfEsuEkGx5g== sig=XZMc00dL6taSzqUTf5yCUMaHJOCWz6VExja7fZ+ffYs/wZZSdgRuKxVNy7U67O6EkWr+yK3Zhb6ptRn0dJNfAg== e=found last=12 s=26 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAuTxaAr/GqBZSw1mb3fBm7RWgmmRWNeHo5CkVLe6HmA8= priv=MC4CAQAwBQYDK2VwBCIEIPMyou8Bz7SWN1ZUwBfomBnawXZYqyaKDlLK3eoEFg9e msg=VMAX6JgZ2sF2WKsmig5Syt3qBBYPXrvvZpYlPBb+z8anmVnnknZsC7FG6t+DoGYyorqjW0VshVnEDdAyAuadHA== sig=IbbHuYvaEyfBv3nbq7BbmdcrZsWR2L52o/FQlPymJXgus8/o38Q33oeaOPfI4diHuaxcpTRMnccDApBUFHm3Bg== e=found last=12 s=27 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA72Y4i9imNsFpihtsnEtcJZypaAfLl6FApiIE40bTRk8= priv=MC4CAQAwBQYDK2VwBCIEIGOvz9s/dTPYFrJx700S50NRx8MvyRCi8GMCQX7JBXmA msg=iM0VJrb/8SmnEQN3fo1nFq50XGmwM+bFXdSTuLmtdoDFJummQnLNNkNE+mOvz9s/dTPYFrJx700S50NRx8MvyQ== sig=id/6/3Be5l+IY7xhtv+SEt94GraKV2Aq9T5piursLVlZn8HGPYQO8s2DwTJavvJefF1h55UxMt5/8zOop4mFBw== e=found last=12 s=28 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAqum/xy7XEnUragS2+q0QcNUnvsc/UbmMTM13DIU2dKY= priv=MC4CAQAwBQYDK2VwBCIEIKnSOR47Lw/cOdYYzU7a69iM8LrxLt9L5+iQpPpLNjFl msg=yOlCeB87KbgQ3sQFMez8ee9cg/gptu1ZGGE73WH3Ud8ZfNErHqnSOR47Lw/cOdYYzU7a69iM8LrxLt9L5+iQpA== sig=NlIdnyNCuorPuz4/BOfpBOdPzOL4xGmaVm0v1UrtU1A5+7MAp1qEx6/J8tpIr1RO+ggbEfrHAGDLleyOURgzBA== e=found last=12 s=29 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAABJBurNCsFqvffm5w7toj6kQqCz0kEdkQ6cNSPNstak= priv=MC4CAQAwBQYDK2VwBCIEIFXIeIj4LeOGufbqVLTYD9X0e1Qc/QBZDGJEr0JmOKqf msg=WRgdqBcJ/VhszmTJhtct1H9VyHiI+C3jhrn26lS02A/V9HtUHP0AWQxiRK9CZjiqn7Njg/YLcb8qRJ4aswB+qA== sig=adfBri6DRHYJYq0D+kNrtfQksNO1gIqVSHu41BMOS5H+WtIux9Kiwmi06ug+QU2vUqYLiKUiU3tv7I5NMZdzAQ== e=found last=12 s=30 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAer+R+/MhPx+529LI7DMEwXtP0kBYZybawVuwzHHKABo= priv=MC4CAQAwBQYDK2VwBCIEIC9eTNAcJ+lfOq5WtpDxdnlqU5Ld6/nqi8QATR6dm5zC msg=b3KNI7MbQiuzGPG3iroM6FGlgsge+3iz1O3lkW5KT1JLjI+2i19UB7ugFxx6Uo0RRsKIhVJXur2Ela0vXkzQHA== sig=b/8yTU8nrM+/1IQZda/oYP+0ALEn3Fv/63aoyy4mgqSyPyn28s9P9nOipM+ZlCTQG0wsFzQPR3prLLo4/ocvBQ== e=found last=12 s=31 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAxmKXakHc6laMdWGM2d5Wlpf7DwXAv6eT8oW+8XyHyTE= priv=MC4CAQAwBQYDK2VwBCIEIKMe92+O1E6pgWqXWO67m51SCZiZWAmTkDvZQ4ZvXKqY msg=abjZIvKggedebpgwH6Me92+O1E6pgWqXWO67m51SCZiZWAmTkDvZQ4ZvXKqY4PtjP62H7QCCSa7W0ausMwAQFw== sig=x1Sa2Kzj5j9YFzy+kkOemFj4jjBjquzzgucvd91Am6AOrdSEHjbTEvqTfCCiBdLOQmcNs7QAEIcwCqJ33odABw== e=found last=12 s=32 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAOm/f4GgAU6v4HGFyuJ6utzgHd5ndu7Sj8hV09YQCZBw= priv=MC4CAQAwBQYDK2VwBCIEIIWo910mHMz5SZvJ3Pf6Ur3pDwZW6FYGWNjC41A3U1mm msg=GHOT9Z8iL2rYqWmGVH/lFvGBkMptl8o29UQDoDrdvRsL7kHXWHtRBEKXuSqJosbXJvUTAt6VprQ1/6lpUhnMrQ== sig=/93D6vOBC2zLzpbl0qZXlU4D0/6TquAQbvWn5ev49qOSlG4Bt36Tvy2QyO2e2ykHmcukEUm1VZdERj195SEnAw== e=found last=12 s=33 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAcb5sXPPlASBpW/ktOeflrTrIXEraMSnhj/rDt+2Ef2M= priv=MC4CAQAwBQYDK2VwBCIEIDinb5HklnHvKWaz3Bn7znaP6jCih+5oY3fSCft0Auxc msg=5y+9fCJerPKmMBOkGC8SpQQ4p2+R5JZx7ylms9wZ+852j+owoofuaGN30gn7dALsXE8hlKhE7FeFp5RP4IIFIg== sig=1nUjYLf0yJFkL44JBF8k8vE8tKnxG8oU2JH+Caz+6jA0+dKpPYU9PAJDLjLJ1G+79K+mfWxShWDHwz5nz8AkDw== e=found last=12 s=34 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhzpqCQ7zeaVjYXCa+NfFveiVQj7REzfGfibsdxctt2M= priv=MC4CAQAwBQYDK2VwBCIEIFSI6qdw+6a0MJtnC94FDVfNhj+APexWWT6XCvuiVONL msg=hjUOxmkZLVW9EBuyqnlHgC/mTQpUiOqncPumtDCbZwveBQ1XzYY/gD3sVlk+lwr7olTjS8Yo3Ajm3xiS9D6VTQ== sig=ZguJwNwYXA3KIRvwPDZScF3tZJYpTQj6wzzdNREdR332AdUHDKfafix6WTg/OG7Hl0x8/gNeiLcv4M30yXABBw== e=found last=12 s=35 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAH3h6LU59C2qd8Y/F0zM9AQvrZp1cqbh8VM5+Jo1/UTs= priv=MC4CAQAwBQYDK2VwBCIEIONC7cA0fJPIsl479OKUBN9aLu0LNLvikx3LSMLt2eD+ msg=amhkiCvizzw7viO4dVlJj1HjQu3ANHyTyLJeO/TilATfWi7tCzS74pMdy0jC7dng/tnhFS0/HUFRc2gjdokR1Q== sig=+aYHktxTZz54KiU/6ctr+vRFKWVZb5yZWfXy7WYEgv1Lu/0nnPgyqLK3b5lQZfkHBoOlWbI6qIsqRTMCeNSTDw== e=found last=12 s=36 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAxEYCYCrM2BT1lZnfebc/HFV9Tw6Cz7zhX7ClbZ8/lYM= priv=MC4CAQAwBQYDK2VwBCIEIECinzCjANriRACYcU6DZg5m/Qhy3Ul03mhf9umVwVyH msg=QKKfMKMA2uJEAJhxToNmDmb9CHLdSXTeaF/26ZXBXIeyy3POthp4GRu+HPoxVH9y8rghurND78l1JHdaZjEetQ== sig=xzuJQ5Uww8J934wMxDUKSs9TWCiufj0wAAXOWo9av6TQ71g5uAesto/6iYIeXZ0mogqFtu1tKDQT80ICcSwkCg== e=found last=13 s=0 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/xZ7RWNWIiCRfE8Oir/evregfQW8or6kla1hB8VM+rI= priv=MC4CAQAwBQYDK2VwBCIEIOWCNx1ah7MAPQ45lrOx6Gmj7KbTc/zbDVoDO2ARtSxI msg=5YI3HVqHswA9DjmWs7HoaaPsptNz/NsNWgM7YBG1LEiVSFizqSJd5Oy6pHWhBeDePs4JEnp2voRa1yMZKCMkiA== sig=i4f3bCYSVsrtECdShp0KjXihDT8Z4wQ3Lyo5hp571qmiumOGKb+nOpeB82DUMz355o03/t4vyF6qwS/Gv9dzCw== e=found last=13 s=1 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAlMQAiNvmyR4t7hSV/8Yk1hzGLKGe1SFlcPlZ0XGwP/4= priv=MC4CAQAwBQYDK2VwBCIEIL2o3zZaz7DYtCaK84BfsZTj/5YdXuuPoGyzjeZkfJcq msg=vajfNlrPsNi0JorzgF+xlOP/lh1e64+gbLON5mR8lypPaSnTsaBpTtGA4CY2SxtLPvA2Sfd2xyRPt2SMWSmYGg== sig=SZ3kgmTPczaBtp0pmX11PNGl7MMFjuFxpYN4NnVlrDKoGc0WtUsztLGBgsLWdHImzYFc+g5VdUgQLXbzTUA/Dw== e=found last=13 s=2 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAEVbkM3cSv4A+0GNHX6g/puvU9z3BjZ+eNxAlKb5PAGE= priv=MC4CAQAwBQYDK2VwBCIEILm1eTKsLq4tbThPDxGevWkQlzSMuCrd6sgp+bkjEY6E msg=ubV5Mqwuri1tOE8PEZ69aRCXNIy4Kt3qyCn5uSMRjoQmi1YmRwyXuWPKFwe11vndjf2L4kdpxi0do3TytOGgAw== sig=1DQlx3l4ZBFa6X+ns5Pw4cp8VDpyf2m+uSPuOTjjWac2I/PWMAbI5qdnzbyd/UTakMKAcYXnrSN63PZWHGd/CA== e=found last=13 s=3 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAOwTzFOxpKywgwQ2va+9gr44x5KbQGw3Jz2KyhiWRR/U= priv=MC4CAQAwBQYDK2VwBCIEINY+999DbIdnYvL+JTJpctuWm0kxLwJ1+TeS50Z2aHk/ msg=1j7330Nsh2di8v4lMmly25abSTEvAnX5N5LnRnZoeT9UCWDbMQG8dflMfvS4pyStSi2vzTgOMqwtmVN8H9IcTw== sig=cWVDnqag+qvpzgMzNaZnO0F4nSADwN3hKyk5RxlNZ/lamejBvvrR2sH95ICvI/+RnvyMBKGYpvfV/tdipkACDQ== e=found last=13 s=4 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA4gd5Yszd4KDokGPYfYuFukOh+nv9FgpQR7jIqx1qQ14= priv=MC4CAQAwBQYDK2VwBCIEIHSw6zDMaLhsdfW0pSVqewdhi4rJm2NDDH99yEdkDtFK msg=dLDrMMxouGx19bSlJWp7B2GLismbY0MMf33IR2QO0Urv2bMpGrDsI1m6c5wylBaxGTFomCDYKt6NzD6GTTn+gQ== sig=Y+fHprdODp1CyF2dVnB/F/xW3QKuGaG6d9fMoj88FB6eQMR2HloxQzda85324il3qqH4q423HSxpS31DhCi3BQ== e=found last=13 s=5 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAvPpM0Dhs1biJjQbZASXQ0wB0sMRkdl/RfVodbo6COfA= priv=MC4CAQAwBQYDK2VwBCIEIEm46Zf7/WsIvGTTopV+gujPW1DqwWYu6D1sGZA/UzBb msg=Sbjpl/v9awi8ZNOilX6C6M9bUOrBZi7oPWwZkD9TMFsql5lhoQox4RA6m3PhFQ8VHzDnFhR8z+N+vYY9muyppA== sig=vr0YFOf3UwN3Dwuppzdi5DAf/TaV6gpM/enB8OtBQEF8yxn0SC7rqrBl2aGrXC/Y9B5ORnXWFnIPj53+I0nJAA== e=found last=13 s=6 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAvnKYzsWm2JK1I153Zea8iGVslGihL9wz6xKdRnnrw0s= priv=MC4CAQAwBQYDK2VwBCIEIF5SNvBsB1DMLW44UjgvbbkKhtOfQLowxnv8RQbaqDOY msg=XlI28GwHUMwtbjhSOC9tuQqG059AujDGe/xFBtqoM5gf2/pvWMpIFa7Pa1nDo7D88tI9WQg0O56Bj+5KOn7whA== sig=zakYde4sm5Ax9EUwW9Av6TfUudlinKTZdPHNpAq3S5RJh0SfJeHFgIftuL9mQyMbx6Jhm6hVzWp1wO4BVHenCg== e=found last=13 s=7 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA9UvqVL90rABRd9so/FWqheyo10kOavrS5jrIl+Ua6jA= priv=MC4CAQAwBQYDK2VwBCIEIMP5+SXCoB6WnQlNMyPY4o/NrVFz1PzEbPfJSElWaG9k msg=w/n5JcKgHpadCU0zI9jij82tUXPU/MRs98lISVZob2TLa8GMyE5NYoAAb+x78jRGn5HbMF42s6bCG2ZzOwdMaw== sig=0KGFd9jfHNDaphagtFlG53gg0GChlSCbv7PDEXcG8kTBlmiWbfpWlkIX9gRxh04BW3tXYJpm3c0gfF0DI/6cAA== e=found last=13 s=8 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA2UquPENIT1af5odjWP8st7YTfH8daYf5dvYmi4lECx8= priv=MC4CAQAwBQYDK2VwBCIEIIlyMwoOArlA3lMYgHU8lkjQmSIBgz2gvu+RRMitO8cO msg=iXIzCg4CuUDeUxiAdTyWSNCZIgGDPaC+75FEyK07xw6eWXDB4OMCoMTkP3wIHj3r+81jmpX16PuIMcLwZzuzKg== sig=GPA2fdkckF+PguSYq3IjN8LSiIDSNVOl9Na3cCmhYEUzfV+4Z17O7cMzCik9NODdbf4e+jnXp/ND8yvrtuFQDw== e=found last=13 s=9 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAe8AjcDAjmDSgyYZ5rGSuq0WfNtvQtS0fuy/rU6dPEig= priv=MC4CAQAwBQYDK2VwBCIEIEpeczlUbNdpwkrCnuvSuAqzjCTBqImGjH5gxXBy5cYZ msg=Sl5zOVRs12nCSsKe69K4CrOMJMGoiYaMfmDFcHLlxhnlUJE+VBRNou81BkxMmlqpm7rq/h/lHgZN4Nc/cC6k2g== sig=bFUh8WU8v38wQGGY7x0t5QLKJax2vsJwUNP/EQd6sT8MkOofg++KUFVAlT7eedfD+JTxHvtbY6RMgqlh2kn0DQ== e=found last=13 s=10 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAAn8A4IVkDUj6vltuJ4zbzyse5ZyWhwFR4fEk50bWp6c= priv=MC4CAQAwBQYDK2VwBCIEIGQwCM7NO1hoeCCU6G8nmlmNDWeE7zBIHRatCw/2lRDv msg=zs07WGh4IJTobyeaWY0NZ4TvMEgdFq0LD/aVEO9HPacc9CrPejVhzFTRmZmSYD/Dv1q3SCfyYy+rP9CE1w/CwQ== sig=XkLQwEQMQGk96CExdexXRZOiXMkS/wq5JFyOV1iB97lK+wOXvCSs0GnFebuDq3sMrjDq+Kgdi+8mGuWwA0OkBw== e=found last=13 s=11 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhM12kMba1FLqBNxPSIN13nCtLrzoXJIX2eLy0U9BOLk= priv=MC4CAQAwBQYDK2VwBCIEIEl+8fCKbfRsUem7XT0BBzr2mcEs7pVyrU6pSaPLDTYP msg=9GxR6btdPQEHOvaZwSzulXKtTqlJo8sNNg/JnphvQaH9rS5n+PQiuB7l1NRfoMomDKQk+rtDC980jyadcTnPfQ== sig=/873e+8ILSEkOPI7YRBT6XvXnSjl5Dec7otrN4L6Nq324kmpwwMMOXQ9Sf+j1/oKNtC5H/oIdCS0eE5ARilcAw== e=found last=13 s=12 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAU7SxiLqEeSPKJUMsp/9f/EDv9TkCgDgCLzUE2+fvIZA= priv=MC4CAQAwBQYDK2VwBCIEIDZjlQuulFxjkiFwwrg75Y2AIRXj5QBSqN1CJqcXctA0 msg=Fk4nHHZdu+gxNCb4WRs78ld488tLMMVrkiN3Hi/eDOXypooVIxC6DLIohzz4HSYOz0cexAByHjsmwiIlpLGf4w== sig=6rta5oSjlXvl6DvIDTxLwBs4pyilz6Y64hIpsuYBVEjK3pjy3J41mxPh3nxhjaD4b7GxZK8g1+C/4hZnBGomDQ== e=found last=13 s=13 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAlp9AdLnkZewJoVCuNAc8NGpMAHBNnUEHF0Maa67xTqc= priv=MC4CAQAwBQYDK2VwBCIEIAPJbOuybgdYeCU7CjyhhyEbFm5kaorPI8XnDOLekkdH msg=3PRTyMrpXc43GT4us7xSnyCeLB6lybE45lNukrrOd0+TqgRc7eSi0Mn43RCPrqVnM0FgpEsfkzKytTUVhSO4sw== sig=FeKSW4Vq+c4ji3GY5BERcfw5NmOgIq6o9rFie8ULUfSqeav39KEieyVVmjcLmzIfJWPygjZfu0wzZpiXu4fkCg== e=found last=13 s=14 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA2ib11ZBxDSqktjZPs9OflN0xuxGklld7sCNDSpteLIU= priv=MC4CAQAwBQYDK2VwBCIEIOk9mgtZA6k1PP4qOLS3yiu/x4MJ/UTC55/lt+lFjAZC msg=tLfKK7/Hgwn9RMLnn+W36UWMBkI8Q03YHZLgQL7ICq503FikVx9GNpVb96a8dfwQ0kPH6aHbI4lrvhPzbHQROg== sig=mzGmwcOrMT2EhDaV00UmX1ZVv9jK8pRwMakfHvLO8qZw1uk33eYJvvgYQ9vdo9f78/ng426EO6aftUHDMiCTAA== e=found last=13 s=15 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEADDLUi2p8YVzNZfiFyf+wCK9zzpep8yW35qsv73/vxUQ= priv=MC4CAQAwBQYDK2VwBCIEIEYNspdQoyfk364Ji75OWh91KlmaXuC+EkZZlHVpoxOt msg=5N+uCYu+TlofdSpZml7gvhJGWZR1aaMTrW4Bnpfim8eHy9CPA/5zERJGAf48wOl8dJRlE4a7vLfnftxB9FkbeA== sig=k0cDkkQED1wlR9so8/tgxtbkzxd+n2/xM03ah1T/WnTvJ5dD5bWw9GCBtEynEvgo2nomLQ5PurteuTKhm8mJAg== e=found last=13 s=16 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA1YFuSTCj7dfWRpipN1mQbKIgoP6CWi3e13iS7YsJzSE= priv=MC4CAQAwBQYDK2VwBCIEIL7DrQ6UWNHorJ2uAYkN3UDe4swZ4a6ZumT840rLfOAR msg=vsOtDpRY0eisna4BiQ3dQN7izBnhrpm6ZPzjSst84BGQvNr37eBB5ADLLvVZtUFVLNjVkAn3/gDAFVoe+JPZhw== sig=w8D+ivrF84UBp52qgcziVgBeEroDODgLlrMi260IIMac/8c3b8LQ9mM3G08p/7M1w6V41zgqDc/xumDrTr2eBw== e=found last=13 s=17 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAwxWNN+Hs3t8vgI/FOiuNP3KooTU0trS14Zi9b+J/IG8= priv=MC4CAQAwBQYDK2VwBCIEIHIBXkSoCHdlA6GEDvmsp39vn3FgqJmSzkaoLgTMf8AZ msg=WO1f9OBLHBkUAf8heQ4K20boQTYUnMJVO3lwvOYs0G6JNSrVKcGxx3cThbgi0CQYn8vhsiqNH+f8qoZkMuUw6Q== sig=XkxeVYNvYYgb3L4CHXWn1aRoBr6FH1V/lI8P7jlZOm2GcADEg+BC5XJHyWkV8RiFniTveCs79iXQGXp7we6kAg== e=found last=13 s=18 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAfPYSPfAeWD2rboqdKqjCafP5goRNA955JijOl7fAYMM= priv=MC4CAQAwBQYDK2VwBCIEIOQ13wHvbkWkfMjOBrcot+qjcCB2oNyByXHZ2ZqCaXHu msg=DAKJx5chFNVi8t9RFw0voIqmqLuDWdqMeI0WtF6UdSrTl8WoAkKjXMTmDHZwpwWZhB8y5TqzRbRryuYn7+qkqQ== sig=QPmPIcVmZGIuqlLq2z7kbiBWPG/KjqsRBvChELQwckoVthIfuRRDXMr66vhFCDELhXOtCyays5BkafVjkogyDw== e=found last=13 s=19 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAsTqBXfJId2wpuAhA/NzVvOkJev7hgajCWI+qxvdaJNo= priv=MC4CAQAwBQYDK2VwBCIEIAhyU50+k06WkaMJb9xVgWTrVZy4smSLnN1fUHzqaT0o msg=nT6TTpaRowlv3FWBZOtVnLiyZIuc3V9QfOppPSg+MTu2OcjGxNksoTTYgs/0d+/gFzcbEZpwtYpPB0R6dqaYTA== sig=N43LnuuUj02pAZlJeCaTaTW/iblHKbMcAiJEOCwPGtiGe88R7vA2FvI0RMN+ZXsAVpiLUxuEKDWaINIehXMZBw== e=found last=13 s=20 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA1VnYS2z3yWhvUnaEFleBKC63u2zCGKfNhPu/u9FZ6Xg= priv=MC4CAQAwBQYDK2VwBCIEIGe4PIT4c18zLs3nOzNBu+RTEpp6fqHaELKyTgdK+/bz msg=njQhDUT1ajZ8oU+Sl8QeTK5wganVeI7JLRURFKbTltvfMZsA+qNiyNcPc+6XGfef82e4PIT4c18zLs3nOzNBuw== sig=J8BZgOmVU/nqJpoL40yggpvrVoqknOGuZC0EjJagyIcXorWFcGHMpGTsN54sSe8c76v/AccnIwIbh6TiBUgVDw== e=found last=13 s=21 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmXY88Wodwhonu9r8USHWyd8fOjgqnrccc10NB5UESnQ= priv=MC4CAQAwBQYDK2VwBCIEIGqut8fuTXKI+l9hLeMhpA9Xn4Bp69Up6NP8mHvmgVxU msg=ZsNBwyqw87SgSK9t45TknCh2/o9M5MxIaRQA8flEXFQvwIMyHM4ysYUdpXKQyd6auhqCbRcvAdevMCjKoRrEIw== sig=l2gBVpwfbBB0I3SJ910/ijqPeZaaU2BwftOj23urkv6Pne3W0N3sSkHDUnVbO1UtiAku3gbRns/q/umRvqnSAw== e=found last=13 s=22 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA0ZubSjEyeBRtcujJDTy2TUvb7gU0Q1uuInKWrjXmigw= priv=MC4CAQAwBQYDK2VwBCIEIBq+pj4BOB1+0tgpImbgDfp7Jv1tx3eXT1v1pLrIEWqO msg=ImbgDfp7Jv1tx3eXT1v1pLrIEWqO98vdqCtPQim/38KizJZtmudvRvTesY/X3babzGWZAMRX5IY30ESgTcP2Xw== sig=FcCOBsbGloAAWCDoZcsAE/Y6QVGcI+5K37DKbno1Xn534PW/ggKBi5OfUd7xPP985VjPOGjbVCeygLc+yM3mDw== e=found last=13 s=23 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhjhieCvP4ot+CR1xhOQHJmZM4mcUPeZzGGQ8DPKK6ZA= priv=MC4CAQAwBQYDK2VwBCIEICMOOFYAEUL197ajXapejXex94f+j8lMpDQETE+Jbyzu msg=htgwES0zbzed8pThd4x1WAbgZ+5yYxefvPJcK8XMaxdDTTA/qa9xy/NQV2WMr7KHyss04SqR1xuFSDukPKYfiw== sig=oWmAzuYgJCjwbw2v3PUQ1p6c/g83ngjQBp8ndZpsNr16CGOZWffdIydp0w589Tr4NXbhrJ990zvmdxDUzimDDw== e=found last=13 s=24 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/ww9LW9EPu6ap9JZyTdlfxhlhYI4v0u8qorI7G2UZbs= priv=MC4CAQAwBQYDK2VwBCIEIBm15B9m2VSK4ZWZQiuF+0WqPdlgJ8oIb3EMbsVzkXn8 msg=c9WoUgAK0iWH3jRxFPnTJVScRQ5hjILt27BbYlRzNYFYRV90QStwlpFd88esrC5ZVc9uRfAtPM3pjjW69hm15A== sig=J7TtssJltWU2hjaj9GqOpyRNDCX6yJplNP4f8cq3AJRI2Ly8DI1Jii8aBAHDyWAcnRvA+N9MBcD3HTyCWDz0DQ== e=found last=13 s=25 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAjoPuogLfEK1bVbvm76Bj9gCfa2ARy4zKWw6WQHf+J7M= priv=MC4CAQAwBQYDK2VwBCIEIGMM4f5U3scHStFaJWvoKY4kkUVR5b14L/OEtoioD+gx msg=X81Kw59EwGFq3W/5pxTl/m90H+1V3XnzgINANoaiZDq4t0ziY3Isb2XqBnKrnWA5NPJlTul6tFwHYExiLg3YJg== sig=tuL3avwptYMrrkyK/NHqya1+WU8lUzMXy4wyYK99QFEiEJ6HYVodsgcK6+FR26dgkmUonb9HRIlXTp81spRRAw== e=found last=13 s=26 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA6NSF4It/S8bNcev8cHaAeP2MSMGrHpbzWpUaIOfwMZQ= priv=MC4CAQAwBQYDK2VwBCIEIJzR54Ymy3zAYZqyVZpK2pfL3NJ6bl5R9leKSH/Gq9/V msg=a3RxzNAZPy1r3eVW3MXSYIeOB+4PKIohk7cR59Dh5bec0eeGJst8wGGaslWaStqXy9zSem5eUfZXikh/xqvf1Q== sig=wNFmm+Yh3sZkon/jFV/zVQP7JS6OxDEFvjUWIPOBejsQrN2iJjJ9fsB2WOQje5E4hYj0f16wld9saWGCJTvjCQ== e=found last=13 s=27 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA+stRpRotKBmDBpYDeeJZuNxZzpmNMoTZ6UfAqE2K3V4= priv=MC4CAQAwBQYDK2VwBCIEIP+1JQZtt/VzfaJ6U6sS9s0U328tueFmPIKMJvQKfJeX msg=bAV8y5Qe6dghH4fo5Z8ZghcpQQcxXoMzhnfkDpyIr53IreitTbOb51sjcqvsw7lyZcIDGbnRvekOt0EED3aLcw== sig=k+Oc2sEfv/UYEkjb1YIdQ341n7E2Spa+1i0jt0i0Y+i3f4h8TtOTCgPgpU9VKXE2+W9zrR5XRQhlsuvwdCFcCw== e=found last=13 s=28 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA1kWEIF7NAa571pSYKFP6/FoHC3UsFtDtS+Zn/tYlDas= priv=MC4CAQAwBQYDK2VwBCIEINti1RWeY9fWHB/JVKEg3lMk48YxHgADqUFa4zMxIT/G msg=IYP+q3L/qMvYj9Ct9PPyWhYTqWPQFR13ueKMITKsN6ShJZgHJM+N7uuaukhNxKplHlREnppQ22LVFZ5j19YcHw== sig=kCFBEtUEAxs+QXMRb6GmAN5v2QhvWCboWk38IiN0dY8EKWKSSlxfasBrUmLktV1lrZNl4tIvdjo4pl+j73NRCg== e=found last=13 s=29 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEABHFFkRu1a99IMjSNz0VSCJdT47/67h4td+/GP14//Yw= priv=MC4CAQAwBQYDK2VwBCIEICq2dhRzznDvtT2M/qSE5ahXyFzpK6DYCFaSAWEWqMur msg=CiMatKjjySsA1xOgKrZ2FHPOcO+1PYz+pITlqFfIXOkroNgIVpIBYRaoy6vHrMCp+s3TxKChHI1IJLQCFrJp2g== sig=04gI7/2bWvcgTGfXTisGn2/A2D6op0sddbR/jId9UpD5Z2XBSGsFSMkBcNf1zoPA3/Hb+FpSruHfi57t87MkDQ== e=found last=13 s=30 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA+Jb6J1+1hyheCbgCioYycSz0k656gIfhu4EfEUBVY2I= priv=MC4CAQAwBQYDK2VwBCIEINCly1IOGxydTAL43jRhRT675BL+sHbQzOZMElkwbLXN msg=Bx3Ixq43xi9PMhcOaNYngHHQpctSDhscnUwC+N40YUU+u+QS/rB20MzmTBJZMGy1zXe+zZJqpdY7mfJ0YR/G3Q== sig=nvl4c2hHz9ZymE+5jy65ztXduFh4ahdOzjAU7XXXUQozJL9YbAjrT93LFbRDdvqgMagGD+pottjpFVfu6DFaDw== e=found last=13 s=31 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEACOHnzv5ruwKgIv0NhYH7n6JMQv1BmDD5MYuJXo9eF5U= priv=MC4CAQAwBQYDK2VwBCIEIDGPwU7MVh2+peJSYgTINr65f0WvSuLZRtjMYh2JyiQU msg=tJOperaG//Z5+JsPTO8+KstuGLGOREOqJyDlYhphh5Wk0lJyWLGQWbuppUZ0mmfG3obzF7lo5ZP33Gi5JVQp4g== sig=iU6HlvfZFOKUXhPz+phCj1rGbO/8GENrpU1/VPTRdQYffgc/NcF0R9ZlSlD4xbfeb65nugZmHg432y5wz37eCA== e=found last=13 s=32 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAm28K7xP/coEXY69+BY5qdlHZbK39j/9xEeVwcLIC74o= priv=MC4CAQAwBQYDK2VwBCIEIG/+kcDtKkv+V6vCunYJrK2SbIlG+oBFXPXNb9vIRlX/ msg=Kkv+V6vCunYJrK2SbIlG+oBFXPXNb9vIRlX/7EDubge1ILVdZPRjlZz3Qjs75vb/rzt6M0Jp5PcGIAUiQ1mnfg== sig=U3cY7ZY60rcwfSFBM2Rn3ljR4laf633Dmdng7LgPXUt4e/CNeMUwk8iuyFYVJooiP+q98dWqxhwv+ucHFhWhDQ== e=found last=13 s=33 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA9BGgy7krNn6RpH0yaWPC1CSZBdKiQ9R1uNpHy+HWsMw= priv=MC4CAQAwBQYDK2VwBCIEIHSDZA/usvlnqN6Dc8v1S26j1nHRBoWeDCZGzYJdutrD msg=YsQ38VyTC6TBQL9CPaHil0xEuWkX1J2DELP+4B7HNiClPEc1oJsEQS/X2cpcHJYZRLxne8L19o90g2QP7rL5Zw== sig=SGST+Ph2sc0FmYxZRtz8w2bC09I2NqxkQipgIRtK/YNbQBY7/5GXN58Lkb5Rxfo4MRSPZpmCANrzUsGTEuAXAQ== e=found last=13 s=34 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAs4IP8oziqUpTza1762bPeIHKICM0uVGWmbqZIC9SXzU= priv=MC4CAQAwBQYDK2VwBCIEIDtlts9zxlcytnBZqrvVCP4RPwXDJri5cbHjwVq5tAqZ msg=Wrm0CpmXOGB8kBIuUTLjJMeDMCbBJuodnBWXpC8VxTI220CI4ayXKjg15QYig1YwM1E50LORBOunvhNa5CXF2Q== sig=CmWRt/hLECO0wAe1mVLOnL0MbDi+wcAtLcEMhqIcVhl4Uztz+kwGxSTfXghg/HJdjvkyDmsDvxlymLFAGcOvAw== e=found last=13 s=35 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEADKD+bv+zegZWgMNKvHoEQ5qsJa1+G7/WNnLNx/an/IY= priv=MC4CAQAwBQYDK2VwBCIEIKGmx/GfGnBASBsSyrH+9mcA79BKcjvQ9E1CEphb9q1d msg=KAZ+E28F8Vdk11K5L3zsykRP9LIlPzLGUa4Edh32ETMV6uBDrOvOER1XXBSFeagmtyCPv0oAwoRPoR36h9/LIg== sig=6srlsZwrDwPWS9xW1JDFuN/Fu3VssfSu+RQJe96YnfTM/PAZOaqiXoLYc4/Y11NC2g2B8F9t5rVPFGq9xscBCg== e=found last=13 s=36 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEArSpVjA5w7LCW7rdqW/K6+qHOgd8N2H/Q66eUmKFyOKE= priv=MC4CAQAwBQYDK2VwBCIEINC+UODfOpEFQuIEyA+fjhLXuoWA3W42JCf0RR8kOrLN msg=0L5Q4N86kQVC4gTID5+OEte6hYDdbjYkJ/RFHyQ6ss1Qfeccz5szjX/4eKg6FeUR3d/DIHcEV+zaQAOMUStHeg== sig=8+TwnBQzQgX7QA0K8IdOfFrdj14pFkb2TIma1mHGfLnX2Iy71/EeCgMac/Cp7VhTlmEg+fxlVARYmvBdvKamCw== e=found last=14 s=0 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAUrmA6SZe1nUZdYSfwll3c5SlP5l+Bx/tSpI036M2dbs= priv=MC4CAQAwBQYDK2VwBCIEIACru9rHDlUynZztpOj3CbrqzsL7/W3xEELplGv4qTKn msg=AKu72scOVTKdnO2k6PcJuurOwvv9bfEQQumUa/ipMqdxt+Vt7olnPDXKiEOYAQ07tYFKNIaimasOTU9G+7jg2Q== sig=eYzDo3KJnjopu9JYoxLmX4K4i/E9QOm/xbii1ov334xvMfqUHAxQh86x3texMkFMkjieJyKyemSkEQyUlV7jAA== e=found last=14 s=1 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEACCfYE0NMvS27KMTrDcGDXkpCRJgfGja59pvAEV0dMSk= priv=MC4CAQAwBQYDK2VwBCIEIF1CkkwLna1/YvpTsdHVoZxutGEahwNHvJEa69v81ppA msg=XUKSTAudrX9i+lOx0dWhnG60YRqHA0e8kRrr2/zWmkA3kkQTXwSVuiJIvIlb1KW4/aT+cMYlrhvf+MIMyoEI3w== sig=/9A7ftDF13H9Ud+HqB4UKyJ4iFkx20w+GOn9Px2pcGXBtI2lJ+yMIswHOhudqEw5iQlcDrkdXOgYVlZaaZKDCQ== e=found last=14 s=2 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAox5pJqmwwzwvJ7F25Pfg2pt3jkDiUOOLQxEtfngHVvU= priv=MC4CAQAwBQYDK2VwBCIEIGnCgE5Xgt2DSOpsVqDoFWOAhV7F0+3dA3RJIPu2d8Eq msg=acKATleC3YNI6mxWoOgVY4CFXsXT7d0DdEkg+7Z3wSr6YWcefb4OPhscmi1VetJkCltAV7SFi2KDachL51GarA== sig=r2lPx0IyrcqXmaNt+7IyBV7FYDhFPWR/nNQ2Jrn79/Zak6WxoMM/fZLXrHtRv4axcldImF/RQQ7ZkQmxdNXhDA== e=found last=14 s=3 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAHr7BzFwIlSraonHssOueXzQzl1oI3MdofgwBpAy4LCM= priv=MC4CAQAwBQYDK2VwBCIEIFds9tS6i66tuvmCKSYlManGPuTvQugih5MWPKRjzoi9 msg=V2z21LqLrq26+YIpJiUxqcY+5O9C6CKHkxY8pGPOiL2cFrEzYgLAW75V4NIIG9DrQMh90M8SIBQ+hy8vzgSUqQ== sig=OTMtvYqHUzmUDFbStGTqV5X7KFD/+JL91kYRLYWBWofMVnAdst2KwZuVxYSFNJNyh0aQGAijp8d4kUfFsqEECA== e=found last=14 s=4 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAH/3N3Bfdi7Z6wyE9HNzG1nyHsv7WjqKyFl88E4M22G4= priv=MC4CAQAwBQYDK2VwBCIEIPq9umF55WV3H/K4IFHcNHThlVowwht95Jr7/CydVsKA msg=+r26YXnlZXcf8rggUdw0dOGVWjDCG33kmvv8LJ1WwoCNmpyxkBxVDn1olXnJ0hPWLESV7RriF8I14Z02x245UQ== sig=h7+Wg1IhpMNxg9PJUIEW1IW/OGdFdBZOjDiDNrr1MbgcETH+i/J8YWV/RPAGRLvi1QlooYxoP5vH3NBaVN6YBw== e=found last=14 s=5 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAIp/klvM5Hd/ycnhGROLdVlMQUuA0WlH2ynpc09yeYPQ= priv=MC4CAQAwBQYDK2VwBCIEIGpFnW1yrCLaWhGR56YzDuzYh7/VhFrOte7qhJj4UCm6 msg=akWdbXKsItpaEZHnpjMO7NiHv9WEWs617uqEmPhQKbr7n4obJhO6tWLay3neIlH5jrH6imjATw721gbdbCdvQA== sig=lNg7ul+IjRHtEegWxbMtMJVjvVzsxtI7PHCyn803sYMtX54FxVQVkG12tHYqreXn+WbN22Gz9dlkCiGHxwSpAA== e=found last=14 s=6 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAXI2KPuYPVRaIa4w3QBTZZ/fJuqvnDjTzAi1lqc7NI/U= priv=MC4CAQAwBQYDK2VwBCIEILIN90CJhBrwHpxvZKt3xrAZ+wUWUk7hvJrqR6S0azSj msg=sg33QImEGvAenG9kq3fGsBn7BRZSTuG8mupHpLRrNKNgT9X3bSqR7V7XUuv6va8NZWdWL8SxmmQfk2VzY6S8JQ== sig=PtuqgEr/bYvG1nWBc4ra/vS6JMePDAYQF7ajDJrCMlXDlIDPeKAKtcsfxRH4ofLiXBw4WuGnDdsIaVker9d8Cg== e=found last=14 s=7 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEATS4Mla+2lh+RdQ1Ocu48PmWV/VM3Wr96KQfDMSyRIMA= priv=MC4CAQAwBQYDK2VwBCIEINmZvIojYq/TlvPypWsuBHUZGZH+7WnLEsUCJgzvGGir msg=2Zm8iiNir9OW8/Klay4EdRkZkf7tacsSxQImDO8YaKsGLMFpYdR2NU5cUqrumBqsbIm0O5EWg82kJrRjvjxHCQ== sig=cEZ9+cTPpPscbkjDq2tw7nknCfYLPiCyC3zV0C/9pkX4cfu9CiMahixL0ga67zHpxQD0J5PrFGx9mPhMkx0RBg== e=found last=14 s=8 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAg44T9uEqGa7QiI7Ju0GPSIIn9Jy2vFHscywQf33drVE= priv=MC4CAQAwBQYDK2VwBCIEIPN1TLnZn7tqLW64n2XtexGqtSrTcsqpMG2ffSFJQjBu msg=dUy52Z+7ai1uuJ9l7XsRqrUq03LKqTBtn30hSUIwbjZuc5ruFeV6hXCX4mWIUBEIY6tjlcWsbFyUOiuVYbbf2w== sig=4gnO3iXjpCv4a/u1UliaGcfvQDhjNc41I58iXt5YwYVUEPDZeLgmPxi44hkFRH3V2DEDNy353E2oOSRtDWA7AQ== e=found last=14 s=9 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAJO2TgZl45QJLSjUam4mWVPQ0h22q4uSlgrYOHbvv1cg= priv=MC4CAQAwBQYDK2VwBCIEICGOCk25WCik0HhVJ0fX/TKLeVBSam20TYwie/xbsRaf msg=uVgopNB4VSdH1/0yi3lQUmpttE2MInv8W7EWn2TUN8W8+zjC3YB0Sm7l5MCk1cjSm5y+jTbEA4f+7+PKYN9X5w== sig=Tvf77WmfrwdWSE5AfJsv0KileFIQsnCou4Crl3xor6Us3RG0IzUbFkLtZjot9ad5+3zcp3xN6lEHNCyulKaQBA== e=found last=14 s=10 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAcuKZD9MkL8m24IgvUHUqNy4m65ieSR+nWFESCPj0wNY= priv=MC4CAQAwBQYDK2VwBCIEIJYQxyjA93dZ6Y2BTsWQKODDYqT5veJQ7Et+8BNIPyh3 msg=lhDHKMD3d1npjYFOxZAo4MNipPm94lDsS37wE0g/KHcsNTFHXhbv6T/dB5aK3cBCYLjGpIKDbDFm9YWgQIIB6w== sig=slqwfNi5DJvcdz6LXGNABQFtVYeAznlruDNIwSqVKQulRqy+PdKTWNvsyMZb/32LrIejPzySYiBes0MvLXm2Bg== e=found last=14 s=11 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgPw478gkjq/g+IidYjWQTpMFu9DdFu8wRQ1JUiAkBi4= priv=MC4CAQAwBQYDK2VwBCIEILkXuYOCJlzQKJ8Fwmu05DtiXJwmDrG3Nca8bPU+V5PT msg=uRe5g4ImXNAonwXCa7TkO2JcnCYOsbc1xrxs9T5Xk9NXRVPYtH+eTCEmspRHeI6B7C4wIFOZpBhq/OTQ5+9SuQ== sig=DohKFdYeN3vhyY6NJWOUzBYYsMVSIU6psNc8b5b9EreIYX2kDdlNPV0WhrEEr3/n4MLHsYcTZnNQp+42SPuWDA== e=found last=14 s=12 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAnHfXEmJ2wVuWTbT98vAhNTK1sD2prZQ2xaxlNhN6NDM= priv=MC4CAQAwBQYDK2VwBCIEINokiK7fOOZlcv5khot6gTzsnB4y9eEb71fWNHuzmvBe msg=/mSGi3qBPOycHjL14RvvV9Y0e7Oa8F6aRJ6FwNqfe1p1Q+sGhy0IKlOngJcqmrs+QHzOk5/ISSCJCHoS2p4gwQ== sig=Wg8mMPHAONYEKBtbX43K+TsvRbIr+E6EWUV8hutmxeSBbeuXYUX/4y4EqofqCS6cHvuSGmLUBYQUuTujDBOVDw== e=found last=14 s=13 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAsmQw4VC+O5aySltPDZpuyLJnIJOT9Jk2ycKrrGiUwGg= priv=MC4CAQAwBQYDK2VwBCIEIIc0vyKV9JO0RUZplWIFWRtgmtwBHgzVprlofSjnRAYh msg=K/RN+IQGEycN5IklrFYJx2aQNXDo3YF+rfhJ6z3MHTw8I8X3bSAJnP+amuWfuCE/EKHdOfeIVx+l7Ew22a9ZXQ== sig=CW0fgUaArksW3RYCgKl33glJ9lpNgVXGDDZs86cqwuzUEGCMBow+0Tz3EAUJgwJOYllIKYSVpNmh46SbwjfmDg== e=found last=14 s=14 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAikZTSHt8+kzMZfj8a02ytJlLnNqTt+rf99oFA/hKybY= priv=MC4CAQAwBQYDK2VwBCIEIFROjMUdRdKV6+fMX6smLk+1ao4mIvN1wUzQxN+jD502 msg=Lk+1ao4mIvN1wUzQxN+jD502fkSboYgOVesHz5fC3H8mMT8zHmQ6zJZeVxTbHLxWAMtMZI7GUXsYY05dU0Bjgg== sig=5f9GEI7zRHrHe2uPlg5OrvNORNp6lOe3FA2olhj9r9y6TjqGTQ312XyTFfRyECJ77phB0nqeG4oszG7uiXFcAQ== e=found last=14 s=15 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAv5BhJX9NY8XwGtTOcf4hQOGBCjoCGRdlj+k78pgt+9w= priv=MC4CAQAwBQYDK2VwBCIEIA86c/pn02koBdJUXMJexT0rDTbpUxDJpTGmHISws3vU msg=Nq0KyaFCnkylokAEirAUcgKt/v631+CU1LMNzoiGmMiAZwewq2kz3+n7+fuq38nTrco3zMagfvSmz4FIZsf9tw== sig=h1OcUwWK8Frv8X1AuCgoZlOJmsAdOfvASg+Vq4E1W9u2q0hokHEaGwN+sewjmLALieVfDOlfMN3QKxYfowMNAA== e=found last=14 s=16 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA0PXwb760cHNZCVG5o3KfzU8pITFcFSXDbi+qQDYk74Y= priv=MC4CAQAwBQYDK2VwBCIEIOnjvFAiRiwj26H9LYPDElxOxjFu9AcBLlgzkiLafQ8Y msg=5b/cNTSfKQSInXyW8Ys3E2oJ8GS3LND/Z61grfV2aHaYMOHunCnsStY3fHwEdeycBe8nVC9+sCksRxQ3udHf0A== sig=8NFnGKdMair7CqzSsLuFOVCUEvSHDjUVH4m5Bz3qr9mOcsl8xgeRs4Ro/KgbU2GJRugHnttocRWvsqIH4frLAA== e=found last=14 s=17 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEACZ7rrcDbw7MkE1xYZvOwrovPyCj1sgcKcXw5U/nqnHg= priv=MC4CAQAwBQYDK2VwBCIEIP9iHYQeTeC6clgwx2kpAP4LwUpPEjguhU8Oi2R2Tr8R msg=gTuUz+Sg7aG4SabALhqX52GK+p+zGyxufWtoLqLq62sUifbrtgj8F4czJIKb+FkIM/ORkDTFeB5AR/NhD4F5LA== sig=T0G7iltrMGbrbavuCtfFDBo+4pVhIdT+5qyZ8zn7YQeJJYT3lrtYJDKny9QYRxknOadayhrwjDc+fMT0zlxcDA== e=found last=14 s=18 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/F8kUfM2pJRmMJRSV9Mir7XOJfQfQUZVQkB0oLnY/II= priv=MC4CAQAwBQYDK2VwBCIEIOyv9DdWii0/m6+Jzy4XoCeqdV3QeYJUsD3ZTzfVLw97 msg=LLyErFZqCsIemoY08F4ZBYx6SddkzGkjGmcBq15mlLzkkXe506LUnCZoNyxmSceompB+QrdOkYAOit0/Tqo8JA== sig=Ft3QMD16hHHV8//MHOyUmHD+WBgbdY5WPB402MjAMhEzY3RCqHIsm8eRt+K/rAx19tNMTfT3geRTeTcUTNN8AA== e=found last=14 s=19 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAfeKoj445Doqbk5QZNmd2K9QP9UaAAjsqx5XknzCJiNo= priv=MC4CAQAwBQYDK2VwBCIEIBN3kDoG/sN9i1GeoKxj7sQq1tjFadHLUVYN/sqC2qbA msg=Zn/K4fF+4QbrLyhdw0yi8FMO7oCdgJMD/M/5RrCnYNIPLsdiTmGnFRN3kDoG/sN9i1GeoKxj7sQq1tjFadHLUQ== sig=qeQYhXNfUoLjWzseUEJswO0qQcxmZdJkLYR39Uhf0CepSj6uP125rbyrNtqtEcqxrB88Cv459wBQ1qPzd4C0Bw== e=found last=14 s=20 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAHaCKjp8TZKIKE3RiV0D3xzfT5+pMRytajmm8WotxMwc= priv=MC4CAQAwBQYDK2VwBCIEIE0HVehlVLFBqmUlBmMrQeW7OyPtf6R2crpoPgIjp7/x msg=6R2sCH5OdA+fOPVfObSrKmrE+cTTcaJx+gNtj333/ZUgrGHkxZU+/hbV/fWVB6yLq4ZzW4QwfWX9v0by94bV2Q== sig=O0co8fmHsPmfEIBiQlw0vx7v5CopGE/1rWceOTgPiIZIvwCNRpj9S1VQRx2kxRv1LE/aIh9RBtfHmVWaFDR8Dg== e=found last=14 s=21 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAG85BbWZTVSSWWduYvGIulQp5XLQFgs+u7Wh//kaQHy4= priv=MC4CAQAwBQYDK2VwBCIEINsxUuFwQSd93SLgK0f1mZ/9sQjxjThULtgYf7xnI8Wy msg=GH+8ZyPFsgSo3ZJiEDC1JMGJ0v+Wml0arKsfZ9OcqDD+4u4fMDyx0QkyIkXufoUfsih0s8HN4iGJifLgNzzCBg== sig=ztVuYKKeKg2+J02hWuqlS+VGPE8l90V01DhwOfbQ3ag6pL8I0HPLofxDXIA/wo78U5p2I0GYWPvSfTeSBLz3Dw== e=found last=14 s=22 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA8QSGVDyHFgS9FCMWJl8TcRm6Uplx4ashpQBSt9maDIM= priv=MC4CAQAwBQYDK2VwBCIEILTSHyHMZTx/0ChAaBLAZAPnqha8dqxCi5tnFT0ElOYk msg=5nOKsEhXrErNncGBFlUitNIfIcxlPH/QKEBoEsBkA+eqFrx2rEKLm2cVPQSU5iSdrKYrJWG4Ozy7zCjo1zIMYw== sig=lsu1Lp++hvOu/fYf08XByAX6aMCk+M5rPE4xDbAhTYJPxIvOk4jLEiWiuIHZsb244byshoX/ZHAvQeDN1jD8Cw== e=found last=14 s=23 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAnNUwb2W/n2Dljqxg3ePBHWP+j/7KaJOY99Cv8XGwgeM= priv=MC4CAQAwBQYDK2VwBCIEICfItpQZvPV3pNXSzUlS7GCwfzuUhvRGv0kRWK3AX+YY msg=uN4608qRJ8i2lBm89Xek1dLNSVLsYLB/O5SG9Ea/SRFYrcBf5hjnOuFZbFDrWPiGYq9ofTr0bAJBCtkk7kfyjg== sig=HnS/m9WOhBLgrPV8W+is3zTZmI/0ruX4R+6Bu+YFXs/gEheFOdTjq34XZP1vqLc7I1eqjdRG/bAShWsWReUcCA== e=found last=14 s=24 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAS5AR1I0Dm0UENSWNm3EL/W+6Ey92G3XKC9qO/as3oGw= priv=MC4CAQAwBQYDK2VwBCIEIGqbGSBspJuPKs8wayqnx6fD19Y6OpP68H4z57FwgB9x msg=x6fD19Y6OpP68H4z57FwgB9xSl/G4z3COsFtZFB1KY2viBSWG5yN47kHfi6sJ+yvpZujPsbY+50fSMHf+DFULA== sig=eD27n4x+5PFxZNVK+Xvg09MPlcUCDhwFclFnzkWoi/+Fh7LQGLik0qHs9O+HZptU6E6lQiCvD8h0B84ByHzUAA== e=found last=14 s=25 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAg1/SoFTJGn9tzkYXB1sOieMwi3PaT2JJMizJQdFixds= priv=MC4CAQAwBQYDK2VwBCIEIDjAoxJoHScHL6KSSJVIDAjCgl4E8UgDtJn57YAx6hNH msg=rs86drHHBXUssV9pqGwycBLHHgYJl2YaYbnUTkqiOwndiN89cxsqGF/gfllou8DplgL9TAnAF0ph3vNh3yJtyw== sig=A4MaSxSQzw8de8p7kH2ENB6dWoDCPnTrgvk7WQQ1RLbQ3wVWqmPUbckTBrOlw0WODVXr2+EPrei3t93bhWd/Dg== e=found last=14 s=26 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAHx9xHm31qQbBuK/rIHdAI2i9Tc+DNCxWPFd6gjJ6MC8= priv=MC4CAQAwBQYDK2VwBCIEIKAnnzu7YXkU/5XV3PUICqh5iXUea8G2wkvfZrgHf0/p msg=h9bV141APtBjH6X2yRGoApRBzzQ7gmDZ7toxiNcATGAiRB+8a2uOco+yc6lxoST9DA7bazISV2IPIKw0flf28g== sig=5Emp63BKMxaoidDd1D+Z4eJ0ra97GL1/YVHaGwZp25wRuXg0TYKh03ZZdv79Qo7SSMywDX/2GB6jrXq/7+FXDQ== e=found last=14 s=27 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAC41msvvc8BsyUrFr1ei9dq1MeqoXyxkbK76OIPFyR+I= priv=MC4CAQAwBQYDK2VwBCIEINkCeYdXwD72aTZU/1GMQ647Gon6OG4wN/Ahd/pq92wH msg=igJZv+3ZAnmHV8A+9mk2VP9RjEOuOxqJ+jhuMDfwIXf6avdsB+xxcruKS3IbRPSltU4XB7DBsPF3B3JsGaym4A== sig=NtQlubz6vG1DooJxHT6ffkWqNsJGMWH4OznyQX3fHJvmKU9Ih9bX+ZrSmuqY2HT0YTFnSM/18l2TrBmH+qpqAQ== e=found last=14 s=28 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAFUEjNOcwiyht7WS7K1CYUg4qo/q1nrJsdNrx7RJ2Wdg= priv=MC4CAQAwBQYDK2VwBCIEIE4qJx1zsL5y7T35Ra2v/AFXrB3IVmyjipp7xCsF07yx msg=xUyrQgk8TMfvh65q4wCsrAJr3/MhRguGTJWWHHPpJr7Jce0VCmA58n8kg83/FoROKicdc7C+cu09+UWtr/wBVw== sig=etmmnB2cknmfBTbRvUEy2tF1RJ3sQxb2pM4nJaOs6FoC1l7+sDvOpOBY0g6AKgKxo4p3IEqvc8XyD5A73UxOAA== e=found last=14 s=29 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA0PMdNjMNCpOf3obup6fWiXn112pRaPhsNJZg0OPzIZU= priv=MC4CAQAwBQYDK2VwBCIEIGld0udu7pjSyOw2U7sWX7p304rhGsj3T7fING7sxv79 msg=Avw7hLn7OshU0ps54aztYKD98ixXxhxVoofx+1RfG7mbiGe3dWVgqts9Dj2Yh6wQfK3441lC/Dd1y21P4G2Ayg== sig=Rh7UYU7AzUWQ1G78MWaW8WeVsaWscRZ3XMAL1C0fBKTs1bHjuckpo5X5oBC54q/O1B8OtzPSwrf3W4gCwAjSAg== e=found last=14 s=30 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAFRpiqT6VYuLbdrrdiWnpYYw74zq68UhIJ1HhmuS8620= priv=MC4CAQAwBQYDK2VwBCIEIJyvVSzvwQu1vZzWWAlij84HmKMkzyXepfMlDrJD/Wiy msg=Yxdh7WvZhDL9533KBxdcg9rRlVPX2kOcr1Us78ELtb2c1lgJYo/OB5ijJM8l3qXzJQ6yQ/1osqKY7E4ESk/Q4g== sig=xq4GCxPoOYStspP15K/8B6gD9iES56nmVDKEk9y8WPzVYyC5YBSPszQUMMtFHZjMF4RokJei9L6CNw3EoIT/Bg== e=found last=14 s=31 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA9FKRQ6OVM95NU4P/Q5940GASqnOAfSzD5CuVJc6aZxM= priv=MC4CAQAwBQYDK2VwBCIEIDLK+c4+cMK/+sJKi9EB8QHNBKNmGLs0S9Bop6/hkB6S msg=0Ginr+GQHpJCGrkF/b6GgkO7jPyb7JDnjTm0YpIlawS6Pp3SrREWv5ThCpUd2trm5ySVlQp5gGGtmjRpAOkAdA== sig=1kpG+hNW865unFQUdnVdHL0F6H3jIFC4CCo0CYKml+wOJe0gSZ4nDI9ol8Rfmq/sALohss79h35b/rd+PQDdDQ== e=found last=14 s=32 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAWreZ+PD6f7dxNGNtoZOPY2Rt0IsBIJnzZSpoFgPkH1g= priv=MC4CAQAwBQYDK2VwBCIEIEW9pQDt2sw3513ox9rby15tT/kZjptFyCckJvkAlKRS msg=bdM5PP16ujRQdJXkBIgX/Zbm8pm/7W9FvaUA7drMN+dd6Mfa28tebU/5GY6bRcgnJCb5AJSkUnKbMJPB2oXxuQ== sig=55E5lhF+7fpIlYDYVinChpbnBHQqaq3ctLjdVpTlt7lU/jo7oMGXC67YEM3cp4H5TcwoY1iwkIsQTvnrb3qXCA== e=found last=14 s=33 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAeWKpkhqvJGaBNUHcGJERJ7jCKeJLPkgf3fFTr4taBl0= priv=MC4CAQAwBQYDK2VwBCIEIGdrR0LQGGbOgaw6UUnF3W1APi9qAeIxiC3Hlp5ne0B4 msg=WxwsPFNjTU5xP/bFOyBj475sdmxmvDhs9jx8R9m++3f7zj3gBsgKv6QDR5zwfAtwK5Zalkp76OIAwDGaqu2nRw== sig=CDPyyj9WRMQMC3M7ZV4iu9mjDNa03X5Yob/rICEZTN7/8LAbRuDzaUaB0uxJ6DzSBjmmQKAZc+iUjOA9+kKrCw== e=found last=14 s=34 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAafrjyw9TmjNAtcYY73p/PgSz0pD2vXNX84Yp7qPvF2I= priv=MC4CAQAwBQYDK2VwBCIEIJA+B7Wcg8xWHPmpEO6/DdGAkUZL2eTXI3BFTRgCO8VZ msg=HPmpEO6/DdGAkUZL2eTXI3BFTRgCO8VZ+b05LT8H2NDG38cvxSimvCE+4UibcfSRvwpq568qd/np2HYRF36eFw== sig=22FROfguVCamKxJIjuTblkoae9nkTRcQ7FN3gd+z3+GC6bTzBje3ZGsAbFlz/xUlMXd7T7j/jom7TzpMbx/QDw== e=found last=14 s=36 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAUC1rrJqYnJUlSjdtw/h7AiRrV35U2JgQZ2y64pkrw3A= priv=MC4CAQAwBQYDK2VwBCIEICIQjYVEZ7sX2zO0WIIt4vq6cJChxbyLRJXT7ZgZrH7X msg=IhCNhURnuxfbM7RYgi3i+rpwkKHFvItEldPtmBmsfteebevNrDJnaxeHi9b+eG1FzrNhLxkb2Qu+i24dz55q7Q== sig=/5siLluNHP7Zne7N6VKXd6MqzHx1n1rBF8hIdAHu/W9F5JCqv2u2OZrt9uVJGPNXuJwtYjCw2MDYtYDfkBAJBg== e=found last=15 s=0 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAK7mCAXGd7DY+OaKT8f4xkBeRzQQ6P7ghcHmCxKg4jQw= priv=MC4CAQAwBQYDK2VwBCIEIGCxM2IVsLPH0NS0iGdDRow0RDA8yore0g8L2GYGr0pk msg=YLEzYhWws8fQ1LSIZ0NGjDREMDzKit7SDwvYZgavSmQUTmsmi9z+bMdIo054TxoZBuniJLX1l0GztsVP8RALsw== sig=58iKbQtzv61RvW1Ksao3euioHPm769UQihSMgopALBaTQG69nbQpEyL2zsYoq35m562Ypnx9/mFq/uV0bj49Dg== e=found last=15 s=1 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAlB/IGlnaOpKHz3qpR/f7i83pbmxsvjt6RC8KLYIcEps= priv=MC4CAQAwBQYDK2VwBCIEIMajxYZbI891LtZscvF1rr5yUe6HZfGNjmTvR9vpQb0t msg=xqPFhlsjz3Uu1mxy8XWuvnJR7odl8Y2OZO9H2+lBvS1y2IjN+pAjgo7J9T56nTUdw6sDZOM0kf2NEM+297ibHw== sig=+LBpQtXaQabx8Be9or19wjlQITyiGMYBTAOOytsgw1MpGGMdq9/f+62kh8F9xjDRLBaXvE75v/V3CJLNNhbBDA== e=found last=15 s=2 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA+iDTbPH8T2ZcDU3mrEibgB7EuWuR3FQh9io3A2YUt8U= priv=MC4CAQAwBQYDK2VwBCIEIOPKqzzSFaUl2i5P5Qb7tKbwLp+7c7e7eeYwexzlWZx7 msg=48qrPNIVpSXaLk/lBvu0pvAun7tzt7t55jB7HOVZnHsUk1b+tisk/cUVzCAVFHKcgpE4yxjy8Jg49zG2o+0jIQ== sig=2LPcnKJ22GfGapX83qmZHGtGmbr/z/Q9VzooWWPvAmnFKg6fkL6+i6mOKCSYB5jGBbtYRcUMP54Ou62OhdccAw== e=found last=15 s=3 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAZsxt8mPXNweru97xumepOhY5AbbMEezJDaTEPMywgQw= priv=MC4CAQAwBQYDK2VwBCIEIF7GRVvIr5AL4KmMDJiO2VZ6M7rqmEkCgXPELMh1Qfrp msg=XsZFW8ivkAvgqYwMmI7ZVnozuuqYSQKBc8QsyHVB+unqEMArYvgAmmtDjuwh5n7n3EoypTj/CWsfXEDCbE+DtA== sig=S1XOmC3InxDBIaxu0XvokHhX2dnDDYgKBWfPS6QhHpBYxeoPHCIg7ZO+ouUzq8FXg8lyg5ZgY8wbiEH9GhimAw== e=found last=15 s=4 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAbK7yF2NavTh6lO6tyNbx55/sGchWhj9ecGPTnruOVig= priv=MC4CAQAwBQYDK2VwBCIEICG9OGZZdue1U3/4/GJ3gICwLnYF/6revXmqkzgtGtf3 msg=Ib04Zll257VTf/j8YneAgLAudgX/qt69eaqTOC0a1/dR4EAofxWxFlrs6k5ZqgwbQdm4huliGWK5ANXdCNvy0Q== sig=/1yj/DisQgb0r1+Sneiu7gmtdNb9a2JnVcOW4J8y88pLJUKSxHZFTqQF9W8hYXoUVoHYSyWUL3FBS8eM6u1hBA== e=found last=15 s=5 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEADMRod3pzq1twUtm+FmvR6kxgZ6Q24kQ83g5kf/5UICQ= priv=MC4CAQAwBQYDK2VwBCIEIBEgR5F50TrSj33KnNi+ApH+SuY+TZCmGBqU7rpU2rN2 msg=ESBHkXnROtKPfcqc2L4Ckf5K5j5NkKYYGpTuulTas3b8+AplIcjUFNBxSKDGenE7wLEu0RlQ8Y99F80jQwp2Mw== sig=en3wCT6xW5B8PC7RywJB5UcNLblIAY7qSe1K/QxqVcn8ozsipa+f3nr3jY+INJreOHUBfP8b8rESOKb8gSlvCg== e=found last=15 s=6 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAScwAAocf4+eGsN2fUEItodZP5Q6Lsd+X26DPLkLqe+Q= priv=MC4CAQAwBQYDK2VwBCIEIBk/m6QC9JIJIX2vDtGfnfn01zZgPJ1aCW366dYgfJUj msg=GT+bpAL0kgkhfa8O0Z+d+fTXNmA8nVoJbfrp1iB8lSOzSO5i9016mC4WHoiFr+5hGOEmSef45Pw2wwNaUVqOWw== sig=YduMLTPNPrkV5bh1ZJKft9/MnUQNLqseKnBib+FrfCCKdoEp76lsTNfRb2+0doyYMvtVIj7qTjrq3WBomLxMDQ== e=found last=15 s=7 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAj7UBug1B7Ut6/UAiZ0Bqbx79V+SeS/TObzAmma5ztLc= priv=MC4CAQAwBQYDK2VwBCIEIN0IMN/PYSPJWBN3hoWVMkICkPY6N8PtR3vcSBs5DtSN msg=3Qgw389hI8lYE3eGhZUyQgKQ9jo3w+1He9xIGzkO1I1G6JqWYplQJNH0pigQVjpHyy9kgBqd6MGsnMgW4HSWAw== sig=C7ckE5H1vLurQFqIkMPVRbTYIdV3th5iAIZHw5cdFdUbVTx0n+WE9NRZDzCwFKAfLd/JxevR9RBjlAcU46PVBQ== e=found last=15 s=8 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA1oNlJXlk2E48SmzxjRyuBYGwA1iJOA4hkurfmtSmKls= priv=MC4CAQAwBQYDK2VwBCIEIIYiRBXxijKkkKfrc/vTdSzLwboBTistMjAeAifnI2b1 msg=hiJEFfGKMqSQp+tz+9N1LMvBugFOKy0yMB4CJ+cjZvUe59xAFclfXuh9CUSR1THLHu4giYzvI9uzLuys1GlwiQ== sig=yIOvn7LBvnkiNzAtI3/GQln/qIbp0QROREHqxAUFQcxovWCiJkDIE4OlYpRPbzwG6+CwzF/zTSAZwvKcnxzhCw== e=found last=15 s=9 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAMyFRGOT27U4hXrLr3CN0WkvNG6yq7duXTxdy4PVjCbQ= priv=MC4CAQAwBQYDK2VwBCIEICSq/dZTvMjrr8Hg+eN0gK65gxyHlaYUe4r1U1sPihCx msg=JKr91lO8yOuvweD543SArrmDHIeVphR7ivVTWw+KELEQxZOwPb86WVJjBvd/ukTHdR7DZPo8VcT0l/ry34EHpA== sig=KFmo8ftzXVqSULCUMRUNhlBMfefmy+0VO8UMolvF+UOotV1JwkEEZOcmSyg9EWVKIXOMB68IfH1K2gXpHQxfAg== e=found last=15 s=10 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAKaDrKtijJqQNTGAs4SjXCDeppFhy/+4hw0EEcP7RDuQ= priv=MC4CAQAwBQYDK2VwBCIEIHvxvxcNZx3ZDWCrYkaKlas9jiasu8iH3H5FwBEIAb7Y msg=e/G/Fw1nHdkNYKtiRoqVqz2OJqy7yIfcfkXAEQgBvtjHAMJR1bUg1qnRH/1HhMbrLxLXGyfulx+F8cjJN1esvA== sig=sFTX3iyflKR5m2sR8rP6ewIsjZipzmf++c2JEeaok2Q39Mr6vk+9fjShgLxcFIFFgT231uefW/NuOaXM55zXBQ== e=found last=15 s=11 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEALXeyps1HGvnry/sfxJFQL74JB4fp364ZLci4sxY20ug= priv=MC4CAQAwBQYDK2VwBCIEIFHTuURvDUZMA5MZBkpI0yzpxlUnfiKV/heGDMn252uR msg=RG8NRkwDkxkGSkjTLOnGVSd+IpX+F4YMyfbna5EukDTld5Q1mSeSpmsVMgHydYkxP2UoedKRk5SnXRNau3LzDg== sig=Z9dj62fa58/n87NByueSsYTRqIVN4fDrPCboA4gn67LbwKvk+mxqW7q1VhuIbezE/zAqnR+gSHBcpqULXNIZCg== e=found last=15 s=12 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA6Dcj4MkHU4xBWLKFifU68MFEWCIF6SghDt6IqlLJmyU= priv=MC4CAQAwBQYDK2VwBCIEIGy4Ilmouhud5VXi0lORWHwOTQJtH6yqrfMdDKP+l15y msg=HQyj/pdectpV18BNI/oKscXVzA/U3FFazG3VudeNQPaqdYKTDgqj90+w39YgmEASEKHAiJFOgBwPCnW9u6nAgA== sig=QEL8y1Mi35lT/oOCeKKpXzl96RA2BBfMLDa0KLiuln4Z2+KR8qchRrIRfXXC9t1H7b2xmJNxYOuRPwXxQcTgDg== e=found last=15 s=13 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAmRhZw8oEnIrry5Z7Car8nId/RZIktNNM21PhHYcC42w= priv=MC4CAQAwBQYDK2VwBCIEIH/2eGpNDL9bt5u/YX/QdVPgipkSn2M4PKJbCGs6VNsF msg=azpU2wVQq8+ivBND+3koNl2tBg4PS0AH4uwQFxtJBPoh9RpJTfn7GFMyU7FMOqKFHuTjUCo2HIHvHTWh/axxNQ== sig=lGfSbaVhYfAin+eplZ4CAjyLEmUsjG7osizR3KuCxWTzFlldvUSsW+Gm35xZKMOauRZ+DkS2WvNTl/N5D6/BAQ== e=found last=15 s=14 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAJOtRlu0L9Bby3Lt6hGKO1ZKBu4ojLFtIsoXYzkqoZ1Q= priv=MC4CAQAwBQYDK2VwBCIEIJPwWgfC2F2+yHHEzn0EnuB1k0u2zf3JFni3uJessp+0 msg=BJ7gdZNLts39yRZ4t7iXrLKftJhRr8cU7oJi6R9tR6HL/5T/Ay6paA99m/5W4xOvnLXMLYyQMiIKWL19xpwl9Q== sig=XW0K1md1tEmNCBTpGoA3yRCB3Op21iusDK2AjsZNAn1QEv8sU0gfryAMsFcVNKBHfD/1O/rFhEnIilJCJzxmBQ== e=found last=15 s=15 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAPNyof7w3fkcXoGkxej+pRuOo/lZZl8llz+sFTC533pA= priv=MC4CAQAwBQYDK2VwBCIEIHepITUh/wU0rOsw+gj0nJDVBOP8NNcfPunnszWuOMD8 msg=9JyQ1QTj/DTXHz7p57M1rjjA/AXTdXJ42Q2agrQ2q6t2/QtKXw38ruzd+Cgn7BiQh34VobH1nI+U8iNs5Y478Q== sig=AjN4sKm3QzWhPmYxz2JaJnI+Lg8W+k6HisEd1zuUUgYtrN87ZU2WW32tV0kIUD9+BN67wc5kHxh+8SEPZavrBw== e=found last=15 s=16 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAzkHxJznPU9DJiucv1+2X0i26nE1i0mT/r1nJhYIN7wE= priv=MC4CAQAwBQYDK2VwBCIEILLR9xTLKQcYv2OZnMfsv+n5SqJa5negXoPMGnUTYGnr msg=wCqaHgQtGsfUQCmB0podKvnqPDPVffe+VledlvNK+WHilMWzUrhGIJxEOs+B9irK4Z2GlpeF5tegvEDotsBcgw== sig=PI7Zrpi35BOUYUSJRSLoByUb9qLm/SMmAHsUBqV0ctRDWbTZ8ykBhtVtJ3goYM7J9iF3shya0vWNN/S9/MJ6Dw== e=found last=15 s=17 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEASGSB0Fn4MOHyAzNSOjsrHujWhMdlF/Y5qUMTUElJ6q0= priv=MC4CAQAwBQYDK2VwBCIEICVS/lslhJXcd8QlVfmCc4pWYQqsLKD99ER6s3sje2i2 msg=cnsPsY/JS6jGU6EGMsR6gXe6J0H4Jl3LZoqzSJNKUmfL/CJ7T+H3Yqhr7FARs1Y3+imigLev/sc4drLSDO3ibw== sig=tJmNH9AY+YoAWCICSnEyaf8fqjM8du3jJRe0EmEtzcdZd6rB3SbW2yQp0wIHClZXd9OOP1srEvo8zJ74rfGqBA== e=found last=15 s=18 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEABRY1yzmzOJvB7iZubJVuf9F5YDn84009N7E4DrBQoLc= priv=MC4CAQAwBQYDK2VwBCIEIKw/q0wCL6AyKPnxq1zTPg+TSbhWXcRkhcOqBu3cWZIl msg=8c8ugaw/q0wCL6AyKPnxq1zTPg+TSbhWXcRkhcOqBu3cWZIl1o/ci9DU3ei+A0CkkTz/4GwCWK3rFm882vaGJA== sig=1naAyx2bkm+SE2S8tZ4iybhTm0TuAdjpSb2UzJrSShRSumNODc8/szccFsPYMJua8Fb+E0jqPHpO0ChRGtrLBQ== e=found last=15 s=19 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAsO6k+vQg7tnj3fZdu6CCQF9CW1s4rvb03pyQBV+2emU= priv=MC4CAQAwBQYDK2VwBCIEIMXKsUH14w6eQ5FZb/QBvsL92Cljl/yJO2wg+phHnhbJ msg=bCD6mEeeFsn6shSIMur/Wm9zCh6elj7Dz433t9O6i6QxXNnrcsPMKiL8o7K3ViU71Yp0/iy7vhZmVfIJ7MHb1Q== sig=GAyYNfKdvvj5RxuMlAAxk3MIEZ3u2zUCF8MXyWpHp9ncBAsr9kNNm1XdcXkBpE6hEXwo4bT8z22cJ3klL5upAQ== e=found last=15 s=20 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAa8VuSIFUJl5cRE4HESdgHI4Dd7es+GAUUHG/X2Qj738= priv=MC4CAQAwBQYDK2VwBCIEIK9ytpbI9HQAiPPTRPX+ex7kGQN93JnCSzrYP261js46 msg=O+C+O3R3/iT72dRyGCMVGFjYtyhHr8Q8YIKd2CWG+J5YHK1/d0RnotxKGbQogPY73Q8yE2/ps+4g+6oiU8fLhg== sig=eIuLHX6OfXEW5V88/1sE8m+wh61ONYtFtY68CvUpKoT8dP/j4xW1SfF0lfqDOQOWswHcaQhk34QFABAYZaP4Cg== e=found last=15 s=21 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAv8+pvop0Ta7Bp8y6uqmlKQSgxDFz8DFObSvPsLV/OVQ= priv=MC4CAQAwBQYDK2VwBCIEIK65NzFFWA2iSgg7W8Qy2e4//YiGET2D3oKUx8MDjxv9 msg=EqQtaCz7Ph9V7ArIxiQ1o6xGj2TYfKWrz7ilGT6CRKi82qCH64MJ4e6DFcEFqfno53vN9pcX/LU1lDeCTa65Nw== sig=czDhSbwPDX9AjPRzvpCWk+S1fabUjOKWxYaqw8m5mt2BYLWm/xWuX1U4lCfCoWU5NIcJvfXEt4aaSQdU4ZRZAA== e=found last=15 s=22 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAH2FcJ9705I7Sba+UcUq/XA5ArgXz70GE86SlYJsgMB4= priv=MC4CAQAwBQYDK2VwBCIEIHlOyKv+3w8wmLp0eDdLxGlfAxLkfuYRhksoIgQNMI0L msg=kRGWQLpyv/xvN/8bp+Mwl7cexrExDFTUZOHGAS3u3jhBW12JVjBs56nGsSrz3wRuBLsifJyzZmGSChIdppFJyg== sig=NnC8xpl6ZuWmYOsgoDkQgUOztz+4dOUc0gtUhxC24dXSa+WVWHk0C8QionrtqbQd5NaD1tvhMiMEhu7L7yzRDQ== e=found last=15 s=23 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAhYWF20bn1TJgI9nVojvNLxpCmUU6Bp5vn3lCoQrwWQk= priv=MC4CAQAwBQYDK2VwBCIEIKqmytRA9JqS+KTTzyoB1QNWBXUUh93QXKzXJsguNt9Q msg=ZuVwdmL4XE5tn3R4jO3MOuXQEMACch5lW/arbCVcwJw/dHSSFDX1IyL1aF4uXOD3upfBDVcTc6qsz/hYbkAUeA== sig=9ouJrxGKnXE6XoIbENg922fQPIt+JywB2BPxwRsR6OlaqBYStgbRPNf3bb9TeGyLDdYNLoSf7dZ70/5eBcjiCg== e=found last=15 s=24 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEADbuzqyVmVCtgx7sD8zb9rjdBy3PJJ5f+kad96WVwLXE= priv=MC4CAQAwBQYDK2VwBCIEIKlw0he26zOG8tEld4PqZQd6EKqdkX3jHDFA8iUTVa+d msg=MQiYzCzXzpuzJAef1LZ/DB6D5cLAoyTxC93ugrpOH+ngfEJ0qsp2VdPqXnYWfBnhYfNbdskoSh9EOvWEpQo2XA== sig=aw6nmXoLl7mdC2UpBflnvCRrlmy2UsnTZMdYyaB2z7qVOGMAEkLjLQJfV5Xv39GK+udw6idE/2gD1//jqf0hDw== e=found last=15 s=25 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAxtErD4XbST61k3wKl2AzQjn8djblZzhft3AwLDp3EZQ= priv=MC4CAQAwBQYDK2VwBCIEIGtv1M/fbNuz5mzZ4szo8wc1GG/yrAu0XHgXQ4vlux89 msg=98TeuUi+a2/Uz99s27PmbNnizOjzBzUYb/KsC7RceBdDi+W7Hz3rY+ZcledEX25EvQ+4qE09Rpl0MC5VBmvkZg== sig=5z4FYvwPVgFIjSRH+ZTiznPatOrhV+bhqFXv1rQUKAlnPcMB0YYyOq0hxU+4ql/qwJEIydp2YcEHr2qwRl2gDA== e=found last=15 s=26 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEApoWJ5QbgT9EsTYL3UsEcdyMvqzCzO8veSi69u481ztI= priv=MC4CAQAwBQYDK2VwBCIEIPqTbXezzGpUggAMJv8t+DVNdliF2nxn/2vDnK1X4o1Q msg=ApbV0RdPCmXpAOUADxiDFlpUVnBwv1UBDe9piYzMrJSHncHvaptndLrZs4wFGd/J2GVHGAFUNc17Ycci+pNtdw== sig=XUcaaMjNU9a2xg+CW+5CZhwu2gTCdM4l6TU/5eX7jlJx5ZXGMXWlMAJlw5ABVf4whhDWKOqJFp3ocNeWNWqhCQ== e=found last=15 s=27 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAIbYAP3Fo1tK++LG+2eJio8eM8bzBtwOAD0keqkXfOE0= priv=MC4CAQAwBQYDK2VwBCIEIPInJkgkuRvqRlVGwWtOPAuvi5Iq7V3+Qi5UnQ5tieTx msg=z4CI26cC34QV7Jt3j6R1l6znuFouxGSu81Z52tlVm64SabIXMtxevkTwKZhsAXc1KaG1uC/frnddJsrAqcmkVg== sig=LNGRpJSbkSoiqd9qOZLGH5l8/lhArVyrKafzN33eXSNn/ivekiIFFihhsJUuggHsKcO/FYVGtTumbVexXITdBg== e=found last=15 s=28 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAg9DBLBPolLjiRgg97rbXGtvBgg6rL/Bh7olb8Wrayp4= priv=MC4CAQAwBQYDK2VwBCIEIOM/uW95eFEFkGFxN/WsaWI9u9WkzWJ8VsgANgosmkvR msg=B1j00+gfooAPuj61aJk6/SiFDhvv3NN0YJrjP7lveXhRBZBhcTf1rGliPbvVpM1ifFbIADYKLJpL0V9EbSbToA== sig=UDVDheI9R7+eG12Jgmly0MNvcARbzXWdFF63GZ+UfsdkmxjT9dwwRDLyJjq8woS6Q95FJCRIbFayEgsYUq61DA== e=found last=15 s=29 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEANvRnMLBo6qzQ6VozhEweNezEzJC9OG39Z+++BsZqRYk= priv=MC4CAQAwBQYDK2VwBCIEIMEP/y4Ie3WP6qNqdGrcOrGMZkJB6gE5gMKHsFlMA2C1 msg=QIUNL4x3zaIeDdZxLa+SlIaEhFQCCTkcGXlYUrFnF0Dk8hcldfJu5QLFoHqym9DZ635m/6pBS/usceli0Syeug== sig=2M4yKpIpuB/EpT0okcwmJRlaI8KgqcciiMBRgZtfhX0f4oByHiTYgO/IuxdtXKyWaOhjA/F2U5awKuhy0Mx6Dg== e=found last=15 s=30 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAgmokf7oW1H+pFBLS4D4m0AxPQJLyH0QC94GmcEycikA= priv=MC4CAQAwBQYDK2VwBCIEIPlPHSQQH7iZdC2feUGAYnXcTcZhjBKfHD3jXIC0mkJ9 msg=ddxNxmGMEp8cPeNcgLSaQn2oXrcT7wQkwsJlZ4tXgrw11lvBbDGR+T5b7e6PG33dPpkezlPbL/H6Aj9TTmS+eg== sig=hLyXjs32r67cou3mo08c/ZXxsnk5tEMIiePjPEFEtxRIEM7YL0IlhmKAiKzTWX7+1+2HizWxp4TMIQls+cCKAg== e=found last=15 s=31 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA3t3wHEsYYdgKhp2i0HEW1Fcnt5pYBPpTsrGfddK8RMo= priv=MC4CAQAwBQYDK2VwBCIEIHxwN3rm97wsulvTSWKpfhq/uk5SPGaRuaO//7n4Y4Cm msg=eub3vCy6W9NJYql+Gr+6TlI8ZpG5o7//ufhjgKbqRqtx5gCkF14PaXUe8DBs+oEHQ7Lb8hHMCNonvXfsiHfbFA== sig=FujuTlPyuZ6ye+N/1+y9jbNJjihFCS2HHGNIQPBLHy/a5JQ/ma2iEu1dQRvy/9X8ApaRKV0+xOsmlk0Zg5FQDA== e=found last=15 s=32 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEA/gy2n68UztL4x3epQEPIklfOMK9t6k0Hg06V+igrrJ8= priv=MC4CAQAwBQYDK2VwBCIEILh/oxGMBqoe9T+9hnzuP+pa406OzjenfQd2rSQmazvU msg=EYwGqh71P72GfO4/6lrjTo7ON6d9B3atJCZrO9SyM3u95m2kRQkhPtB8EPrrbN+sSAY5v2+vMXwb+Hn0mAYjTw== sig=zO+8encogwn/U4SF91n//S/wNXR3pZrhU50v3nVy8eprI6AKcGF4T131Rk2bmrXdmtt6CaLkKQ9UP2GPohDfCg== e=found last=15 s=33 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAHtYhM7lFrRHW9FqjuSEdDZ1tctjede+MoV0R1UMtVVg= priv=MC4CAQAwBQYDK2VwBCIEIJD6PKp3MulK/B/Np+Cdu+Cfo6x2EPkJJliRnj1G9xs/ msg=Q/p5WuG23JyPgshQbo5YGam23fQ5OVqjC0fCzYVXRw+C9vDQdLODe5D6PKp3MulK/B/Np+Cdu+Cfo6x2EPkJJg== sig=t4XSeew/w5x52oghg7VR7yDP6cP2JkP+1qCbuYJyUNW/lmNKD16Tk3SWktl4o3HzmpQewS3lxx1vR2pKhkPqAw== e=found last=15 s=34 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAEI/536MsgF7aZ9O6hLaT2cGEwCIQRajWmvxE+iv+5Ig= priv=MC4CAQAwBQYDK2VwBCIEIE5+N8mBMqbcslWpsFiYUJLEbnKC1CZgwnql5scPhVqA msg=1CZgwnql5scPhVqAJy5QN89FfioiZlPgPcwVjCM2AgM5Frk3eACOherjcVcSUSth7u2NWh3IJGkOy+UgE6g3/w== sig=9iS9EP9mkQOoxQoGzcznIChrPQGdAA763KQjwnN5k4HmVBX/abYK5XIk6H+sfZ88Qq7VOFy8c1H1CwYb465AAg== e=found last=15 s=35 in subShifted_NP",
+ "pub=MCowBQYDK2VwAyEAvdP5ffItF2siN+QBywHeCpXDFhjxK7SZwT2MfjSoipU= priv=MC4CAQAwBQYDK2VwBCIEINx5YWaFb57Vnoqc93w5yK8TSWlY+7GEYVjpc2WkiPI/ msg=Ggwp5bmATPmRhoheAaYfJTYxkSrIXYcSTqxi3HlhZoVvntWeipz3fDnIrxNJaVj7sYRhWOlzZaSI8j9oTJ1ygA== sig=c5HoX+KDVG2wM7o0o4dKJUy/zczPaKDUcnWhsmP3d6evqfDbRNAQpLopFdO9dyfuEv1H1gn+qLQUVvZcuwLDDw== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAvdP5ffItF2siN+QBywHeCpXDFhjxK7SZwT2MfjSoipU= priv=MC4CAQAwBQYDK2VwBCIEINx5YWaFb57Vnoqc93w5yK8TSWlY+7GEYVjpc2WkiPI/ msg=Ggwp5bmATPmRhoheAaYfJTYxkSrIXYcSTqxi3HlhZoVvntWeipz3fDnIrxNJaVj7sYRhWOlzZaSI8j9oTJ1ygA== sig=c5HoX+KDVG2wM7o0o4dKJUy/zczPaKDUcnWhsmP3d6evqfDbRNAQpLopFdO9dyfuEv1H1gn+qLQUVvZcuwLDDw== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAhPw0vNPFREOs5U1MkD0yCWZ3WCOmwVSvN2jF1Oizqbk= priv=MC4CAQAwBQYDK2VwBCIEIP80+hG+p3eZq1Ez2fIwZVisdXlokktg+bLNtBeM/GQA msg=2I3ilxrJP/fye0bwPSNTluAceuuI6hS1a9t7J9YSlIX9WOwvrnoz2BUKVPkLpHmyEK7JHMDttj4l6BQiCOl//w== sig=kp9BeH0HbGR8wWV5vERw/tZtGHuYdpNvcUO7fyzEAp+avoeJFptyh7jzuvic/lcH8+W43kjvq2wn7t+Y4QOCAA== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEA6yB65NH24xZ3gPJpAf2oZiobm/CDOsW2mTA5NYHiu9Q= priv=MC4CAQAwBQYDK2VwBCIEIA8QPr2HS5Ph1RitdsIwIn6rAvIhxGzrI0iMNTQXdaOK msg=xaumAcR/MN99ugA1y5nJ/KZ89v2ubNtaOKMr85InQXbcd6tQUDJKVgi1s5E00FUzZNayymWz0FIZmpuB+B3D6A== sig=2Hh82APLUonf07pjWJPbqNkIvH0FKaGuqR6uZy0SolDLBOQRUUo19t6txaNjafroKvKivxp4BJZK//UZANV/AQ== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAjzPeoBYWUh6lK8tL5zvJMe3quOc9DHDHqjaqmlQ9eCs= priv=MC4CAQAwBQYDK2VwBCIEIM/KKNbVtHGuvVjVRndMVx+uGHioSJfRTLV3mMT/qs0O msg=xoQTj8hSoCBUbsW5fls1TN4WIBm8+r9Q4dG8neWlAU5D0pb5V7PzbBUFJWeMN0nvqEZA2EOlmOckFJwvw4kbvg== sig=RvTiLTOBLVlUPXgblZ51/UkOE6Yen7x4M02mxNRnKQIQvRW6Xy3qME2Z0Am2zJnQUl5NzmX7bwYSxgxpmI88AQ== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAOMqNF1zplUOboWpKGEScst68qibTpF7Ty7VY/uEvaNU= priv=MC4CAQAwBQYDK2VwBCIEIJJEH78Xa97lbOZ9O6bgZKJcrcU3smco0u0Px5GkGxTV msg=4RytsCg8AEt67XM/kkQfvxdr3uVs5n07puBkolytxTeyZyjS7Q/HkaQbFNVojP80jljxWzNLoGaGN7N1kr2qSg== sig=f9A3HtPy45UhJ3k5woskx1PE0Gkk9Lb3WJdwYlWLkvPR5U3U3twjEF7C7yTQ/GqOHDQPn/oRZjkr6BAezbrQAQ== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAn2s7D0uz1lKQ3j1cJQXWJEJ0Wh8kfI024cBGrsoWS94= priv=MC4CAQAwBQYDK2VwBCIEIPvpiAgD9MjVzjq4GBEEvyJRG7qBtOA8LhyL8TxM9zxh msg=TPc8YdLsCNMm5JB7iuu+8qy8DRSFi0fGLIdlMQxyHKr52bnlHDKvhOXdJfm4MNi2nwnHKety6zzPKhdsz5N0AA== sig=k/NSvGBfyOC9cFSGbMk4VRRZAD26DZoYFTfPI1nqv26HRtzmyOPRUt1XUKVdlPCk9BWJKxMIOViE5fubQtr9Cg== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEARcA9TGMLvA1xCpTlIBTFBqX4BmnojWpbQrHqeuGtTUQ= priv=MC4CAQAwBQYDK2VwBCIEIFcykuAmQTTxkQFc39T6K/esqAVIzjf4BvD9w4Ahh1uh msg=K/esqAVIzjf4BvD9w4Ahh1uhbFnf3RWoWc5DBj2U1Wlr2XkEMiCIphy2Vb+nVG60fxCc0imaymlJcl3DaK1FIQ== sig=T2XgkyPeNG3Bcmss6YCOLZnVZmzP1bB/traUHj3kFdLx/auEXgaF9U0q2aELe2gejVOX4SODJ9KBHKcwNZMcBg== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAEFWkTeyURoIn6Fdnr9db6WjB/JI4C1a93wJNXpE+n2g= priv=MC4CAQAwBQYDK2VwBCIEIJer93jUjXCZbxF8P9jpHcFh5/ERuJ9y1K0GUsg1rpA3 msg=Wi4GxXDWlO0X6fW7ceLYt9zsTRM/RODJRDt4+8iOqvV3Llhdd9bPhSNUX+5tURNUCmoimd3zQHNB7/fqwbmYhg== sig=bpus92mglDkcS+4xjQ+Ss5Ft1CwwIpULew8VxDr96oZkn7fUKd/qzvWB3bpPRLVZvDbn62DC/LnB+lXSy+MCBg== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAIcToYs2BkuC7McB+khCggsYBK/z+V6bESJv1eUURkUw= priv=MC4CAQAwBQYDK2VwBCIEIMJVSyDIMf6tDX+3WusTQgjWUh0fHmZF6iW7u6u+gE5b msg=t1rrE0II1lIdHx5mReolu7urvoBOWzYTMa6Os5soq/7Qpkx03upSddEsdODq6HCFlmQFnFbohWP41Uz2lgBTtw== sig=a9y3fKIcCCZHwj7X/2MEewgV/Xv4pB9Zz8uXbEBaIGv1v07OfhOXpxxgyNVDmf4Vt82ZMz5i1W3TOnf9vaw2AQ== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEA+WkpaGYP1Cvz8vBKHJx04KpK9zvI8I2hTJWaGnDJE7M= priv=MC4CAQAwBQYDK2VwBCIEIET7Foh0nuhOMyT4pwuSE6YCWA54Xvec6sh+9uc2ePGW msg=USWDYo45MeZ+xhVE+xaIdJ7oTjMk+KcLkhOmAlgOeF73nOrIfvbnNnjxlt9BBgMDMjVHespfGh1nnVWNl5Smfg== sig=uC/wtzmLNI2UbMX9XT1oUMULIUjxNyVyqlrXkoqNg2MqrE6E5Gcz7DkhBQ/Ol/oTZOYXPFguXpWGqhcmPdmDAw== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEA0at7YQAiYd3RvIpYZeHUsNUbyD4rUIABSZyqSPPnXjY= priv=MC4CAQAwBQYDK2VwBCIEIExle8MpAA8rxusxmLjsBOb2+W1ICTbAKlCkmFX7qcNr msg=6l+NN69pJyLPhPHmX1oFxraO8QIpuDmQ+Uxle8MpAA8rxusxmLjsBOb2+W1ICTbAKlCkmFX7qcNrgJ31OoRIqQ== sig=zl36421pKuQEwy4ntSijob95iSlcogE3m9IfgmXLAM48qcj0949WG0ntxb2Dl586oHWBxzmeoFuq6fzUzQtQBg== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAE0fGq8+sf4e5ickaVLPbQPgHBO+ZeaWtpK2higapw1M= priv=MC4CAQAwBQYDK2VwBCIEIG/IPZ4pMEkp6savNxRiP6quWDYQK+QphYwNjnkLYZBL msg=q2P8BeCMaOU0+waVNHyZYzyqlWE/2blKeAbHVkpa/Jm/51KUZapuwDEubITmJ9Z6RMenYnNe8sLIFUkrfKWkkA== sig=ZjKYto3cRI88GehOVcKB2QNkv8IdXZ3h+HtCHIvhF7GgpYjWARP9VI8zsUJW33uVo1Kp+5++TKqY/34+SqLUCA== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAFMeh30CrxMMFUGihtrh1E7r2A50qRb8Jxm/1Z8peFMA= priv=MC4CAQAwBQYDK2VwBCIEIFFX9MW5r0TrFR+GweEl0UA2ecEVXapCRsJPcEPk+Xf2 msg=qpfc0g0cQGsgzFtZILynE9onlFFX9MW5r0TrFR+GweEl0UA2ecEVXapCRsJPcEPk+Xf2nFZ2cbWMkyFX5Ic6FQ== sig=bCT+JnzEdUpa6x0K+FnAPa1fnUhy4pmK5EAYs7ORaGs45qp62ENQUWj1BMn8ZpFAfUYV1tuGBhhua73MXB3jBA== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAgKIrpZiZVMIQ3DmybKkOaOWEKOlkijaFC9tSdgZ+6mI= priv=MC4CAQAwBQYDK2VwBCIEIINS33IrrrEnxMCTDJEQ//g6WKEyEuCwVzp5uXoqQDmh msg=H2fmoXw40oSrSe3Fcx/YGCYR/RvtoE0xqxRalfjlWQDMmzi6Bog0of2dUZlmxI9iWaAsyrtIyVKwRN5Ujbxocg== sig=dwHERSdPaxQryZmDLnWub8m66a8wxZPuCuTKkOPmwZ5IuYWUl63iD3s+aoJfiJk8+xAlKlDtPUnGx+6fOzV4AQ== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAVTk5x6SQaQHh7UH7zfBGl6U4+Txb+pOxqmPOIo8PyGI= priv=MC4CAQAwBQYDK2VwBCIEIJtw2GsoqhwCCtOgUtYXiYpUyWzo2XP9MDakoofhTCOk msg=AgrToFLWF4mKVMls6Nlz/TA2pKKH4UwjpBHkfNY7KkqtW18eIhEu1M7D+AnhdfnsQVkDczHBzFtuPgwaZ9xc7A== sig=ZPB3kbWf3G0ySlhg6Bvbxh4S28WvRAELGYf/v/T/hAwgMQ6Oq3pPiY93KUvDEe+80AAVInG37+dGKVT9RbioCg== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAc4H7Rb8wDjfvj94WftKwolGe9mwglkEpUkiLR+Jty6A= priv=MC4CAQAwBQYDK2VwBCIEIKvCOCYg1Q7U4+fgMnRRYn3Lmht/xc55aM/WtBF4ZsJh msg=uaJtcfOWBY0KxeIXXV2vWCUB4vIcUC8TeEzWWWniuImpUU7wPZHsFWnf4XiUJar5+Am19TjeUfYIQK2QZh9dxg== sig=DBW8lV47/jBOCGxQUBdi2QUwkx6KeXFgcRsChQffiMhm/Unrqzk5zvhWbXPrSsinG9wyTmUz/h2M/GeCiirnAg== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAxXas85OYbLLHbFEE9nW61ip2ov4wzmMm2zkUlsHhyOU= priv=MC4CAQAwBQYDK2VwBCIEIKarC8sbbYxXbGTaWwJjCxMX6MCKbDiIfdvCKblsmQd6 msg=E3zm8Nva7r1TcFRgXVOBVYxhG/3b822pblFZEdf03s4dbUqjx1qdA3tLUczSs7NuNmY+6t1Vnp3q70OYUtJTNg== sig=W5ItndbbkVnAWv3xoM/Bj7SvcQC4lErIKKRVd/d7jT090BREWsANppGc82oj17nshxVixxr+BxRRv36+a4IOAA== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEAlKpznUGJM4bQhLgPau5E6MQvqQnBCcvofDwkU5QhlRU= priv=MC4CAQAwBQYDK2VwBCIEICumaRhwUVQTUkSBfw5WtTNVajg+0w8HBRWZOB2FXDgi msg=7UkYLhNEfWfsBQDQVsYNNFaDDFRd1LNbyM9VNtNOe9ctGtYrpmkYcFFUE1JEgX8OVrUzVWo4PtMPBwUVmTgdhQ== sig=XA8nmvcN7v3nHMnSTtRo5Yy516C/ba0+gFdHGBj/tQ241veNGhQSB1lX8iHHtMnuEf+g9MebNCooXTTv4dbSAg== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEANg3t8r6SaUHzAkC3bSq3njFriUtFxo/HNr9f3cJjrtA= priv=MC4CAQAwBQYDK2VwBCIEIGpGaYZfVHakKwQqYoptONNYpQKvYIwvL8Vyj8vg3YuM msg=aYZfVHakKwQqYoptONNYpQKvYIwvL8Vyj8vg3YuMN6uGjDsal51/W8o7BK0nsSMc/XuQzHFgSonaZS50YAl76g== sig=XRPIQLqcqeZYZtd0OV/ugRKYT1aZKJmwS1wbIxRHjEdTgOSvLRexlEYh8xPrspcfPXh8FM6E70PSrk4+sGwvCg== e=infinite loop regression",
+ "pub=MCowBQYDK2VwAyEA69MJYVrwsGt5DugorT6VD7zSG3WQ4yOqXiRjUOP3LCQ= priv=MC4CAQAwBQYDK2VwBCIEIL2PFNE+QWZ53Ah9hoHeuEEEbw0Ew2ypwWts3l02nNOP msg=UG8S6ZNCvY8U0T5BZnncCH2Ggd64QQRvDQTDbKnBa2zeXTac04/SEviN0EcPRMD4b6uP03S9WDO2T2MYPkoXMw== sig=1Dgxn3qUqRaC+CMASAT16JtFBWL8qoF8SEBbQL8YYM/SPzN72c/7EbKCIUkdgrUD4iHVc2IHLCjHDeQPbSqnAw== e=infinite loop regression",
+ };
+
+ for (String test : testCases)
+ {
+ String[] parts = test.split(" ", 5);
+ if (!parts[0].startsWith("pub=") || !parts[1].startsWith("priv=") || !parts[2].startsWith("msg=") || !parts[3].startsWith("sig=") || !parts[4].startsWith("e="))
+ {
+ fail("invalid test case format; expected five parts (pub=, priv=, msg=, sig=, e=), but got " + test);
+ }
+
+ byte[] x509PubBytes = Base64.decode(parts[0].substring("pub=".length()));
+ byte[] x509PrivBytes = Base64.decode(parts[1].substring("priv=".length()));
+ byte[] msg = Base64.decode(parts[2].substring("msg=".length()));
+ byte[] sig = Base64.decode(parts[3].substring("sig=".length()));
+ String error = parts[4].substring("e=".length());
+
+ byte[] pubBytes = Arrays.copyOfRange(x509PubBytes, 12, x509PubBytes.length);
+ byte[] privBytes = Arrays.copyOfRange(x509PrivBytes, 16, x509PrivBytes.length);
+
+ Ed25519PublicKeyParameters pub = new Ed25519PublicKeyParameters(pubBytes);
+ Ed25519PrivateKeyParameters priv = new Ed25519PrivateKeyParameters(privBytes);
+ Ed25519PublicKeyParameters pubDerived = priv.generatePublicKey();
+
+ if (!Arrays.areEqual(pubDerived.getEncoded(), pub.getEncoded())) {
+ fail("different derived public keys; expected=" + Hex.toHexString(pub.getEncoded()) + " derived=" + Hex.toHexString(pubDerived.getEncoded()));
+ }
+
+ Signer signer = new Ed25519Signer();
+ signer.init(true, priv);
+ signer.update(msg, 0, msg.length);
+ byte[] sigDerived = signer.generateSignature();
+
+ if (!Arrays.areEqual(sigDerived, sig)) {
+ fail("different signatures of message; expected=" + Hex.toHexString(sig) + " actual=" + Hex.toHexString(sigDerived));
+ }
+
+ signer.init(false, pub);
+ signer.update(msg, 0, msg.length);
+ if (!signer.verifySignature(sig)) {
+ fail("signature verification failed for test vector: " + error);
+ }
+ }
+ }
}
From 44bd356614c4364fd4cb423718401dd106532059 Mon Sep 17 00:00:00 2001
From: royb
Date: Fri, 15 Mar 2024 15:02:21 -0400
Subject: [PATCH 0159/1846] enabled broken mls tests (now fixed)
---
.../bouncycastle/mls/test/ClientVectorTest.java | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java b/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java
index 28fb0f13d9..4b96ccc867 100644
--- a/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java
+++ b/mls/src/test/java/org/bouncycastle/mls/test/ClientVectorTest.java
@@ -57,15 +57,14 @@ public void testPassiveClientWelcome() throws Exception
{
runPassiveClientTest("passive-client-welcome.txt");
}
- //TODO: Replace with new test vectors when available
-// public void testPassiveClientRandom() throws Exception
-// {
-// runPassiveClientTest("passive-client-random.txt");
-// }
-// public void testPassiveClientHandlingCommit() throws Exception
-// {
-// runPassiveClientTest("passive-client-handling-commit.txt");
-// }
+ public void testPassiveClientRandom() throws Exception
+ {
+ runPassiveClientTest("passive-client-random.txt");
+ }
+ public void testPassiveClientHandlingCommit() throws Exception
+ {
+ runPassiveClientTest("passive-client-handling-commit.txt");
+ }
private void runPassiveClientTest(String filename)
throws Exception
From 51c681116f980cf14e110e234dcb5cf956a2f32a Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 14:54:39 +1100
Subject: [PATCH 0160/1846] fixed typo in releasenotes.html tweaking of
exception throwing in CMP to improve exception messages.
---
docs/releasenotes.html | 2 +-
.../cert/cmp/test/ElgamalDSATest.java | 75 +--------
.../cert/cmp/test/InvalidMessagesTest.java | 153 ++++++++++++++++++
.../bouncycastle/cert/cmp/test/TestUtils.java | 80 +++++++++
.../org/bouncycastle/asn1/cmp/PKIBody.java | 138 +++++++++-------
.../org/bouncycastle/asn1/cmp/PKIMessage.java | 9 +-
6 files changed, 324 insertions(+), 133 deletions(-)
create mode 100644 pkix/src/test/java/org/bouncycastle/cert/cmp/test/InvalidMessagesTest.java
create mode 100644 pkix/src/test/java/org/bouncycastle/cert/cmp/test/TestUtils.java
diff --git a/docs/releasenotes.html b/docs/releasenotes.html
index 60e2b90bf1..518b1ee2b2 100644
--- a/docs/releasenotes.html
+++ b/docs/releasenotes.html
@@ -73,7 +73,7 @@ 2.2.4 Notes.
- Kyber and Dilithium have been updated according to the latest draft of the standard. Dilithium-AES and Kyber-AES have now been removed. Kyber now produces 256 bit secrets for all parameter sets (in line with the draft standard).
- NTRU has been updated to produce 256 bit secrets in line with Kyber.
- SPHINCS+ can now be used to generate certificates in line with those used by (Open Quantum Safe) OQS.
-- Falcon object idenitifiers are now in line with OQS as well.
+- Falcon object identifiers are now in line with OQS as well.
- PQC CMS SignedData now defaults to SHA-256 for signed attributes rather than SHAKE-256. This is also a compatibility change, but may change further again as the IETF standard for CMS is updated.
diff --git a/pkix/src/test/java/org/bouncycastle/cert/cmp/test/ElgamalDSATest.java b/pkix/src/test/java/org/bouncycastle/cert/cmp/test/ElgamalDSATest.java
index 4bb37c02a3..e012c2bf88 100644
--- a/pkix/src/test/java/org/bouncycastle/cert/cmp/test/ElgamalDSATest.java
+++ b/pkix/src/test/java/org/bouncycastle/cert/cmp/test/ElgamalDSATest.java
@@ -3,14 +3,8 @@
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
-import java.security.PublicKey;
import java.security.Security;
import java.security.spec.DSAParameterSpec;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Iterator;
import junit.framework.TestCase;
import org.bouncycastle.asn1.cmp.CMPCertificate;
@@ -19,16 +13,9 @@
import org.bouncycastle.asn1.cmp.PKIStatusInfo;
import org.bouncycastle.asn1.crmf.CertTemplate;
import org.bouncycastle.asn1.crmf.SubsequentMessage;
-import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.x500.X500Name;
-import org.bouncycastle.asn1.x509.BasicConstraints;
-import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
-import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import org.bouncycastle.cert.CertException;
-import org.bouncycastle.cert.CertIOException;
import org.bouncycastle.cert.X509CertificateHolder;
-import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.cmp.CertificateConfirmationContent;
import org.bouncycastle.cert.cmp.CertificateConfirmationContentBuilder;
import org.bouncycastle.cert.cmp.ProtectedPKIMessage;
@@ -42,13 +29,10 @@
import org.bouncycastle.cert.crmf.CertificateResponseBuilder;
import org.bouncycastle.cert.crmf.jcajce.JcaCertificateRequestMessageBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
-import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.cms.CMSAlgorithm;
import org.bouncycastle.cms.CMSEnvelopedData;
import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
import org.bouncycastle.cms.CMSProcessableByteArray;
-import org.bouncycastle.cms.RecipientInformation;
-import org.bouncycastle.cms.RecipientInformationStore;
import org.bouncycastle.cms.jcajce.JceCMSContentEncryptorBuilder;
import org.bouncycastle.cms.jcajce.JceKeyTransEnvelopedRecipient;
import org.bouncycastle.cms.jcajce.JceKeyTransRecipientInfoGenerator;
@@ -58,9 +42,7 @@
import org.bouncycastle.jcajce.spec.DHDomainParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
-import org.bouncycastle.operator.ContentVerifierProvider;
import org.bouncycastle.operator.MacCalculator;
-import org.bouncycastle.operator.OperatorCreationException;
import org.bouncycastle.operator.PBEMacCalculatorProvider;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
@@ -98,7 +80,7 @@ public void testElgamalWithDSA()
KeyPair dsaKp = dsaKpGen.generateKeyPair();
- X509CertificateHolder caCert = makeV3Certificate("CN=DSA Issuer", dsaKp);
+ X509CertificateHolder caCert = TestUtils.makeV3Certificate("CN=DSA Issuer", dsaKp);
KeyPairGenerator elgKpGen = KeyPairGenerator.getInstance("Elgamal", "BC");
@@ -140,7 +122,7 @@ public void testElgamalWithDSA()
CertificateRequestMessage senderReqMessage = requestMessages.getRequests()[0];
CertTemplate certTemplate = senderReqMessage.getCertTemplate();
- X509CertificateHolder cert = makeV3Certificate(certTemplate.getPublicKey(), certTemplate.getSubject(), dsaKp, "CN=DSA Issuer");
+ X509CertificateHolder cert = TestUtils.makeV3Certificate(certTemplate.getPublicKey(), certTemplate.getSubject(), dsaKp, "CN=DSA Issuer");
// Send response with encrypted certificate
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
@@ -204,57 +186,4 @@ public void testElgamalWithDSA()
assertTrue(recContent.getStatusMessages()[0].isVerified(receivedCert, new JcaDigestCalculatorProviderBuilder().build()));
}
- private static X509CertificateHolder makeV3Certificate(String _subDN, KeyPair issKP)
- throws OperatorCreationException, CertException, CertIOException
- {
- PrivateKey issPriv = issKP.getPrivate();
- PublicKey issPub = issKP.getPublic();
-
- X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
- new X500Name(_subDN),
- BigInteger.valueOf(System.currentTimeMillis()),
- new Date(System.currentTimeMillis()),
- new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
- new X500Name(_subDN),
- issKP.getPublic());
-
- certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0));
-
- ContentSigner signer = new JcaContentSignerBuilder("SHA256withDSA").build(issPriv);
-
- X509CertificateHolder certHolder = certGen.build(signer);
-
- ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().build(issPub);
-
- assertTrue(certHolder.isSignatureValid(verifier));
-
- return certHolder;
- }
-
- private static X509CertificateHolder makeV3Certificate(SubjectPublicKeyInfo pubKey, X500Name _subDN, KeyPair issKP, String _issDN)
- throws OperatorCreationException, CertException, CertIOException
- {
- PrivateKey issPriv = issKP.getPrivate();
- PublicKey issPub = issKP.getPublic();
-
- X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
- new X500Name(_issDN),
- BigInteger.valueOf(System.currentTimeMillis()),
- new Date(System.currentTimeMillis()),
- new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
- _subDN,
- pubKey);
-
- certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
-
- ContentSigner signer = new JcaContentSignerBuilder("SHA256withDSA").build(issPriv);
-
- X509CertificateHolder certHolder = certGen.build(signer);
-
- ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().build(issPub);
-
- assertTrue(certHolder.isSignatureValid(verifier));
-
- return certHolder;
- }
}
diff --git a/pkix/src/test/java/org/bouncycastle/cert/cmp/test/InvalidMessagesTest.java b/pkix/src/test/java/org/bouncycastle/cert/cmp/test/InvalidMessagesTest.java
new file mode 100644
index 0000000000..de267a19d7
--- /dev/null
+++ b/pkix/src/test/java/org/bouncycastle/cert/cmp/test/InvalidMessagesTest.java
@@ -0,0 +1,153 @@
+package org.bouncycastle.cert.cmp.test;
+
+import java.io.IOException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Security;
+import java.security.spec.DSAParameterSpec;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.bouncycastle.asn1.cmp.PKIBody;
+import org.bouncycastle.asn1.pkcs.CertificationRequest;
+import org.bouncycastle.cert.CertIOException;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.cmp.CMPException;
+import org.bouncycastle.cert.cmp.GeneralPKIMessage;
+import org.bouncycastle.cert.cmp.ProtectedPKIMessage;
+import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.bouncycastle.crypto.params.DSAParameters;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+import org.bouncycastle.pkcs.PKCS10CertificationRequest;
+import org.bouncycastle.pkcs.PKCSException;
+import org.bouncycastle.test.TestResourceFinder;
+import org.bouncycastle.util.io.Streams;
+
+public class InvalidMessagesTest
+ extends TestCase
+{
+ public void setUp()
+ {
+ if (Security.getProvider("BC") == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ }
+
+ public void testBadNoBodyWithProtection()
+ throws Exception
+ {
+ try
+ {
+ new ProtectedPKIMessage(fetchPkiMessage("bad-no-body"));
+ }
+ catch (CertIOException e)
+ {
+ Assert.assertEquals("malformed data: malformed body found: body type of 0 has incorrect type got: class org.bouncycastle.asn1.DERBitString", e.getMessage());
+ }
+ }
+
+ public void testBadNoBody()
+ throws Exception
+ {
+ try
+ {
+ new ProtectedPKIMessage(fetchPkiMessage("bad-no-body-after-header"));
+ }
+ catch (CertIOException e)
+ {
+ Assert.assertEquals("malformed data: PKIMessage missing PKIBody structure", e.getMessage());
+ }
+ }
+
+ public void testBadOidSigAlg()
+ throws Exception
+ {
+ ProtectedPKIMessage message = new ProtectedPKIMessage(fetchPkiMessage("bad-oid-sigalg"));
+
+ PKIBody body = message.getBody();
+
+ Assert.assertEquals(body.getType(), PKIBody.TYPE_P10_CERT_REQ);
+
+ PKCS10CertificationRequest certReq = new PKCS10CertificationRequest(CertificationRequest.getInstance(body.getContent()));
+ try
+ {
+ certReq.isSignatureValid(new JcaContentVerifierProviderBuilder().setProvider("BC").build(certReq.getSubjectPublicKeyInfo()));
+ }
+ catch (PKCSException e)
+ {
+ Assert.assertEquals("unable to process signature: exception on setup: java.security.NoSuchAlgorithmException: no such algorithm: 1.2.840.113549.2097035 for provider BC", e.getMessage());
+ }
+ }
+
+ public void testBadProtection()
+ throws Exception
+ {
+ KeyPairGenerator dsaKpGen = KeyPairGenerator.getInstance("DSA", "BC");
+
+ DSAParameters dsaParams = (DSAParameters)CryptoServicesRegistrar.getSizedProperty(CryptoServicesRegistrar.Property.DSA_DEFAULT_PARAMS, 2048);
+
+ dsaKpGen.initialize(new DSAParameterSpec(dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()));
+
+ KeyPair dsaKp = dsaKpGen.generateKeyPair();
+
+ X509CertificateHolder caCert = TestUtils.makeV3Certificate("CN=DSA Issuer", dsaKp);
+
+ ProtectedPKIMessage message = new ProtectedPKIMessage(fetchPkiMessage("bad-protection"));
+
+ try
+ {
+ message.verify(new JcaContentVerifierProviderBuilder().build(caCert));
+ }
+ catch (CMPException e)
+ {
+ Assert.assertEquals("unable to verify signature: exception on setup: java.security.NoSuchAlgorithmException: 1.2.840.113549.2.11 Signature not available", e.getMessage());
+ }
+ }
+
+ public void testBadTagBody15vs4()
+ throws Exception
+ {
+ try
+ {
+ new ProtectedPKIMessage(fetchPkiMessage("bad-tag-body-15-vs-4"));
+ }
+ catch (CertIOException e)
+ {
+ Assert.assertEquals("malformed data: malformed body found: body type of 15 has incorrect type got: class org.bouncycastle.asn1.DLSequence", e.getMessage());
+ }
+ }
+
+ public void testBadTagBody29vs4()
+ throws Exception
+ {
+ try
+ {
+ new ProtectedPKIMessage(fetchPkiMessage("bad-tag-body-29-vs-4"));
+ }
+ catch (IOException e)
+ {
+ Assert.assertEquals("unknown tag 29 encountered", e.getMessage());
+ }
+ }
+
+ public void testBadTypeSequenceVsChoice()
+ throws Exception
+ {
+ try
+ {
+ new ProtectedPKIMessage(fetchPkiMessage("bad-body-seq-vs-choice"));
+ }
+ catch (CertIOException e)
+ {
+ Assert.assertEquals("malformed data: Invalid object: org.bouncycastle.asn1.DLSequence", e.getMessage());
+ }
+ }
+
+ private GeneralPKIMessage fetchPkiMessage(String s)
+ throws IOException
+ {
+ return new GeneralPKIMessage(Streams.readAll(TestResourceFinder.findTestResource("cmp/invalid-messages", s)));
+ }
+}
diff --git a/pkix/src/test/java/org/bouncycastle/cert/cmp/test/TestUtils.java b/pkix/src/test/java/org/bouncycastle/cert/cmp/test/TestUtils.java
new file mode 100644
index 0000000000..ca3fa25134
--- /dev/null
+++ b/pkix/src/test/java/org/bouncycastle/cert/cmp/test/TestUtils.java
@@ -0,0 +1,80 @@
+package org.bouncycastle.cert.cmp.test;
+
+import java.math.BigInteger;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Date;
+
+import junit.framework.Assert;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.BasicConstraints;
+import org.bouncycastle.asn1.x509.Extension;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.cert.CertException;
+import org.bouncycastle.cert.CertIOException;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.ContentVerifierProvider;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder;
+
+class TestUtils
+{
+ static X509CertificateHolder makeV3Certificate(String _subDN, KeyPair issKP)
+ throws OperatorCreationException, CertException, CertIOException
+ {
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
+ new X500Name(_subDN),
+ BigInteger.valueOf(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ new X500Name(_subDN),
+ issKP.getPublic());
+
+ certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0));
+
+ ContentSigner signer = new JcaContentSignerBuilder("SHA256withDSA").build(issPriv);
+
+ X509CertificateHolder certHolder = certGen.build(signer);
+
+ ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().build(issPub);
+
+ Assert.assertTrue(certHolder.isSignatureValid(verifier));
+
+ return certHolder;
+ }
+
+ static X509CertificateHolder makeV3Certificate(SubjectPublicKeyInfo pubKey, X500Name _subDN, KeyPair issKP, String _issDN)
+ throws OperatorCreationException, CertException, CertIOException
+ {
+ PrivateKey issPriv = issKP.getPrivate();
+ PublicKey issPub = issKP.getPublic();
+
+ X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(
+ new X500Name(_issDN),
+ BigInteger.valueOf(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis()),
+ new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 100)),
+ _subDN,
+ pubKey);
+
+ certGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(false));
+
+ ContentSigner signer = new JcaContentSignerBuilder("SHA256withDSA").build(issPriv);
+
+ X509CertificateHolder certHolder = certGen.build(signer);
+
+ ContentVerifierProvider verifier = new JcaContentVerifierProviderBuilder().build(issPub);
+
+ Assert.assertTrue(certHolder.isSignatureValid(verifier));
+
+ return certHolder;
+ }
+}
diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java
index 2da4c6f092..49f0eef4c6 100644
--- a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java
+++ b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIBody.java
@@ -78,7 +78,18 @@ public class PKIBody
private PKIBody(ASN1TaggedObject tagged)
{
tagNo = tagged.getTagNo();
- body = getBodyForType(tagNo, tagged.getExplicitBaseObject());
+ try
+ {
+ body = getBodyForType(tagNo, tagged.getExplicitBaseObject());
+ }
+ catch (ClassCastException e)
+ {
+ throw new IllegalArgumentException("malformed body found: " + e.getMessage(), e);
+ }
+ catch (IllegalArgumentException e)
+ {
+ throw new IllegalArgumentException("malformed body found: " + e.getMessage(), e);
+ }
}
/**
@@ -114,64 +125,75 @@ private static ASN1Encodable getBodyForType(
int type,
ASN1Encodable o)
{
- switch (type)
+ try
+ {
+ switch (type)
+ {
+ case TYPE_INIT_REQ:
+ return CertReqMessages.getInstance(o);
+ case TYPE_INIT_REP:
+ return CertRepMessage.getInstance(o);
+ case TYPE_CERT_REQ:
+ return CertReqMessages.getInstance(o);
+ case TYPE_CERT_REP:
+ return CertRepMessage.getInstance(o);
+ case TYPE_P10_CERT_REQ:
+ return CertificationRequest.getInstance(o);
+ case TYPE_POPO_CHALL:
+ return POPODecKeyChallContent.getInstance(o);
+ case TYPE_POPO_REP:
+ return POPODecKeyRespContent.getInstance(o);
+ case TYPE_KEY_UPDATE_REQ:
+ return CertReqMessages.getInstance(o);
+ case TYPE_KEY_UPDATE_REP:
+ return CertRepMessage.getInstance(o);
+ case TYPE_KEY_RECOVERY_REQ:
+ return CertReqMessages.getInstance(o);
+ case TYPE_KEY_RECOVERY_REP:
+ return KeyRecRepContent.getInstance(o);
+ case TYPE_REVOCATION_REQ:
+ return RevReqContent.getInstance(o);
+ case TYPE_REVOCATION_REP:
+ return RevRepContent.getInstance(o);
+ case TYPE_CROSS_CERT_REQ:
+ return CertReqMessages.getInstance(o);
+ case TYPE_CROSS_CERT_REP:
+ return CertRepMessage.getInstance(o);
+ case TYPE_CA_KEY_UPDATE_ANN:
+ return CAKeyUpdAnnContent.getInstance(o);
+ case TYPE_CERT_ANN:
+ return CMPCertificate.getInstance(o);
+ case TYPE_REVOCATION_ANN:
+ return RevAnnContent.getInstance(o);
+ case TYPE_CRL_ANN:
+ return CRLAnnContent.getInstance(o);
+ case TYPE_CONFIRM:
+ return PKIConfirmContent.getInstance(o);
+ case TYPE_NESTED:
+ return PKIMessages.getInstance(o);
+ case TYPE_GEN_MSG:
+ return GenMsgContent.getInstance(o);
+ case TYPE_GEN_REP:
+ return GenRepContent.getInstance(o);
+ case TYPE_ERROR:
+ return ErrorMsgContent.getInstance(o);
+ case TYPE_CERT_CONFIRM:
+ return CertConfirmContent.getInstance(o);
+ case TYPE_POLL_REQ:
+ return PollReqContent.getInstance(o);
+ case TYPE_POLL_REP:
+ return PollRepContent.getInstance(o);
+ default:
+ throw new IllegalArgumentException("unknown tag number: " + type);
+ }
+ }
+ catch (ClassCastException e)
+ {
+ throw new IllegalArgumentException("body type of " + type + " has incorrect type got: " + o.getClass());
+ }
+ catch (IllegalArgumentException e)
{
- case TYPE_INIT_REQ:
- return CertReqMessages.getInstance(o);
- case TYPE_INIT_REP:
- return CertRepMessage.getInstance(o);
- case TYPE_CERT_REQ:
- return CertReqMessages.getInstance(o);
- case TYPE_CERT_REP:
- return CertRepMessage.getInstance(o);
- case TYPE_P10_CERT_REQ:
- return CertificationRequest.getInstance(o);
- case TYPE_POPO_CHALL:
- return POPODecKeyChallContent.getInstance(o);
- case TYPE_POPO_REP:
- return POPODecKeyRespContent.getInstance(o);
- case TYPE_KEY_UPDATE_REQ:
- return CertReqMessages.getInstance(o);
- case TYPE_KEY_UPDATE_REP:
- return CertRepMessage.getInstance(o);
- case TYPE_KEY_RECOVERY_REQ:
- return CertReqMessages.getInstance(o);
- case TYPE_KEY_RECOVERY_REP:
- return KeyRecRepContent.getInstance(o);
- case TYPE_REVOCATION_REQ:
- return RevReqContent.getInstance(o);
- case TYPE_REVOCATION_REP:
- return RevRepContent.getInstance(o);
- case TYPE_CROSS_CERT_REQ:
- return CertReqMessages.getInstance(o);
- case TYPE_CROSS_CERT_REP:
- return CertRepMessage.getInstance(o);
- case TYPE_CA_KEY_UPDATE_ANN:
- return CAKeyUpdAnnContent.getInstance(o);
- case TYPE_CERT_ANN:
- return CMPCertificate.getInstance(o);
- case TYPE_REVOCATION_ANN:
- return RevAnnContent.getInstance(o);
- case TYPE_CRL_ANN:
- return CRLAnnContent.getInstance(o);
- case TYPE_CONFIRM:
- return PKIConfirmContent.getInstance(o);
- case TYPE_NESTED:
- return PKIMessages.getInstance(o);
- case TYPE_GEN_MSG:
- return GenMsgContent.getInstance(o);
- case TYPE_GEN_REP:
- return GenRepContent.getInstance(o);
- case TYPE_ERROR:
- return ErrorMsgContent.getInstance(o);
- case TYPE_CERT_CONFIRM:
- return CertConfirmContent.getInstance(o);
- case TYPE_POLL_REQ:
- return PollReqContent.getInstance(o);
- case TYPE_POLL_REP:
- return PollRepContent.getInstance(o);
- default:
- throw new IllegalArgumentException("unknown tag number: " + type);
+ throw new IllegalArgumentException("body type of " + type + " has incorrect type got: " + o.getClass());
}
}
diff --git a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIMessage.java b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIMessage.java
index d883835a91..7971b2efa9 100644
--- a/util/src/main/java/org/bouncycastle/asn1/cmp/PKIMessage.java
+++ b/util/src/main/java/org/bouncycastle/asn1/cmp/PKIMessage.java
@@ -34,7 +34,14 @@ private PKIMessage(ASN1Sequence seq)
Enumeration en = seq.getObjects();
header = PKIHeader.getInstance(en.nextElement());
- body = PKIBody.getInstance(en.nextElement());
+ if (en.hasMoreElements())
+ {
+ body = PKIBody.getInstance(en.nextElement());
+ }
+ else
+ {
+ throw new IllegalArgumentException("PKIMessage missing PKIBody structure");
+ }
ASN1BitString protection = null;
ASN1Sequence extraCerts = null;
From 98a0fbe40c780433f6c25a0f51b7f337748af6ae Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 15:26:32 +1100
Subject: [PATCH 0161/1846] added sanity checks for boolean flags - related to
github #1575
---
.../org/bouncycastle/bcpg/sig/Exportable.java | 2 +-
.../bouncycastle/bcpg/sig/PrimaryUserID.java | 2 +-
.../org/bouncycastle/bcpg/sig/Revocable.java | 2 +-
.../java/org/bouncycastle/bcpg/sig/Utils.java | 29 +++++++++
.../openpgp/test/BytesBooleansTest.java | 60 +++++++++++++++++++
5 files changed, 92 insertions(+), 3 deletions(-)
create mode 100644 pg/src/test/java/org/bouncycastle/openpgp/test/BytesBooleansTest.java
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/Exportable.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/Exportable.java
index a323b5d55c..e5160edf72 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/Exportable.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/Exportable.java
@@ -26,6 +26,6 @@ public Exportable(
public boolean isExportable()
{
- return data[0] != 0;
+ return Utils.booleanFromByteArray(data);
}
}
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/PrimaryUserID.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/PrimaryUserID.java
index d1385f0e56..53ac5ec829 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/PrimaryUserID.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/PrimaryUserID.java
@@ -26,6 +26,6 @@ public PrimaryUserID(
public boolean isPrimaryUserID()
{
- return data[0] != 0;
+ return Utils.booleanFromByteArray(data);
}
}
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/Revocable.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/Revocable.java
index 74b1346120..8ac92b50f1 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/Revocable.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/Revocable.java
@@ -26,6 +26,6 @@ public Revocable(
public boolean isRevocable()
{
- return data[0] != 0;
+ return Utils.booleanFromByteArray(data);
}
}
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java
index 33927b0ec8..cb46936df7 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java
@@ -19,6 +19,35 @@ static byte[] booleanToByteArray(boolean value)
return data;
}
+ /**
+ * Convert a one-entry byte array into a boolean.
+ * If the byte array doesn't have one entry, or if this entry is neither a 0 nor 1, this method throws an
+ * {@link IllegalArgumentException}.
+ * A 1 is translated into true, a 0 into false.
+ *
+ * @param bytes byte array
+ * @return boolean
+ */
+ static boolean booleanFromByteArray(byte[] bytes)
+ {
+ if (bytes.length != 1)
+ {
+ throw new IllegalStateException("Byte array has unexpected length. Expected length 1, got " + bytes.length);
+ }
+ if (bytes[0] == 0)
+ {
+ return false;
+ }
+ else if (bytes[0] == 1)
+ {
+ return true;
+ }
+ else
+ {
+ throw new IllegalStateException("Unexpected byte value for boolean encoding: " + bytes[0]);
+ }
+ }
+
static byte[] timeToBytes(
long t)
{
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/BytesBooleansTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/BytesBooleansTest.java
new file mode 100644
index 0000000000..755ac0a223
--- /dev/null
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/BytesBooleansTest.java
@@ -0,0 +1,60 @@
+package org.bouncycastle.util.utiltest;
+
+import junit.framework.TestCase;
+import org.bouncycastle.bcpg.sig.PrimaryUserID;
+
+public class BytesBooleansTest
+ extends TestCase
+{
+ public void testParseFalse()
+ {
+ PrimaryUserID primaryUserID = new PrimaryUserID(true, false);
+
+ byte[] bFalse = primaryUserID.getData();
+ assertEquals(1, bFalse.length);
+ assertEquals(0, bFalse[0]);
+ assertFalse(primaryUserID.isPrimaryUserID());
+ }
+
+ public void testParseTrue()
+ {
+ PrimaryUserID primaryUserID = new PrimaryUserID(true, true);
+
+ byte[] bTrue = primaryUserID.getData();
+
+ assertEquals(1, bTrue.length);
+ assertEquals(1, bTrue[0]);
+ assertTrue(primaryUserID.isPrimaryUserID());
+ }
+
+ public void testParseTooShort()
+ {
+ PrimaryUserID primaryUserID = new PrimaryUserID(true, false, new byte[0]);
+ byte[] bTooShort = primaryUserID.getData();
+ try
+ {
+ primaryUserID.isPrimaryUserID();
+ fail("Should throw.");
+ }
+ catch (IllegalStateException e)
+ {
+ // expected.
+ }
+ }
+
+ public void testParseTooLong()
+ {
+ PrimaryUserID primaryUserID = new PrimaryUserID(true, false, new byte[42]);
+ byte[] bTooLong = primaryUserID.getData();
+
+ try
+ {
+ primaryUserID.isPrimaryUserID();
+ fail("Should throw.");
+ }
+ catch (IllegalStateException e)
+ {
+ // expected.
+ }
+ }
+}
From a679ef15d30fa699dadaca8b761ed6e03434ce06 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 16:17:19 +1100
Subject: [PATCH 0162/1846] conflict resolution
---
.../asn1/misc/MiscObjectIdentifiers.java | 27 ++
.../test/compositeCertificateExampleRFC.pem | 88 ------
.../cert/test/compositePrivateKeyExample.pem | 88 ------
.../test/compositePublicKeyExampleRFC.pem | 32 ---
.../jcajce/CompositePrivateKey.java | 2 +-
.../jcajce/CompositePublicKey.java | 2 +-
.../CompositeSignaturesConstants.java | 38 +--
.../compositesignatures/KeyFactorySpi.java | 258 +++++++++---------
.../KeyPairGeneratorSpi.java | 250 +++++++++--------
.../compositesignatures/SignatureSpi.java | 227 ++++++++-------
10 files changed, 440 insertions(+), 572 deletions(-)
delete mode 100644 pkix/src/test/resources/org/bouncycastle/cert/test/compositeCertificateExampleRFC.pem
delete mode 100644 pkix/src/test/resources/org/bouncycastle/cert/test/compositePrivateKeyExample.pem
delete mode 100644 pkix/src/test/resources/org/bouncycastle/cert/test/compositePublicKeyExampleRFC.pem
diff --git a/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java
index a88c98e0d0..0ff100ec7b 100644
--- a/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java
+++ b/core/src/main/java/org/bouncycastle/internal/asn1/misc/MiscObjectIdentifiers.java
@@ -163,4 +163,31 @@ public interface MiscObjectIdentifiers
ASN1ObjectIdentifier id_composite_key = new ASN1ObjectIdentifier("2.16.840.1.114027.80.4.1");
ASN1ObjectIdentifier id_oracle_pkcs12_trusted_key_usage = new ASN1ObjectIdentifier("2.16.840.1.113894.746875.1.1");
+
+ // COMPOSITE SIGNATURES START
+ // -- To be replaced by IANA
+ // Composite signature related OIDs. Based https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
+ // The current OIDs are EXPERIMENTAL and are going to change.
+ ASN1ObjectIdentifier id_composite_signatures = new ASN1ObjectIdentifier("2.16.840.1.114027.80.8.1");
+ ASN1ObjectIdentifier id_MLDSA44_RSA2048_PSS_SHA256 = id_composite_signatures.branch("1");
+ ASN1ObjectIdentifier id_MLDSA44_RSA2048_PKCS15_SHA256 = id_composite_signatures.branch("2");
+ ASN1ObjectIdentifier id_MLDSA44_Ed25519_SHA512 = id_composite_signatures.branch("3");
+ ASN1ObjectIdentifier id_MLDSA44_ECDSA_P256_SHA256 = id_composite_signatures.branch("4");
+ ASN1ObjectIdentifier id_MLDSA44_ECDSA_brainpoolP256r1_SHA256 = id_composite_signatures.branch("5");
+ ASN1ObjectIdentifier id_MLDSA65_RSA3072_PSS_SHA512 = id_composite_signatures.branch("6");
+ ASN1ObjectIdentifier id_MLDSA65_RSA3072_PKCS15_SHA512 = id_composite_signatures.branch("7");
+ ASN1ObjectIdentifier id_MLDSA65_ECDSA_P256_SHA512 = id_composite_signatures.branch("8");
+ ASN1ObjectIdentifier id_MLDSA65_ECDSA_brainpoolP256r1_SHA512 = id_composite_signatures.branch("9");
+ ASN1ObjectIdentifier id_MLDSA65_Ed25519_SHA512 = id_composite_signatures.branch("10");
+ ASN1ObjectIdentifier id_MLDSA87_ECDSA_P384_SHA512 = id_composite_signatures.branch("11");
+ ASN1ObjectIdentifier id_MLDSA87_ECDSA_brainpoolP384r1_SHA512 = id_composite_signatures.branch("12");
+ ASN1ObjectIdentifier id_MLDSA87_Ed448_SHA512 = id_composite_signatures.branch("13");
+
+ // Falcon-based composites below were removed from the IETF draft in version 13 and are expected to be included in a later/separate standard.
+ // Most likely due to the fact that the Falcon (FN-DSA) NIST standard is going to be released after the Dilithium (ML-DSA) standard.
+ // However, we still leave their implementation for experimental usage.
+ ASN1ObjectIdentifier id_Falcon512_ECDSA_P256_SHA256 = id_composite_signatures.branch("14");
+ ASN1ObjectIdentifier id_Falcon512_ECDSA_brainpoolP256r1_SHA256 = id_composite_signatures.branch("15");
+ ASN1ObjectIdentifier id_Falcon512_Ed25519_SHA512 = id_composite_signatures.branch("16");
+ // COMPOSITE SIGNATURES END
}
diff --git a/pkix/src/test/resources/org/bouncycastle/cert/test/compositeCertificateExampleRFC.pem b/pkix/src/test/resources/org/bouncycastle/cert/test/compositeCertificateExampleRFC.pem
deleted file mode 100644
index dcabdc5733..0000000000
--- a/pkix/src/test/resources/org/bouncycastle/cert/test/compositeCertificateExampleRFC.pem
+++ /dev/null
@@ -1,88 +0,0 @@
------BEGIN CERTIFICATE-----
-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
-F2ljUsBn8vo47P9JvA==
------END CERTIFICATE-----
\ No newline at end of file
diff --git a/pkix/src/test/resources/org/bouncycastle/cert/test/compositePrivateKeyExample.pem b/pkix/src/test/resources/org/bouncycastle/cert/test/compositePrivateKeyExample.pem
deleted file mode 100644
index 49de731723..0000000000
--- a/pkix/src/test/resources/org/bouncycastle/cert/test/compositePrivateKeyExample.pem
+++ /dev/null
@@ -1,88 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIP8wIBADANBgtghkgBhvprUAgBBASCD90wgg/ZMIIPPwIBATANBgsrBgEEAQKC
-CwwEBASCCgQEggoAB8M5YHncIEYvJbm8ZXT1b4aI0Y8GVlnuQLONT86ktAcZ8ESM
-+F+YKz/zu13TYkF8o8c0cYKgGXgZxxwfPW3Zhp5mnOAyht9x7a1Zvs29og9cRKll
-pbrZw+Z5Br2OLuAHEwzgkgSkKmyGf7V20s2Lx2rOAkUKRPjysVJJ8Ac35L7KgDCU
-JE2JIC4DSImahkGLQoSIRGFQBApjOC6jsARahoVMCEEUR0nMCGkQE4kQBJBMGIIT
-h4QhlUATyYHEoEDJCEiRKGDCNJEMoYRYiEVQFIgioIwBM0iDNgYYRmZMxkAEgwTa
-kE0URVLDKDAESQlaMGIKSEREsoQSRQDDJg0kFmVMIoZUsIVKIk1KuHDcNAVDEI0U
-kQVJkE0cmElbwBFIMCiCghEhg2CSSCSUogkMggQTBSIKN46MgCnMJIygFoVKQIhU
-qG1TJgpKsFEDpkQIhU2MFG3YAkCIJlDbJI0YMoQICChJpkUEIwHKIHLEwmQZE4gR
-CCokoSBKuI0MSJBbEgHMNHEkIiaaFkLKME1LFmGQmEUhpk0UmSnTBJDgKIYLohAc
-EnIco2DiMmxiMkSZCCJKImmRgklTtoTSSFHSpE0aEwIaKZAUAgDklIAQAQYTQGHk
-xCBAAIxLIAKbFnAAhCUYxpGJNHGRFpEYCGphhkygiE0YAQKIADLjEmTDwoyMxmkj
-tpAasZEBGXDZJBLMBhLKBi4kuA0TGAZcIi1IBiwcBSQDoAEJOCQioU1IgG0ZwwQE
-KYGjIA4CECJAkjBQBmlhEAEBp1ARNCagxGwDCVGCuCGMIA6ZOAKBlG1buCBcRmyj
-iEQQFirRmERMGAKiCAYjNEQAQ4rCBiaJGATCKGrIokWEEHIZxAlYCA3UMADANnBK
-NnDgAnBMCIwCNCwDQg5KJkSaoJEapUwYoQ3cNHAUoUnIMEEjKSAUyYUMRjJgtJEU
-QI2KMI4RpQCiFk1glIhkFIYBJUKiSEWiJkmkFIocGQaZtJCcFkFElo2cwEwhKS7c
-EoISQUTglmEYSCCYOIALNBICIFKZNHISMYUaMUXagmFhsFDEkoEEIk0DggQACDLR
-kAQbiTCDMCSglG2khExbRmYBQwaKIo7SKC4bEEWawE3CsAAjFVIRsxEAQxEDKA3Q
-BEmJsE0jgZFjJkSTEgjCOJLIMo2JNlIQqEDDRkEEJU7KRozUJkXBuGSZlIXDEXkH
-AIUAo/a+EGi6LPCqIuASAWbUsRYGTWdlyx2s2eKmeURpVe2JSHfOOA/rRzjEsWKD
-e4lKGAuAwwJp00D1UcmTnHwtzWHVtg+Xam86I0eglszXYcpLkQYqBObnfmj+EAH0
-/8StFIC80/4g5GRCCRQtknRk4nj533hvmhPjGZeXrx7L+2XBNvu0lw2yVTIuKklL
-edzH7FIZk2b7+JaSCzcqS5EGbz6aJ1dylOhShEYdhYrrjPEmOrA5lG4UzbNYTAYj
-KBVKPLeRj+x404lY5gjlBEWCjFsSxmURQ3e1+OFeoJ0LYFg5HkoJyMr7DX6X7azW
-AjTfhp9Hab9uMcNSEl864x5AFKY6BgD/4omchb2RzFUIFtpgVQcBlDF8ee93Ggqv
-r1sQh4hUPZNXiqWjMQ7Rr9jicygs/6x/BGp3F7GcrAC2tyoqWcAMi0hOHOP7oCli
-PS2nb0mXwDFvLWry6nOZTAURhjlobLDCpsO6nqVpHxSOW4SS4AVVqyA5BgkN8Mrm
-ZTfYv4vZUPgAI/PEn71aPD0W5EwRdG8118fhla3vcnrBMDaQxeTlTgdM7JZDd+kp
-cx0csBZ1d3c9FutMXiaJwmM/24YahQAoMwCpne73mt2F027YM0AlMEV7jIOlWEVj
-qAlRerlb5LBRsDG1MmhieqIbfDl5fsbPfCh7IZUtuFWpA8hL23X9+EgoblPFvupK
-oPRjTNhXCyqJRLiOYft7fu969pBTDfWadbDcgXazKnFTzJ9mkRSO+VfVHrKzCnVH
-xO+v8/GU1ZFvcu1mRjgemPysA0/DU/v2gSTuYFMjJKxAl7vkRgH4VTBXOe5NR61+
-EvhUT1pOScXgrkttoGuh9rT8M/fS4wSohr7xo0CUzAixcEhQifouxNgzwbLo1QFr
-s9mMqDa2pCtVN3ENXnmP+yPmHQMa5c44c3AELsDcc+90TlalwlAO6z4XfNCAF6bG
-a466YemTXTri+WInGkCRT8r4t8zsIKKeskewanKNL6qOY3xFngqiiI1ZjoEQlumC
-NvOjrJ9TnE8o35sv3jfyoohH+jzpm1pINgxT0wYHAnS5TqJMxAg4G3zak4U9dnSC
-SPOyDhHHxWCEvCbmNDfcsOd57fw/gxtkj6BM+mIDCq6pZV0UvveXKpCFR0LYzqqy
-dzSV2DYKuyj0wo5TEAhYR8BG1l8ANPsyjafSw0zxpMtpcIklXqwLM1w5AtXblVRj
-DtHtUd24Uhd1iaZnxnwBHEhWcHENSmAFwSXFuKK+D5OkgYtTG4QVp+CGIXuxgDit
-1eu+2IusrEmhREkVAIsEQTOLww0sh9HhkR035EgmC3z6vD2cPXWjYTsQyll+1Zk5
-9c3AKWAnwuOA+ZgfgRox8SU7lUhr7vx3TCp2xtIJHeulxSbrbbZI4g4Qm3PRmzgf
-NPFuY0nvz9baov5pb9FaSOjFz1q+s9ewObKkjd9ggMLMlUJP3fp0tH8PgZ+sKGNH
-liu0uopVSCdw8iFUacEzuA3wwXNzdjoLJ9860fpRTeLQ09DiNq5x2F8mt3NlTS1+
-G65Vv559QnUqyv25QExsaaE6QrH1fvqLrp8LMFA6/BCak07zhmJCMSAHIMcfENiR
-1gUWPBLlBxoRbRpr8/aUrdx6k3j81uaS8OSCP8G5dddv88yV/74ysGmW59OWHkKY
-lvJQeSJCHn0BanCeBIzxyclB6MlLSN092+GnfT2SM2EpK6RF8FCPOoKK/8BQlySt
-fUg5XSAL6ybXOaojSwgM8yE5bRw0ujft5do7GAW6II2O0ZDO1Wo+q7DFOM1ONQTf
-iOiCGwjTfGPrRZIOglgx48HY+bljCJMafZC2YMFbCZKo8bxVg3JHRU3NJYEy9JJL
-I3p4d8CSMXqZTVm4kyxUtAROn96pN/EzLSLRPUUOzng58YUu8C1CmzoB+O388LJk
-fU+NJKOaooqX/xSp3RlcSFnZ+phSS8qbVDDB7sdMKzMZ8e1j+/jOMetEb+EzX0WR
-EewWFP97cZaEI98y5ARq7SyNVRId8GHPnbCjr4zNVI62AdMopHXTmjYLYg6Wq7iC
-6PGdVTQ6GZhZ/N9zSDr6/LivDb5zps32nXMcle9Lc5V0pLyCTLd0v8If031Cx9VZ
-18FIgslLHXQY99GqMkgIwKRPoXFUtwm/4PR+UJVfqYb3krFzFBmPZ6Wk3rlghKIs
-SJpcGphYgPajVHP3zOzzPCsKfas23fX2hveVRoGCBSEAB8M5YHncIEYvJbm8ZXT1
-b4aI0Y8GVlnuQLONT86ktAeGcdB5sxGBb4blFSVPcrWc+mxSdiEtaPefbsJCqBWA
-vREJWERdbGs1kRHwDy0dHJk/8eP6MEBJ+lUDwkIA68qpeiBtf42b+3VlwiFglCv3
-+lMvqAQe/Nh/5lfvsT2yUIuCnbGJ5DBEpWAznh2mIPcQGNvea3icXZ1v043ruF7H
-/Fb9TZr54Y0ULDlpDvrC3fIbXPmYAEVVqOKEbrJijaa7HEVbiLIBN9R0BRdObQcy
-zLNkp0vIMXVDTfZwIvznT+SHrbomfpgBr8R0Ujp3fFwPM1GloLuC6agWO/LnmRq5
-HqF9ktoxbC/moU2PEHybPKLuC9poz1sBH/ph6/MDwZPBZChOZr1ITvCLbrlug1fl
-6+FFzS71WPLr1sgk5VKoJaxtegKSA1m2rUSFAhjUrJJMTenoVo/cR66BQsPt8KQv
-FLXSxEEAP8/K/0hXaCySOaeIDtMM07jGDW5YLS1s42+boBpa0s01Ie17OV/qTHPC
-9k7ns3AWceKn5UpeRbh5kkz65Ft+ZlpmDQhOUVQw01QP4OPIDQS5N6jKXGWSSA2e
-bV1Zkw6u5GDL/tWmBvwYkVIxTpj9PUioiab48d3XiV2R+CYoGk0TA4zSLDQ3oKzl
-9V2fyGgWCjiahaKp8cRQ5BXFRscBC4pOaODwTVJtbGpMm5kTU2acSxIVEPK+w6af
-s5V0Xt7Ge0Hc+jJ6AD/NuJVhUAqFPbjxH8u35KHPeY8n9ri+fkzh/im8Kvl+/tk7
-Lq2MBgkocyweIoQwZLLRxV5Wtk/Qhlz6AWu1ovJpfYqFuBI/FvQe2eSA4qW8hjtg
-88VpAOL3BzAQfS/TuYZBCqMv5VToqyLrU3yQcyXvkdmLRaX7czsAL7fW4NGzP3Pf
-aL5Mmc8sM6tl61f3rWcc9igYqHWitqc9ifrA/Jq10Pjf0xptp/9Ko5goRUMIlIDS
-m2NKGCA8kRwTUuesQK9Uq3/4OVZeRnagtV5Y5cbrPsQ6hrv+S0z7h0ke++37BxOV
-3YC0+IRjcowF9zih2jNyfqOol8hl+jqaPORTHPRQR6ihILxTTpmMZASh2q+Aw2a9
-RV7ErXNQOgznCk49vFhl8gxZJda4HYGW58uzlQoVzdkc+Ypbwnj0EYBDh09gEyO0
-BC33Oo2f7l7eyr9DSCNulwL3UMvaAm6+Xa0MnwoX8Pe6abLCfF6GMAy14nI8QrOu
-To1J/O1QsKFFRro8c8bxXuQf+q6zqe/LTkZ3AYSKuLNyVoU2Fcw6/eZ44D1LISId
-rKHZZjxSQxYkpQ1/1tTzLcg9VMumZ0GbF1K9yllpnWrS7hNquq1XOmPIoyMVuRZm
-y2JVlx8AmktR0e4tWbZG8RSfxihfyufxHwTAHRXTtESo5tPW0TaOhObj9pYX+M1G
-kdJu50m+XfXfjAVnrD/fr3m1oISWuPs7vhVL5Hc1vmx9XgT1mDM2cZGfZakIoza3
-BOFLpJYrVBnfeHEOUmwFm76RP/O2eAexg1RBb6llWWW7gwV2JDKID8Ki76cB9xFz
-XPhQZxhph/bv85gk3ITyVI0tGy2E2RJulNQQn6i5OG4gCaC6NBj/+adcxRT9ogS2
-Z55LBcP0yM5jt1zAmAvw4jOHGuOG1aqO1zx3hymiN5ZuwQCCD1KoyHj4JOAzi9P2
-17kO0SuMTPY6XtiWg8a73FwfXEZCiumZJzJLMfNIAMQ2f+fz8ko6xwD66ryjD0xy
-NjCBkwIBADATBgcqhkjOPQIBBggqhkjOPQMBBwR5MHcCAQEEIL9avjavjJtExqu1
-kvmhHhODaeG81gc+T/1cH4qPOMQJoAoGCCqGSM49AwEHoUQDQgAEHB2eX9m9qrpd
-bw15t5uTLTS03NBbIRDYRv6voN9GC9S2USTzRqkcX3tjEN4kPLXAvfTh5BOL9PIF
-l6+7Vd1+Zw==
------END PRIVATE KEY-----
diff --git a/pkix/src/test/resources/org/bouncycastle/cert/test/compositePublicKeyExampleRFC.pem b/pkix/src/test/resources/org/bouncycastle/cert/test/compositePublicKeyExampleRFC.pem
deleted file mode 100644
index a68694ea77..0000000000
--- a/pkix/src/test/resources/org/bouncycastle/cert/test/compositePublicKeyExampleRFC.pem
+++ /dev/null
@@ -1,32 +0,0 @@
------BEGIN PUBLIC KEY-----
-MIIFgTANBgtghkgBhvprUAgBBAOCBW4AMIIFaQOCBSEAJaSzbEOXCT27FgXshv87
-2HLTgePmYCJCH2OVUi/PB9YTyBXXnw+smoXT4w0pcq3WPs7qQXz6GKj7R0mFfTjp
-Rd6uH3hgdS5cbg+PwMWsRKigE6mWFpMwrliS8CfR2yYgjhRav7wGa4ja7RdmZoLz
-T8UBN2Yg6P/KceWA1gX6rdVUalrUvmcfR64ry06IfotXXNFwQc3vI6s7khHSUZX5
-Rsw55RK3E0ElNpZxfFHv17d2xwFkGRAYqJao+qo37WtfG6Ynx4cqQyLJzlRn++5R
-G6K1nCwqhErpk4vDR2uHIwAPiW0StX9ZbBjO2smRTIuWS2WhmhZwJkDqSHmCiRI2
-tPsxCtLpM8t2IhTVy/ObAdQGPDngTNIPH8kuoRrBhWGIiWJMlo8LkImCRt5m/8Di
-aL8C2BQNL+BWBBcak/JZrLkKZOZM7pFwWruHVEd0608XerfiVO3ypqAxImJ2xcdD
-kLys4jDlEMsC3oz4RQGXahj2Pr8Jxu8i0TIDDdV5MZw9wId/m+0/vSD8BOAu09Wu
-V6ppUWkDZLHlzf12zx3ZzBF/CMqZNsxMdTFNbu2qQ2/CZMlEvZ9f0gxn6qNf8NHC
-UqdeRr7p9z8PuGHErLHqCvQMrzia71cD4URV//SR8EUQkoo9imtw3XT2uKGUIjT/
-dDyqWl8BlAZ64dUp9EWmHwG1cyKBcu2dtD0d4BMol1g4TOF7u/3hHcgOoiR+ON/3
-7MoxkX9mHt6tP7hkVWy0Mb3Sjej12DG75D9z8gAzHyQhOs3suNliCzCUmUVYm5Mv
-WdySiuShm6yu+9Ah+GqvESuNr/h6s1gZGbdCe9llGdFPniilhL5J9oDgYMp+wi2I
-EeOugOFoaY1e2OI1OPjBpg1071ko9B3CGD+0PkPvKYmMGs0HTnzFWCLPj5dG2kg7
-PEltarKvLVTIxrbjw03l3SXmqpNPU8SqFJ7hB3OpFJgjqL95IRTa68UM8aaUKLMa
-Qjjx08+e13P3wwY3niCR5U751fus4ArGLN2JgfPB7bPSdz043PIvxsCYZxUQXSW3
-xWhWQqaHJLml19obvnf/tEXQZLheAr7hOEb/UTNUIBj/A6LfB0Gs012B1aXfne4W
-9K/OFXc9p0C7aWIfjfMrA/idOrd1Eoo2NGLid+wp8aXyDZkCf5OUretEFHqQcQ2J
-znh8R4mh2Tf7hT8+Gj5Su6bZggHi9iIJZ1G7i0j4Wm3g6DJAXF6KbChMayKRunDp
-k6Nm5iOeTmT+Vi4OJncuI6HezZMzO2s+2iY33uDL7tFR8fVn7dQiF78c1aNhWjfm
-fIsLNQdZxt6orvnwSrZpdVhOtAu+vYVaEAShdHgfzvPSDHIjgyxs6mGdk0uDsGpP
-f5d3e9KV40rXir2OXaYMOq2KTkLb6KHHxZayLG0D9/qSBOnSE/aXNhh1cHtKeYAe
-jjXmfzsmgNELPNxFRrx8pEHG1Se0GJNJVZE9u6B2r9f09TgTxgPX/6XpBNUrlz21
-fsIvNpRL48cwLHOCgYP/SAgE3gzRC6G5NEE19wQZHsFNGeUeGvrvUQgTyT1YwLx+
-Abvp57bVjgLWli185/K1a8BmJ204RHfDhSFe7sVAIoI2pUcz7ydb178DCAvupP20
-CxUIkgOk3C+cgUzTwsFU4iiix282ZBa8/nTUnH9r3IDJQJwdWtMCnByCc43UeVSh
-WV3isRF+ANl6lSevNj0uzGE07a5gPahctBWMmevh6qFcv5XucwNRe7en96o7CgK+
-5QNCAAReie6V/SXhsV0+AAEPt/7UjJqzbrZU1ZHKBLCDbX1cv1Zkpy+SabE2Pfpd
-K7SzfBpZw0txE+bjIUT4j3zjgIDa
------END PUBLIC KEY-----
\ No newline at end of file
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
index 054ebb6fe0..6f616ded19 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
@@ -4,7 +4,7 @@
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeSignaturesConstants;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
index 82e34dd169..4ec08674fe 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
@@ -4,7 +4,7 @@
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeSignaturesConstants;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java
index d4fbb1d537..ace19ae7c0 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java
@@ -1,11 +1,11 @@
package org.bouncycastle.jcajce.provider.asymmetric.compositesignatures;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.asn1.misc.MiscObjectIdentifiers;
-
import java.util.HashMap;
import java.util.Map.Entry;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
+
/**
* Helper class containing constants/mappings for composite signatures.
@@ -17,22 +17,22 @@ public abstract class CompositeSignaturesConstants
* An array of supported identifiers of composite signature schemes.
*/
public static final ASN1ObjectIdentifier[] supportedIdentifiers = {
- MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256,
- MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256,
- MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512,
- MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256,
- MiscObjectIdentifiers.id_MLDSA44_ECDSA_brainpoolP256r1_SHA256,
- MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512,
- MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512,
- MiscObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512,
- MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512,
- MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512,
- MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512,
- MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512,
- MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512,
- MiscObjectIdentifiers.id_Falcon512_ECDSA_P256_SHA256,
- MiscObjectIdentifiers.id_Falcon512_ECDSA_brainpoolP256r1_SHA256,
- MiscObjectIdentifiers.id_Falcon512_Ed25519_SHA512,
+ MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256,
+ MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256,
+ MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512,
+ MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256,
+ MiscObjectIdentifiers.id_MLDSA44_ECDSA_brainpoolP256r1_SHA256,
+ MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512,
+ MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512,
+ MiscObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512,
+ MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512,
+ MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512,
+ MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512,
+ MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512,
+ MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512,
+ MiscObjectIdentifiers.id_Falcon512_ECDSA_P256_SHA256,
+ MiscObjectIdentifiers.id_Falcon512_ECDSA_brainpoolP256r1_SHA256,
+ MiscObjectIdentifiers.id_Falcon512_Ed25519_SHA512,
};
/**
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java
index 78a9a88db8..6c8bab5e26 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java
@@ -1,44 +1,45 @@
package org.bouncycastle.jcajce.provider.asymmetric.compositesignatures;
-import org.bouncycastle.asn1.ASN1Sequence;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import java.io.IOException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
import org.bouncycastle.asn1.ASN1BitString;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
-import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
-import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
-import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.asn1.x9.X962Parameters;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
+import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
+import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
+import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
+import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.jcajce.CompositePrivateKey;
import org.bouncycastle.jcajce.CompositePublicKey;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
-import java.io.IOException;
-import java.security.PrivateKey;
-import java.security.Key;
-import java.security.PublicKey;
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.InvalidKeyException;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
/**
* KeyFactory for composite signatures. List of supported combinations is in CompositeSignaturesConstants
*/
-public class KeyFactorySpi extends BaseKeyFactorySpi
+public class KeyFactorySpi
+ extends BaseKeyFactorySpi
{
//Specific algorithm identifiers of all component signature algorithms for SubjectPublicKeyInfo. These do not need to be all initialized here but makes the code more readable IMHO.
@@ -54,7 +55,8 @@ public class KeyFactorySpi extends BaseKeyFactorySpi
private static final AlgorithmIdentifier ecdsaP384Identifier = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(SECObjectIdentifiers.secp384r1));
private static final AlgorithmIdentifier ecdsaBrainpoolP384r1Identifier = new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, new X962Parameters(TeleTrusTObjectIdentifiers.brainpoolP384r1));
- protected Key engineTranslateKey(Key key) throws InvalidKeyException
+ protected Key engineTranslateKey(Key key)
+ throws InvalidKeyException
{
try
{
@@ -84,7 +86,8 @@ else if (key instanceof PublicKey)
* @return A CompositePrivateKey created from all components in the sequence.
* @throws IOException
*/
- public PrivateKey generatePrivate(PrivateKeyInfo keyInfo) throws IOException
+ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
+ throws IOException
{
ASN1Sequence seq = DERSequence.getInstance(keyInfo.parsePrivateKey());
ASN1ObjectIdentifier keyIdentifier = keyInfo.getPrivateKeyAlgorithm().getAlgorithm();
@@ -118,7 +121,8 @@ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo) throws IOException
* @return
* @throws IOException
*/
- public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) throws IOException
+ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
+ throws IOException
{
ASN1Sequence seq = DERSequence.getInstance(keyInfo.getPublicKeyData().getBytes());
ASN1ObjectIdentifier keyIdentifier = keyInfo.getAlgorithm().getAlgorithm();
@@ -134,11 +138,11 @@ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) throws IOException
// but currently the example public keys are OCTET STRING. So we leave it for interoperability.
if (seq.getObjectAt(i) instanceof DEROctetString)
{
- componentBitStrings[i] = new DERBitString(((DEROctetString) seq.getObjectAt(i)).getOctets());
+ componentBitStrings[i] = new DERBitString(((DEROctetString)seq.getObjectAt(i)).getOctets());
}
else
{
- componentBitStrings[i] = (DERBitString) seq.getObjectAt(i);
+ componentBitStrings[i] = (DERBitString)seq.getObjectAt(i);
}
}
@@ -166,49 +170,50 @@ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) throws IOException
* @throws NoSuchAlgorithmException
* @throws NoSuchProviderException
*/
- private List getKeyFactoriesFromIdentifier(ASN1ObjectIdentifier algorithmIdentifier) throws NoSuchAlgorithmException, NoSuchProviderException
+ private List getKeyFactoriesFromIdentifier(ASN1ObjectIdentifier algorithmIdentifier)
+ throws NoSuchAlgorithmException, NoSuchProviderException
{
List factories = new ArrayList<>();
List algorithmNames = new ArrayList<>();
switch (CompositeSignaturesConstants.ASN1IdentifierCompositeNameMap.get(algorithmIdentifier))
{
- case MLDSA44_Ed25519_SHA512:
- case MLDSA65_Ed25519_SHA512:
- algorithmNames.add("Dilithium");
- algorithmNames.add("Ed25519");
- break;
- case MLDSA87_Ed448_SHA512:
- algorithmNames.add("Dilithium");
- algorithmNames.add("Ed448");
- break;
- case MLDSA44_RSA2048_PSS_SHA256:
- case MLDSA44_RSA2048_PKCS15_SHA256:
- case MLDSA65_RSA3072_PSS_SHA512:
- case MLDSA65_RSA3072_PKCS15_SHA512:
- algorithmNames.add("Dilithium");
- algorithmNames.add("RSA");
- break;
- case MLDSA44_ECDSA_P256_SHA256:
- case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
- case MLDSA65_ECDSA_P256_SHA512:
- case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
- case MLDSA87_ECDSA_P384_SHA512:
- case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
- algorithmNames.add("Dilithium");
- algorithmNames.add("ECDSA");
- break;
- case Falcon512_Ed25519_SHA512:
- algorithmNames.add("Falcon");
- algorithmNames.add("Ed25519");
- break;
- case Falcon512_ECDSA_P256_SHA256:
- case Falcon512_ECDSA_brainpoolP256r1_SHA256:
- algorithmNames.add("Falcon");
- algorithmNames.add("ECDSA");
- break;
- default:
- throw new IllegalArgumentException("Cannot create KeyFactories. Unsupported algorithm identifier.");
+ case MLDSA44_Ed25519_SHA512:
+ case MLDSA65_Ed25519_SHA512:
+ algorithmNames.add("Dilithium");
+ algorithmNames.add("Ed25519");
+ break;
+ case MLDSA87_Ed448_SHA512:
+ algorithmNames.add("Dilithium");
+ algorithmNames.add("Ed448");
+ break;
+ case MLDSA44_RSA2048_PSS_SHA256:
+ case MLDSA44_RSA2048_PKCS15_SHA256:
+ case MLDSA65_RSA3072_PSS_SHA512:
+ case MLDSA65_RSA3072_PKCS15_SHA512:
+ algorithmNames.add("Dilithium");
+ algorithmNames.add("RSA");
+ break;
+ case MLDSA44_ECDSA_P256_SHA256:
+ case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
+ case MLDSA65_ECDSA_P256_SHA512:
+ case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
+ case MLDSA87_ECDSA_P384_SHA512:
+ case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
+ algorithmNames.add("Dilithium");
+ algorithmNames.add("ECDSA");
+ break;
+ case Falcon512_Ed25519_SHA512:
+ algorithmNames.add("Falcon");
+ algorithmNames.add("Ed25519");
+ break;
+ case Falcon512_ECDSA_P256_SHA256:
+ case Falcon512_ECDSA_brainpoolP256r1_SHA256:
+ algorithmNames.add("Falcon");
+ algorithmNames.add("ECDSA");
+ break;
+ default:
+ throw new IllegalArgumentException("Cannot create KeyFactories. Unsupported algorithm identifier.");
}
factories.add(KeyFactory.getInstance(algorithmNames.get(0), "BC"));
@@ -226,73 +231,74 @@ private List getKeyFactoriesFromIdentifier(ASN1ObjectIdentifier algo
* @return An array of X509EncodedKeySpecs
* @throws IOException
*/
- private X509EncodedKeySpec[] getKeysSpecs(ASN1ObjectIdentifier algorithmIdentifier, ASN1BitString[] subjectPublicKeys) throws IOException
+ private X509EncodedKeySpec[] getKeysSpecs(ASN1ObjectIdentifier algorithmIdentifier, ASN1BitString[] subjectPublicKeys)
+ throws IOException
{
X509EncodedKeySpec[] specs = new X509EncodedKeySpec[subjectPublicKeys.length];
SubjectPublicKeyInfo[] keyInfos = new SubjectPublicKeyInfo[subjectPublicKeys.length];
switch (CompositeSignaturesConstants.ASN1IdentifierCompositeNameMap.get(algorithmIdentifier))
{
- case MLDSA44_Ed25519_SHA512:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium2Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ed25519Identifier, subjectPublicKeys[1]);
- break;
- case MLDSA44_ECDSA_P256_SHA256:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium2Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ecdsaP256Identifier, subjectPublicKeys[1]);
- break;
- case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium2Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ecdsaBrainpoolP256r1Identifier, subjectPublicKeys[1]);
- break;
- case MLDSA44_RSA2048_PSS_SHA256:
- case MLDSA44_RSA2048_PKCS15_SHA256:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium2Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(rsaIdentifier, subjectPublicKeys[1]);
- break;
- case MLDSA65_Ed25519_SHA512:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium3Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ed25519Identifier, subjectPublicKeys[1]);
- break;
- case MLDSA65_ECDSA_P256_SHA512:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium3Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ecdsaP256Identifier, subjectPublicKeys[1]);
- break;
- case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium3Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ecdsaBrainpoolP256r1Identifier, subjectPublicKeys[1]);
- break;
- case MLDSA65_RSA3072_PSS_SHA512:
- case MLDSA65_RSA3072_PKCS15_SHA512:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium3Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(rsaIdentifier, subjectPublicKeys[1]);
- break;
- case MLDSA87_Ed448_SHA512:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium5Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ed448Identifier, subjectPublicKeys[1]);
- break;
- case MLDSA87_ECDSA_P384_SHA512:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium5Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ecdsaP384Identifier, subjectPublicKeys[1]);
- break;
- case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
- keyInfos[0] = new SubjectPublicKeyInfo(dilithium5Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ecdsaBrainpoolP384r1Identifier, subjectPublicKeys[1]);
- break;
- case Falcon512_Ed25519_SHA512:
- keyInfos[0] = new SubjectPublicKeyInfo(falcon512Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ed25519Identifier, subjectPublicKeys[1]);
- break;
- case Falcon512_ECDSA_P256_SHA256:
- keyInfos[0] = new SubjectPublicKeyInfo(falcon512Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ecdsaP256Identifier, subjectPublicKeys[1]);
- break;
- case Falcon512_ECDSA_brainpoolP256r1_SHA256:
- keyInfos[0] = new SubjectPublicKeyInfo(falcon512Identifier, subjectPublicKeys[0]);
- keyInfos[1] = new SubjectPublicKeyInfo(ecdsaBrainpoolP256r1Identifier, subjectPublicKeys[1]);
- break;
- default:
- throw new IllegalArgumentException("Cannot create key specs. Unsupported algorithm identifier.");
+ case MLDSA44_Ed25519_SHA512:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium2Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ed25519Identifier, subjectPublicKeys[1]);
+ break;
+ case MLDSA44_ECDSA_P256_SHA256:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium2Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ecdsaP256Identifier, subjectPublicKeys[1]);
+ break;
+ case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium2Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ecdsaBrainpoolP256r1Identifier, subjectPublicKeys[1]);
+ break;
+ case MLDSA44_RSA2048_PSS_SHA256:
+ case MLDSA44_RSA2048_PKCS15_SHA256:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium2Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(rsaIdentifier, subjectPublicKeys[1]);
+ break;
+ case MLDSA65_Ed25519_SHA512:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium3Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ed25519Identifier, subjectPublicKeys[1]);
+ break;
+ case MLDSA65_ECDSA_P256_SHA512:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium3Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ecdsaP256Identifier, subjectPublicKeys[1]);
+ break;
+ case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium3Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ecdsaBrainpoolP256r1Identifier, subjectPublicKeys[1]);
+ break;
+ case MLDSA65_RSA3072_PSS_SHA512:
+ case MLDSA65_RSA3072_PKCS15_SHA512:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium3Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(rsaIdentifier, subjectPublicKeys[1]);
+ break;
+ case MLDSA87_Ed448_SHA512:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium5Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ed448Identifier, subjectPublicKeys[1]);
+ break;
+ case MLDSA87_ECDSA_P384_SHA512:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium5Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ecdsaP384Identifier, subjectPublicKeys[1]);
+ break;
+ case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
+ keyInfos[0] = new SubjectPublicKeyInfo(dilithium5Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ecdsaBrainpoolP384r1Identifier, subjectPublicKeys[1]);
+ break;
+ case Falcon512_Ed25519_SHA512:
+ keyInfos[0] = new SubjectPublicKeyInfo(falcon512Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ed25519Identifier, subjectPublicKeys[1]);
+ break;
+ case Falcon512_ECDSA_P256_SHA256:
+ keyInfos[0] = new SubjectPublicKeyInfo(falcon512Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ecdsaP256Identifier, subjectPublicKeys[1]);
+ break;
+ case Falcon512_ECDSA_brainpoolP256r1_SHA256:
+ keyInfos[0] = new SubjectPublicKeyInfo(falcon512Identifier, subjectPublicKeys[0]);
+ keyInfos[1] = new SubjectPublicKeyInfo(ecdsaBrainpoolP256r1Identifier, subjectPublicKeys[1]);
+ break;
+ default:
+ throw new IllegalArgumentException("Cannot create key specs. Unsupported algorithm identifier.");
}
specs[0] = new X509EncodedKeySpec(keyInfos[0].getEncoded());
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
index b9aa0fce1f..358dcb34c2 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
@@ -1,30 +1,31 @@
package org.bouncycastle.jcajce.provider.asymmetric.compositesignatures;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import org.bouncycastle.jcajce.CompositePrivateKey;
-import org.bouncycastle.jcajce.CompositePublicKey;
-import org.bouncycastle.pqc.jcajce.spec.DilithiumParameterSpec;
-import org.bouncycastle.pqc.jcajce.spec.FalconParameterSpec;
-
-import java.security.PrivateKey;
-import java.security.PublicKey;
+import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
-import java.security.SecureRandom;
-import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.jcajce.CompositePrivateKey;
+import org.bouncycastle.jcajce.CompositePublicKey;
+import org.bouncycastle.pqc.jcajce.spec.DilithiumParameterSpec;
+import org.bouncycastle.pqc.jcajce.spec.FalconParameterSpec;
+
/**
* KeyPairGenerator class for composite signatures. Selected algorithm is set by the "subclasses" at the end of this file.
*/
-public class KeyPairGeneratorSpi extends java.security.KeyPairGeneratorSpi
+public class KeyPairGeneratorSpi
+ extends java.security.KeyPairGeneratorSpi
{
//Enum value of the selected composite signature algorithm.
private final CompositeSignaturesConstants.CompositeName algorithmIdentifier;
@@ -61,94 +62,94 @@ private void initializeParameters()
{
switch (this.algorithmIdentifier)
{
- case MLDSA44_Ed25519_SHA512:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("Ed25519", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium2, this.secureRandom);
- generators.get(1).initialize(256, this.secureRandom);
- break;
- case MLDSA65_Ed25519_SHA512:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("Ed25519", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium3, this.secureRandom);
- generators.get(1).initialize(256, this.secureRandom);
- break;
- case MLDSA87_Ed448_SHA512:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("Ed448", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium5, this.secureRandom);
- generators.get(1).initialize(448, this.secureRandom);
- break;
- case MLDSA44_RSA2048_PSS_SHA256:
- case MLDSA44_RSA2048_PKCS15_SHA256:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("RSA", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium2, this.secureRandom);
- generators.get(1).initialize(2048, this.secureRandom);
- break;
- case MLDSA65_RSA3072_PSS_SHA512:
- case MLDSA65_RSA3072_PKCS15_SHA512:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("RSA", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium3, this.secureRandom);
- generators.get(1).initialize(3072, this.secureRandom);
- break;
- case MLDSA44_ECDSA_P256_SHA256:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium2, this.secureRandom);
- generators.get(1).initialize(new ECGenParameterSpec("P-256"), this.secureRandom);
- break;
- case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium2, this.secureRandom);
- generators.get(1).initialize(new ECGenParameterSpec("brainpoolP256r1"), this.secureRandom);
- break;
- case MLDSA65_ECDSA_P256_SHA512:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium3, this.secureRandom);
- generators.get(1).initialize(new ECGenParameterSpec("P-256"), this.secureRandom);
- break;
- case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium3, this.secureRandom);
- generators.get(1).initialize(new ECGenParameterSpec("brainpoolP256r1"), this.secureRandom);
- break;
- case MLDSA87_ECDSA_P384_SHA512:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium5, this.secureRandom);
- generators.get(1).initialize(new ECGenParameterSpec("P-384"), this.secureRandom);
- break;
- case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
- generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
- generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
- generators.get(0).initialize(DilithiumParameterSpec.dilithium5, this.secureRandom);
- generators.get(1).initialize(new ECGenParameterSpec("brainpoolP384r1"), this.secureRandom);
- break;
- case Falcon512_ECDSA_P256_SHA256:
- generators.add(KeyPairGenerator.getInstance("Falcon", "BC"));
- generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
- generators.get(0).initialize(FalconParameterSpec.falcon_512, this.secureRandom);
- generators.get(1).initialize(new ECGenParameterSpec("P-256"), this.secureRandom);
- break;
- case Falcon512_ECDSA_brainpoolP256r1_SHA256:
- generators.add(KeyPairGenerator.getInstance("Falcon", "BC"));
- generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
- generators.get(0).initialize(FalconParameterSpec.falcon_512, this.secureRandom);
- generators.get(1).initialize(new ECGenParameterSpec("brainpoolP256r1"), this.secureRandom);
- break;
- case Falcon512_Ed25519_SHA512:
- generators.add(KeyPairGenerator.getInstance("Falcon", "BC"));
- generators.add(KeyPairGenerator.getInstance("Ed25519", "BC"));
- generators.get(0).initialize(FalconParameterSpec.falcon_512, this.secureRandom);
- generators.get(1).initialize(256, this.secureRandom);
- break;
- default:
- throw new IllegalStateException("Generators not correctly initialized. Unsupported composite algorithm.");
+ case MLDSA44_Ed25519_SHA512:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("Ed25519", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium2, this.secureRandom);
+ generators.get(1).initialize(256, this.secureRandom);
+ break;
+ case MLDSA65_Ed25519_SHA512:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("Ed25519", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium3, this.secureRandom);
+ generators.get(1).initialize(256, this.secureRandom);
+ break;
+ case MLDSA87_Ed448_SHA512:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("Ed448", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium5, this.secureRandom);
+ generators.get(1).initialize(448, this.secureRandom);
+ break;
+ case MLDSA44_RSA2048_PSS_SHA256:
+ case MLDSA44_RSA2048_PKCS15_SHA256:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("RSA", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium2, this.secureRandom);
+ generators.get(1).initialize(2048, this.secureRandom);
+ break;
+ case MLDSA65_RSA3072_PSS_SHA512:
+ case MLDSA65_RSA3072_PKCS15_SHA512:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("RSA", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium3, this.secureRandom);
+ generators.get(1).initialize(3072, this.secureRandom);
+ break;
+ case MLDSA44_ECDSA_P256_SHA256:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium2, this.secureRandom);
+ generators.get(1).initialize(new ECGenParameterSpec("P-256"), this.secureRandom);
+ break;
+ case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium2, this.secureRandom);
+ generators.get(1).initialize(new ECGenParameterSpec("brainpoolP256r1"), this.secureRandom);
+ break;
+ case MLDSA65_ECDSA_P256_SHA512:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium3, this.secureRandom);
+ generators.get(1).initialize(new ECGenParameterSpec("P-256"), this.secureRandom);
+ break;
+ case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium3, this.secureRandom);
+ generators.get(1).initialize(new ECGenParameterSpec("brainpoolP256r1"), this.secureRandom);
+ break;
+ case MLDSA87_ECDSA_P384_SHA512:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium5, this.secureRandom);
+ generators.get(1).initialize(new ECGenParameterSpec("P-384"), this.secureRandom);
+ break;
+ case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
+ generators.add(KeyPairGenerator.getInstance("Dilithium", "BC"));
+ generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
+ generators.get(0).initialize(DilithiumParameterSpec.dilithium5, this.secureRandom);
+ generators.get(1).initialize(new ECGenParameterSpec("brainpoolP384r1"), this.secureRandom);
+ break;
+ case Falcon512_ECDSA_P256_SHA256:
+ generators.add(KeyPairGenerator.getInstance("Falcon", "BC"));
+ generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
+ generators.get(0).initialize(FalconParameterSpec.falcon_512, this.secureRandom);
+ generators.get(1).initialize(new ECGenParameterSpec("P-256"), this.secureRandom);
+ break;
+ case Falcon512_ECDSA_brainpoolP256r1_SHA256:
+ generators.add(KeyPairGenerator.getInstance("Falcon", "BC"));
+ generators.add(KeyPairGenerator.getInstance("ECDSA", "BC"));
+ generators.get(0).initialize(FalconParameterSpec.falcon_512, this.secureRandom);
+ generators.get(1).initialize(new ECGenParameterSpec("brainpoolP256r1"), this.secureRandom);
+ break;
+ case Falcon512_Ed25519_SHA512:
+ generators.add(KeyPairGenerator.getInstance("Falcon", "BC"));
+ generators.add(KeyPairGenerator.getInstance("Ed25519", "BC"));
+ generators.get(0).initialize(FalconParameterSpec.falcon_512, this.secureRandom);
+ generators.get(1).initialize(256, this.secureRandom);
+ break;
+ default:
+ throw new IllegalStateException("Generators not correctly initialized. Unsupported composite algorithm.");
}
}
catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchProviderException e)
@@ -182,7 +183,8 @@ public void initialize(int keySize, SecureRandom random)
* @param secureRandom A SecureRandom used by component key generators.
* @throws InvalidAlgorithmParameterException
*/
- public void initialize(AlgorithmParameterSpec paramSpec, SecureRandom secureRandom) throws InvalidAlgorithmParameterException
+ public void initialize(AlgorithmParameterSpec paramSpec, SecureRandom secureRandom)
+ throws InvalidAlgorithmParameterException
{
if (paramSpec != null)
{
@@ -224,7 +226,8 @@ private KeyPair getCompositeKeyPair()
return new KeyPair(compositePublicKey, compositePrivateKey);
}
- public static final class MLDSA44andEd25519 extends KeyPairGeneratorSpi
+ public static final class MLDSA44andEd25519
+ extends KeyPairGeneratorSpi
{
public MLDSA44andEd25519()
{
@@ -232,7 +235,8 @@ public MLDSA44andEd25519()
}
}
- public static final class MLDSA65andEd25519 extends KeyPairGeneratorSpi
+ public static final class MLDSA65andEd25519
+ extends KeyPairGeneratorSpi
{
public MLDSA65andEd25519()
{
@@ -240,7 +244,8 @@ public MLDSA65andEd25519()
}
}
- public static final class MLDSA87andEd448 extends KeyPairGeneratorSpi
+ public static final class MLDSA87andEd448
+ extends KeyPairGeneratorSpi
{
public MLDSA87andEd448()
{
@@ -248,7 +253,8 @@ public MLDSA87andEd448()
}
}
- public static final class MLDSA44andRSA2048PSS extends KeyPairGeneratorSpi
+ public static final class MLDSA44andRSA2048PSS
+ extends KeyPairGeneratorSpi
{
public MLDSA44andRSA2048PSS()
{
@@ -256,7 +262,8 @@ public MLDSA44andRSA2048PSS()
}
}
- public static final class MLDSA44andRSA2048PKCS15 extends KeyPairGeneratorSpi
+ public static final class MLDSA44andRSA2048PKCS15
+ extends KeyPairGeneratorSpi
{
public MLDSA44andRSA2048PKCS15()
{
@@ -264,7 +271,8 @@ public MLDSA44andRSA2048PKCS15()
}
}
- public static final class MLDSA65andRSA3072PSS extends KeyPairGeneratorSpi
+ public static final class MLDSA65andRSA3072PSS
+ extends KeyPairGeneratorSpi
{
public MLDSA65andRSA3072PSS()
{
@@ -272,7 +280,8 @@ public MLDSA65andRSA3072PSS()
}
}
- public static final class MLDSA65andRSA3072PKCS15 extends KeyPairGeneratorSpi
+ public static final class MLDSA65andRSA3072PKCS15
+ extends KeyPairGeneratorSpi
{
public MLDSA65andRSA3072PKCS15()
{
@@ -280,7 +289,8 @@ public MLDSA65andRSA3072PKCS15()
}
}
- public static final class MLDSA44andECDSAP256 extends KeyPairGeneratorSpi
+ public static final class MLDSA44andECDSAP256
+ extends KeyPairGeneratorSpi
{
public MLDSA44andECDSAP256()
{
@@ -288,7 +298,8 @@ public MLDSA44andECDSAP256()
}
}
- public static final class MLDSA44andECDSAbrainpoolP256r1 extends KeyPairGeneratorSpi
+ public static final class MLDSA44andECDSAbrainpoolP256r1
+ extends KeyPairGeneratorSpi
{
public MLDSA44andECDSAbrainpoolP256r1()
{
@@ -296,7 +307,8 @@ public MLDSA44andECDSAbrainpoolP256r1()
}
}
- public static final class MLDSA65andECDSAP256 extends KeyPairGeneratorSpi
+ public static final class MLDSA65andECDSAP256
+ extends KeyPairGeneratorSpi
{
public MLDSA65andECDSAP256()
{
@@ -304,7 +316,8 @@ public MLDSA65andECDSAP256()
}
}
- public static final class MLDSA65andECDSAbrainpoolP256r1 extends KeyPairGeneratorSpi
+ public static final class MLDSA65andECDSAbrainpoolP256r1
+ extends KeyPairGeneratorSpi
{
public MLDSA65andECDSAbrainpoolP256r1()
{
@@ -312,7 +325,8 @@ public MLDSA65andECDSAbrainpoolP256r1()
}
}
- public static final class MLDSA87andECDSAP384 extends KeyPairGeneratorSpi
+ public static final class MLDSA87andECDSAP384
+ extends KeyPairGeneratorSpi
{
public MLDSA87andECDSAP384()
{
@@ -320,7 +334,8 @@ public MLDSA87andECDSAP384()
}
}
- public static final class MLDSA87andECDSAbrainpoolP384r1 extends KeyPairGeneratorSpi
+ public static final class MLDSA87andECDSAbrainpoolP384r1
+ extends KeyPairGeneratorSpi
{
public MLDSA87andECDSAbrainpoolP384r1()
{
@@ -328,7 +343,8 @@ public MLDSA87andECDSAbrainpoolP384r1()
}
}
- public static final class Falcon512andEd25519 extends KeyPairGeneratorSpi
+ public static final class Falcon512andEd25519
+ extends KeyPairGeneratorSpi
{
public Falcon512andEd25519()
{
@@ -336,7 +352,8 @@ public Falcon512andEd25519()
}
}
- public static final class Falcon512andECDSAP256 extends KeyPairGeneratorSpi
+ public static final class Falcon512andECDSAP256
+ extends KeyPairGeneratorSpi
{
public Falcon512andECDSAP256()
{
@@ -344,7 +361,8 @@ public Falcon512andECDSAP256()
}
}
- public static final class Falcon512andECDSAbrainpoolP256r1 extends KeyPairGeneratorSpi
+ public static final class Falcon512andECDSAbrainpoolP256r1
+ extends KeyPairGeneratorSpi
{
public Falcon512andECDSAbrainpoolP256r1()
{
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
index fbdf8d4b3d..7afabb6a37 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
@@ -1,34 +1,35 @@
package org.bouncycastle.jcajce.provider.asymmetric.compositesignatures;
-import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.InvalidKeyException;
+import java.security.InvalidParameterException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERBitString;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.jcajce.CompositePrivateKey;
import org.bouncycastle.jcajce.CompositePublicKey;
-import java.io.IOException;
-import java.security.PublicKey;
-import java.security.PrivateKey;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.InvalidKeyException;
-import java.security.SignatureException;
-import java.security.Signature;
-import java.security.InvalidParameterException;
-import java.security.AlgorithmParameters;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
/**
* Signature class for composite signatures. Selected algorithm is set by the "subclasses" at the end of this file.
*/
-public class SignatureSpi extends java.security.SignatureSpi
+public class SignatureSpi
+ extends java.security.SignatureSpi
{
//Enum value of the selected composite signature algorithm.
private final CompositeSignaturesConstants.CompositeName algorithmIdentifier;
@@ -53,64 +54,64 @@ public class SignatureSpi extends java.security.SignatureSpi
{
switch (this.algorithmIdentifier)
{
- case MLDSA44_Ed25519_SHA512:
- case MLDSA65_Ed25519_SHA512:
- componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
- componentSignatures.add(Signature.getInstance("Ed25519", "BC"));
- this.digest = DigestFactory.createSHA512();
- break;
- case MLDSA87_Ed448_SHA512:
- componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
- componentSignatures.add(Signature.getInstance("Ed448", "BC"));
- this.digest = DigestFactory.createSHA512();
- break;
- case MLDSA44_RSA2048_PSS_SHA256:
- componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
- componentSignatures.add(Signature.getInstance("SHA256withRSA/PSS", "BC")); //PSS with SHA-256 as digest algo and MGF.
- this.digest = DigestFactory.createSHA256();
- break;
- case MLDSA65_RSA3072_PSS_SHA512:
- componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
- componentSignatures.add(Signature.getInstance("SHA512withRSA/PSS", "BC")); //PSS with SHA-512 as digest algo and MGF.
- this.digest = DigestFactory.createSHA512();
- break;
- case MLDSA44_RSA2048_PKCS15_SHA256:
- componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
- componentSignatures.add(Signature.getInstance("SHA256withRSA", "BC")); //PKCS15
- this.digest = DigestFactory.createSHA256();
- break;
- case MLDSA65_RSA3072_PKCS15_SHA512:
- componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
- componentSignatures.add(Signature.getInstance("SHA512withRSA", "BC")); //PKCS15
- this.digest = DigestFactory.createSHA512();
- break;
- case MLDSA44_ECDSA_P256_SHA256:
- case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
- componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
- componentSignatures.add(Signature.getInstance("SHA256withECDSA", "BC"));
- this.digest = DigestFactory.createSHA256();
- break;
- case MLDSA65_ECDSA_P256_SHA512:
- case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
- case MLDSA87_ECDSA_P384_SHA512:
- case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
- componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
- componentSignatures.add(Signature.getInstance("SHA512withECDSA", "BC"));
- this.digest = DigestFactory.createSHA512();
- break;
- case Falcon512_ECDSA_P256_SHA256:
- case Falcon512_ECDSA_brainpoolP256r1_SHA256:
- componentSignatures.add(Signature.getInstance("Falcon", "BC"));
- componentSignatures.add(Signature.getInstance("SHA256withECDSA", "BC"));
- this.digest = DigestFactory.createSHA256();
- break;
- case Falcon512_Ed25519_SHA512:
- componentSignatures.add(Signature.getInstance("Falcon", "BC"));
- componentSignatures.add(Signature.getInstance("Ed25519", "BC"));
- this.digest = DigestFactory.createSHA512();
- break;
- default:
- throw new RuntimeException("Unknown composite algorithm.");
+ case MLDSA44_Ed25519_SHA512:
+ case MLDSA65_Ed25519_SHA512:
+ componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
+ componentSignatures.add(Signature.getInstance("Ed25519", "BC"));
+ this.digest = DigestFactory.createSHA512();
+ break;
+ case MLDSA87_Ed448_SHA512:
+ componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
+ componentSignatures.add(Signature.getInstance("Ed448", "BC"));
+ this.digest = DigestFactory.createSHA512();
+ break;
+ case MLDSA44_RSA2048_PSS_SHA256:
+ componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
+ componentSignatures.add(Signature.getInstance("SHA256withRSA/PSS", "BC")); //PSS with SHA-256 as digest algo and MGF.
+ this.digest = DigestFactory.createSHA256();
+ break;
+ case MLDSA65_RSA3072_PSS_SHA512:
+ componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
+ componentSignatures.add(Signature.getInstance("SHA512withRSA/PSS", "BC")); //PSS with SHA-512 as digest algo and MGF.
+ this.digest = DigestFactory.createSHA512();
+ break;
+ case MLDSA44_RSA2048_PKCS15_SHA256:
+ componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
+ componentSignatures.add(Signature.getInstance("SHA256withRSA", "BC")); //PKCS15
+ this.digest = DigestFactory.createSHA256();
+ break;
+ case MLDSA65_RSA3072_PKCS15_SHA512:
+ componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
+ componentSignatures.add(Signature.getInstance("SHA512withRSA", "BC")); //PKCS15
+ this.digest = DigestFactory.createSHA512();
+ break;
+ case MLDSA44_ECDSA_P256_SHA256:
+ case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
+ componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
+ componentSignatures.add(Signature.getInstance("SHA256withECDSA", "BC"));
+ this.digest = DigestFactory.createSHA256();
+ break;
+ case MLDSA65_ECDSA_P256_SHA512:
+ case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
+ case MLDSA87_ECDSA_P384_SHA512:
+ case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
+ componentSignatures.add(Signature.getInstance("Dilithium", "BC"));
+ componentSignatures.add(Signature.getInstance("SHA512withECDSA", "BC"));
+ this.digest = DigestFactory.createSHA512();
+ break;
+ case Falcon512_ECDSA_P256_SHA256:
+ case Falcon512_ECDSA_brainpoolP256r1_SHA256:
+ componentSignatures.add(Signature.getInstance("Falcon", "BC"));
+ componentSignatures.add(Signature.getInstance("SHA256withECDSA", "BC"));
+ this.digest = DigestFactory.createSHA256();
+ break;
+ case Falcon512_Ed25519_SHA512:
+ componentSignatures.add(Signature.getInstance("Falcon", "BC"));
+ componentSignatures.add(Signature.getInstance("Ed25519", "BC"));
+ this.digest = DigestFactory.createSHA512();
+ break;
+ default:
+ throw new RuntimeException("Unknown composite algorithm.");
}
//get bytes of composite signature algorithm OID in DER
@@ -124,7 +125,8 @@ public class SignatureSpi extends java.security.SignatureSpi
this.componentSignatures = Collections.unmodifiableList(componentSignatures);
}
- protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException
+ protected void engineInitVerify(PublicKey publicKey)
+ throws InvalidKeyException
{
if (!(publicKey instanceof CompositePublicKey))
@@ -132,7 +134,7 @@ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException
throw new InvalidKeyException("Public key is not composite.");
}
- CompositePublicKey compositePublicKey = (CompositePublicKey) publicKey;
+ CompositePublicKey compositePublicKey = (CompositePublicKey)publicKey;
if (!compositePublicKey.getAlgorithmIdentifier().equals(this.algorithmIdentifierASN1))
{
@@ -146,14 +148,15 @@ protected void engineInitVerify(PublicKey publicKey) throws InvalidKeyException
}
}
- protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException
+ protected void engineInitSign(PrivateKey privateKey)
+ throws InvalidKeyException
{
if (!(privateKey instanceof CompositePrivateKey))
{
throw new InvalidKeyException("Private key is not composite.");
}
- CompositePrivateKey compositePrivateKey = (CompositePrivateKey) privateKey;
+ CompositePrivateKey compositePrivateKey = (CompositePrivateKey)privateKey;
if (!compositePrivateKey.getAlgorithmIdentifier().equals(this.algorithmIdentifierASN1))
{
@@ -168,12 +171,14 @@ protected void engineInitSign(PrivateKey privateKey) throws InvalidKeyException
}
- protected void engineUpdate(byte b) throws SignatureException
+ protected void engineUpdate(byte b)
+ throws SignatureException
{
digest.update(b);
}
- protected void engineUpdate(byte[] bytes, int off, int len) throws SignatureException
+ protected void engineUpdate(byte[] bytes, int off, int len)
+ throws SignatureException
{
digest.update(bytes, off, len);
}
@@ -185,7 +190,8 @@ protected void engineUpdate(byte[] bytes, int off, int len) throws SignatureExce
* @return composite signature bytes
* @throws SignatureException
*/
- protected byte[] engineSign() throws SignatureException
+ protected byte[] engineSign()
+ throws SignatureException
{
ASN1EncodableVector signatureSequence = new ASN1EncodableVector();
try
@@ -220,7 +226,8 @@ protected byte[] engineSign() throws SignatureException
* @return
* @throws SignatureException
*/
- protected boolean engineVerify(byte[] signature) throws SignatureException
+ protected boolean engineVerify(byte[] signature)
+ throws SignatureException
{
ASN1Sequence signatureSequence = DERSequence.getInstance(signature);
@@ -252,12 +259,14 @@ protected boolean engineVerify(byte[] signature) throws SignatureException
return !fail;
}
- protected void engineSetParameter(String s, Object o) throws InvalidParameterException
+ protected void engineSetParameter(String s, Object o)
+ throws InvalidParameterException
{
throw new UnsupportedOperationException("engineSetParameter unsupported");
}
- protected Object engineGetParameter(String s) throws InvalidParameterException
+ protected Object engineGetParameter(String s)
+ throws InvalidParameterException
{
throw new UnsupportedOperationException("engineGetParameter unsupported");
}
@@ -267,7 +276,8 @@ protected AlgorithmParameters engineGetParameters()
return null;
}
- public final static class MLDSA44andEd25519 extends SignatureSpi
+ public final static class MLDSA44andEd25519
+ extends SignatureSpi
{
public MLDSA44andEd25519()
{
@@ -275,7 +285,8 @@ public MLDSA44andEd25519()
}
}
- public final static class MLDSA65andEd25519 extends SignatureSpi
+ public final static class MLDSA65andEd25519
+ extends SignatureSpi
{
public MLDSA65andEd25519()
{
@@ -283,7 +294,8 @@ public MLDSA65andEd25519()
}
}
- public final static class MLDSA87andEd448 extends SignatureSpi
+ public final static class MLDSA87andEd448
+ extends SignatureSpi
{
public MLDSA87andEd448()
{
@@ -291,7 +303,8 @@ public MLDSA87andEd448()
}
}
- public final static class MLDSA44andRSA2048PSS extends SignatureSpi
+ public final static class MLDSA44andRSA2048PSS
+ extends SignatureSpi
{
public MLDSA44andRSA2048PSS()
{
@@ -299,7 +312,8 @@ public MLDSA44andRSA2048PSS()
}
}
- public final static class MLDSA44andRSA2048PKCS15 extends SignatureSpi
+ public final static class MLDSA44andRSA2048PKCS15
+ extends SignatureSpi
{
public MLDSA44andRSA2048PKCS15()
{
@@ -307,7 +321,8 @@ public MLDSA44andRSA2048PKCS15()
}
}
- public final static class MLDSA65andRSA3072PSS extends SignatureSpi
+ public final static class MLDSA65andRSA3072PSS
+ extends SignatureSpi
{
public MLDSA65andRSA3072PSS()
{
@@ -315,7 +330,8 @@ public MLDSA65andRSA3072PSS()
}
}
- public final static class MLDSA65andRSA3072PKCS15 extends SignatureSpi
+ public final static class MLDSA65andRSA3072PKCS15
+ extends SignatureSpi
{
public MLDSA65andRSA3072PKCS15()
{
@@ -323,7 +339,8 @@ public MLDSA65andRSA3072PKCS15()
}
}
- public final static class MLDSA44andECDSAP256 extends SignatureSpi
+ public final static class MLDSA44andECDSAP256
+ extends SignatureSpi
{
public MLDSA44andECDSAP256()
{
@@ -331,7 +348,8 @@ public MLDSA44andECDSAP256()
}
}
- public final static class MLDSA44andECDSAbrainpoolP256r1 extends SignatureSpi
+ public final static class MLDSA44andECDSAbrainpoolP256r1
+ extends SignatureSpi
{
public MLDSA44andECDSAbrainpoolP256r1()
{
@@ -339,7 +357,8 @@ public MLDSA44andECDSAbrainpoolP256r1()
}
}
- public final static class MLDSA65andECDSAP256 extends SignatureSpi
+ public final static class MLDSA65andECDSAP256
+ extends SignatureSpi
{
public MLDSA65andECDSAP256()
{
@@ -347,7 +366,8 @@ public MLDSA65andECDSAP256()
}
}
- public final static class MLDSA65andECDSAbrainpoolP256r1 extends SignatureSpi
+ public final static class MLDSA65andECDSAbrainpoolP256r1
+ extends SignatureSpi
{
public MLDSA65andECDSAbrainpoolP256r1()
{
@@ -355,7 +375,8 @@ public MLDSA65andECDSAbrainpoolP256r1()
}
}
- public final static class MLDSA87andECDSAP384 extends SignatureSpi
+ public final static class MLDSA87andECDSAP384
+ extends SignatureSpi
{
public MLDSA87andECDSAP384()
{
@@ -363,7 +384,8 @@ public MLDSA87andECDSAP384()
}
}
- public final static class MLDSA87andECDSAbrainpoolP384r1 extends SignatureSpi
+ public final static class MLDSA87andECDSAbrainpoolP384r1
+ extends SignatureSpi
{
public MLDSA87andECDSAbrainpoolP384r1()
{
@@ -371,7 +393,8 @@ public MLDSA87andECDSAbrainpoolP384r1()
}
}
- public final static class Falcon512andEd25519 extends SignatureSpi
+ public final static class Falcon512andEd25519
+ extends SignatureSpi
{
public Falcon512andEd25519()
{
@@ -379,7 +402,8 @@ public Falcon512andEd25519()
}
}
- public final static class Falcon512andECDSAP256 extends SignatureSpi
+ public final static class Falcon512andECDSAP256
+ extends SignatureSpi
{
public Falcon512andECDSAP256()
{
@@ -387,7 +411,8 @@ public Falcon512andECDSAP256()
}
}
- public final static class Falcon512andECDSAbrainpoolP256r1 extends SignatureSpi
+ public final static class Falcon512andECDSAbrainpoolP256r1
+ extends SignatureSpi
{
public Falcon512andECDSAbrainpoolP256r1()
{
From c518429d008d6686519f4104c6ae69660da0202a Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 17:38:40 +1100
Subject: [PATCH 0163/1846] standard digest tests for PGP (draft) relates to
GitHub #1566
---
.../operator/jcajce/OperatorHelper.java | 42 ++++++++++++-------
.../openpgp/test/OperatorBcTest.java | 35 +++++++++++++++-
.../openpgp/test/OperatorJcajceTest.java | 34 +++++++++++++++
3 files changed, 93 insertions(+), 18 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
index 91ba8d54ab..2a552d1730 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
@@ -1,5 +1,21 @@
package org.bouncycastle.openpgp.operator.jcajce;
+import java.io.InputStream;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.KeyPairGenerator;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Signature;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyAgreement;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
import org.bouncycastle.bcpg.HashAlgorithmTags;
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
@@ -11,22 +27,6 @@
import org.bouncycastle.openpgp.operator.PGPDataDecryptor;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
-import javax.crypto.Cipher;
-import javax.crypto.KeyAgreement;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-import java.io.InputStream;
-import java.security.AlgorithmParameters;
-import java.security.GeneralSecurityException;
-import java.security.KeyFactory;
-import java.security.KeyPairGenerator;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
-import java.security.Signature;
-
class OperatorHelper
{
private JcaJceHelper helper;
@@ -65,6 +65,16 @@ String getDigestName(
return "SHA-512";
case HashAlgorithmTags.SHA224:
return "SHA-224";
+ case HashAlgorithmTags.SHA3_256:
+ case HashAlgorithmTags.SHA3_256_OLD:
+ return "SHA3-256";
+ case HashAlgorithmTags.SHA3_384: // OLD
+ return "SHA3-384";
+ case HashAlgorithmTags.SHA3_512:
+ case HashAlgorithmTags.SHA3_512_OLD:
+ return "SHA3-512";
+ case HashAlgorithmTags.SHA3_224:
+ return "SHA3-224";
case HashAlgorithmTags.TIGER_192:
return "TIGER";
default:
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
index da4d1d1f40..c1a0097338 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorBcTest.java
@@ -11,7 +11,6 @@
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.ECGenParameterSpec;
-
import java.util.Date;
import java.util.Iterator;
@@ -33,7 +32,6 @@
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.X25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
-import org.bouncycastle.jcajce.provider.asymmetric.edec.KeyAgreementSpi;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec;
import org.bouncycastle.openpgp.PGPEncryptedData;
@@ -55,6 +53,7 @@
import org.bouncycastle.openpgp.jcajce.JcaPGPObjectFactory;
import org.bouncycastle.openpgp.operator.PGPContentVerifier;
import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
import org.bouncycastle.openpgp.operator.bc.BcPGPDataEncryptorBuilder;
@@ -75,6 +74,7 @@
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
import org.bouncycastle.util.test.UncloseableOutputStream;
@@ -106,6 +106,37 @@ public void performTest()
testBcPGPContentVerifierBuilderProvider();
//testBcPBESecretKeyDecryptorBuilder();
testBcKeyFingerprintCalculator();
+ testBcStandardDigests();
+ }
+
+ private void testBcStandardDigests()
+ throws Exception
+ {
+ PGPDigestCalculatorProvider digCalcBldr = new BcPGPDigestCalculatorProvider();
+
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.MD5), Hex.decode("900150983cd24fb0d6963f7d28e17f72"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA1), Hex.decode("a9993e364706816aba3e25717850c26c9cd0d89d"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.RIPEMD160), Hex.decode("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA256), Hex.decode("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA384), Hex.decode("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA512), Hex.decode("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA224), Hex.decode("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA3_256), Hex.decode("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA3_512), Hex.decode("b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"));
+ }
+
+ private void testDigestCalc(PGPDigestCalculator digCalc, byte[] expected)
+ throws IOException
+ {
+ OutputStream dOut = digCalc.getOutputStream();
+
+ dOut.write(Strings.toByteArray("abc"));
+
+ dOut.close();
+
+ byte[] res = digCalc.getDigest();
+
+ isTrue(Arrays.areEqual(res, expected));
}
public void testBcKeyFingerprintCalculator()
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
index 8eb4a5d8f3..9683ec2eb5 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
@@ -1,5 +1,7 @@
package org.bouncycastle.openpgp.test;
+import java.io.IOException;
+import java.io.OutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
@@ -70,6 +72,38 @@ public void performTest()
testJcaPGPDigestCalculatorProviderBuilder();
testJcePGPDataEncryptorBuilder();
testJcaKeyFingerprintCalculator();
+ testStandardDigests();
+ }
+
+ private void testStandardDigests()
+ throws Exception
+ {
+ PGPDigestCalculatorProvider digCalcBldr =
+ new JcaPGPDigestCalculatorProviderBuilder().setProvider("BC").build();
+
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.MD5), Hex.decode("900150983cd24fb0d6963f7d28e17f72"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA1), Hex.decode("a9993e364706816aba3e25717850c26c9cd0d89d"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.RIPEMD160), Hex.decode("8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA256), Hex.decode("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA384), Hex.decode("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA512), Hex.decode("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA224), Hex.decode("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA3_256), Hex.decode("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532"));
+ testDigestCalc(digCalcBldr.get(HashAlgorithmTags.SHA3_512), Hex.decode("b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0"));
+ }
+
+ private void testDigestCalc(PGPDigestCalculator digCalc, byte[] expected)
+ throws IOException
+ {
+ OutputStream dOut = digCalc.getOutputStream();
+
+ dOut.write(Strings.toByteArray("abc"));
+
+ dOut.close();
+
+ byte[] res = digCalc.getDigest();
+
+ isTrue(Arrays.areEqual(res, expected));
}
public void testJcaKeyFingerprintCalculator()
From 7f95854ed62f7b8540a1a4069cd68d898c0ac357 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 17:39:39 +1100
Subject: [PATCH 0164/1846] added use of TestResourceFinder.
---
.../org/bouncycastle/cert/test/CertTest.java | 81 +++---
.../jcajce/provider/test/AllTests.java | 2 +
.../test/CompositeSignaturesTest.java | 256 ++++++++++--------
3 files changed, 180 insertions(+), 159 deletions(-)
diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java b/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java
index b0d4fa2e26..aef7a297ef 100644
--- a/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java
+++ b/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java
@@ -2,8 +2,8 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
-import java.io.InputStreamReader;
import java.io.IOException;
+import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
@@ -137,6 +137,7 @@
import org.bouncycastle.pqc.jcajce.spec.SPHINCSPlusParameterSpec;
import org.bouncycastle.pqc.jcajce.spec.XMSSMTParameterSpec;
import org.bouncycastle.pqc.jcajce.spec.XMSSParameterSpec;
+import org.bouncycastle.test.TestResourceFinder;
import org.bouncycastle.util.Encodable;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Base64;
@@ -2965,7 +2966,7 @@ public void checkCRLCompositeCreation()
{
isTrue(e.getMessage().equals("no matching key found"));
}
-
+
// single key test
crl.verify(ecPub, BC);
@@ -4034,7 +4035,7 @@ public void checkCreationECDSA()
}
public void checkCreationPicnic()
- throws Exception
+ throws Exception
{
if (Security.getProvider("BCPQC") == null)
{
@@ -4060,12 +4061,12 @@ public void checkCreationPicnic()
//
ContentSigner sigGen = new JcaContentSignerBuilder("PICNIC").setProvider("BCPQC").build(privKey);
X509v3CertificateBuilder certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubKey)
- .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
- new X509KeyUsage(X509KeyUsage.encipherOnly))
- .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
- new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
- .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
- new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.15"), true,
+ new X509KeyUsage(X509KeyUsage.encipherOnly))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.37"), true,
+ new DERSequence(KeyPurposeId.anyExtendedKeyUsage))
+ .addExtension(new ASN1ObjectIdentifier("2.5.29.17"), true,
+ new GeneralNames(new GeneralName(GeneralName.rfc822Name, "test@test.test")));
X509Certificate baseCert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
@@ -4077,8 +4078,8 @@ public void checkCreationPicnic()
//
certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), pubKey)
- .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, baseCert)
- .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.37"), false, baseCert);
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, baseCert)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.37"), false, baseCert);
X509Certificate cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
@@ -4122,8 +4123,8 @@ public void checkCreationPicnic()
KeyPair nhKp = kpGen.generateKeyPair();
certGen = new JcaX509v3CertificateBuilder(builder.build(), BigInteger.valueOf(1), new Date(System.currentTimeMillis() - 50000), new Date(System.currentTimeMillis() + 50000), builder.build(), nhKp.getPublic())
- .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, baseCert)
- .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.37"), false, baseCert);
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.15"), true, baseCert)
+ .copyAndAddExtension(new ASN1ObjectIdentifier("2.5.29.37"), false, baseCert);
cert = new JcaX509CertificateConverter().setProvider(BC).getCertificate(certGen.build(sigGen));
@@ -4620,7 +4621,7 @@ public void checkCreationComposite()
if (System.getProperty("java.version").indexOf("1.5.") < 0)
{
cert.verify(ecPub, new BouncyCastleProvider()); // ec key only
-
+
cert.verify(lmsPub, new BouncyCastlePQCProvider()); // lms key only
}
@@ -5425,23 +5426,23 @@ private void checkSerialisation()
// TESTS REGARDING COMPOSITES https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
private static String[] compositeSignaturesOIDs = {
- "2.16.840.1.114027.80.8.1.1", //id-MLDSA44-RSA2048-PSS-SHA256
- "2.16.840.1.114027.80.8.1.2", //id-MLDSA44-RSA2048-PKCS15-SHA256
- "2.16.840.1.114027.80.8.1.3", //id-MLDSA44-Ed25519-SHA512
- "2.16.840.1.114027.80.8.1.4", //id-MLDSA44-ECDSA-P256-SHA256
- "2.16.840.1.114027.80.8.1.5", //id-MLDSA44-ECDSA-brainpoolP256r1-SHA256
- "2.16.840.1.114027.80.8.1.6", //id-MLDSA65-RSA3072-PSS-SHA512
- "2.16.840.1.114027.80.8.1.7", //id-MLDSA65-RSA3072-PKCS15-SHA512
- "2.16.840.1.114027.80.8.1.8", //id-MLDSA65-ECDSA-P256-SHA512
- "2.16.840.1.114027.80.8.1.9", //id-MLDSA65-ECDSA-brainpoolP256r1-SHA512
- "2.16.840.1.114027.80.8.1.10", //id-MLDSA65-Ed25519-SHA512
- "2.16.840.1.114027.80.8.1.11", //id-MLDSA87-ECDSA-P384-SHA512
- "2.16.840.1.114027.80.8.1.12", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512
- "2.16.840.1.114027.80.8.1.13", //id-MLDSA87-Ed448-SHA512
- // Falcon composites below were excluded from the draft. See MiscObjectIdentifiers for details.
- "2.16.840.1.114027.80.8.1.14", //id-Falcon512-ECDSA-P256-SHA256
- "2.16.840.1.114027.80.8.1.15", //id-Falcon512-ECDSA-brainpoolP256r1-SHA256
- "2.16.840.1.114027.80.8.1.16", //id-Falcon512-Ed25519-SHA512
+ "2.16.840.1.114027.80.8.1.1", //id-MLDSA44-RSA2048-PSS-SHA256
+ "2.16.840.1.114027.80.8.1.2", //id-MLDSA44-RSA2048-PKCS15-SHA256
+ "2.16.840.1.114027.80.8.1.3", //id-MLDSA44-Ed25519-SHA512
+ "2.16.840.1.114027.80.8.1.4", //id-MLDSA44-ECDSA-P256-SHA256
+ "2.16.840.1.114027.80.8.1.5", //id-MLDSA44-ECDSA-brainpoolP256r1-SHA256
+ "2.16.840.1.114027.80.8.1.6", //id-MLDSA65-RSA3072-PSS-SHA512
+ "2.16.840.1.114027.80.8.1.7", //id-MLDSA65-RSA3072-PKCS15-SHA512
+ "2.16.840.1.114027.80.8.1.8", //id-MLDSA65-ECDSA-P256-SHA512
+ "2.16.840.1.114027.80.8.1.9", //id-MLDSA65-ECDSA-brainpoolP256r1-SHA512
+ "2.16.840.1.114027.80.8.1.10", //id-MLDSA65-Ed25519-SHA512
+ "2.16.840.1.114027.80.8.1.11", //id-MLDSA87-ECDSA-P384-SHA512
+ "2.16.840.1.114027.80.8.1.12", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512
+ "2.16.840.1.114027.80.8.1.13", //id-MLDSA87-Ed448-SHA512
+ // Falcon composites below were excluded from the draft. See MiscObjectIdentifiers for details.
+ "2.16.840.1.114027.80.8.1.14", //id-Falcon512-ECDSA-P256-SHA256
+ "2.16.840.1.114027.80.8.1.15", //id-Falcon512-ECDSA-brainpoolP256r1-SHA256
+ "2.16.840.1.114027.80.8.1.16", //id-Falcon512-Ed25519-SHA512
};
private void checkCompositeSignatureCertificateCreation()
@@ -5465,7 +5466,7 @@ private void checkCompositeSignatureCertificateCreation()
X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
isEquals(oid, cert.getSigAlgOID());
- CompositePublicKey compositePublicKey = (CompositePublicKey) cert.getPublicKey();
+ CompositePublicKey compositePublicKey = (CompositePublicKey)cert.getPublicKey();
isEquals(CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(new ASN1ObjectIdentifier(oid)), compositePublicKey.getAlgorithm());
isEquals(subjectName, cert.getSubjectX500Principal().getName());
@@ -5475,7 +5476,7 @@ private void checkCompositeSignatureCertificateCreation()
}
}
catch (NoSuchAlgorithmException | NoSuchProviderException | CertificateException | OperatorCreationException |
- SignatureException | InvalidKeyException | TestFailedException e)
+ SignatureException | InvalidKeyException | TestFailedException e)
{
fail("checkCompositeSignatureCertificateCreation failed: " + e.getMessage());
}
@@ -5486,8 +5487,8 @@ private void checkParseCompositePublicKey()
try
{
//compositePublicKeyExampleRFC.pem contains the sample public key from https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
- PEMParser pemParser = new PEMParser(new InputStreamReader(this.getClass().getResourceAsStream("compositePublicKeyExampleRFC.pem")));
- SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) pemParser.readObject();
+ PEMParser pemParser = new PEMParser(new InputStreamReader(TestResourceFinder.findTestResource("pqc/composite", "compositePublicKeyExampleRFC.pem")));
+ SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo)pemParser.readObject();
isEquals(subjectPublicKeyInfo.getAlgorithm().getAlgorithm(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256);
CompositePublicKey compositePublicKey = new CompositePublicKey(subjectPublicKeyInfo);
@@ -5508,8 +5509,8 @@ private void checkParseCompositePrivateKey()
//compositePrivateKeyExample.pem does NOT contain the sample private key from https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
//because the at this moment, the Dilithium private key formats don't match.
//this sample was generated from this BC implementation
- PEMParser pemParser = new PEMParser(new InputStreamReader(this.getClass().getResourceAsStream("compositePrivateKeyExample.pem")));
- PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo) pemParser.readObject();
+ PEMParser pemParser = new PEMParser(new InputStreamReader(TestResourceFinder.findTestResource("pqc/composite", "compositePrivateKeyExample.pem")));
+ PrivateKeyInfo privateKeyInfo = (PrivateKeyInfo)pemParser.readObject();
isEquals(privateKeyInfo.getPrivateKeyAlgorithm().getAlgorithm(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256);
@@ -5529,14 +5530,14 @@ private void checkParseAndVerifyCompositeCertificate()
try
{
//compositeCertificateExampleRFC.pem contains the sample certificate from https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
- PEMParser pemParser = new PEMParser(new InputStreamReader(this.getClass().getResourceAsStream("compositeCertificateExampleRFC.pem")));
- X509CertificateHolder certificateHolder = (X509CertificateHolder) pemParser.readObject();
+ PEMParser pemParser = new PEMParser(new InputStreamReader(TestResourceFinder.findTestResource("pqc/composite", "compositeCertificateExampleRFC.pem")));
+ X509CertificateHolder certificateHolder = (X509CertificateHolder)pemParser.readObject();
JcaX509CertificateConverter x509Converter = new JcaX509CertificateConverter().setProvider("BC");
X509Certificate certificate = x509Converter.getCertificate(certificateHolder);
isEquals(certificate.getSigAlgOID(), MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256.toString());
- CompositePublicKey compositePublicKey = (CompositePublicKey) certificate.getPublicKey();
+ CompositePublicKey compositePublicKey = (CompositePublicKey)certificate.getPublicKey();
isEquals(compositePublicKey.getPublicKeys().get(0).getAlgorithm(), "DILITHIUM2");
isEquals(compositePublicKey.getPublicKeys().get(1).getAlgorithm(), "ECDSA");
diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java
index 51f57888d3..662cd00fe9 100644
--- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java
+++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java
@@ -29,6 +29,8 @@ public static Test suite()
suite.addTestSuite(RandomTest.class);
suite.addTestSuite(RFC3211WrapTest.class);
suite.addTestSuite(SP80038GTest.class);
+ suite.addTestSuite(CompositeKeyTest.class);
+ suite.addTestSuite(CompositeSignaturesTest.class);
suite.addTestSuite(BouncyCastleProviderTest.class);
return new BCTestSetup(suite);
diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java
index 084c06f714..8ca3699913 100644
--- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java
+++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java
@@ -1,5 +1,16 @@
package org.bouncycastle.jcajce.provider.test;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Security;
+import java.security.Signature;
+import java.security.spec.X509EncodedKeySpec;
+
import junit.framework.TestCase;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.jcajce.CompositePrivateKey;
@@ -7,47 +18,49 @@
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeSignaturesConstants;
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.test.TestResourceFinder;
import org.bouncycastle.util.encoders.Base64;
-import java.io.BufferedReader;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import java.security.*;
-import java.security.spec.X509EncodedKeySpec;
-
-public class CompositeSignaturesTest extends TestCase {
+public class CompositeSignaturesTest
+ extends TestCase
+{
private static String[] compositeSignaturesOIDs = {
- "2.16.840.1.114027.80.8.1.1", //id-MLDSA44-RSA2048-PSS-SHA256
- "2.16.840.1.114027.80.8.1.2", //id-MLDSA44-RSA2048-PKCS15-SHA256
- "2.16.840.1.114027.80.8.1.3", //id-MLDSA44-Ed25519-SHA512
- "2.16.840.1.114027.80.8.1.4", //id-MLDSA44-ECDSA-P256-SHA256
- "2.16.840.1.114027.80.8.1.5", //id-MLDSA44-ECDSA-brainpoolP256r1-SHA256
- "2.16.840.1.114027.80.8.1.6", //id-MLDSA65-RSA3072-PSS-SHA512
- "2.16.840.1.114027.80.8.1.7", //id-MLDSA65-RSA3072-PKCS15-SHA512
- "2.16.840.1.114027.80.8.1.8", //id-MLDSA65-ECDSA-P256-SHA512
- "2.16.840.1.114027.80.8.1.9", //id-MLDSA65-ECDSA-brainpoolP256r1-SHA512
- "2.16.840.1.114027.80.8.1.10", //id-MLDSA65-Ed25519-SHA512
- "2.16.840.1.114027.80.8.1.11", //id-MLDSA87-ECDSA-P384-SHA512
- "2.16.840.1.114027.80.8.1.12", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512
- "2.16.840.1.114027.80.8.1.13", //id-MLDSA87-Ed448-SHA512
- // Falcon composites below were excluded from the draft. See MiscObjectIdentifiers for details.
- "2.16.840.1.114027.80.8.1.14", //id-Falcon512-ECDSA-P256-SHA256
- "2.16.840.1.114027.80.8.1.15", //id-Falcon512-ECDSA-brainpoolP256r1-SHA256
- "2.16.840.1.114027.80.8.1.16", //id-Falcon512-Ed25519-SHA512
+ "2.16.840.1.114027.80.8.1.1", //id-MLDSA44-RSA2048-PSS-SHA256
+ "2.16.840.1.114027.80.8.1.2", //id-MLDSA44-RSA2048-PKCS15-SHA256
+ "2.16.840.1.114027.80.8.1.3", //id-MLDSA44-Ed25519-SHA512
+ "2.16.840.1.114027.80.8.1.4", //id-MLDSA44-ECDSA-P256-SHA256
+ "2.16.840.1.114027.80.8.1.5", //id-MLDSA44-ECDSA-brainpoolP256r1-SHA256
+ "2.16.840.1.114027.80.8.1.6", //id-MLDSA65-RSA3072-PSS-SHA512
+ "2.16.840.1.114027.80.8.1.7", //id-MLDSA65-RSA3072-PKCS15-SHA512
+ "2.16.840.1.114027.80.8.1.8", //id-MLDSA65-ECDSA-P256-SHA512
+ "2.16.840.1.114027.80.8.1.9", //id-MLDSA65-ECDSA-brainpoolP256r1-SHA512
+ "2.16.840.1.114027.80.8.1.10", //id-MLDSA65-Ed25519-SHA512
+ "2.16.840.1.114027.80.8.1.11", //id-MLDSA87-ECDSA-P384-SHA512
+ "2.16.840.1.114027.80.8.1.12", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512
+ "2.16.840.1.114027.80.8.1.13", //id-MLDSA87-Ed448-SHA512
+ // Falcon composites below were excluded from the draft. See MiscObjectIdentifiers for details.
+ "2.16.840.1.114027.80.8.1.14", //id-Falcon512-ECDSA-P256-SHA256
+ "2.16.840.1.114027.80.8.1.15", //id-Falcon512-ECDSA-brainpoolP256r1-SHA256
+ "2.16.840.1.114027.80.8.1.16", //id-Falcon512-Ed25519-SHA512
};
public static final String messageToBeSigned = "Hello, how was your day?";
- public void testKeyPairGeneration() throws Exception {
+ public void setUp()
+ {
Security.addProvider(new BouncyCastleProvider());
+ }
- for (String oid : compositeSignaturesOIDs) {
+ public void testKeyPairGeneration()
+ throws Exception
+ {
+ for (String oid : compositeSignaturesOIDs)
+ {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(oid, "BC");
KeyPair keyPair = keyPairGenerator.generateKeyPair();
- CompositePublicKey compositePublicKey = (CompositePublicKey) keyPair.getPublic();
- CompositePrivateKey compositePrivateKey = (CompositePrivateKey) keyPair.getPrivate();
+ CompositePublicKey compositePublicKey = (CompositePublicKey)keyPair.getPublic();
+ CompositePrivateKey compositePrivateKey = (CompositePrivateKey)keyPair.getPrivate();
String firstPublicKeyAlgorithm = compositePublicKey.getPublicKeys().get(0).getAlgorithm().toUpperCase();
String secondPublicKeyAlgorithm = compositePublicKey.getPublicKeys().get(1).getAlgorithm().toUpperCase();
@@ -57,92 +70,94 @@ public void testKeyPairGeneration() throws Exception {
BCRSAPublicKey rsaPublicKey = null;
BCRSAPublicKey rsaPrivateKey = null;
- switch (CompositeSignaturesConstants.ASN1IdentifierCompositeNameMap.get(new ASN1ObjectIdentifier(oid))) {
- case MLDSA44_RSA2048_PSS_SHA256:
- case MLDSA44_RSA2048_PKCS15_SHA256:
- TestCase.assertEquals("DILITHIUM2", firstPublicKeyAlgorithm);
- TestCase.assertEquals("DILITHIUM2", firstPrivateKeyAlgorithm);
- TestCase.assertEquals("RSA", secondPublicKeyAlgorithm);
- TestCase.assertEquals("RSA", secondPrivateKeyAlgorithm);
- rsaPublicKey = (BCRSAPublicKey) compositePublicKey.getPublicKeys().get(1);
- rsaPrivateKey = (BCRSAPublicKey) compositePublicKey.getPublicKeys().get(1);
- TestCase.assertEquals(2048, rsaPublicKey.getModulus().bitLength());
- TestCase.assertEquals(2048, rsaPrivateKey.getModulus().bitLength());
- break;
- case MLDSA44_Ed25519_SHA512:
- TestCase.assertEquals("DILITHIUM2", firstPublicKeyAlgorithm);
- TestCase.assertEquals("DILITHIUM2", firstPrivateKeyAlgorithm);
- TestCase.assertEquals("ED25519", secondPublicKeyAlgorithm);
- TestCase.assertEquals("ED25519", secondPrivateKeyAlgorithm);
- break;
- case MLDSA44_ECDSA_P256_SHA256:
- case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
- TestCase.assertEquals("DILITHIUM2", firstPublicKeyAlgorithm);
- TestCase.assertEquals("DILITHIUM2", firstPrivateKeyAlgorithm);
- TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm);
- TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm);
- break;
- case MLDSA65_RSA3072_PSS_SHA512:
- case MLDSA65_RSA3072_PKCS15_SHA512:
- TestCase.assertEquals("DILITHIUM3", firstPublicKeyAlgorithm);
- TestCase.assertEquals("DILITHIUM3", firstPrivateKeyAlgorithm);
- TestCase.assertEquals("RSA", secondPublicKeyAlgorithm);
- TestCase.assertEquals("RSA", secondPrivateKeyAlgorithm);
- rsaPublicKey = (BCRSAPublicKey) compositePublicKey.getPublicKeys().get(1);
- rsaPrivateKey = (BCRSAPublicKey) compositePublicKey.getPublicKeys().get(1);
- TestCase.assertEquals(3072, rsaPublicKey.getModulus().bitLength());
- TestCase.assertEquals(3072, rsaPrivateKey.getModulus().bitLength());
- break;
- case MLDSA65_Ed25519_SHA512:
- TestCase.assertEquals("DILITHIUM3", firstPublicKeyAlgorithm);
- TestCase.assertEquals("DILITHIUM3", firstPrivateKeyAlgorithm);
- TestCase.assertEquals("ED25519", secondPublicKeyAlgorithm);
- TestCase.assertEquals("ED25519", secondPrivateKeyAlgorithm);
- break;
- case MLDSA65_ECDSA_P256_SHA512:
- case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
- TestCase.assertEquals("DILITHIUM3", firstPublicKeyAlgorithm);
- TestCase.assertEquals("DILITHIUM3", firstPrivateKeyAlgorithm);
- TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm);
- TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm);
- break;
- case MLDSA87_Ed448_SHA512:
- TestCase.assertEquals("DILITHIUM5", firstPublicKeyAlgorithm);
- TestCase.assertEquals("DILITHIUM5", firstPrivateKeyAlgorithm);
- TestCase.assertEquals("ED448", secondPublicKeyAlgorithm);
- TestCase.assertEquals("ED448", secondPrivateKeyAlgorithm);
- break;
- case MLDSA87_ECDSA_P384_SHA512:
- case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
- TestCase.assertEquals("DILITHIUM5", firstPublicKeyAlgorithm);
- TestCase.assertEquals("DILITHIUM5", firstPrivateKeyAlgorithm);
- TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm);
- TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm);
- break;
- case Falcon512_Ed25519_SHA512:
- TestCase.assertEquals("FALCON-512", firstPublicKeyAlgorithm);
- TestCase.assertEquals("FALCON-512", firstPrivateKeyAlgorithm);
- TestCase.assertEquals("ED25519", secondPublicKeyAlgorithm);
- TestCase.assertEquals("ED25519", secondPrivateKeyAlgorithm);
- break;
- case Falcon512_ECDSA_P256_SHA256:
- case Falcon512_ECDSA_brainpoolP256r1_SHA256:
- TestCase.assertEquals("FALCON-512", firstPublicKeyAlgorithm);
- TestCase.assertEquals("FALCON-512", firstPrivateKeyAlgorithm);
- TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm);
- TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm);
- break;
- default:
- throw new IllegalStateException(
- "Unexpected key algorithm." + CompositeSignaturesConstants.ASN1IdentifierCompositeNameMap.get(new ASN1ObjectIdentifier(oid)));
+ switch (CompositeSignaturesConstants.ASN1IdentifierCompositeNameMap.get(new ASN1ObjectIdentifier(oid)))
+ {
+ case MLDSA44_RSA2048_PSS_SHA256:
+ case MLDSA44_RSA2048_PKCS15_SHA256:
+ TestCase.assertEquals("DILITHIUM2", firstPublicKeyAlgorithm);
+ TestCase.assertEquals("DILITHIUM2", firstPrivateKeyAlgorithm);
+ TestCase.assertEquals("RSA", secondPublicKeyAlgorithm);
+ TestCase.assertEquals("RSA", secondPrivateKeyAlgorithm);
+ rsaPublicKey = (BCRSAPublicKey)compositePublicKey.getPublicKeys().get(1);
+ rsaPrivateKey = (BCRSAPublicKey)compositePublicKey.getPublicKeys().get(1);
+ TestCase.assertEquals(2048, rsaPublicKey.getModulus().bitLength());
+ TestCase.assertEquals(2048, rsaPrivateKey.getModulus().bitLength());
+ break;
+ case MLDSA44_Ed25519_SHA512:
+ TestCase.assertEquals("DILITHIUM2", firstPublicKeyAlgorithm);
+ TestCase.assertEquals("DILITHIUM2", firstPrivateKeyAlgorithm);
+ TestCase.assertEquals("ED25519", secondPublicKeyAlgorithm);
+ TestCase.assertEquals("ED25519", secondPrivateKeyAlgorithm);
+ break;
+ case MLDSA44_ECDSA_P256_SHA256:
+ case MLDSA44_ECDSA_brainpoolP256r1_SHA256:
+ TestCase.assertEquals("DILITHIUM2", firstPublicKeyAlgorithm);
+ TestCase.assertEquals("DILITHIUM2", firstPrivateKeyAlgorithm);
+ TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm);
+ TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm);
+ break;
+ case MLDSA65_RSA3072_PSS_SHA512:
+ case MLDSA65_RSA3072_PKCS15_SHA512:
+ TestCase.assertEquals("DILITHIUM3", firstPublicKeyAlgorithm);
+ TestCase.assertEquals("DILITHIUM3", firstPrivateKeyAlgorithm);
+ TestCase.assertEquals("RSA", secondPublicKeyAlgorithm);
+ TestCase.assertEquals("RSA", secondPrivateKeyAlgorithm);
+ rsaPublicKey = (BCRSAPublicKey)compositePublicKey.getPublicKeys().get(1);
+ rsaPrivateKey = (BCRSAPublicKey)compositePublicKey.getPublicKeys().get(1);
+ TestCase.assertEquals(3072, rsaPublicKey.getModulus().bitLength());
+ TestCase.assertEquals(3072, rsaPrivateKey.getModulus().bitLength());
+ break;
+ case MLDSA65_Ed25519_SHA512:
+ TestCase.assertEquals("DILITHIUM3", firstPublicKeyAlgorithm);
+ TestCase.assertEquals("DILITHIUM3", firstPrivateKeyAlgorithm);
+ TestCase.assertEquals("ED25519", secondPublicKeyAlgorithm);
+ TestCase.assertEquals("ED25519", secondPrivateKeyAlgorithm);
+ break;
+ case MLDSA65_ECDSA_P256_SHA512:
+ case MLDSA65_ECDSA_brainpoolP256r1_SHA512:
+ TestCase.assertEquals("DILITHIUM3", firstPublicKeyAlgorithm);
+ TestCase.assertEquals("DILITHIUM3", firstPrivateKeyAlgorithm);
+ TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm);
+ TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm);
+ break;
+ case MLDSA87_Ed448_SHA512:
+ TestCase.assertEquals("DILITHIUM5", firstPublicKeyAlgorithm);
+ TestCase.assertEquals("DILITHIUM5", firstPrivateKeyAlgorithm);
+ TestCase.assertEquals("ED448", secondPublicKeyAlgorithm);
+ TestCase.assertEquals("ED448", secondPrivateKeyAlgorithm);
+ break;
+ case MLDSA87_ECDSA_P384_SHA512:
+ case MLDSA87_ECDSA_brainpoolP384r1_SHA512:
+ TestCase.assertEquals("DILITHIUM5", firstPublicKeyAlgorithm);
+ TestCase.assertEquals("DILITHIUM5", firstPrivateKeyAlgorithm);
+ TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm);
+ TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm);
+ break;
+ case Falcon512_Ed25519_SHA512:
+ TestCase.assertEquals("FALCON-512", firstPublicKeyAlgorithm);
+ TestCase.assertEquals("FALCON-512", firstPrivateKeyAlgorithm);
+ TestCase.assertEquals("ED25519", secondPublicKeyAlgorithm);
+ TestCase.assertEquals("ED25519", secondPrivateKeyAlgorithm);
+ break;
+ case Falcon512_ECDSA_P256_SHA256:
+ case Falcon512_ECDSA_brainpoolP256r1_SHA256:
+ TestCase.assertEquals("FALCON-512", firstPublicKeyAlgorithm);
+ TestCase.assertEquals("FALCON-512", firstPrivateKeyAlgorithm);
+ TestCase.assertEquals("ECDSA", secondPublicKeyAlgorithm);
+ TestCase.assertEquals("ECDSA", secondPrivateKeyAlgorithm);
+ break;
+ default:
+ throw new IllegalStateException(
+ "Unexpected key algorithm." + CompositeSignaturesConstants.ASN1IdentifierCompositeNameMap.get(new ASN1ObjectIdentifier(oid)));
}
}
}
- public void testSigningAndVerificationInternal() throws Exception {
- Security.addProvider(new BouncyCastleProvider());
-
- for (String oid : compositeSignaturesOIDs) {
+ public void testSigningAndVerificationInternal()
+ throws Exception
+ {
+ for (String oid : compositeSignaturesOIDs)
+ {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(oid, "BC");
KeyPair keyPair = keyPairGenerator.generateKeyPair();
Signature signature = Signature.getInstance(oid, "BC");
@@ -156,21 +171,24 @@ public void testSigningAndVerificationInternal() throws Exception {
}
}
- public void testDecodingAndVerificationExternal() throws Exception {
- Security.addProvider(new BouncyCastleProvider());
-
- InputStream is = this.getClass().getResourceAsStream("compositeSignatures.sample");
+ public void testDecodingAndVerificationExternal()
+ throws Exception
+ {
+ InputStream is = TestResourceFinder.findTestResource("pqc/composite", "compositeSignatures.sample");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
int count = 0;
- while((line = reader.readLine()) != null) {
- if (line.isEmpty()) {
+ while ((line = reader.readLine()) != null)
+ {
+ if (line.isEmpty())
+ {
continue;
}
String[] lineParts = line.split(";");
- if (lineParts.length != 4) {
+ if (lineParts.length != 4)
+ {
throw new IllegalStateException("Input file has unexpected format.");
}
String oid = lineParts[0];
@@ -180,7 +198,7 @@ public void testDecodingAndVerificationExternal() throws Exception {
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(Base64.decode(publicKeyBase64));
KeyFactory keyFactory = KeyFactory.getInstance(oid, "BC");
- CompositePublicKey compositePublicKey = (CompositePublicKey) keyFactory.generatePublic(pubKeySpec);
+ CompositePublicKey compositePublicKey = (CompositePublicKey)keyFactory.generatePublic(pubKeySpec);
Signature signature = Signature.getInstance(oid, "BC");
signature.initVerify(compositePublicKey);
From 2adbe3dadfb962d3fa7399d5b2499014ebd293ab Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 18:41:14 +1100
Subject: [PATCH 0165/1846] Initial cut of RFC 9215 for GOST-3410 relates to
github #1586
---
.../GOST3410PublicKeyAlgParameters.java | 27 +++-
.../org/bouncycastle/cms/test/AllTests.java | 2 +
...STR3410_2012_256CmsSignVerifyDetached.java | 153 ++++++++++++++++++
.../jce/spec/GOST3410ParameterSpec.java | 9 +-
4 files changed, 187 insertions(+), 4 deletions(-)
create mode 100644 pkix/src/test/java/org/bouncycastle/cms/test/GOSTR3410_2012_256CmsSignVerifyDetached.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java
index 560cb4adca..18c6d2f56d 100644
--- a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java
+++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java
@@ -7,6 +7,7 @@
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERSequence;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
public class GOST3410PublicKeyAlgParameters
extends ASN1Object
@@ -60,8 +61,24 @@ public GOST3410PublicKeyAlgParameters(
private GOST3410PublicKeyAlgParameters(
ASN1Sequence seq)
{
- this.publicKeyParamSet = (ASN1ObjectIdentifier)seq.getObjectAt(0);
- this.digestParamSet = (ASN1ObjectIdentifier)seq.getObjectAt(1);
+ this.publicKeyParamSet = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
+
+ if (publicKeyParamSet.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetA))
+ {
+ if (seq.size() > 1)
+ {
+ digestParamSet = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(1));
+ }
+ }
+ else if (publicKeyParamSet.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetB)
+ || publicKeyParamSet.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetC)
+ || publicKeyParamSet.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetD))
+ {
+ if (seq.size() > 1)
+ {
+ throw new IllegalArgumentException("digestParamSet expected to be absent");
+ }
+ }
if (seq.size() > 2)
{
@@ -89,7 +106,11 @@ public ASN1Primitive toASN1Primitive()
ASN1EncodableVector v = new ASN1EncodableVector(3);
v.add(publicKeyParamSet);
- v.add(digestParamSet);
+
+ if (digestParamSet != null)
+ {
+ v.add(digestParamSet);
+ }
if (encryptionParamSet != null)
{
diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/AllTests.java b/pkix/src/test/java/org/bouncycastle/cms/test/AllTests.java
index 8cb1b712bc..edc7aff46d 100644
--- a/pkix/src/test/java/org/bouncycastle/cms/test/AllTests.java
+++ b/pkix/src/test/java/org/bouncycastle/cms/test/AllTests.java
@@ -39,6 +39,8 @@ public static Test suite()
suite.addTest(BcSignedDataTest.suite());
suite.addTest(CMSAuthEnvelopedDataStreamGeneratorTest.suite());
suite.addTest(InputStreamWithMACTest.suite());
+
+ suite.addTest(new CMSTestSetup(new TestSuite(GOSTR3410_2012_256CmsSignVerifyDetached.class)));
try
{
diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/GOSTR3410_2012_256CmsSignVerifyDetached.java b/pkix/src/test/java/org/bouncycastle/cms/test/GOSTR3410_2012_256CmsSignVerifyDetached.java
new file mode 100644
index 0000000000..fb75c25bfe
--- /dev/null
+++ b/pkix/src/test/java/org/bouncycastle/cms/test/GOSTR3410_2012_256CmsSignVerifyDetached.java
@@ -0,0 +1,153 @@
+package org.bouncycastle.cms.test;
+
+import java.security.Security;
+import java.security.cert.CertPathBuilder;
+import java.security.cert.CertificateException;
+import java.security.cert.PKIXBuilderParameters;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.jcajce.JcaCertStoreBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
+import org.bouncycastle.cms.CMSException;
+import org.bouncycastle.cms.CMSProcessableByteArray;
+import org.bouncycastle.cms.CMSSignedData;
+import org.bouncycastle.cms.SignerInformation;
+import org.bouncycastle.cms.SignerInformationStore;
+import org.bouncycastle.cms.SignerInformationVerifier;
+import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.Store;
+
+public class GOSTR3410_2012_256CmsSignVerifyDetached
+ extends TestCase
+{
+ /**
+ * Test GOST 2012-256 signature with id-tc26-gost-3410-2012-256-paramSetB key parameters generated by
+ * rtpkcs11ecp library.
+ */
+ private static final String SIGNATURE = "MIIDDAYJKoZIhvcNAQcCoIIC/TCCAvkCAQExDDAKBggqhQMHAQECAjALBgkqhkiG9w0BBwGgggGTMIIB" +
+ "jzCCATygAwIBAgIVANpDv+oXKyFqD3f8s/iV0sgLZxMuMAoGCCqFAwcBAQMCMCsxCzAJBgNVBAYTAlJV" +
+ "MQswCQYDVQQDDAJDQTEPMA0GA1UECAwGTW9zY293MB4XDTI0MDIwNzEyNTIwMFoXDTI1MDIwNzEyNTIw" +
+ "MFowZTEQMA4GA1UEAwwHSXZhbm9mZjELMAkGA1UEBhMCUlUxFDASBgNVBAUTCzEyMzEyMzEyMzEyMR0w" +
+ "GwYJKoZIhvcNAQkBFg5pdmFub3ZAbWFpbC5ydTEPMA0GA1UECAwGTW9zY293MF4wFwYIKoUDBwEBAQEw" +
+ "CwYJKoUDBwECAQECA0MABEC8jIpHpWxBuYhMdgbly1RJR0ECHcL1SMklZX3u5TNdOjs66n8U5y9nt5vR" +
+ "KGdvecbPo5cYIlEojrprtlDuALjsMAoGCCqFAwcBAQMCA0EAAJvuewDPWkDfDFEC0L/o+6BipHCcz0Qg" +
+ "Mr4TU7XRXKcVkxVD8SjIc4SaWL/f/htpNIdvP91EeYDlFoOwNqDhHDGCAUAwggE8AgEBMEQwKzELMAkG" +
+ "A1UEBhMCUlUxCzAJBgNVBAMMAkNBMQ8wDQYDVQQIDAZNb3Njb3cCFQDaQ7/qFyshag93/LP4ldLIC2cT" +
+ "LjAKBggqhQMHAQECAqCBlDAYBgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0y" +
+ "NDAyMDcxMjUyMDBaMCkGCSqGSIb3DQEJNDEcMBowCgYIKoUDBwEBAgKhDAYIKoUDBwEBAQEFADAvBgkq" +
+ "hkiG9w0BCQQxIgQg7A98XV1Tkli/l3PXrT/6cGLM/m8odS26UHEGHEPBYgMwDAYIKoUDBwEBAQEFAARA" +
+ "CcueaEjcNVIccepoDiU9aCbHPPF7A3zGw90Zl11T9ITBH4jNOMi4IGVn90ANgiinwKIuiu9mWMk9Y/mc" +
+ "jcCkQw==";
+
+ /**
+ * Expires in 2045.
+ */
+ private static final String CA_CERTIFICATE = "MIIBTzCB+wIJAMGuFHcbok4sMAwGCCqFAwcBAQMCBQAwKzELMAkGA1UEBhMCUlUx"
+ + "CzAJBgNVBAMMAkNBMQ8wDQYDVQQIDAZNb3Njb3cwHhcNMTgwNjA2MTAyNzA4WhcN"
+ + "NDUxMDIyMTAyNzA4WjArMQswCQYDVQQGEwJSVTELMAkGA1UEAwwCQ0ExDzANBgNV"
+ + "BAgMBk1vc2NvdzBmMB8GCCqFAwcBAQEBMBMGByqFAwICIwEGCCqFAwcBAQICA0MA"
+ + "BECM6iQnPgDs6K2jmUVLHf4V63xwO2j4vO2X2kNQVELu2bROK+wBaNWkTX5TW+IO"
+ + "9gLZFioYMSEK2LxsIO3Zf+JeMAwGCCqFAwcBAQMCBQADQQATx6Ksy1KUuvfa2q8X"
+ + "kfo3pDN1x1aGo4AmQolzEpbXvzbyMy3vk+VOqegdd8KP4E3x43zaTmHmnu/G1v20"
+ + "VzwO";
+
+ private static final byte[] SIGNED_DATA = {0x01, 0x02, 0x03};
+
+ public void setUp()
+ throws Exception
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+
+ public void testGost3410_2012_256()
+ throws Exception
+ {
+ byte[] detachedCms = Base64.getDecoder().decode(SIGNATURE);
+ byte[] rootCertificate = Base64.getDecoder().decode(CA_CERTIFICATE);
+ List trustedCertificates = new ArrayList<>();
+ trustedCertificates.add(new X509CertificateHolder(rootCertificate));
+
+ boolean isSignatureValid = verifyDetached(SIGNED_DATA, detachedCms, trustedCertificates);
+
+ Assert.assertTrue(isSignatureValid);
+ }
+
+ private static boolean verifyDetached(byte[] data, byte[] detachedCms,
+ List trustedCertificates)
+ throws CMSException
+ {
+ CMSSignedData cmsSignedData = new CMSSignedData(new CMSProcessableByteArray(data), detachedCms);
+
+ boolean result = false;
+ try
+ {
+ HashSet trustAnchors = new HashSet<>();
+ for (X509CertificateHolder trustedCert : trustedCertificates)
+ {
+ TrustAnchor trustAnchor = new TrustAnchor(getX509Certificate(trustedCert), null);
+ trustAnchors.add(trustAnchor);
+ }
+
+ CertPathBuilder certPathBuilder =
+ CertPathBuilder.getInstance("PKIX", BouncyCastleProvider.PROVIDER_NAME);
+ Store cmsCertStore = cmsSignedData.getCertificates();
+ SignerInformationStore signers = cmsSignedData.getSignerInfos();
+
+ for (SignerInformation signer : signers.getSigners())
+ {
+ Collection signerCertCollection = cmsCertStore.getMatches(signer.getSID());
+
+ for (X509CertificateHolder signerCert : signerCertCollection)
+ {
+ // Validate signer's signature
+ SignerInformationVerifier verifier = new JcaSimpleSignerInfoVerifierBuilder()
+ .setProvider(BouncyCastleProvider.PROVIDER_NAME)
+ .build(signerCert);
+ if (!signer.verify(verifier))
+ {
+ return false;
+ }
+
+ // Validate signer's certificate chain
+ X509CertSelector constraints = new X509CertSelector();
+ constraints.setCertificate(getX509Certificate(signerCert));
+ PKIXBuilderParameters params = new PKIXBuilderParameters(trustAnchors, constraints);
+
+ JcaCertStoreBuilder certStoreBuilder = new JcaCertStoreBuilder();
+ certStoreBuilder.addCertificate(signerCert);
+
+ params.addCertStore(certStoreBuilder.build());
+ params.setRevocationEnabled(false);
+ certPathBuilder.build(params);
+ result = true;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ System.out.println(e.getMessage());
+ e.printStackTrace();
+ result = false;
+ }
+
+ return result;
+ }
+
+ private static X509Certificate getX509Certificate(X509CertificateHolder certificateHolder)
+ throws CertificateException
+ {
+ return new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME)
+ .getCertificate(certificateHolder);
+ }
+}
diff --git a/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java b/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java
index 6e0980db7d..b5657a8823 100644
--- a/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java
+++ b/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java
@@ -127,7 +127,14 @@ public static GOST3410ParameterSpec fromPublicKeyAlg(
}
else
{
- return new GOST3410ParameterSpec(params.getPublicKeyParamSet().getId(), params.getDigestParamSet().getId());
+ if (params.getDigestParamSet() != null)
+ {
+ return new GOST3410ParameterSpec(params.getPublicKeyParamSet().getId(), params.getDigestParamSet().getId());
+ }
+ else
+ {
+ return new GOST3410ParameterSpec(params.getPublicKeyParamSet().getId(), null);
+ }
}
}
}
From 7b3a2bc91d17f4f2dfdcf7073022f507ec170400 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 19:22:11 +1100
Subject: [PATCH 0166/1846] additional work on RFC 9215 parameter restrictions
github #1586
---
...GOSTR3410_2012_256GenerateCertificate.java | 112 ++++++++++++++++++
.../ecgost12/BCECGOST3410_2012PublicKey.java | 39 ++++--
.../ecgost12/KeyPairGeneratorSpi.java | 14 ++-
3 files changed, 156 insertions(+), 9 deletions(-)
create mode 100644 pkix/src/test/java/org/bouncycastle/cert/test/GOSTR3410_2012_256GenerateCertificate.java
diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/GOSTR3410_2012_256GenerateCertificate.java b/pkix/src/test/java/org/bouncycastle/cert/test/GOSTR3410_2012_256GenerateCertificate.java
new file mode 100644
index 0000000000..8ef1842940
--- /dev/null
+++ b/pkix/src/test/java/org/bouncycastle/cert/test/GOSTR3410_2012_256GenerateCertificate.java
@@ -0,0 +1,112 @@
+package org.bouncycastle.cert.test;
+
+import java.math.BigInteger;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.spec.ECGenParameterSpec;
+import java.time.ZonedDateTime;
+import java.util.Date;
+
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.cert.X509CertificateHolder;
+import org.bouncycastle.cert.X509v3CertificateBuilder;
+import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.operator.ContentSigner;
+import org.bouncycastle.operator.OperatorCreationException;
+import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import org.bouncycastle.util.test.SimpleTest;
+
+public class GOSTR3410_2012_256GenerateCertificate
+ extends SimpleTest
+{
+ public static final String PARAMS = "Tc26-Gost-3410-12-256-paramSetB";
+ public static final String SIGNATURE_ALGORITHM = "GOST3411WITHGOST3410-2012-256";
+ private static final String ALGORITHM = "ECGOST3410-2012";
+
+ public String getName()
+ {
+ return "GOSTR3410_2012_256GenerateCertificate";
+ }
+
+ public void performTest()
+ throws Exception
+ {
+ Provider bcProvider = new BouncyCastleProvider();
+ Security.addProvider(bcProvider);
+
+ X509CertificateHolder certificate = generateSelfSignedCertificate();
+
+ ASN1Sequence parameters =
+ (ASN1Sequence)certificate.getSubjectPublicKeyInfo().getAlgorithm().getParameters();
+ isEquals("Expected parameters size: 1, actual: " + parameters.size(), 1, parameters.size());
+ }
+
+ private static X509CertificateHolder generateSelfSignedCertificate()
+ {
+ try
+ {
+ KeyPairGenerator keygen = KeyPairGenerator.getInstance(ALGORITHM, BouncyCastleProvider.PROVIDER_NAME);
+ keygen.initialize(new ECGenParameterSpec(PARAMS));
+
+ KeyPair keyPair = keygen.generateKeyPair();
+
+ X500Name subject = new X500Name("CN=TEST");
+ X500Name issuer = subject;
+ BigInteger serial = BigInteger.ONE;
+ ZonedDateTime notBefore = ZonedDateTime.now();
+ ZonedDateTime notAfter = notBefore.plusYears(1);
+
+ X509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(
+ issuer,
+ serial,
+ Date.from(notBefore.toInstant()),
+ Date.from(notAfter.toInstant()),
+ subject,
+ keyPair.getPublic()
+ );
+ ContentSigner contentSigner =
+ new JcaContentSignerBuilder(SIGNATURE_ALGORITHM).build(keyPair.getPrivate());
+
+ return certificateBuilder.build(contentSigner);
+ }
+ catch (OperatorCreationException e)
+ {
+ System.out.println("Can not create certificate. " + e.getMessage());
+ e.printStackTrace();
+ }
+ catch (NoSuchAlgorithmException e)
+ {
+ System.out.printf("Algorithm %s is not found. %s\n", ALGORITHM, e.getMessage());
+ e.printStackTrace();
+ }
+ catch (InvalidAlgorithmParameterException e)
+ {
+ System.out.printf("Initialization parameter %s is not found for algorithm %s. %s\n", PARAMS, ALGORITHM,
+ e.getMessage());
+ e.printStackTrace();
+ }
+ catch (NoSuchProviderException e)
+ {
+ System.out.printf("Crypto provider BC is not found. %s\n", e.getMessage());
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ public static void main(
+ String[] args)
+ throws Exception
+ {
+ Security.addProvider(new BouncyCastleProvider());
+
+ runTest(new GOSTR3410_2012_256GenerateCertificate());
+ }
+}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java
index f06f96ab81..96cc09aced 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java
@@ -261,17 +261,28 @@ public byte[] getEncoded()
{
if (ecSpec instanceof ECNamedCurveSpec)
{
+ ASN1ObjectIdentifier gostCurveOid = ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName());
if (is512)
{
params = new GOST3410PublicKeyAlgParameters(
- ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
+ gostCurveOid,
RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512);
}
else
{
- params = new GOST3410PublicKeyAlgParameters(
- ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
- RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256);
+ if (gostCurveOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetB)
+ || gostCurveOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetC)
+ || gostCurveOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetD))
+ {
+ // RFC 9215
+ params = new GOST3410PublicKeyAlgParameters(gostCurveOid, null);
+ }
+ else
+ {
+ params = new GOST3410PublicKeyAlgParameters(
+ gostCurveOid,
+ RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256);
+ }
}
}
else
@@ -438,17 +449,29 @@ public GOST3410PublicKeyAlgParameters getGostParams()
// need to detect key size
boolean is512 = (bX.bitLength() > 256);
+ ASN1ObjectIdentifier gostCurveOid = ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName());
if (is512)
{
this.gostParams = new GOST3410PublicKeyAlgParameters(
- ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
+ gostCurveOid,
RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512);
}
else
{
- this.gostParams = new GOST3410PublicKeyAlgParameters(
- ECGOST3410NamedCurves.getOID(((ECNamedCurveSpec)ecSpec).getName()),
- RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256);
+ if (gostCurveOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetB)
+ || gostCurveOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetC)
+ || gostCurveOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetD))
+ {
+ this.gostParams = new GOST3410PublicKeyAlgParameters(
+ gostCurveOid,
+ null);
+ }
+ else
+ {
+ this.gostParams = new GOST3410PublicKeyAlgParameters(
+ gostCurveOid,
+ RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256);
+ }
}
}
return gostParams;
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyPairGeneratorSpi.java
index 4742303f60..3be4e0c159 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyPairGeneratorSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyPairGeneratorSpi.java
@@ -8,6 +8,7 @@
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
@@ -18,6 +19,7 @@
import org.bouncycastle.crypto.params.ECNamedDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.internal.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
import org.bouncycastle.jcajce.spec.GOST3410ParameterSpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -118,7 +120,17 @@ else if (params instanceof ECGenParameterSpec || params instanceof ECNamedCurveG
curveName = ((ECNamedCurveGenParameterSpec)params).getName();
}
- init(new GOST3410ParameterSpec(curveName), random);
+ ASN1ObjectIdentifier curveOid = ECGOST3410NamedCurves.getOID(curveName);
+ if (curveOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetB)
+ || curveOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetC)
+ || curveOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetD))
+ {
+ init(new GOST3410ParameterSpec(ECGOST3410NamedCurves.getOID(curveName), null), random);
+ }
+ else
+ {
+ init(new GOST3410ParameterSpec(curveName), random);
+ }
}
else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() != null)
{
From 98d5c168cac77716d049086c50598b0ec8f5215c Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 21:49:21 +1100
Subject: [PATCH 0167/1846] additional work on RFC 9215 parameter restrictions,
more nulls - github #1586
---
.../provider/asymmetric/gost/BCGOST3410PrivateKey.java | 2 +-
.../org/bouncycastle/jce/spec/GOST3410ParameterSpec.java | 5 +++--
.../org/bouncycastle/jce/provider/test/GOST3410Test.java | 8 ++++----
3 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java
index 8992d5faeb..2fc4dba0b4 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java
@@ -179,7 +179,7 @@ public boolean equals(
return this.getX().equals(other.getX())
&& this.getParameters().getPublicKeyParameters().equals(other.getParameters().getPublicKeyParameters())
- && this.getParameters().getDigestParamSetOID().equals(other.getParameters().getDigestParamSetOID())
+ && compareObj(this.getParameters().getDigestParamSetOID(), other.getParameters().getDigestParamSetOID())
&& compareObj(this.getParameters().getEncryptionParamSetOID(), other.getParameters().getEncryptionParamSetOID());
}
diff --git a/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java b/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java
index b5657a8823..ba2bd01965 100644
--- a/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java
+++ b/prov/src/main/java/org/bouncycastle/jce/spec/GOST3410ParameterSpec.java
@@ -103,8 +103,9 @@ public boolean equals(Object o)
{
GOST3410ParameterSpec other = (GOST3410ParameterSpec)o;
- return this.keyParameters.equals(other.keyParameters)
- && this.digestParamSetOID.equals(other.digestParamSetOID)
+ return this.keyParameters.equals(other.keyParameters)
+ && (this.digestParamSetOID == other.digestParamSetOID
+ || (this.digestParamSetOID != null && this.digestParamSetOID.equals(other.digestParamSetOID)))
&& (this.encryptionParamSetOID == other.encryptionParamSetOID
|| (this.encryptionParamSetOID != null && this.encryptionParamSetOID.equals(other.encryptionParamSetOID)));
}
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java
index c22deda20d..c875e20e54 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/GOST3410Test.java
@@ -491,7 +491,7 @@ private void ecGOST2012NameCurveGenerationTest()
kp = kpGen.generateKeyPair();
expectedAlgId = new AlgorithmIdentifier(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256,
- new GOST3410PublicKeyAlgParameters(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetB, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256));
+ new GOST3410PublicKeyAlgParameters(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetB, null));
checkKeyPairAlgId(kp, expectedAlgId);
@@ -500,7 +500,7 @@ private void ecGOST2012NameCurveGenerationTest()
kp = kpGen.generateKeyPair();
expectedAlgId = new AlgorithmIdentifier(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256,
- new GOST3410PublicKeyAlgParameters(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetC, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256));
+ new GOST3410PublicKeyAlgParameters(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetC, null));
checkKeyPairAlgId(kp, expectedAlgId);
@@ -509,7 +509,7 @@ private void ecGOST2012NameCurveGenerationTest()
kp = kpGen.generateKeyPair();
expectedAlgId = new AlgorithmIdentifier(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256,
- new GOST3410PublicKeyAlgParameters(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetD, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256));
+ new GOST3410PublicKeyAlgParameters(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetD, null));
checkKeyPairAlgId(kp, expectedAlgId);
@@ -899,7 +899,7 @@ public void performTest()
ecGOST2012VerifyTest("ECGOST3410-2012-256", ecgostData, ecgost2012_256Key, ecgost2012_256Sig);
ecGOST2012VerifyTest("ECGOST3410-2012-512", ecgostData, ecgost2012_512Key, ecgost2012_512Sig);
}
-
+
generationTest();
parametersTest();
}
From d3d90740528d107ca22456b7c70cbccd38a03053 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 21:58:08 +1100
Subject: [PATCH 0168/1846] additional work on RFC 9215 parameter restrictions,
capturing reduced sequence size - github #1586
---
.../asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java
index 2c80490e48..64e44d96da 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java
@@ -200,7 +200,8 @@ private void populateFromPrivKeyInfo(PrivateKeyInfo info)
{
ASN1Primitive p = info.getPrivateKeyAlgorithm().getParameters().toASN1Primitive();
- if (p instanceof ASN1Sequence && (ASN1Sequence.getInstance(p).size() == 2 || ASN1Sequence.getInstance(p).size() == 3))
+ if (p instanceof ASN1Sequence &&
+ (ASN1Sequence.getInstance(p).size() <= 3))
{
gostParams = GOST3410PublicKeyAlgParameters.getInstance(info.getPrivateKeyAlgorithm().getParameters());
From 212cce1350bf5af0da7f70a1023471121b835354 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 22:36:42 +1100
Subject: [PATCH 0169/1846] added setting of digestParam for old GOST params
---
.../asn1/cryptopro/GOST3410PublicKeyAlgParameters.java | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java
index 18c6d2f56d..f593fb21e1 100644
--- a/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java
+++ b/core/src/main/java/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java
@@ -79,6 +79,13 @@ else if (publicKeyParamSet.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410
throw new IllegalArgumentException("digestParamSet expected to be absent");
}
}
+ else
+ {
+ if (seq.size() > 1)
+ {
+ digestParamSet = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(1));
+ }
+ }
if (seq.size() > 2)
{
From 2958d6ef4c4f6e853ad19ef8614f5155d535a52a Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 16 Mar 2024 22:36:49 +1100
Subject: [PATCH 0170/1846] minor cleanup
---
.../bouncycastle/jcajce/provider/test/CompositeKeyTest.java | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeKeyTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeKeyTest.java
index 00b29ba82e..75d7a41762 100644
--- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeKeyTest.java
+++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeKeyTest.java
@@ -6,8 +6,6 @@
import java.security.spec.X509EncodedKeySpec;
import junit.framework.TestCase;
-import org.bouncycastle.asn1.ASN1Primitive;
-import org.bouncycastle.asn1.util.ASN1Dump;
import org.bouncycastle.jcajce.CompositePrivateKey;
import org.bouncycastle.jcajce.CompositePublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
@@ -112,7 +110,7 @@ public void testGenericCompositeKey()
KeyFactory keyFact = KeyFactory.getInstance("COMPOSITE", "BC");
CompositePublicKey compPubKey = (CompositePublicKey)keyFact.generatePublic(new X509EncodedKeySpec(genPubKey));
- System.err.println(ASN1Dump.dumpAsString(ASN1Primitive.fromByteArray(genPrivKey))) ;
+
CompositePrivateKey compPrivKey = (CompositePrivateKey)keyFact.generatePrivate(new PKCS8EncodedKeySpec(genPrivKey));
}
From 506875ab8dea5f631754fcfa27ec61489f27b4d6 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sun, 17 Mar 2024 13:13:02 +1100
Subject: [PATCH 0171/1846] removed external dependency on provider composite
name class standardised names to RFC draft.
---
...ultSignatureAlgorithmIdentifierFinder.java | 23 +++++--
.../org/bouncycastle/cert/test/CertTest.java | 65 +++++++++++-------
.../jcajce/CompositePrivateKey.java | 18 ++---
.../jcajce/CompositePublicKey.java | 18 ++---
.../asymmetric/CompositeSignatures.java | 20 +++---
.../CompositeSignaturesConstants.java | 58 ++++++++--------
.../KeyPairGeneratorSpi.java | 64 +++++++++---------
.../compositesignatures/SignatureSpi.java | 66 +++++++++----------
8 files changed, 181 insertions(+), 151 deletions(-)
diff --git a/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
index f84765042b..977d1a25fb 100644
--- a/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
+++ b/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
@@ -26,7 +26,6 @@
import org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeSignaturesConstants;
import org.bouncycastle.util.Strings;
public class DefaultSignatureAlgorithmIdentifierFinder
@@ -235,12 +234,22 @@ public class DefaultSignatureAlgorithmIdentifierFinder
algorithms.put("SHA3-512WITHPICNIC", BCObjectIdentifiers.picnic_with_sha3_512);
algorithms.put("SHAKE256WITHPICNIC", BCObjectIdentifiers.picnic_with_shake256);
- //Load composite signatures
- for (ASN1ObjectIdentifier oid : CompositeSignaturesConstants.supportedIdentifiers)
- {
- algorithms.put(CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(oid).toUpperCase(), oid);
- algorithms.put(oid.toString(), oid);
- }
+ algorithms.put("MLDSA44-RSA2048-PSS-SHA256", MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256);
+ algorithms.put("MLDSA44-RSA2048-PKCS15-SHA256", MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256);
+ algorithms.put("MLDSA44-ECDSA-P256-SHA256", MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256);
+ algorithms.put("MLDSA44-ECDSA-BRAINPOOLP256R1-SHA256", MiscObjectIdentifiers.id_MLDSA44_ECDSA_brainpoolP256r1_SHA256);
+ algorithms.put("MLDSA44-ED25519-SHA512", MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512);
+ algorithms.put("MLDSA65-RSA3072-PSS-SHA512", MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512);
+ algorithms.put("MLDSA65-RSA3072-PKCS15-SHA512", MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512);
+ algorithms.put("MLDSA65-ECDSA-BRAINPOOLP256R1-SHA512", MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512);
+ algorithms.put("MLDSA65-ECDSA-P256-SHA512", MiscObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512);
+ algorithms.put("MLDSA65-ED25519-SHA512", MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512);
+ algorithms.put("MLDSA87-ECDSA-P384-SHA512", MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512);
+ algorithms.put("MLDSA87-ECDSA-BRAINPOOLP384R1-SHA512", MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512);
+ algorithms.put("MLDSA87-ED448-SHA512", MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512);
+ algorithms.put("FALCON512-ECDSA-P256-SHA256", MiscObjectIdentifiers.id_Falcon512_ECDSA_P256_SHA256);
+ algorithms.put("FALCON512-ECDSA-BRAINPOOLP256R1-SHA256", MiscObjectIdentifiers.id_Falcon512_ECDSA_brainpoolP256r1_SHA256);
+ algorithms.put("FALCON512-ED25519-SHA512", MiscObjectIdentifiers.id_Falcon512_Ed25519_SHA512);
//
// According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java b/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java
index aef7a297ef..87b8eb99f7 100644
--- a/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java
+++ b/pkix/src/test/java/org/bouncycastle/cert/test/CertTest.java
@@ -1367,8 +1367,6 @@ public void checkCertificate(
Certificate cert = fact.generateCertificate(bIn);
PublicKey k = cert.getPublicKey();
-// System.out.println("****** " + id + " ******");
-// System.out.println(cert);
}
catch (Exception e)
{
@@ -5426,29 +5424,49 @@ private void checkSerialisation()
// TESTS REGARDING COMPOSITES https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html
private static String[] compositeSignaturesOIDs = {
- "2.16.840.1.114027.80.8.1.1", //id-MLDSA44-RSA2048-PSS-SHA256
- "2.16.840.1.114027.80.8.1.2", //id-MLDSA44-RSA2048-PKCS15-SHA256
- "2.16.840.1.114027.80.8.1.3", //id-MLDSA44-Ed25519-SHA512
- "2.16.840.1.114027.80.8.1.4", //id-MLDSA44-ECDSA-P256-SHA256
- "2.16.840.1.114027.80.8.1.5", //id-MLDSA44-ECDSA-brainpoolP256r1-SHA256
- "2.16.840.1.114027.80.8.1.6", //id-MLDSA65-RSA3072-PSS-SHA512
- "2.16.840.1.114027.80.8.1.7", //id-MLDSA65-RSA3072-PKCS15-SHA512
- "2.16.840.1.114027.80.8.1.8", //id-MLDSA65-ECDSA-P256-SHA512
- "2.16.840.1.114027.80.8.1.9", //id-MLDSA65-ECDSA-brainpoolP256r1-SHA512
- "2.16.840.1.114027.80.8.1.10", //id-MLDSA65-Ed25519-SHA512
- "2.16.840.1.114027.80.8.1.11", //id-MLDSA87-ECDSA-P384-SHA512
- "2.16.840.1.114027.80.8.1.12", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512
- "2.16.840.1.114027.80.8.1.13", //id-MLDSA87-Ed448-SHA512
- // Falcon composites below were excluded from the draft. See MiscObjectIdentifiers for details.
- "2.16.840.1.114027.80.8.1.14", //id-Falcon512-ECDSA-P256-SHA256
- "2.16.840.1.114027.80.8.1.15", //id-Falcon512-ECDSA-brainpoolP256r1-SHA256
- "2.16.840.1.114027.80.8.1.16", //id-Falcon512-Ed25519-SHA512
+ "2.16.840.1.114027.80.8.1.1", //id-MLDSA44-RSA2048-PSS-SHA256
+ "2.16.840.1.114027.80.8.1.2", //id-MLDSA44-RSA2048-PKCS15-SHA256
+ "2.16.840.1.114027.80.8.1.3", //id-MLDSA44-Ed25519-SHA512
+ "2.16.840.1.114027.80.8.1.4", //id-MLDSA44-ECDSA-P256-SHA256
+ "2.16.840.1.114027.80.8.1.5", //id-MLDSA44-ECDSA-brainpoolP256r1-SHA256
+ "2.16.840.1.114027.80.8.1.6", //id-MLDSA65-RSA3072-PSS-SHA512
+ "2.16.840.1.114027.80.8.1.7", //id-MLDSA65-RSA3072-PKCS15-SHA512
+ "2.16.840.1.114027.80.8.1.8", //id-MLDSA65-ECDSA-P256-SHA512
+ "2.16.840.1.114027.80.8.1.9", //id-MLDSA65-ECDSA-brainpoolP256r1-SHA512
+ "2.16.840.1.114027.80.8.1.10", //id-MLDSA65-Ed25519-SHA512
+ "2.16.840.1.114027.80.8.1.11", //id-MLDSA87-ECDSA-P384-SHA512
+ "2.16.840.1.114027.80.8.1.12", //id-MLDSA87-ECDSA-brainpoolP384r1-SHA512
+ "2.16.840.1.114027.80.8.1.13", //id-MLDSA87-Ed448-SHA512
+ // Falcon composites below were excluded from the draft. See MiscObjectIdentifiers for details.
+ "2.16.840.1.114027.80.8.1.14", //id-Falcon512-ECDSA-P256-SHA256
+ "2.16.840.1.114027.80.8.1.15", //id-Falcon512-ECDSA-brainpoolP256r1-SHA256
+ "2.16.840.1.114027.80.8.1.16", //id-Falcon512-Ed25519-SHA512
+ };
+
+ private static String[] compositeSignaturesIDs = {
+ "MLDSA44-RSA2048-PSS-SHA256",
+ "MLDSA44-RSA2048-PKCS15-SHA256",
+ "MLDSA44-ED25519-SHA512",
+ "MLDSA44-ECDSA-P256-SHA256",
+ "MLDSA44-ECDSA-BRAINPOOLP256R1-SHA256",
+ "MLDSA65-RSA3072-PSS-SHA512",
+ "MLDSA65-RSA3072-PKCS15-SHA512",
+ "MLDSA65-ECDSA-P256-SHA512",
+ "MLDSA65-ECDSA-BRAINPOOLP256R1-SHA512",
+ "MLDSA65-ED25519-SHA512",
+ "MLDSA87-ECDSA-P384-SHA512",
+ "MLDSA87-ECDSA-BRAINPOOLP384R1-SHA512",
+ "MLDSA87-ED448-SHA512",
+ "FALCON512-ECDSA-P256-SHA256",
+ "FALCON512-ECDSA-BRAINPOOLP256R1-SHA256",
+ "FALCON512-ED25519-SHA512"
};
private void checkCompositeSignatureCertificateCreation()
{
try
{
+ int index = 0;
for (String oid : compositeSignaturesOIDs)
{
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(oid, "BC");
@@ -5462,22 +5480,23 @@ private void checkCompositeSignatureCertificateCreation()
X500Name subject = new X500Name(subjectName);
JcaX509v3CertificateBuilder certificateBuilder = new JcaX509v3CertificateBuilder(issuer, serial, notBefore, notAfter, subject, keyPair.getPublic());
- X509CertificateHolder certHolder = certificateBuilder.build(new JcaContentSignerBuilder(oid).build(keyPair.getPrivate()));
+ X509CertificateHolder certHolder = certificateBuilder.build(new JcaContentSignerBuilder(compositeSignaturesIDs[index]).build(keyPair.getPrivate()));
X509Certificate cert = new JcaX509CertificateConverter().setProvider("BC").getCertificate(certHolder);
isEquals(oid, cert.getSigAlgOID());
CompositePublicKey compositePublicKey = (CompositePublicKey)cert.getPublicKey();
- isEquals(CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(new ASN1ObjectIdentifier(oid)), compositePublicKey.getAlgorithm());
+ isEquals(CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(new ASN1ObjectIdentifier(oid)).getId(), compositePublicKey.getAlgorithm());
+
isEquals(subjectName, cert.getSubjectX500Principal().getName());
cert.verify(cert.getPublicKey());
-
+ index++;
}
}
catch (NoSuchAlgorithmException | NoSuchProviderException | CertificateException | OperatorCreationException |
SignatureException | InvalidKeyException | TestFailedException e)
- {
+ { e.printStackTrace();
fail("checkCompositeSignatureCertificateCreation failed: " + e.getMessage());
}
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
index 6f616ded19..65788feb76 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
@@ -1,23 +1,23 @@
package org.bouncycastle.jcajce;
+import java.io.IOException;
+import java.security.PrivateKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeSignaturesConstants;
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.KeyFactorySpi;
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
-import java.io.IOException;
-import java.security.PrivateKey;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
/**
* A composite private key class.
*/
@@ -107,7 +107,7 @@ public List getPrivateKeys()
public String getAlgorithm()
{
- return CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(this.algorithmIdentifier);
+ return CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(this.algorithmIdentifier).getId();
}
public ASN1ObjectIdentifier getAlgorithmIdentifier()
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
index 4ec08674fe..ea26b64961 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
@@ -1,23 +1,23 @@
package org.bouncycastle.jcajce;
+import java.io.IOException;
+import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERSequence;
-import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeSignaturesConstants;
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.KeyFactorySpi;
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
-import java.io.IOException;
-import java.security.PublicKey;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
/**
* A composite key class.
*/
@@ -108,7 +108,7 @@ public List getPublicKeys()
public String getAlgorithm()
{
- return CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(this.algorithmIdentifier);
+ return CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(this.algorithmIdentifier).getId();
}
public ASN1ObjectIdentifier getAlgorithmIdentifier()
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java
index 00563d06f1..93c635901c 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java
@@ -1,14 +1,14 @@
package org.bouncycastle.jcajce.provider.asymmetric;
+import java.util.HashMap;
+import java.util.Map;
+
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeSignaturesConstants;
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.KeyFactorySpi;
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
-import java.util.HashMap;
-import java.util.Map;
-
/**
* Experimental implementation of composite signatures according to https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.
*/
@@ -35,15 +35,15 @@ public void configure(ConfigurableProvider provider)
{
for (ASN1ObjectIdentifier oid : CompositeSignaturesConstants.supportedIdentifiers)
{
- String algName = CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(oid);
- provider.addAlgorithm("KeyFactory." + algName, PREFIX + "KeyFactorySpi"); //Key factory is the same for all composite signatures.
- provider.addAlgorithm("Alg.Alias.KeyFactory", oid, algName);
+ CompositeSignaturesConstants.CompositeName algName = CompositeSignaturesConstants.ASN1IdentifierAlgorithmNameMap.get(oid);
+ provider.addAlgorithm("KeyFactory." + algName.getId(), PREFIX + "KeyFactorySpi"); //Key factory is the same for all composite signatures.
+ provider.addAlgorithm("Alg.Alias.KeyFactory", oid, algName.getId());
- provider.addAlgorithm("KeyPairGenerator." + algName, PREFIX + "KeyPairGeneratorSpi$" + algName);
- provider.addAlgorithm("Alg.Alias.KeyPairGenerator", oid, algName);
+ provider.addAlgorithm("KeyPairGenerator." + algName.getId(), PREFIX + "KeyPairGeneratorSpi$" + algName);
+ provider.addAlgorithm("Alg.Alias.KeyPairGenerator", oid, algName.getId());
- provider.addAlgorithm("Signature." + algName, PREFIX + "SignatureSpi$" + algName);
- provider.addAlgorithm("Alg.Alias.Signature", oid, algName);
+ provider.addAlgorithm("Signature." + algName.getId(), PREFIX + "SignatureSpi$" + algName);
+ provider.addAlgorithm("Alg.Alias.Signature", oid, algName.getId());
provider.addKeyInfoConverter(oid, new KeyFactorySpi());
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java
index ace19ae7c0..430a0d145f 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java
@@ -40,22 +40,34 @@ public abstract class CompositeSignaturesConstants
*/
public enum CompositeName
{
- MLDSA44_RSA2048_PSS_SHA256,
- MLDSA44_RSA2048_PKCS15_SHA256,
- MLDSA44_ECDSA_P256_SHA256,
- MLDSA44_ECDSA_brainpoolP256r1_SHA256,
- MLDSA44_Ed25519_SHA512,
- MLDSA65_RSA3072_PSS_SHA512,
- MLDSA65_RSA3072_PKCS15_SHA512,
- MLDSA65_ECDSA_brainpoolP256r1_SHA512,
- MLDSA65_ECDSA_P256_SHA512,
- MLDSA65_Ed25519_SHA512,
- MLDSA87_ECDSA_P384_SHA512,
- MLDSA87_ECDSA_brainpoolP384r1_SHA512,
- MLDSA87_Ed448_SHA512,
- Falcon512_ECDSA_P256_SHA256,
- Falcon512_ECDSA_brainpoolP256r1_SHA256,
- Falcon512_Ed25519_SHA512,
+ MLDSA44_RSA2048_PSS_SHA256("MLDSA44-RSA2048-PSS-SHA256"),
+ MLDSA44_RSA2048_PKCS15_SHA256("MLDSA44-RSA2048-PKCS15-SHA256"),
+ MLDSA44_Ed25519_SHA512("MLDSA44-Ed25519-SHA512"),
+ MLDSA44_ECDSA_P256_SHA256("MLDSA44-ECDSA-P256-SHA256"),
+ MLDSA44_ECDSA_brainpoolP256r1_SHA256("MLDSA44-ECDSA-brainpoolP256r1-SHA256"),
+ MLDSA65_RSA3072_PSS_SHA512("MLDSA65-RSA3072-PSS-SHA512"),
+ MLDSA65_RSA3072_PKCS15_SHA512("MLDSA65-RSA3072-PKCS15-SHA512"),
+ MLDSA65_ECDSA_brainpoolP256r1_SHA512("MLDSA65-ECDSA-brainpoolP256r1-SHA512"),
+ MLDSA65_ECDSA_P256_SHA512("MLDSA65-ECDSA-P256-SHA512"),
+ MLDSA65_Ed25519_SHA512("MLDSA65-Ed25519-SHA512"),
+ MLDSA87_ECDSA_P384_SHA512("MLDSA87-ECDSA-P384-SHA512"),
+ MLDSA87_ECDSA_brainpoolP384r1_SHA512("MLDSA87-ECDSA-brainpoolP384r1-SHA512"),
+ MLDSA87_Ed448_SHA512("MLDSA87-Ed448-SHA512"),
+ Falcon512_ECDSA_P256_SHA256("Falcon512-ECDSA-P256-SHA256"),
+ Falcon512_ECDSA_brainpoolP256r1_SHA256("Falcon512-ECDSA-brainpoolP256r1-SHA256"),
+ Falcon512_Ed25519_SHA512("Falcon512-Ed25519-SHA512");
+
+ private String id;
+
+ private CompositeName(String id)
+ {
+ this.id = id;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
}
/**
@@ -101,24 +113,14 @@ public enum CompositeName
/**
* Map from ASN1 identifier to a readable string used as the composite signature name for the JCA/JCE API.
*/
- public static final HashMap ASN1IdentifierAlgorithmNameMap;
+ public static final HashMap ASN1IdentifierAlgorithmNameMap;
static
{
ASN1IdentifierAlgorithmNameMap = new HashMap<>();
for (ASN1ObjectIdentifier oid : supportedIdentifiers)
{
- String algNameFromEnum = ASN1IdentifierCompositeNameMap.get(oid).name(); //Get enum so we can get name() value.
- String[] parts = algNameFromEnum.split("_");
- String algName = null;
- if (parts.length < 4)
- { //no 2nd "param", e.g., in the case of Ed25519, 3rd hash function is ignored
- algName = parts[0] + "and" + parts[1]; // e.g., MLDSA44_Ed25519_SHA512 => MLDSA44andEd25519
- }
- else
- {
- algName = parts[0] + "and" + parts[1] + parts[2]; // e.g., MLDSA44_RSA2048_PSS_SHA256 => MLDSA44andRSA2048PSS
- }
+ CompositeName algName = ASN1IdentifierCompositeNameMap.get(oid); //Get enum so we can get name() value.
ASN1IdentifierAlgorithmNameMap.put(oid, algName);
}
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
index 358dcb34c2..56f646bc92 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
@@ -226,145 +226,145 @@ private KeyPair getCompositeKeyPair()
return new KeyPair(compositePublicKey, compositePrivateKey);
}
- public static final class MLDSA44andEd25519
+ public static final class MLDSA44_Ed25519_SHA512
extends KeyPairGeneratorSpi
{
- public MLDSA44andEd25519()
+ public MLDSA44_Ed25519_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA44_Ed25519_SHA512);
}
}
- public static final class MLDSA65andEd25519
+ public static final class MLDSA65_Ed25519_SHA512
extends KeyPairGeneratorSpi
{
- public MLDSA65andEd25519()
+ public MLDSA65_Ed25519_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA65_Ed25519_SHA512);
}
}
- public static final class MLDSA87andEd448
+ public static final class MLDSA87_Ed448_SHA512
extends KeyPairGeneratorSpi
{
- public MLDSA87andEd448()
+ public MLDSA87_Ed448_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA87_Ed448_SHA512);
}
}
- public static final class MLDSA44andRSA2048PSS
+ public static final class MLDSA44_RSA2048_PSS_SHA256
extends KeyPairGeneratorSpi
{
- public MLDSA44andRSA2048PSS()
+ public MLDSA44_RSA2048_PSS_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA44_RSA2048_PSS_SHA256);
}
}
- public static final class MLDSA44andRSA2048PKCS15
+ public static final class MLDSA44_RSA2048_PKCS15_SHA256
extends KeyPairGeneratorSpi
{
- public MLDSA44andRSA2048PKCS15()
+ public MLDSA44_RSA2048_PKCS15_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA44_RSA2048_PKCS15_SHA256);
}
}
- public static final class MLDSA65andRSA3072PSS
+ public static final class MLDSA65_RSA3072_PSS_SHA512
extends KeyPairGeneratorSpi
{
- public MLDSA65andRSA3072PSS()
+ public MLDSA65_RSA3072_PSS_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA65_RSA3072_PSS_SHA512);
}
}
- public static final class MLDSA65andRSA3072PKCS15
+ public static final class MLDSA65_RSA3072_PKCS15_SHA512
extends KeyPairGeneratorSpi
{
- public MLDSA65andRSA3072PKCS15()
+ public MLDSA65_RSA3072_PKCS15_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA65_RSA3072_PKCS15_SHA512);
}
}
- public static final class MLDSA44andECDSAP256
+ public static final class MLDSA44_ECDSA_P256_SHA256
extends KeyPairGeneratorSpi
{
- public MLDSA44andECDSAP256()
+ public MLDSA44_ECDSA_P256_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA44_ECDSA_P256_SHA256);
}
}
- public static final class MLDSA44andECDSAbrainpoolP256r1
+ public static final class MLDSA44_ECDSA_brainpoolP256r1_SHA256
extends KeyPairGeneratorSpi
{
- public MLDSA44andECDSAbrainpoolP256r1()
+ public MLDSA44_ECDSA_brainpoolP256r1_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA44_ECDSA_brainpoolP256r1_SHA256);
}
}
- public static final class MLDSA65andECDSAP256
+ public static final class MLDSA65_ECDSA_P256_SHA512
extends KeyPairGeneratorSpi
{
- public MLDSA65andECDSAP256()
+ public MLDSA65_ECDSA_P256_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA65_ECDSA_P256_SHA512);
}
}
- public static final class MLDSA65andECDSAbrainpoolP256r1
+ public static final class MLDSA65_ECDSA_brainpoolP256r1_SHA512
extends KeyPairGeneratorSpi
{
- public MLDSA65andECDSAbrainpoolP256r1()
+ public MLDSA65_ECDSA_brainpoolP256r1_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA65_ECDSA_brainpoolP256r1_SHA512);
}
}
- public static final class MLDSA87andECDSAP384
+ public static final class MLDSA87_ECDSA_P384_SHA512
extends KeyPairGeneratorSpi
{
- public MLDSA87andECDSAP384()
+ public MLDSA87_ECDSA_P384_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA87_ECDSA_P384_SHA512);
}
}
- public static final class MLDSA87andECDSAbrainpoolP384r1
+ public static final class MLDSA87_ECDSA_brainpoolP384r1_SHA512
extends KeyPairGeneratorSpi
{
- public MLDSA87andECDSAbrainpoolP384r1()
+ public MLDSA87_ECDSA_brainpoolP384r1_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA87_ECDSA_brainpoolP384r1_SHA512);
}
}
- public static final class Falcon512andEd25519
+ public static final class Falcon512_Ed25519_SHA512
extends KeyPairGeneratorSpi
{
- public Falcon512andEd25519()
+ public Falcon512_Ed25519_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.Falcon512_Ed25519_SHA512);
}
}
- public static final class Falcon512andECDSAP256
+ public static final class Falcon512_ECDSA_P256_SHA256
extends KeyPairGeneratorSpi
{
- public Falcon512andECDSAP256()
+ public Falcon512_ECDSA_P256_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.Falcon512_ECDSA_P256_SHA256);
}
}
- public static final class Falcon512andECDSAbrainpoolP256r1
+ public static final class Falcon512_ECDSA_brainpoolP256r1_SHA256
extends KeyPairGeneratorSpi
{
- public Falcon512andECDSAbrainpoolP256r1()
+ public Falcon512_ECDSA_brainpoolP256r1_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.Falcon512_ECDSA_brainpoolP256r1_SHA256);
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
index 7afabb6a37..e95b0d6ecd 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
@@ -157,7 +157,7 @@ protected void engineInitSign(PrivateKey privateKey)
}
CompositePrivateKey compositePrivateKey = (CompositePrivateKey)privateKey;
-
+
if (!compositePrivateKey.getAlgorithmIdentifier().equals(this.algorithmIdentifierASN1))
{
throw new InvalidKeyException("Provided composite private key cannot be used with the composite signature algorithm.");
@@ -276,145 +276,145 @@ protected AlgorithmParameters engineGetParameters()
return null;
}
- public final static class MLDSA44andEd25519
+ public final static class MLDSA44_Ed25519_SHA512
extends SignatureSpi
{
- public MLDSA44andEd25519()
+ public MLDSA44_Ed25519_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA44_Ed25519_SHA512);
}
}
- public final static class MLDSA65andEd25519
+ public final static class MLDSA65_Ed25519_SHA512
extends SignatureSpi
{
- public MLDSA65andEd25519()
+ public MLDSA65_Ed25519_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA65_Ed25519_SHA512);
}
}
- public final static class MLDSA87andEd448
+ public final static class MLDSA87_Ed448_SHA512
extends SignatureSpi
{
- public MLDSA87andEd448()
+ public MLDSA87_Ed448_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA87_Ed448_SHA512);
}
}
- public final static class MLDSA44andRSA2048PSS
+ public final static class MLDSA44_RSA2048_PSS_SHA256
extends SignatureSpi
{
- public MLDSA44andRSA2048PSS()
+ public MLDSA44_RSA2048_PSS_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA44_RSA2048_PSS_SHA256);
}
}
- public final static class MLDSA44andRSA2048PKCS15
+ public final static class MLDSA44_RSA2048_PKCS15_SHA256
extends SignatureSpi
{
- public MLDSA44andRSA2048PKCS15()
+ public MLDSA44_RSA2048_PKCS15_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA44_RSA2048_PKCS15_SHA256);
}
}
- public final static class MLDSA65andRSA3072PSS
+ public final static class MLDSA65_RSA3072_PSS_SHA512
extends SignatureSpi
{
- public MLDSA65andRSA3072PSS()
+ public MLDSA65_RSA3072_PSS_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA65_RSA3072_PSS_SHA512);
}
}
- public final static class MLDSA65andRSA3072PKCS15
+ public final static class MLDSA65_RSA3072_PKCS15_SHA512
extends SignatureSpi
{
- public MLDSA65andRSA3072PKCS15()
+ public MLDSA65_RSA3072_PKCS15_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA65_RSA3072_PKCS15_SHA512);
}
}
- public final static class MLDSA44andECDSAP256
+ public final static class MLDSA44_ECDSA_P256_SHA256
extends SignatureSpi
{
- public MLDSA44andECDSAP256()
+ public MLDSA44_ECDSA_P256_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA44_ECDSA_P256_SHA256);
}
}
- public final static class MLDSA44andECDSAbrainpoolP256r1
+ public final static class MLDSA44_ECDSA_brainpoolP256r1_SHA256
extends SignatureSpi
{
- public MLDSA44andECDSAbrainpoolP256r1()
+ public MLDSA44_ECDSA_brainpoolP256r1_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA44_ECDSA_brainpoolP256r1_SHA256);
}
}
- public final static class MLDSA65andECDSAP256
+ public final static class MLDSA65_ECDSA_P256_SHA512
extends SignatureSpi
{
- public MLDSA65andECDSAP256()
+ public MLDSA65_ECDSA_P256_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA65_ECDSA_P256_SHA512);
}
}
- public final static class MLDSA65andECDSAbrainpoolP256r1
+ public final static class MLDSA65_ECDSA_brainpoolP256r1_SHA512
extends SignatureSpi
{
- public MLDSA65andECDSAbrainpoolP256r1()
+ public MLDSA65_ECDSA_brainpoolP256r1_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA65_ECDSA_brainpoolP256r1_SHA512);
}
}
- public final static class MLDSA87andECDSAP384
+ public final static class MLDSA87_ECDSA_P384_SHA512
extends SignatureSpi
{
- public MLDSA87andECDSAP384()
+ public MLDSA87_ECDSA_P384_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA87_ECDSA_P384_SHA512);
}
}
- public final static class MLDSA87andECDSAbrainpoolP384r1
+ public final static class MLDSA87_ECDSA_brainpoolP384r1_SHA512
extends SignatureSpi
{
- public MLDSA87andECDSAbrainpoolP384r1()
+ public MLDSA87_ECDSA_brainpoolP384r1_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.MLDSA87_ECDSA_brainpoolP384r1_SHA512);
}
}
- public final static class Falcon512andEd25519
+ public final static class Falcon512_Ed25519_SHA512
extends SignatureSpi
{
- public Falcon512andEd25519()
+ public Falcon512_Ed25519_SHA512()
{
super(CompositeSignaturesConstants.CompositeName.Falcon512_Ed25519_SHA512);
}
}
- public final static class Falcon512andECDSAP256
+ public final static class Falcon512_ECDSA_P256_SHA256
extends SignatureSpi
{
- public Falcon512andECDSAP256()
+ public Falcon512_ECDSA_P256_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.Falcon512_ECDSA_P256_SHA256);
}
}
- public final static class Falcon512andECDSAbrainpoolP256r1
+ public final static class Falcon512_ECDSA_brainpoolP256r1_SHA256
extends SignatureSpi
{
- public Falcon512andECDSAbrainpoolP256r1()
+ public Falcon512_ECDSA_brainpoolP256r1_SHA256()
{
super(CompositeSignaturesConstants.CompositeName.Falcon512_ECDSA_brainpoolP256r1_SHA256);
}
From 3d66c26822caccfceaec0e029eaf6b6ebe17006a Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sun, 17 Mar 2024 15:02:18 +1100
Subject: [PATCH 0172/1846] 256 bit NTRU parameters
---
.../asn1/bc/BCObjectIdentifiers.java | 2 ++
.../pqc/crypto/ntru/NTRUParameters.java | 13 ++++++++
.../pqc/crypto/util/PublicKeyFactory.java | 2 ++
.../bouncycastle/pqc/crypto/util/Utils.java | 4 +++
.../math/ntru/parameters/NTRUHPS40961229.java | 30 +++++++++++++++++++
.../math/ntru/parameters/NTRUHRSS1373.java | 22 ++++++++++++++
.../pqc/crypto/test/NTRUParametersTest.java | 2 ++
.../pqc/crypto/test/NTRUTest.java | 15 ++++++++--
.../ntru/NTRUKeyPairGeneratorSpi.java | 2 ++
.../pqc/jcajce/spec/NTRUParameterSpec.java | 2 ++
.../test/NTRUKeyPairGeneratorTest.java | 4 ++-
11 files changed, 94 insertions(+), 4 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHPS40961229.java
create mode 100644 core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHRSS1373.java
diff --git a/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
index 8a7741032f..6c5db36169 100644
--- a/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
+++ b/core/src/main/java/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java
@@ -376,6 +376,8 @@ public interface BCObjectIdentifiers
ASN1ObjectIdentifier ntruhps2048677 = pqc_kem_ntru.branch("2");
ASN1ObjectIdentifier ntruhps4096821 = pqc_kem_ntru.branch("3");
ASN1ObjectIdentifier ntruhrss701 = pqc_kem_ntru.branch("4");
+ ASN1ObjectIdentifier ntruhps40961229 = pqc_kem_ntru.branch("5");
+ ASN1ObjectIdentifier ntruhrss1373 = pqc_kem_ntru.branch("6");
/**
* Kyber
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java
index b2d05d040a..32fa186f73 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java
@@ -4,7 +4,9 @@
import org.bouncycastle.pqc.crypto.KEMParameters;
import org.bouncycastle.pqc.math.ntru.parameters.NTRUHPS2048509;
import org.bouncycastle.pqc.math.ntru.parameters.NTRUHPS2048677;
+import org.bouncycastle.pqc.math.ntru.parameters.NTRUHPS40961229;
import org.bouncycastle.pqc.math.ntru.parameters.NTRUHPS4096821;
+import org.bouncycastle.pqc.math.ntru.parameters.NTRUHRSS1373;
import org.bouncycastle.pqc.math.ntru.parameters.NTRUHRSS701;
import org.bouncycastle.pqc.math.ntru.parameters.NTRUParameterSet;
@@ -27,11 +29,22 @@ public class NTRUParameters
*/
public static final NTRUParameters ntruhps4096821 = new NTRUParameters("ntruhps4096821", new NTRUHPS4096821());
+ /**
+ * NTRU-HPS parameter set with n = 1229 and q = 4096.
+ */
+ public static final NTRUParameters ntruhps40961229 = new NTRUParameters("ntruhps40961229", new NTRUHPS40961229());
+
/**
* NTRU-HRSS parameter set with n = 701.
*/
public static final NTRUParameters ntruhrss701 = new NTRUParameters("ntruhrss701", new NTRUHRSS701());
+ /**
+ * NTRU-HRSS parameter set with n = 1373.
+ */
+ // TODO
+ // public static final NTRUParameters ntruhrss1373 = new NTRUParameters("ntruhrss1373", new NTRUHRSS1373());
+
private final String name;
/**
* Currently selected parameter set
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
index f9914f5c38..b5b0decbae 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
@@ -188,7 +188,9 @@ public class PublicKeyFactory
converters.put(BCObjectIdentifiers.ntruhps2048509, new NtruConverter());
converters.put(BCObjectIdentifiers.ntruhps2048677, new NtruConverter());
converters.put(BCObjectIdentifiers.ntruhps4096821, new NtruConverter());
+ converters.put(BCObjectIdentifiers.ntruhps40961229, new NtruConverter());
converters.put(BCObjectIdentifiers.ntruhrss701, new NtruConverter());
+ converters.put(BCObjectIdentifiers.ntruhrss1373, new NtruConverter());
converters.put(BCObjectIdentifiers.falcon_512, new FalconConverter());
converters.put(BCObjectIdentifiers.falcon_1024, new FalconConverter());
converters.put(BCObjectIdentifiers.kyber512, new KyberConverter());
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
index 8e7421fe24..37ca5fa969 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
@@ -203,12 +203,16 @@ class Utils
ntruOids.put(NTRUParameters.ntruhps2048509, BCObjectIdentifiers.ntruhps2048509);
ntruOids.put(NTRUParameters.ntruhps2048677, BCObjectIdentifiers.ntruhps2048677);
ntruOids.put(NTRUParameters.ntruhps4096821, BCObjectIdentifiers.ntruhps4096821);
+ ntruOids.put(NTRUParameters.ntruhps40961229, BCObjectIdentifiers.ntruhps40961229);
ntruOids.put(NTRUParameters.ntruhrss701, BCObjectIdentifiers.ntruhrss701);
+// ntruOids.put(NTRUParameters.ntruhrss1373, BCObjectIdentifiers.ntruhrss1373);
ntruParams.put(BCObjectIdentifiers.ntruhps2048509, NTRUParameters.ntruhps2048509);
ntruParams.put(BCObjectIdentifiers.ntruhps2048677, NTRUParameters.ntruhps2048677);
ntruParams.put(BCObjectIdentifiers.ntruhps4096821, NTRUParameters.ntruhps4096821);
+ ntruParams.put(BCObjectIdentifiers.ntruhps40961229, NTRUParameters.ntruhps40961229);
ntruParams.put(BCObjectIdentifiers.ntruhrss701, NTRUParameters.ntruhrss701);
+// ntruParams.put(BCObjectIdentifiers.ntruhrss1373, NTRUParameters.ntruhrss1373);
falconOids.put(FalconParameters.falcon_512, BCObjectIdentifiers.falcon_512);
falconOids.put(FalconParameters.falcon_1024, BCObjectIdentifiers.falcon_1024);
diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHPS40961229.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHPS40961229.java
new file mode 100644
index 0000000000..1e55a9fcd8
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHPS40961229.java
@@ -0,0 +1,30 @@
+package org.bouncycastle.pqc.math.ntru.parameters;
+
+import org.bouncycastle.pqc.math.ntru.HPS4096Polynomial;
+import org.bouncycastle.pqc.math.ntru.Polynomial;
+
+/**
+ * NTRU-HPS parameter set with n = 1229 and q = 4096.
+ *
+ * @see NTRUHPSParameterSet
+ */
+public class NTRUHPS40961229
+ extends NTRUHPSParameterSet
+{
+ public NTRUHPS40961229()
+ {
+ super(
+ 1229,
+ 12,
+ 32,
+ 32,
+ 32 // Category 5 (local model)
+ );
+ }
+
+ @Override
+ public Polynomial createPolynomial()
+ {
+ return new HPS4096Polynomial(this);
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHRSS1373.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHRSS1373.java
new file mode 100644
index 0000000000..2bdfafc77d
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHRSS1373.java
@@ -0,0 +1,22 @@
+package org.bouncycastle.pqc.math.ntru.parameters;
+
+
+/**
+ * NTRU-HRSS parameter set with n = 701.
+ *
+ * @see NTRUHRSSParameterSet
+ */
+public class NTRUHRSS1373
+ extends NTRUHRSSParameterSet
+{
+ public NTRUHRSS1373()
+ {
+ super(
+ 1373,
+ 14,
+ 32,
+ 32,
+ 32 // Category 5 (local model) - KATs based on 256 bit
+ );
+ }
+}
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUParametersTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUParametersTest.java
index 2e23d777d5..e1f2a9096a 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUParametersTest.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUParametersTest.java
@@ -14,8 +14,10 @@ public void testParameters()
assertEquals(256, NTRUParameters.ntruhps2048509.getSessionKeySize());
assertEquals(256, NTRUParameters.ntruhps2048677.getSessionKeySize());
assertEquals(256, NTRUParameters.ntruhps4096821.getSessionKeySize());
+ assertEquals(256, NTRUParameters.ntruhps40961229.getSessionKeySize());
assertEquals(256, NTRUParameters.ntruhrss701.getSessionKeySize());
+// assertEquals(256, NTRUParameters.ntruhrss1373.getSessionKeySize());
}
public void testHpsParameters()
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java
index 76d5875fa8..d6ec3c98a5 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java
@@ -36,19 +36,27 @@ public class NTRUTest
NTRUParameters.ntruhps2048509,
NTRUParameters.ntruhps2048677,
NTRUParameters.ntruhps4096821,
- NTRUParameters.ntruhrss701
+ NTRUParameters.ntruhps40961229,
+ NTRUParameters.ntruhrss701,
+// NTRUParameters.ntruhrss1373
};
+
private final String[] katBase = {
"ntruhps2048509",
"ntruhps2048677",
"ntruhps4096821",
- "ntruhrss701"
+ "ntruhps40961229",
+ "ntruhrss701",
+// "ntruhrss1373"
};
+
private final String[] katFiles = {
"PQCkemKAT_935.rsp",
"PQCkemKAT_1234.rsp",
"PQCkemKAT_1590.rsp",
- "PQCkemKAT_1450.rsp"
+ "PQCkemKAT_2366.rsp",
+ "PQCkemKAT_1450.rsp",
+ "PQCkemKAT_2983.rsp"
};
public void testPrivInfoGeneration()
@@ -76,6 +84,7 @@ public void testPQCgenKAT_kem()
for (int i = 0; i < this.params.length; i++)
{
NTRUParameters param = params[i];
+
InputStream src = TestResourceFinder.findTestResource("pqc/crypto/ntru/" + katBase[i], katFiles[i]);
List kats = NTRUKAT.getKAT(src);
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java
index 944938e27d..286c6b22d2 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java
@@ -28,7 +28,9 @@ public class NTRUKeyPairGeneratorSpi
parameters.put(NTRUParameterSpec.ntruhps2048509.getName(), NTRUParameters.ntruhps2048509);
parameters.put(NTRUParameterSpec.ntruhps2048677.getName(), NTRUParameters.ntruhps2048677);
parameters.put(NTRUParameterSpec.ntruhps4096821.getName(), NTRUParameters.ntruhps4096821);
+ parameters.put(NTRUParameterSpec.ntruhps40961229.getName(), NTRUParameters.ntruhps40961229);
parameters.put(NTRUParameterSpec.ntruhrss701.getName(), NTRUParameters.ntruhrss701);
+// parameters.put(NTRUParameterSpec.ntruhrss1373.getName(), NTRUParameters.ntruhrss1373);
}
NTRUKeyGenerationParameters param;
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUParameterSpec.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUParameterSpec.java
index 2f23040f68..7b4fabf9c5 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUParameterSpec.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUParameterSpec.java
@@ -13,7 +13,9 @@ public class NTRUParameterSpec
public static final NTRUParameterSpec ntruhps2048509 = new NTRUParameterSpec(NTRUParameters.ntruhps2048509);
public static final NTRUParameterSpec ntruhps2048677 = new NTRUParameterSpec(NTRUParameters.ntruhps2048677);
public static final NTRUParameterSpec ntruhps4096821 = new NTRUParameterSpec(NTRUParameters.ntruhps4096821);
+ public static final NTRUParameterSpec ntruhps40961229 = new NTRUParameterSpec(NTRUParameters.ntruhps40961229);
public static final NTRUParameterSpec ntruhrss701 = new NTRUParameterSpec(NTRUParameters.ntruhrss701);
+// public static final NTRUParameterSpec ntruhrss1373 = new NTRUParameterSpec(NTRUParameters.ntruhrss1373);
private static Map parameters = new HashMap();
diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUKeyPairGeneratorTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUKeyPairGeneratorTest.java
index dbf43b611a..36d335e22f 100644
--- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUKeyPairGeneratorTest.java
+++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUKeyPairGeneratorTest.java
@@ -40,7 +40,9 @@ public void testKeyPairEncoding()
NTRUParameterSpec.ntruhps2048509,
NTRUParameterSpec.ntruhps2048677,
NTRUParameterSpec.ntruhps4096821,
- NTRUParameterSpec.ntruhrss701
+ NTRUParameterSpec.ntruhps40961229,
+ NTRUParameterSpec.ntruhrss701,
+// NTRUParameterSpec.ntruhrss1373
};
kf = KeyFactory.getInstance("NTRU", "BC");
From 5efe4651b471d49384019d92787966c13b871d26 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 18 Mar 2024 11:33:32 +1100
Subject: [PATCH 0173/1846] added support for NTRU HRSS 1373
---
.../pqc/crypto/ntru/NTRUParameters.java | 3 +-
.../bouncycastle/pqc/crypto/util/Utils.java | 4 +-
.../pqc/math/ntru/HRSS1373Polynomial.java | 84 +++++++++++++++++++
.../pqc/math/ntru/HRSSPolynomial.java | 26 +++---
.../ntru/parameters/NTRUHRSSParameterSet.java | 3 +-
.../pqc/crypto/test/NTRUTest.java | 4 +-
docs/releasenotes.html | 1 +
.../ntru/NTRUKeyPairGeneratorSpi.java | 2 +-
.../pqc/jcajce/spec/NTRUParameterSpec.java | 4 +-
.../test/NTRUKeyPairGeneratorTest.java | 2 +-
10 files changed, 110 insertions(+), 23 deletions(-)
create mode 100644 core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSS1373Polynomial.java
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java
index 32fa186f73..2d8582496a 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/ntru/NTRUParameters.java
@@ -42,8 +42,7 @@ public class NTRUParameters
/**
* NTRU-HRSS parameter set with n = 1373.
*/
- // TODO
- // public static final NTRUParameters ntruhrss1373 = new NTRUParameters("ntruhrss1373", new NTRUHRSS1373());
+ public static final NTRUParameters ntruhrss1373 = new NTRUParameters("ntruhrss1373", new NTRUHRSS1373());
private final String name;
/**
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java b/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
index 37ca5fa969..5a92b52a99 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/util/Utils.java
@@ -205,14 +205,14 @@ class Utils
ntruOids.put(NTRUParameters.ntruhps4096821, BCObjectIdentifiers.ntruhps4096821);
ntruOids.put(NTRUParameters.ntruhps40961229, BCObjectIdentifiers.ntruhps40961229);
ntruOids.put(NTRUParameters.ntruhrss701, BCObjectIdentifiers.ntruhrss701);
-// ntruOids.put(NTRUParameters.ntruhrss1373, BCObjectIdentifiers.ntruhrss1373);
+ ntruOids.put(NTRUParameters.ntruhrss1373, BCObjectIdentifiers.ntruhrss1373);
ntruParams.put(BCObjectIdentifiers.ntruhps2048509, NTRUParameters.ntruhps2048509);
ntruParams.put(BCObjectIdentifiers.ntruhps2048677, NTRUParameters.ntruhps2048677);
ntruParams.put(BCObjectIdentifiers.ntruhps4096821, NTRUParameters.ntruhps4096821);
ntruParams.put(BCObjectIdentifiers.ntruhps40961229, NTRUParameters.ntruhps40961229);
ntruParams.put(BCObjectIdentifiers.ntruhrss701, NTRUParameters.ntruhrss701);
-// ntruParams.put(BCObjectIdentifiers.ntruhrss1373, NTRUParameters.ntruhrss1373);
+ ntruParams.put(BCObjectIdentifiers.ntruhrss1373, NTRUParameters.ntruhrss1373);
falconOids.put(FalconParameters.falcon_512, BCObjectIdentifiers.falcon_512);
falconOids.put(FalconParameters.falcon_1024, BCObjectIdentifiers.falcon_1024);
diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSS1373Polynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSS1373Polynomial.java
new file mode 100644
index 0000000000..b69f73ea55
--- /dev/null
+++ b/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSS1373Polynomial.java
@@ -0,0 +1,84 @@
+package org.bouncycastle.pqc.math.ntru;
+
+import org.bouncycastle.pqc.math.ntru.parameters.NTRUHRSSParameterSet;
+
+public class HRSS1373Polynomial
+ extends HRSSPolynomial
+{
+ private static final int L = ((1373 + 31) / 32) * 32;
+ private static final int M = L / 4;
+ private static final int K = L / 16;
+
+ public HRSS1373Polynomial(NTRUHRSSParameterSet params)
+ {
+ super(params);
+ }
+
+ @Override
+ public byte[] sqToBytes(int len)
+ {
+ byte[] r = new byte[len];
+ int i, j;
+ short[] t = new short[4];
+
+ for (i = 0; i < params.packDegree() / 4; i++)
+ {
+ for (j = 0; j < 4; j++)
+ {
+ t[j] = (short)modQ(this.coeffs[4 * i + j] & 0xffff, params.q());
+ }
+
+ // t0 t1 t2 t3
+ // r0 8
+ // r1 6 | 2
+ // r2 8
+ // r3 4 | 4
+ // r4 8
+ // r5 2 | 6
+ // r6 8
+
+ r[7 * i + 0] = (byte)(t[0] & 0xff);
+ r[7 * i + 1] = (byte)((t[0] >>> 8) | ((t[1] & 0x03) << 6));
+ r[7 * i + 2] = (byte)((t[1] >>> 2) & 0xff);
+ r[7 * i + 3] = (byte)((t[1] >>> 10) | ((t[2] & 0x0f) << 4));
+ r[7 * i + 4] = (byte)((t[2] >>> 4) & 0xff);
+ r[7 * i + 5] = (byte)((t[2] >>> 12) | ((t[3] & 0x3f) << 2));
+ r[7 * i + 6] = (byte)(t[3] >>> 6);
+ }
+
+ // i=NTRU_PACK_DEG/4;
+ if (params.packDegree() % 4 == 2)
+ {
+ t[0] = (short)modQ(this.coeffs[params.packDegree() - 2] & 0xffff, params.q());
+ t[1] = (short)modQ(this.coeffs[params.packDegree() - 1] & 0xffff, params.q());
+ r[7 * i + 0] = (byte)(t[0] & 0xff);
+ r[7 * i + 1] = (byte)((t[0] >>> 8) | ((t[1] & 0x03) << 6));
+ r[7 * i + 2] = (byte)((t[1] >>> 2) & 0xff);
+ r[7 * i + 3] = (byte)(t[1] >>> 10);
+ }
+
+ return r;
+ }
+
+ @Override
+ public void sqFromBytes(byte[] a)
+ {
+ int i;
+ for (i = 0; i < params.packDegree() / 4; i++)
+ {
+ this.coeffs[4 * i + 0] = (short)((a[7 * i + 0] & 0xff) | (((short)(a[7 * i + 1] & 0xff) & 0x3f) << 8));
+ this.coeffs[4 * i + 1] = (short)(((a[7 * i + 1] & 0xff) >>> 6) | (((short)(a[7 * i + 2] & 0xff)) << 2) | ((short)(a[7 * i + 3] & 0x0f) << 10));
+ this.coeffs[4 * i + 2] = (short)(((a[7 * i + 3] & 0xff) >>> 4) | (((short)(a[7 * i + 4] & 0xff) & 0xff) << 4) | ((short)(a[7 * i + 5] & 0x03) << 12));
+ this.coeffs[4 * i + 3] = (short)(((a[7 * i + 5] & 0xff) >>> 2) | (((short)(a[7 * i + 6] & 0xff)) << 6));
+ }
+
+ // i=NTRU_PACK_DEG/4;
+ if (params.packDegree() % 4 == 2)
+ {
+ this.coeffs[4 * i + 0] = (short)(a[7 * i + 0] | ((a[7 * i + 1] & 0x3f) << 8));
+ this.coeffs[4 * i + 1] = (short)((a[7 * i + 1] >>> 6) | (((short)a[7 * i + 2]) << 2) | (((short)a[7 * i + 3] & 0x0f) << 10));
+ }
+
+ this.coeffs[params.n() - 1] = 0;
+ }
+}
diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSSPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSSPolynomial.java
index 091f81420a..0bea6a321c 100644
--- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSSPolynomial.java
+++ b/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSSPolynomial.java
@@ -117,7 +117,7 @@ public void lift(Polynomial a)
/* NOTE: Assumes input is in {0,1,2}^N */
/* Produces output in [0,Q-1]^N */
int i;
- HRSSPolynomial b = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
+ Polynomial b = this.params.createPolynomial();
short t, zj;
/* Define z by = delta_{i,0} mod 3: */
@@ -166,30 +166,30 @@ public void lift(Polynomial a)
@Override
public void r2Inv(Polynomial a)
{
- HRSSPolynomial f = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
- HRSSPolynomial g = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
- HRSSPolynomial v = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
- HRSSPolynomial w = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
+ Polynomial f = this.params.createPolynomial();
+ Polynomial g = this.params.createPolynomial();
+ Polynomial v = this.params.createPolynomial();
+ Polynomial w = this.params.createPolynomial();
this.r2Inv(a, f, g, v, w);
}
@Override
public void rqInv(Polynomial a)
{
- HRSSPolynomial ai2 = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
- HRSSPolynomial b = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
- HRSSPolynomial c = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
- HRSSPolynomial s = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
+ Polynomial ai2 = this.params.createPolynomial();
+ Polynomial b = this.params.createPolynomial();
+ Polynomial c = this.params.createPolynomial();
+ Polynomial s = this.params.createPolynomial();
this.rqInv(a, ai2, b, c, s);
}
@Override
public void s3Inv(Polynomial a)
{
- HRSSPolynomial f = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
- HRSSPolynomial g = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
- HRSSPolynomial v = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
- HRSSPolynomial w = new HRSSPolynomial((NTRUHRSSParameterSet)this.params);
+ Polynomial f = this.params.createPolynomial();
+ Polynomial g = this.params.createPolynomial();
+ Polynomial v = this.params.createPolynomial();
+ Polynomial w = this.params.createPolynomial();
this.s3Inv(a, f, g, v, w);
}
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHRSSParameterSet.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHRSSParameterSet.java
index 2e6f7f50ff..89986f2f97 100644
--- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHRSSParameterSet.java
+++ b/core/src/main/java/org/bouncycastle/pqc/math/ntru/parameters/NTRUHRSSParameterSet.java
@@ -1,5 +1,6 @@
package org.bouncycastle.pqc.math.ntru.parameters;
+import org.bouncycastle.pqc.math.ntru.HRSS1373Polynomial;
import org.bouncycastle.pqc.math.ntru.HRSSPolynomial;
import org.bouncycastle.pqc.math.ntru.Polynomial;
@@ -22,7 +23,7 @@ public abstract class NTRUHRSSParameterSet
@Override
public Polynomial createPolynomial()
{
- return new HRSSPolynomial(this);
+ return this.n() == 1373 ? new HRSS1373Polynomial(this) : new HRSSPolynomial(this);
}
@Override
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java
index d6ec3c98a5..7624329cca 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/NTRUTest.java
@@ -38,7 +38,7 @@ public class NTRUTest
NTRUParameters.ntruhps4096821,
NTRUParameters.ntruhps40961229,
NTRUParameters.ntruhrss701,
-// NTRUParameters.ntruhrss1373
+ NTRUParameters.ntruhrss1373
};
private final String[] katBase = {
@@ -47,7 +47,7 @@ public class NTRUTest
"ntruhps4096821",
"ntruhps40961229",
"ntruhrss701",
-// "ntruhrss1373"
+ "ntruhrss1373"
};
private final String[] katFiles = {
diff --git a/docs/releasenotes.html b/docs/releasenotes.html
index 518b1ee2b2..afec80affe 100644
--- a/docs/releasenotes.html
+++ b/docs/releasenotes.html
@@ -28,6 +28,7 @@ 2.1.2 Defects Fixed
2.1.3 Additional Features and Functionality
- An implementation of MLS (RFC 9420 - The Messaging Layer Security Protocol) has been added as a new module.
+- NTRU now supports NTRU-HPS4096-1229 and NTRU-HRSS-1373.
2.1.4 Notes.
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java
index 286c6b22d2..c7ef183c18 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKeyPairGeneratorSpi.java
@@ -30,7 +30,7 @@ public class NTRUKeyPairGeneratorSpi
parameters.put(NTRUParameterSpec.ntruhps4096821.getName(), NTRUParameters.ntruhps4096821);
parameters.put(NTRUParameterSpec.ntruhps40961229.getName(), NTRUParameters.ntruhps40961229);
parameters.put(NTRUParameterSpec.ntruhrss701.getName(), NTRUParameters.ntruhrss701);
-// parameters.put(NTRUParameterSpec.ntruhrss1373.getName(), NTRUParameters.ntruhrss1373);
+ parameters.put(NTRUParameterSpec.ntruhrss1373.getName(), NTRUParameters.ntruhrss1373);
}
NTRUKeyGenerationParameters param;
diff --git a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUParameterSpec.java b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUParameterSpec.java
index 7b4fabf9c5..e974e1b2ee 100644
--- a/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUParameterSpec.java
+++ b/prov/src/main/java/org/bouncycastle/pqc/jcajce/spec/NTRUParameterSpec.java
@@ -15,7 +15,7 @@ public class NTRUParameterSpec
public static final NTRUParameterSpec ntruhps4096821 = new NTRUParameterSpec(NTRUParameters.ntruhps4096821);
public static final NTRUParameterSpec ntruhps40961229 = new NTRUParameterSpec(NTRUParameters.ntruhps40961229);
public static final NTRUParameterSpec ntruhrss701 = new NTRUParameterSpec(NTRUParameters.ntruhrss701);
-// public static final NTRUParameterSpec ntruhrss1373 = new NTRUParameterSpec(NTRUParameters.ntruhrss1373);
+ public static final NTRUParameterSpec ntruhrss1373 = new NTRUParameterSpec(NTRUParameters.ntruhrss1373);
private static Map parameters = new HashMap();
@@ -24,7 +24,9 @@ public class NTRUParameterSpec
parameters.put("ntruhps2048509", ntruhps2048509);
parameters.put("ntruhps2048677", ntruhps2048677);
parameters.put("ntruhps4096821", ntruhps4096821);
+ parameters.put("ntruhps40961229", ntruhps40961229);
parameters.put("ntruhrss701", ntruhrss701);
+ parameters.put("ntruhrss1373", ntruhrss1373);
}
private final String name;
diff --git a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUKeyPairGeneratorTest.java b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUKeyPairGeneratorTest.java
index 36d335e22f..e0712eb702 100644
--- a/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUKeyPairGeneratorTest.java
+++ b/prov/src/test/java/org/bouncycastle/pqc/jcajce/provider/test/NTRUKeyPairGeneratorTest.java
@@ -42,7 +42,7 @@ public void testKeyPairEncoding()
NTRUParameterSpec.ntruhps4096821,
NTRUParameterSpec.ntruhps40961229,
NTRUParameterSpec.ntruhrss701,
-// NTRUParameterSpec.ntruhrss1373
+ NTRUParameterSpec.ntruhrss1373
};
kf = KeyFactory.getInstance("NTRU", "BC");
From 2afa6ad0ec3b1fd810a52f359357c1ebb0e56f0e Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 18 Mar 2024 11:45:42 +1100
Subject: [PATCH 0174/1846] minor refactoring - removal of common code.
---
.../pqc/math/ntru/HPSPolynomial.java | 32 ----------------
.../pqc/math/ntru/HRSSPolynomial.java | 30 ---------------
.../pqc/math/ntru/Polynomial.java | 38 ++++++++++++++-----
3 files changed, 29 insertions(+), 71 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/HPSPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/HPSPolynomial.java
index 855c2236ff..107cc597e1 100644
--- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/HPSPolynomial.java
+++ b/core/src/main/java/org/bouncycastle/pqc/math/ntru/HPSPolynomial.java
@@ -112,36 +112,4 @@ public void lift(Polynomial a)
System.arraycopy(a.coeffs, 0, this.coeffs, 0, n);
this.z3ToZq();
}
-
- @Override
- public void r2Inv(Polynomial a)
- {
- HPSPolynomial f = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- HPSPolynomial g = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- HPSPolynomial v = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- HPSPolynomial w = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- this.r2Inv(a, f, g, v, w);
- }
-
- @Override
- public void rqInv(Polynomial a)
- {
- HPSPolynomial ai2 = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- HPSPolynomial b = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- HPSPolynomial c = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- HPSPolynomial s = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- this.rqInv(a, ai2, b, c, s);
- }
-
- @Override
- public void s3Inv(Polynomial a)
- {
- HPSPolynomial f = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- HPSPolynomial g = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- HPSPolynomial v = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- HPSPolynomial w = new HPSPolynomial((NTRUHPSParameterSet)this.params);
- this.s3Inv(a, f, g, v, w);
- }
-
-
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSSPolynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSSPolynomial.java
index 0bea6a321c..e71fb09d2e 100644
--- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSSPolynomial.java
+++ b/core/src/main/java/org/bouncycastle/pqc/math/ntru/HRSSPolynomial.java
@@ -162,34 +162,4 @@ public void lift(Polynomial a)
this.coeffs[i + 1] = (short)(b.coeffs[i] - b.coeffs[i + 1]);
}
}
-
- @Override
- public void r2Inv(Polynomial a)
- {
- Polynomial f = this.params.createPolynomial();
- Polynomial g = this.params.createPolynomial();
- Polynomial v = this.params.createPolynomial();
- Polynomial w = this.params.createPolynomial();
- this.r2Inv(a, f, g, v, w);
- }
-
- @Override
- public void rqInv(Polynomial a)
- {
- Polynomial ai2 = this.params.createPolynomial();
- Polynomial b = this.params.createPolynomial();
- Polynomial c = this.params.createPolynomial();
- Polynomial s = this.params.createPolynomial();
- this.rqInv(a, ai2, b, c, s);
- }
-
- @Override
- public void s3Inv(Polynomial a)
- {
- Polynomial f = this.params.createPolynomial();
- Polynomial g = this.params.createPolynomial();
- Polynomial v = this.params.createPolynomial();
- Polynomial w = this.params.createPolynomial();
- this.s3Inv(a, f, g, v, w);
- }
}
diff --git a/core/src/main/java/org/bouncycastle/pqc/math/ntru/Polynomial.java b/core/src/main/java/org/bouncycastle/pqc/math/ntru/Polynomial.java
index 1dcc5b43b7..f207f25cc4 100644
--- a/core/src/main/java/org/bouncycastle/pqc/math/ntru/Polynomial.java
+++ b/core/src/main/java/org/bouncycastle/pqc/math/ntru/Polynomial.java
@@ -257,9 +257,35 @@ public void rqToS3(Polynomial a)
this.mod3PhiN();
}
-
// defined in poly_r2_inv.c
- public abstract void r2Inv(Polynomial a);
+ public void r2Inv(Polynomial a)
+ {
+ Polynomial f = this.params.createPolynomial();
+ Polynomial g = this.params.createPolynomial();
+ Polynomial v = this.params.createPolynomial();
+ Polynomial w = this.params.createPolynomial();
+ this.r2Inv(a, f, g, v, w);
+ }
+
+ // defined in poly.c
+ public void rqInv(Polynomial a)
+ {
+ Polynomial ai2 = this.params.createPolynomial();
+ Polynomial b = this.params.createPolynomial();
+ Polynomial c = this.params.createPolynomial();
+ Polynomial s = this.params.createPolynomial();
+ this.rqInv(a, ai2, b, c, s);
+ }
+
+ // defined in poly_s3_inv.c
+ public void s3Inv(Polynomial a)
+ {
+ Polynomial f = this.params.createPolynomial();
+ Polynomial g = this.params.createPolynomial();
+ Polynomial v = this.params.createPolynomial();
+ Polynomial w = this.params.createPolynomial();
+ this.s3Inv(a, f, g, v, w);
+ }
void r2Inv(Polynomial a, Polynomial f, Polynomial g, Polynomial v, Polynomial w)
{
@@ -326,9 +352,6 @@ void r2Inv(Polynomial a, Polynomial f, Polynomial g, Polynomial v, Polynomial w)
this.coeffs[n - 1] = 0;
}
- // defined in poly.c
- public abstract void rqInv(Polynomial a);
-
void rqInv(Polynomial a, Polynomial ai2, Polynomial b, Polynomial c, Polynomial s)
{
ai2.r2Inv(a);
@@ -365,10 +388,7 @@ private void r2InvToRqInv(Polynomial ai, Polynomial a, Polynomial b, Polynomial
c.coeffs[0] += 2;
this.rqMul(c, s);
}
-
- // defined in poly_s3_inv.c
- public abstract void s3Inv(Polynomial a);
-
+
void s3Inv(Polynomial a, Polynomial f, Polynomial g, Polynomial v, Polynomial w)
{
int n = this.coeffs.length;
From 66e042be7db2c165e5cba6b331b54835ffc8a073 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 18 Mar 2024 11:57:57 +1100
Subject: [PATCH 0175/1846] added additional NTRU OIDs to provider.
---
.../org/bouncycastle/jcajce/provider/asymmetric/NTRU.java | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/NTRU.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/NTRU.java
index f5edaffc1a..22400dcc70 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/NTRU.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/NTRU.java
@@ -27,7 +27,9 @@ public void configure(ConfigurableProvider provider)
provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps2048509, "NTRU");
provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps2048677, "NTRU");
provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps4096821, "NTRU");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhps40961229, "NTRU");
provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhrss701, "NTRU");
+ provider.addAlgorithm("Alg.Alias.KeyGenerator." + BCObjectIdentifiers.ntruhrss1373, "NTRU");
AsymmetricKeyInfoConverter keyFact = new NTRUKeyFactorySpi();
@@ -36,13 +38,17 @@ public void configure(ConfigurableProvider provider)
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps2048509, "NTRU");
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps2048677, "NTRU");
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps4096821, "NTRU");
+ provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhps40961229, "NTRU");
provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhrss701, "NTRU");
+ provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.ntruhrss1373, "NTRU");
registerOid(provider, BCObjectIdentifiers.pqc_kem_ntru, "NTRU", keyFact);
registerOid(provider, BCObjectIdentifiers.ntruhps2048509, "NTRU", keyFact);
registerOid(provider, BCObjectIdentifiers.ntruhps2048677, "NTRU", keyFact);
registerOid(provider, BCObjectIdentifiers.ntruhps4096821, "NTRU", keyFact);
+ registerOid(provider, BCObjectIdentifiers.ntruhps40961229, "NTRU", keyFact);
registerOid(provider, BCObjectIdentifiers.ntruhrss701, "NTRU", keyFact);
+ registerOid(provider, BCObjectIdentifiers.ntruhrss1373, "NTRU", keyFact);
}
}
}
From a034f61fa3ef87c06269aed003b475f92d0e233e Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 18 Mar 2024 12:13:27 +1100
Subject: [PATCH 0176/1846] change to use this.read() relates to github #1577
---
pg/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java b/pg/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java
index 5a008ae66e..f965ec3503 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/BCPGInputStream.java
@@ -151,7 +151,7 @@ public int nextPacketTag()
{
try
{
- nextB = in.read();
+ nextB = this.read();
}
catch (EOFException e)
{
From 3604e4b280cd3d30ad9360000697ab9f3004015a Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 19 Mar 2024 14:26:59 +1100
Subject: [PATCH 0177/1846] fixed license reference, minor adjustments
---
CONTRIBUTING.md | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b12cc67d5b..b0b7f1c3ca 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -15,15 +15,22 @@ Or you can [start a new discussion](../../discussions/new/choose) and ask your q
If you find a problem with Bouncy Castle, [search if an issue already exists](../../issues).
-If a related discussion or issue doesn't exist, you can [open a new issue](../../issues/new). An issue can be converted into a discussion if regarded as one.
+If the issue is a potential security problem, please contact us at feedback-crypto@bouncycastle.org before posting anything public.
+
+If a related discussion or issue doesn't exist, and the issue is not security related, you can [open a new issue](../../issues/new). An issue can be converted into a discussion if regarded as one.
### Contribute to the code
+For substantial, non-trivial contributions, you may be asked to sign a contributor assignment agreement. Optionally, you can also have your name and contact information listed in [Contributors](https://www.bouncycastle.org/contributors.html).
+
+Please note we are unable to accept contributions which cannot be released under the [Bouncy Castle License](https://www.bouncycastle.org/licence.html). Issuing a pull request on our public github mirror is taken as agreement to issuing under the Bouncy Castle License.
+
#### Create a pull request
-You are welcome to send patches, under the LGPLv2.1+ license, as pull requests. For more information, see [Creating a pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). For minor updates, you can instead choose to create an issue with short snippets of code. See above.
+You are welcome to send patches, under the Bouncy Castle License, as pull requests. For more information, see [Creating a pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request). For minor updates, you can instead choose to create an issue with short snippets of code. See above.
-* Create a JUnit test case for your change, it may be a simple addition to an existing test. If you do not know how to do this, ask us and we will help you.
+* For contributions touching multiple files try and split up the pull request, smaller changes are easier to review and test, as well as being less likely to run into merge issues.
+* Create a test cases for your change, it may be a simple addition to an existing test. If you do not know how to do this, ask us and we will help you.
* If you run into any merge issues, check out this [git tutorial](https://github.com/skills/resolve-merge-conflicts) to help you resolve merge conflicts and other issues.
For more information, refer to the Bouncy Castle documentation on [Getting Started with Bouncy Castle](https://doc.primekey.com/bouncycastle/introduction#Introduction-GettingStartedwithBouncyCastle).
@@ -39,4 +46,3 @@ Don't forget to self-review. Please follow these simple guidelines:
For acceptance, pull requests need to meet specific quality criteria, including tests for anything substantial. Someone on the Bouncy Castle core team will review the pull request when there is time, and let you know if something is missing or suggest improvements. If it is a useful and generic feature it will be integrated in Bouncy Castle to be available in a later release.
-For substantial, non-trivial contributions, you will be asked to sign a contributor assignment agreement. Optionally, you can also have your name and contact information listed in [Contributors](https://www.bouncycastle.org/contributors.html).
From 13828532b4b36fb91b216fbe871d4918546f0c28 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 19 Mar 2024 14:36:15 +1100
Subject: [PATCH 0178/1846] minor wording, added mention of FIPS
---
SECURITY.md | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/SECURITY.md b/SECURITY.md
index ed92b93b20..3813599af0 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -1,14 +1,17 @@
# Security Policy
## Reporting a Vulnerability
+
If you think that you have found a security vulnerability, please report it to this email address: [feedback-crypto@bouncycastle.org](mailto:feedback-crypto@bouncycastle.org)
Describe the issue including all details, for example:
* Short summary of the problem
* Steps to reproduce
-* Affected product versions
+* Affected API versions
* Logs if available
-The Keyfactor team will send a response indicating the next steps in handling your report. You may be asked to provide additional information or guidance.
+The Bouncy Castle team will send a response indicating the next steps in handling your report. You may be asked to provide additional information or guidance.
+
+If the issue is confirmed as a vulnerability, we will open a Security Advisory and acknowledge your contributions as part of it. Optionally, you can have your name and contact information listed in [Contributors](https://www.bouncycastle.org/contributors.html) as well.
-If the issue is confirmed as a vulnerability, we will open a Security Advisory and acknowledge your contributions as part of it. Optionally, you can have your name and contact information listed in [Contributors](https://www.bouncycastle.org/contributors.html).
+Please note we endeavor to issue patched releases that deal with security issues as soon as they are made known to us, ideally prior to issuing a Security Advisory where otherwise possible. In some cases, particularly if it relates to a FIPS release, delays due to external processes may delay the issuing of a Security Advisory.
From deb0954e63fcaa1a391851a82dd945f3e4995149 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 20 Mar 2024 12:59:03 +0700
Subject: [PATCH 0179/1846] Further checks in bcpg.sig
---
.../bcpg/sig/KeyExpirationTime.java | 11 +++++----
.../bcpg/sig/SignatureCreationTime.java | 23 ++++++++-----------
.../bcpg/sig/SignatureExpirationTime.java | 13 ++++++-----
.../java/org/bouncycastle/bcpg/sig/Utils.java | 18 +++++++++++----
.../openpgp/test/BytesBooleansTest.java | 5 ++--
5 files changed, 39 insertions(+), 31 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyExpirationTime.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyExpirationTime.java
index 813cd02fc3..e618720b59 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyExpirationTime.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/KeyExpirationTime.java
@@ -9,6 +9,9 @@
public class KeyExpirationTime
extends SignatureSubpacket
{
+ /**
+ * @deprecated Will be removed
+ */
protected static byte[] timeToBytes(
long t)
{
@@ -22,14 +25,14 @@ public KeyExpirationTime(
{
super(SignatureSubpacketTags.KEY_EXPIRE_TIME, critical, isLongLength, data);
}
-
+
public KeyExpirationTime(
boolean critical,
long seconds)
{
super(SignatureSubpacketTags.KEY_EXPIRE_TIME, critical, false, Utils.timeToBytes(seconds));
}
-
+
/**
* Return the number of seconds after creation time a key is valid for.
*
@@ -37,8 +40,6 @@ public KeyExpirationTime(
*/
public long getTime()
{
- long time = ((long)(data[0] & 0xff) << 24) | ((data[1] & 0xff) << 16) | ((data[2] & 0xff) << 8) | (data[3] & 0xff);
-
- return time;
+ return Utils.timeFromBytes(data);
}
}
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureCreationTime.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureCreationTime.java
index 220de3cbf6..deeebae46c 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureCreationTime.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureCreationTime.java
@@ -11,20 +11,16 @@
public class SignatureCreationTime
extends SignatureSubpacket
{
+ /**
+ * @deprecated Will be removed
+ */
protected static byte[] timeToBytes(
Date date)
{
- byte[] data = new byte[4];
- long t = date.getTime() / 1000;
-
- data[0] = (byte)(t >> 24);
- data[1] = (byte)(t >> 16);
- data[2] = (byte)(t >> 8);
- data[3] = (byte)t;
-
- return data;
+ long t = date.getTime() / 1000;
+ return Utils.timeToBytes(t);
}
-
+
public SignatureCreationTime(
boolean critical,
boolean isLongLength,
@@ -32,18 +28,17 @@ public SignatureCreationTime(
{
super(SignatureSubpacketTags.CREATION_TIME, critical, isLongLength, data);
}
-
+
public SignatureCreationTime(
boolean critical,
Date date)
{
super(SignatureSubpacketTags.CREATION_TIME, critical, false, timeToBytes(date));
}
-
+
public Date getTime()
{
- long time = ((long)(data[0] & 0xff) << 24) | ((data[1] & 0xff) << 16) | ((data[2] & 0xff) << 8) | (data[3] & 0xff);
-
+ long time = Utils.timeFromBytes(data);
return new Date(time * 1000);
}
}
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java
index f5293a6a86..4065985018 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/SignatureExpirationTime.java
@@ -9,12 +9,15 @@
public class SignatureExpirationTime
extends SignatureSubpacket
{
+ /**
+ * @deprecated Will be removed
+ */
protected static byte[] timeToBytes(
long t)
{
return Utils.timeToBytes(t);
}
-
+
public SignatureExpirationTime(
boolean critical,
boolean isLongLength,
@@ -22,21 +25,19 @@ public SignatureExpirationTime(
{
super(SignatureSubpacketTags.EXPIRE_TIME, critical, isLongLength, data);
}
-
+
public SignatureExpirationTime(
boolean critical,
long seconds)
{
super(SignatureSubpacketTags.EXPIRE_TIME, critical, false, Utils.timeToBytes(seconds));
}
-
+
/**
* return time in seconds before signature expires after creation time.
*/
public long getTime()
{
- long time = ((long)(data[0] & 0xff) << 24) | ((data[1] & 0xff) << 16) | ((data[2] & 0xff) << 8) | (data[3] & 0xff);
-
- return time;
+ return Utils.timeFromBytes(data);
}
}
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java b/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java
index cb46936df7..074a38760b 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/sig/Utils.java
@@ -48,16 +48,26 @@ else if (bytes[0] == 1)
}
}
- static byte[] timeToBytes(
- long t)
+ static long timeFromBytes(byte[] bytes)
{
- byte[] data = new byte[4];
+ if (bytes.length != 4)
+ {
+ throw new IllegalStateException("Byte array has unexpected length. Expected length 4, got " + bytes.length);
+ }
+
+ return ((long)(bytes[0] & 0xff) << 24)
+ | ((bytes[1] & 0xff) << 16)
+ | ((bytes[2] & 0xff) << 8)
+ | (bytes[3] & 0xff);
+ }
+ static byte[] timeToBytes(long t)
+ {
+ byte[] data = new byte[4];
data[0] = (byte)(t >> 24);
data[1] = (byte)(t >> 16);
data[2] = (byte)(t >> 8);
data[3] = (byte)t;
-
return data;
}
}
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/BytesBooleansTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/BytesBooleansTest.java
index 755ac0a223..a8b5dc23e9 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/BytesBooleansTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/BytesBooleansTest.java
@@ -1,8 +1,9 @@
-package org.bouncycastle.util.utiltest;
+package org.bouncycastle.openpgp.test;
-import junit.framework.TestCase;
import org.bouncycastle.bcpg.sig.PrimaryUserID;
+import junit.framework.TestCase;
+
public class BytesBooleansTest
extends TestCase
{
From ebe1c75579170072dc59b8dee2b55ce31663178f Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 20 Mar 2024 13:57:09 +0700
Subject: [PATCH 0180/1846] EdDSA: Explicit guard against infinite looping
---
.../bouncycastle/math/ec/rfc8032/Ed25519.java | 14 ++++++++--
.../bouncycastle/math/ec/rfc8032/Ed448.java | 14 ++++++++--
.../math/ec/rfc8032/Scalar25519.java | 10 ++++++-
.../math/ec/rfc8032/Scalar448.java | 10 ++++++-
.../math/ec/rfc8032/ScalarUtil.java | 28 +++++++++----------
5 files changed, 56 insertions(+), 20 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed25519.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed25519.java
index a9248176b1..7aedfb90ef 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed25519.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed25519.java
@@ -566,7 +566,12 @@ private static boolean implVerify(byte[] sig, int sigOff, byte[] pk, int pkOff,
int[] v0 = new int[4];
int[] v1 = new int[4];
- Scalar25519.reduceBasisVar(nA, v0, v1);
+
+ if (!Scalar25519.reduceBasisVar(nA, v0, v1))
+ {
+ throw new IllegalStateException();
+ }
+
Scalar25519.multiply128Var(nS, v1, nS);
PointAccum pZ = new PointAccum();
@@ -628,7 +633,12 @@ private static boolean implVerify(byte[] sig, int sigOff, PublicPoint publicPoin
int[] v0 = new int[4];
int[] v1 = new int[4];
- Scalar25519.reduceBasisVar(nA, v0, v1);
+
+ if (!Scalar25519.reduceBasisVar(nA, v0, v1))
+ {
+ throw new IllegalStateException();
+ }
+
Scalar25519.multiply128Var(nS, v1, nS);
PointAccum pZ = new PointAccum();
diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed448.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed448.java
index 9fc9bed9b7..2d2053e649 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed448.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed448.java
@@ -510,7 +510,12 @@ private static boolean implVerify(byte[] sig, int sigOff, byte[] pk, int pkOff,
int[] v0 = new int[8];
int[] v1 = new int[8];
- Scalar448.reduceBasisVar(nA, v0, v1);
+
+ if (!Scalar448.reduceBasisVar(nA, v0, v1))
+ {
+ throw new IllegalStateException();
+ }
+
Scalar448.multiply225Var(nS, v1, nS);
PointProjective pZ = new PointProjective();
@@ -569,7 +574,12 @@ private static boolean implVerify(byte[] sig, int sigOff, PublicPoint publicPoin
int[] v0 = new int[8];
int[] v1 = new int[8];
- Scalar448.reduceBasisVar(nA, v0, v1);
+
+ if (!Scalar448.reduceBasisVar(nA, v0, v1))
+ {
+ throw new IllegalStateException();
+ }
+
Scalar448.multiply225Var(nS, v1, nS);
PointProjective pZ = new PointProjective();
diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java
index a760625798..175513fba4 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar25519.java
@@ -295,7 +295,7 @@ static byte[] reduce512(byte[] n)
return r;
}
- static void reduceBasisVar(int[] k, int[] z0, int[] z1)
+ static boolean reduceBasisVar(int[] k, int[] z0, int[] z1)
{
/*
* Split scalar k into two half-size scalars z0 and z1, such that z1 * k == z0 mod L.
@@ -312,11 +312,18 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1)
int[] v0 = new int[4]; System.arraycopy(k, 0, v0, 0, 4);
int[] v1 = new int[4]; v1[0] = 1;
+ // Conservative upper bound on the number of loop iterations needed
+ int iterations = TARGET_LENGTH * 4;
int last = 15;
int len_Nv = ScalarUtil.getBitLengthPositive(last, Nv);
while (len_Nv > TARGET_LENGTH)
{
+ if (--iterations < 0)
+ {
+ return false;
+ }
+
int len_p = ScalarUtil.getBitLength(last, p);
int s = len_p - len_Nv;
s &= ~(s >> 31);
@@ -346,6 +353,7 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1)
// v1 * k == v0 mod L
System.arraycopy(v0, 0, z0, 0, 4);
System.arraycopy(v1, 0, z1, 0, 4);
+ return true;
}
static void toSignedDigits(int bits, int[] z)
diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java
index edac5c02da..f6ba495f97 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/Scalar448.java
@@ -560,7 +560,7 @@ static byte[] reduce912(byte[] n)
return r;
}
- static void reduceBasisVar(int[] k, int[] z0, int[] z1)
+ static boolean reduceBasisVar(int[] k, int[] z0, int[] z1)
{
/*
* Split scalar k into two half-size scalars z0 and z1, such that z1 * k == z0 mod L.
@@ -577,11 +577,18 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1)
int[] v0 = new int[8]; System.arraycopy(k, 0, v0, 0, 8);
int[] v1 = new int[8]; v1[0] = 1;
+ // Conservative upper bound on the number of loop iterations needed
+ int iterations = TARGET_LENGTH * 4;
int last = 27;
int len_Nv = ScalarUtil.getBitLengthPositive(last, Nv);
while (len_Nv > TARGET_LENGTH)
{
+ if (--iterations < 0)
+ {
+ return false;
+ }
+
int len_p = ScalarUtil.getBitLength(last, p);
int s = len_p - len_Nv;
s &= ~(s >> 31);
@@ -614,6 +621,7 @@ static void reduceBasisVar(int[] k, int[] z0, int[] z1)
// v1 * k == v0 mod L
System.arraycopy(v0, 0, z0, 0, 8);
System.arraycopy(v1, 0, z1, 0, 8);
+ return true;
}
static void toSignedDigits(int bits, int[] x, int[] z)
diff --git a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java
index 100fd485e7..483bf477d9 100644
--- a/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java
+++ b/core/src/main/java/org/bouncycastle/math/ec/rfc8032/ScalarUtil.java
@@ -22,11 +22,11 @@ static void addShifted_NP(int last, int s, int[] Nu, int[] Nv, int[] p, int[] t)
cc_p += p_i & M;
cc_p += Nv[i] & M;
- p_i = (int)cc_p; cc_p >>= 32;
- p[i] = p_i;
+ p_i = (int)cc_p; cc_p >>>= 32;
+ p[i] = p_i;
cc_Nu += p_i & M;
- Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
+ Nu[i] = (int)cc_Nu; cc_Nu >>>= 32;
}
}
else if (s < 32)
@@ -50,20 +50,20 @@ else if (s < 32)
cc_p += p_i & M;
cc_p += v_s & M;
- p_i = (int)cc_p; cc_p >>= 32;
+ p_i = (int)cc_p; cc_p >>>= 32;
p[i] = p_i;
int q_s = (p_i << s) | (prev_q >>> -s);
- prev_q =p_i;
+ prev_q = p_i;
cc_Nu += q_s & M;
- Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
+ Nu[i] = (int)cc_Nu; cc_Nu >>>= 32;
}
}
else
{
- // Keep the original value of p in t.
- System.arraycopy(p, 0, t, 0, p.length);
+ // Copy the low limbs of the original p
+ System.arraycopy(p, 0, t, 0, last);
int sWords = s >>> 5; int sBits = s & 31;
if (sBits == 0)
@@ -75,10 +75,10 @@ else if (s < 32)
cc_p += p[i] & M;
cc_p += Nv[i - sWords] & M;
- p[i] = (int)cc_p; cc_p >>= 32;
+ p[i] = (int)cc_p; cc_p >>>= 32;
cc_Nu += p[i - sWords] & M;
- Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
+ Nu[i] = (int)cc_Nu; cc_Nu >>>= 32;
}
}
else
@@ -102,14 +102,14 @@ else if (s < 32)
cc_p += p[i] & M;
cc_p += v_s & M;
- p[i] = (int)cc_p; cc_p >>= 32;
+ p[i] = (int)cc_p; cc_p >>>= 32;
int next_q = p[i - sWords];
int q_s = (next_q << sBits) | (prev_q >>> -sBits);
prev_q = next_q;
cc_Nu += q_s & M;
- Nu[i] = (int)cc_Nu; cc_Nu >>= 32;
+ Nu[i] = (int)cc_Nu; cc_Nu >>>= 32;
}
}
}
@@ -251,8 +251,8 @@ else if (s < 32)
}
else
{
- // Keep the original value of p in t.
- System.arraycopy(p, 0, t, 0, p.length);
+ // Copy the low limbs of the original p
+ System.arraycopy(p, 0, t, 0, last);
int sWords = s >>> 5; int sBits = s & 31;
if (sBits == 0)
From eb98ec6278de13a169159cfb215d2bf825dbfa71 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 20 Mar 2024 14:56:40 +0700
Subject: [PATCH 0181/1846] Remove duplicate test case
---
core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java | 1 -
1 file changed, 1 deletion(-)
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java b/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java
index 993200cf3a..87bdd0467e 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java
@@ -780,7 +780,6 @@ private void testRegressionInfiniteLoop() throws Exception
"pub=MCowBQYDK2VwAyEAHtYhM7lFrRHW9FqjuSEdDZ1tctjede+MoV0R1UMtVVg= priv=MC4CAQAwBQYDK2VwBCIEIJD6PKp3MulK/B/Np+Cdu+Cfo6x2EPkJJliRnj1G9xs/ msg=Q/p5WuG23JyPgshQbo5YGam23fQ5OVqjC0fCzYVXRw+C9vDQdLODe5D6PKp3MulK/B/Np+Cdu+Cfo6x2EPkJJg== sig=t4XSeew/w5x52oghg7VR7yDP6cP2JkP+1qCbuYJyUNW/lmNKD16Tk3SWktl4o3HzmpQewS3lxx1vR2pKhkPqAw== e=found last=15 s=34 in subShifted_NP",
"pub=MCowBQYDK2VwAyEAEI/536MsgF7aZ9O6hLaT2cGEwCIQRajWmvxE+iv+5Ig= priv=MC4CAQAwBQYDK2VwBCIEIE5+N8mBMqbcslWpsFiYUJLEbnKC1CZgwnql5scPhVqA msg=1CZgwnql5scPhVqAJy5QN89FfioiZlPgPcwVjCM2AgM5Frk3eACOherjcVcSUSth7u2NWh3IJGkOy+UgE6g3/w== sig=9iS9EP9mkQOoxQoGzcznIChrPQGdAA763KQjwnN5k4HmVBX/abYK5XIk6H+sfZ88Qq7VOFy8c1H1CwYb465AAg== e=found last=15 s=35 in subShifted_NP",
"pub=MCowBQYDK2VwAyEAvdP5ffItF2siN+QBywHeCpXDFhjxK7SZwT2MfjSoipU= priv=MC4CAQAwBQYDK2VwBCIEINx5YWaFb57Vnoqc93w5yK8TSWlY+7GEYVjpc2WkiPI/ msg=Ggwp5bmATPmRhoheAaYfJTYxkSrIXYcSTqxi3HlhZoVvntWeipz3fDnIrxNJaVj7sYRhWOlzZaSI8j9oTJ1ygA== sig=c5HoX+KDVG2wM7o0o4dKJUy/zczPaKDUcnWhsmP3d6evqfDbRNAQpLopFdO9dyfuEv1H1gn+qLQUVvZcuwLDDw== e=infinite loop regression",
- "pub=MCowBQYDK2VwAyEAvdP5ffItF2siN+QBywHeCpXDFhjxK7SZwT2MfjSoipU= priv=MC4CAQAwBQYDK2VwBCIEINx5YWaFb57Vnoqc93w5yK8TSWlY+7GEYVjpc2WkiPI/ msg=Ggwp5bmATPmRhoheAaYfJTYxkSrIXYcSTqxi3HlhZoVvntWeipz3fDnIrxNJaVj7sYRhWOlzZaSI8j9oTJ1ygA== sig=c5HoX+KDVG2wM7o0o4dKJUy/zczPaKDUcnWhsmP3d6evqfDbRNAQpLopFdO9dyfuEv1H1gn+qLQUVvZcuwLDDw== e=infinite loop regression",
"pub=MCowBQYDK2VwAyEAhPw0vNPFREOs5U1MkD0yCWZ3WCOmwVSvN2jF1Oizqbk= priv=MC4CAQAwBQYDK2VwBCIEIP80+hG+p3eZq1Ez2fIwZVisdXlokktg+bLNtBeM/GQA msg=2I3ilxrJP/fye0bwPSNTluAceuuI6hS1a9t7J9YSlIX9WOwvrnoz2BUKVPkLpHmyEK7JHMDttj4l6BQiCOl//w== sig=kp9BeH0HbGR8wWV5vERw/tZtGHuYdpNvcUO7fyzEAp+avoeJFptyh7jzuvic/lcH8+W43kjvq2wn7t+Y4QOCAA== e=infinite loop regression",
"pub=MCowBQYDK2VwAyEA6yB65NH24xZ3gPJpAf2oZiobm/CDOsW2mTA5NYHiu9Q= priv=MC4CAQAwBQYDK2VwBCIEIA8QPr2HS5Ph1RitdsIwIn6rAvIhxGzrI0iMNTQXdaOK msg=xaumAcR/MN99ugA1y5nJ/KZ89v2ubNtaOKMr85InQXbcd6tQUDJKVgi1s5E00FUzZNayymWz0FIZmpuB+B3D6A== sig=2Hh82APLUonf07pjWJPbqNkIvH0FKaGuqR6uZy0SolDLBOQRUUo19t6txaNjafroKvKivxp4BJZK//UZANV/AQ== e=infinite loop regression",
"pub=MCowBQYDK2VwAyEAjzPeoBYWUh6lK8tL5zvJMe3quOc9DHDHqjaqmlQ9eCs= priv=MC4CAQAwBQYDK2VwBCIEIM/KKNbVtHGuvVjVRndMVx+uGHioSJfRTLV3mMT/qs0O msg=xoQTj8hSoCBUbsW5fls1TN4WIBm8+r9Q4dG8neWlAU5D0pb5V7PzbBUFJWeMN0nvqEZA2EOlmOckFJwvw4kbvg== sig=RvTiLTOBLVlUPXgblZ51/UkOE6Yen7x4M02mxNRnKQIQvRW6Xy3qME2Z0Am2zJnQUl5NzmX7bwYSxgxpmI88AQ== e=infinite loop regression",
From 73449dfa013b0f3e90489d0eea618cfb42505179 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 20 Mar 2024 19:16:33 +1100
Subject: [PATCH 0182/1846] fixed dodgy test...
---
pg/src/test/java/org/bouncycastle/gpg/keybox/AllTests.java | 1 -
.../org/bouncycastle/gpg/keybox/KeyBoxByteBufferTest.java | 4 ++--
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/pg/src/test/java/org/bouncycastle/gpg/keybox/AllTests.java b/pg/src/test/java/org/bouncycastle/gpg/keybox/AllTests.java
index 57c0e8f0ce..e5c299fc6a 100644
--- a/pg/src/test/java/org/bouncycastle/gpg/keybox/AllTests.java
+++ b/pg/src/test/java/org/bouncycastle/gpg/keybox/AllTests.java
@@ -7,7 +7,6 @@
import junit.framework.TestCase;
import junit.framework.TestSuite;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.bouncycastle.openpgp.test.RegressionTest;
import org.bouncycastle.test.PrintTestResult;
import org.bouncycastle.util.test.SimpleTestResult;
diff --git a/pg/src/test/java/org/bouncycastle/gpg/keybox/KeyBoxByteBufferTest.java b/pg/src/test/java/org/bouncycastle/gpg/keybox/KeyBoxByteBufferTest.java
index 476afef312..047720190f 100644
--- a/pg/src/test/java/org/bouncycastle/gpg/keybox/KeyBoxByteBufferTest.java
+++ b/pg/src/test/java/org/bouncycastle/gpg/keybox/KeyBoxByteBufferTest.java
@@ -123,11 +123,11 @@ public void testExceptions()
testException("size exceeds buffer remaining", "IllegalArgumentException", () -> buf.consume(buf.remaining() + 1));
- testException("size less than 0", "IllegalArgumentException", () -> buf.consume(buf.size()));
+ testException("size less than 0", "IllegalArgumentException", () -> buf.bN(-1));
testException("size exceeds buffer remaining", "IllegalArgumentException", () -> {
KeyBoxByteBuffer buf1 = KeyBoxByteBuffer.wrap(new byte[21]);
- buf1.consume(buf1.getBuffer().remaining() + 1);
+ buf1.consume(22);
});
}
From 4155ab201f584333314c9320395a0c6ab6982f12 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sun, 24 Mar 2024 00:44:29 +1100
Subject: [PATCH 0183/1846] Initial cut for id-alg-cek-hkdf-sha256 CMS support.
---
.../crypto/test/HKDFGeneratorTest.java | 95 ++++++--
.../cms/CMSEncryptedDataGenerator.java | 4 +-
.../java/org/bouncycastle/cms/CMSUtils.java | 11 +-
.../cms/jcajce/EnvelopedDataHelper.java | 66 +++++-
.../jcajce/JceCMSContentEncryptorBuilder.java | 205 ++++++++++++------
.../cms/jcajce/JceKEKRecipient.java | 2 +-
.../cms/jcajce/JceKEMRecipient.java | 2 +-
.../cms/jcajce/JceKTSKeyTransRecipient.java | 2 +-
.../cms/jcajce/JceKeyTransRecipient.java | 14 +-
...ultSignatureAlgorithmIdentifierFinder.java | 20 ++
.../cms/test/AuthEnvelopedDataTest.java | 107 +++++++++
.../cms/test/NewEnvelopedDataTest.java | 78 ++++++-
.../asn1/cms/CMSObjectIdentifiers.java | 6 +
13 files changed, 509 insertions(+), 103 deletions(-)
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/HKDFGeneratorTest.java b/core/src/test/java/org/bouncycastle/crypto/test/HKDFGeneratorTest.java
index ec646147d5..f4524ec2bf 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/HKDFGeneratorTest.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/HKDFGeneratorTest.java
@@ -5,6 +5,7 @@
import org.bouncycastle.crypto.digests.SHA256Digest;
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
import org.bouncycastle.crypto.params.HKDFParameters;
+import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -262,32 +263,92 @@ public void performTest()
// (salt defaults to HashLen zero octets)
// this test is identical to test 7 in all ways bar the IKM value
+ {
+ Digest hash = new SHA1Digest();
+ byte[] ikm = Hex
+ .decode("2adccada18779e7c2077ad2eb19d3f3e731385dd");
+ byte[] info = new byte[0];
+ int l = 255 * hash.getDigestSize();
+ byte[] okm = new byte[l];
- Digest hash = new SHA1Digest();
- byte[] ikm = Hex
- .decode("2adccada18779e7c2077ad2eb19d3f3e731385dd");
- byte[] info = new byte[0];
- int l = 255 * hash.getDigestSize();
- byte[] okm = new byte[l];
+ HKDFParameters params = HKDFParameters.skipExtractParameters(ikm, info);
- HKDFParameters params = HKDFParameters.skipExtractParameters(ikm, info);
+ HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash);
+ hkdf.init(params);
+ hkdf.generateBytes(okm, 0, l);
- HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash);
- hkdf.init(params);
- hkdf.generateBytes(okm, 0, l);
+ int zeros = 0;
+ for (int i = 0; i < hash.getDigestSize(); i++)
+ {
+ if (okm[i] == 0)
+ {
+ zeros++;
+ }
+ }
- int zeros = 0;
- for (int i = 0; i < hash.getDigestSize(); i++)
- {
- if (okm[i] == 0)
+ if (zeros == hash.getDigestSize())
{
- zeros++;
+ fail("HKDF failed generator test " + 102);
}
}
- if (zeros == hash.getDigestSize())
{
- fail("HKDF failed generator test " + 102);
+ // CMS_CEK_HKDF_SHA256 B.1
+ // IKM = c702e7d0a9e064b09ba55245fb733cf3
+ //
+ // The AES-128-CGM AlgorithmIdentifier:
+ // algorithm=2.16.840.1.101.3.4.1.6
+ // parameters=GCMParameters:
+ // aes-nonce=0x5c79058ba2f43447639d29e2
+ // aes-ICVlen is ommited; it indicates the DEFAULT of 12
+ //
+ // DER-encoded AlgorithmIdentifier:
+ // 301b0609608648016503040106300e040c5c79058ba2f43447639d29e2
+ //
+ // OKM = 2124ffb29fac4e0fbbc7d5d87492bff3
+ Digest hash = new SHA256Digest();
+ byte[] ikm = Hex.decode("c702e7d0a9e064b09ba55245fb733cf3");
+ byte[] salt = Strings.toByteArray("The Cryptographic Message Syntax");
+ byte[] info = Hex.decode("301b0609608648016503040106300e040c5c79058ba2f43447639d29e2");
+ byte[] okm = Hex.decode("2124ffb29fac4e0fbbc7d5d87492bff3");
+ byte[] genOkm = new byte[okm.length];
+
+ HKDFParameters params = new HKDFParameters(ikm, salt, info);
+
+ HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash);
+ hkdf.init(params);
+ hkdf.generateBytes(genOkm, 0, genOkm.length);
+
+ compareOKM(8, genOkm, okm);
+ }
+
+ {
+ // CMS_CEK_HKDF_SHA256 B.1
+ //
+ // IKM = c702e7d0a9e064b09ba55245fb733cf3
+ //
+ // The AES-128-CBC AlgorithmIdentifier:
+ // algorithm=2.16.840.1.101.3.4.1.2
+ // parameters=AES-IV=0x651f722ffd512c52fe072e507d72b377
+ //
+ // DER-encoded AlgorithmIdentifier:
+ // 301d06096086480165030401020410651f722ffd512c52fe072e507d72b377
+ //
+ // OKM = 9cd102c52f1e19ece8729b35bfeceb50
+ Digest hash = new SHA256Digest();
+ byte[] ikm = Hex.decode("c702e7d0a9e064b09ba55245fb733cf3");
+ byte[] salt = Strings.toByteArray("The Cryptographic Message Syntax");
+ byte[] info = Hex.decode("301d06096086480165030401020410651f722ffd512c52fe072e507d72b377");
+ byte[] okm = Hex.decode("9cd102c52f1e19ece8729b35bfeceb50");
+ byte[] genOkm = new byte[okm.length];
+
+ HKDFParameters params = new HKDFParameters(ikm, salt, info);
+
+ HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash);
+ hkdf.init(params);
+ hkdf.generateBytes(genOkm, 0, genOkm.length);
+
+ compareOKM(9, genOkm, okm);
}
}
diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java b/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java
index 9e17d5c1c6..dac06a1732 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/CMSEncryptedDataGenerator.java
@@ -70,10 +70,10 @@ private CMSEncryptedData doGenerate(
encContent = new BEROctetString(encryptedContent);
- EncryptedContentInfo eci = new EncryptedContentInfo(
+ EncryptedContentInfo eci = CMSUtils.getEncryptedContentInfo(
content.getContentType(),
encAlgId,
- encContent);
+ encryptedContent);
ASN1Set unprotectedAttrSet = CMSUtils.getAttrBERSet(unprotectedAttributeGenerator);
diff --git a/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java b/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java
index 5a11cedae8..80cdb1fa3b 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/CMSUtils.java
@@ -423,14 +423,19 @@ static OutputStream getSafeTeeOutputStream(OutputStream s1,
}
static EncryptedContentInfo getEncryptedContentInfo(CMSTypedData content, OutputEncryptor contentEncryptor, byte[] encryptedContent)
- throws CMSException
{
- AlgorithmIdentifier encAlgId = contentEncryptor.getAlgorithmIdentifier();
+ return getEncryptedContentInfo(
+ content.getContentType(),
+ contentEncryptor.getAlgorithmIdentifier(),
+ encryptedContent);
+ }
+ static EncryptedContentInfo getEncryptedContentInfo(ASN1ObjectIdentifier encryptedContentType, AlgorithmIdentifier encAlgId, byte[] encryptedContent)
+ {
ASN1OctetString encContent = new BEROctetString(encryptedContent);
return new EncryptedContentInfo(
- content.getContentType(),
+ encryptedContentType,
encAlgId,
encContent);
}
diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java
index 1a1ca1e83f..65aa3fba4b 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/EnvelopedDataHelper.java
@@ -1,5 +1,6 @@
package org.bouncycastle.cms.jcajce;
+import java.io.IOException;
import java.security.AlgorithmParameterGenerator;
import java.security.AlgorithmParameters;
import java.security.GeneralSecurityException;
@@ -32,11 +33,13 @@
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1Null;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PBKDF2Params;
@@ -47,6 +50,9 @@
import org.bouncycastle.cms.CMSEnvelopedDataGenerator;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.cms.PasswordRecipient;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
+import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.operator.AsymmetricKeyUnwrapper;
import org.bouncycastle.operator.DefaultSecretKeySizeProvider;
import org.bouncycastle.operator.GenericKey;
@@ -54,10 +60,13 @@
import org.bouncycastle.operator.SymmetricKeyUnwrapper;
import org.bouncycastle.operator.jcajce.JceAsymmetricKeyUnwrapper;
import org.bouncycastle.operator.jcajce.JceKTSKeyUnwrapper;
+import org.bouncycastle.util.Strings;
public class EnvelopedDataHelper
{
protected static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE;
+ private static final byte[] hkdfSalt = Strings.toByteArray("The Cryptographic Message Syntax");
+
private static final Set authEnvelopedAlgorithms = new HashSet();
protected static final Map BASE_CIPHER_NAMES = new HashMap();
@@ -203,6 +212,46 @@ public Key getJceKey(ASN1ObjectIdentifier algorithm, GenericKey key)
throw new IllegalArgumentException("unknown generic key type");
}
+ public Key getJceKey(AlgorithmIdentifier algId, GenericKey key)
+ throws CMSException
+ {
+ if (algId.getAlgorithm().equals(CMSObjectIdentifiers.id_alg_cek_hkdf_sha256))
+ {
+ byte[] keyData = null;
+
+ if (key.getRepresentation() instanceof Key)
+ {
+ keyData = ((Key)key.getRepresentation()).getEncoded();
+ }
+
+ if (key.getRepresentation() instanceof byte[])
+ {
+ keyData = (byte[])key.getRepresentation();
+ }
+
+ AlgorithmIdentifier encAlgId = AlgorithmIdentifier.getInstance(algId.getParameters());
+
+ // TODO: at the moment assumes HKDF with SHA256
+ HKDFBytesGenerator kdf = new HKDFBytesGenerator(new SHA256Digest());
+ try
+ {
+ kdf.init(new HKDFParameters(keyData, hkdfSalt, encAlgId.getEncoded(ASN1Encoding.DER)));
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to encode enc algorithm parameters", e);
+ }
+
+ kdf.generateBytes(keyData, 0, keyData.length);
+
+ return new SecretKeySpec(keyData, getBaseCipherName(encAlgId.getAlgorithm()));
+ }
+ else
+ {
+ return getJceKey(algId.getAlgorithm(), key);
+ }
+ }
+
public void keySizeCheck(AlgorithmIdentifier keyAlgorithm, Key key)
throws CMSException
{
@@ -363,15 +412,24 @@ public Object doInJCE()
InvalidKeyException, InvalidParameterSpecException, NoSuchAlgorithmException,
NoSuchPaddingException, NoSuchProviderException
{
- Cipher cipher = createCipher(encryptionAlgID.getAlgorithm());
- ASN1Encodable sParams = encryptionAlgID.getParameters();
- String encAlg = encryptionAlgID.getAlgorithm().getId();
+ AlgorithmIdentifier encAlgId;
+ if (encryptionAlgID.getAlgorithm().equals(CMSObjectIdentifiers.id_alg_cek_hkdf_sha256))
+ {
+ encAlgId = AlgorithmIdentifier.getInstance(encryptionAlgID.getParameters());
+ }
+ else
+ {
+ encAlgId = encryptionAlgID;
+ }
+ Cipher cipher = createCipher(encAlgId.getAlgorithm());
+ ASN1Encodable sParams = encAlgId.getParameters();
+ String encAlg = encAlgId.getAlgorithm().getId();
if (sParams != null && !(sParams instanceof ASN1Null))
{
try
{
- AlgorithmParameters params = createAlgorithmParameters(encryptionAlgID.getAlgorithm());
+ AlgorithmParameters params = createAlgorithmParameters(encAlgId.getAlgorithm());
CMSUtils.loadParameters(params, sParams);
diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
index 78cdf40964..91b4ae4047 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceCMSContentEncryptorBuilder.java
@@ -1,5 +1,6 @@
package org.bouncycastle.cms.jcajce;
+import java.io.IOException;
import java.io.OutputStream;
import java.security.AccessController;
import java.security.AlgorithmParameters;
@@ -11,16 +12,22 @@
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERNull;
+import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.GCMParameters;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.cms.CMSException;
import org.bouncycastle.crypto.CryptoServicesRegistrar;
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
+import org.bouncycastle.crypto.params.HKDFParameters;
import org.bouncycastle.jcajce.io.CipherOutputStream;
import org.bouncycastle.operator.DefaultSecretKeySizeProvider;
import org.bouncycastle.operator.GenericKey;
@@ -29,6 +36,7 @@
import org.bouncycastle.operator.OutputEncryptor;
import org.bouncycastle.operator.SecretKeySizeProvider;
import org.bouncycastle.operator.jcajce.JceGenericKey;
+import org.bouncycastle.util.Strings;
/**
* Builder for the content encryptor in EnvelopedData - used to encrypt the actual transmitted content.
@@ -36,6 +44,7 @@
public class JceCMSContentEncryptorBuilder
{
private static final SecretKeySizeProvider KEY_SIZE_PROVIDER = DefaultSecretKeySizeProvider.INSTANCE;
+ private static final byte[] hkdfSalt = Strings.toByteArray("The Cryptographic Message Syntax");
private final ASN1ObjectIdentifier encryptionOID;
private final int keySize;
@@ -44,6 +53,7 @@ public class JceCMSContentEncryptorBuilder
private SecureRandom random;
private AlgorithmIdentifier algorithmIdentifier;
private AlgorithmParameters algorithmParameters;
+ private ASN1ObjectIdentifier kdfAlgorithm;
public JceCMSContentEncryptorBuilder(ASN1ObjectIdentifier encryptionOID)
{
@@ -93,6 +103,31 @@ public JceCMSContentEncryptorBuilder(AlgorithmIdentifier encryptionAlgId)
this.algorithmIdentifier = encryptionAlgId;
}
+ public JceCMSContentEncryptorBuilder setEnableSha256HKdf(boolean useSha256Hkdf)
+ {
+ if (useSha256Hkdf)
+ {
+ // eventually this will be the default.
+ this.kdfAlgorithm = CMSObjectIdentifiers.id_alg_cek_hkdf_sha256;
+ }
+ else
+ {
+ if (this.kdfAlgorithm != null)
+ {
+ if (this.kdfAlgorithm.equals(CMSObjectIdentifiers.id_alg_cek_hkdf_sha256))
+ {
+ this.kdfAlgorithm = null;
+ }
+ else
+ {
+ throw new IllegalStateException("SHA256 HKDF not enabled");
+ }
+ }
+ }
+
+ return this;
+ }
+
/**
* Set the provider to use for content encryption.
*
@@ -152,9 +187,9 @@ public OutputEncryptor build()
{
if (helper.isAuthEnveloped(encryptionOID))
{
- return new CMSAuthOutputEncryptor(encryptionOID, keySize, algorithmParameters, random);
+ return new CMSAuthOutputEncryptor(kdfAlgorithm, encryptionOID, keySize, algorithmParameters, random);
}
- return new CMSOutputEncryptor(encryptionOID, keySize, algorithmParameters, random);
+ return new CMSOutputEncryptor(kdfAlgorithm, encryptionOID, keySize, algorithmParameters, random);
}
if (algorithmIdentifier != null)
{
@@ -176,19 +211,47 @@ public OutputEncryptor build()
if (helper.isAuthEnveloped(encryptionOID))
{
- return new CMSAuthOutputEncryptor(encryptionOID, keySize, algorithmParameters, random);
+ return new CMSAuthOutputEncryptor(kdfAlgorithm, encryptionOID, keySize, algorithmParameters, random);
}
- return new CMSOutputEncryptor(encryptionOID, keySize, algorithmParameters, random);
+ return new CMSOutputEncryptor(kdfAlgorithm, encryptionOID, keySize, algorithmParameters, random);
}
- private class CMSOutputEncryptor
- implements OutputEncryptor
+ private class CMSOutEncryptor
{
- private SecretKey encKey;
- private AlgorithmIdentifier algorithmIdentifier;
- private Cipher cipher;
+ protected SecretKey encKey;
+ protected AlgorithmIdentifier algorithmIdentifier;
+ protected Cipher cipher;
+
+ private void applyKdf(ASN1ObjectIdentifier kdfAlgorithm, AlgorithmParameters params, SecureRandom random)
+ throws CMSException
+ {
+ // TODO: at the moment assumes HKDF with SHA256
+ HKDFBytesGenerator kdf = new HKDFBytesGenerator(new SHA256Digest());
+ byte[] encKeyEncoded = encKey.getEncoded();
+ try
+ {
+ kdf.init(new HKDFParameters(encKeyEncoded, hkdfSalt, algorithmIdentifier.getEncoded(ASN1Encoding.DER)));
+ }
+ catch (IOException e)
+ {
+ throw new CMSException("unable to encode enc algorithm parameters", e);
+ }
- CMSOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random)
+ kdf.generateBytes(encKeyEncoded, 0, encKeyEncoded.length);
+
+ SecretKeySpec derivedKey = new SecretKeySpec(encKeyEncoded, encKey.getAlgorithm());
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, derivedKey, params, random);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("unable to initialize cipher: " + e.getMessage(), e);
+ }
+ algorithmIdentifier = new AlgorithmIdentifier(kdfAlgorithm, algorithmIdentifier);
+ }
+
+ protected void init(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random)
throws CMSException
{
KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID);
@@ -211,26 +274,62 @@ private class CMSOutputEncryptor
{
params = helper.generateParameters(encryptionOID, encKey, random);
}
-
- try
+
+ if (params != null)
{
- cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random);
+ algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params);
+
+ if (kdfAlgorithm != null)
+ {
+ applyKdf(kdfAlgorithm, params, random);
+ }
+ else
+ {
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("unable to initialize cipher: " + e.getMessage(), e);
+ }
+ }
}
- catch (GeneralSecurityException e)
+ else
{
- throw new CMSException("unable to initialize cipher: " + e.getMessage(), e);
- }
+ //
+ // If params are null we try and second guess on them as some providers don't provide
+ // algorithm parameter generation explicitly but instead generate them under the hood.
+ //
+ try
+ {
+ cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new CMSException("unable to initialize cipher: " + e.getMessage(), e);
+ }
- //
- // If params are null we try and second guess on them as some providers don't provide
- // algorithm parameter generation explicitly but instead generate them under the hood.
- //
- if (params == null)
- {
params = cipher.getParameters();
+
+ algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params);
+
+ if (kdfAlgorithm != null)
+ {
+ applyKdf(kdfAlgorithm, params, random);
+ }
}
+ }
+ }
- algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params);
+ private class CMSOutputEncryptor
+ extends CMSOutEncryptor
+ implements OutputEncryptor
+ {
+ CMSOutputEncryptor(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random)
+ throws CMSException
+ {
+ init(kdfAlgorithm, encryptionOID, keySize, params, random);
}
public AlgorithmIdentifier getAlgorithmIdentifier()
@@ -250,56 +349,15 @@ public GenericKey getKey()
}
private class CMSAuthOutputEncryptor
+ extends CMSOutEncryptor
implements OutputAEADEncryptor
{
- private SecretKey encKey;
- private AlgorithmIdentifier algorithmIdentifier;
- private Cipher cipher;
private MacCaptureStream macOut;
- CMSAuthOutputEncryptor(ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random)
+ CMSAuthOutputEncryptor(ASN1ObjectIdentifier kdfAlgorithm, ASN1ObjectIdentifier encryptionOID, int keySize, AlgorithmParameters params, SecureRandom random)
throws CMSException
{
- KeyGenerator keyGen = helper.createKeyGenerator(encryptionOID);
-
- random = CryptoServicesRegistrar.getSecureRandom(random);
-
- if (keySize < 0)
- {
- keyGen.init(random);
- }
- else
- {
- keyGen.init(keySize, random);
- }
-
- cipher = helper.createCipher(encryptionOID);
- encKey = keyGen.generateKey();
-
- if (params == null)
- {
- params = helper.generateParameters(encryptionOID, encKey, random);
- }
-
- try
- {
- cipher.init(Cipher.ENCRYPT_MODE, encKey, params, random);
- }
- catch (GeneralSecurityException e)
- {
- throw new CMSException("unable to initialize cipher: " + e.getMessage(), e);
- }
-
- //
- // If params are null we try and second guess on them as some providers don't provide
- // algorithm parameter generation explicitly but instead generate them under the hood.
- //
- if (params == null)
- {
- params = cipher.getParameters();
- }
-
- algorithmIdentifier = helper.getAlgorithmIdentifier(encryptionOID, params);
+ init(kdfAlgorithm, encryptionOID, keySize, params, random);
}
public AlgorithmIdentifier getAlgorithmIdentifier()
@@ -309,9 +367,18 @@ public AlgorithmIdentifier getAlgorithmIdentifier()
public OutputStream getOutputStream(OutputStream dOut)
{
+ AlgorithmIdentifier algId;
+ if (kdfAlgorithm != null)
+ {
+ algId = AlgorithmIdentifier.getInstance(algorithmIdentifier.getParameters());
+ }
+ else
+ {
+ algId = algorithmIdentifier;
+ }
+
// TODO: works for CCM too, but others will follow.
- GCMParameters p = GCMParameters.getInstance(algorithmIdentifier.getParameters());
-
+ GCMParameters p = GCMParameters.getInstance(algId.getParameters());
macOut = new MacCaptureStream(dOut, p.getIcvLen());
return new CipherOutputStream(macOut, cipher);
}
diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKRecipient.java
index d0e41644ac..9f8bf096b5 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKRecipient.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEKRecipient.java
@@ -102,7 +102,7 @@ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, Algor
try
{
- Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedContentEncryptionKey));
+ Key key = helper.getJceKey(encryptedKeyAlgorithm, unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedContentEncryptionKey));
if (validateKeySize)
{
diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEMRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEMRecipient.java
index f6b705661e..a900a3cc21 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEMRecipient.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKEMRecipient.java
@@ -159,7 +159,7 @@ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, Algor
try
{
- Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey));
+ Key key = helper.getJceKey(encryptedKeyAlgorithm, unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey));
if (validateKeySize)
{
diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKTSKeyTransRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKTSKeyTransRecipient.java
index 75db768bd5..6d72b784d0 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKTSKeyTransRecipient.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKTSKeyTransRecipient.java
@@ -138,7 +138,7 @@ protected Key extractSecretKey(AlgorithmIdentifier keyEncryptionAlgorithm, Algor
try
{
- Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey));
+ Key key = helper.getJceKey(encryptedKeyAlgorithm, unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey));
if (validateKeySize)
{
diff --git a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipient.java b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipient.java
index f4b08baac0..360a9f2fec 100644
--- a/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipient.java
+++ b/pkix/src/main/java/org/bouncycastle/cms/jcajce/JceKeyTransRecipient.java
@@ -209,7 +209,7 @@ else if (CMSObjectIdentifiers.id_ori_kem.equals(keyEncryptionAlgorithm.getAlgori
try
{
- Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey));
+ Key key = helper.getJceKey(encryptedKeyAlgorithm, unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey));
if (validateKeySize)
{
@@ -239,11 +239,19 @@ else if (CMSObjectIdentifiers.id_ori_kem.equals(keyEncryptionAlgorithm.getAlgori
try
{
- Key key = helper.getJceKey(encryptedKeyAlgorithm.getAlgorithm(), unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey));
+ Key key = helper.getJceKey(encryptedKeyAlgorithm, unwrapper.generateUnwrappedKey(encryptedKeyAlgorithm, encryptedEncryptionKey));
if (validateKeySize)
{
- helper.keySizeCheck(encryptedKeyAlgorithm, key);
+ if (encryptedEncryptionKey.equals(CMSObjectIdentifiers.id_alg_cek_hkdf_sha256))
+ {
+ helper.keySizeCheck(
+ AlgorithmIdentifier.getInstance(encryptedKeyAlgorithm.getParameters()), key);
+ }
+ else
+ {
+ helper.keySizeCheck(encryptedKeyAlgorithm, key);
+ }
}
return key;
diff --git a/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java b/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
index 977d1a25fb..93807dcd06 100644
--- a/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
+++ b/pkix/src/main/java/org/bouncycastle/operator/DefaultSignatureAlgorithmIdentifierFinder.java
@@ -412,6 +412,26 @@ public class DefaultSignatureAlgorithmIdentifierFinder
noParams.add(CMSObjectIdentifiers.id_ecdsa_with_shake128);
noParams.add(CMSObjectIdentifiers.id_ecdsa_with_shake256);
+ //
+ // Composite - Draft 13
+ //
+ noParams.add(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA44_ECDSA_brainpoolP256r1_SHA256);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA44_Ed25519_SHA512);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PSS_SHA512);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA65_RSA3072_PKCS15_SHA512);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA65_ECDSA_brainpoolP256r1_SHA512);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA65_ECDSA_P256_SHA512);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA65_Ed25519_SHA512);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA87_ECDSA_P384_SHA512);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA87_ECDSA_brainpoolP384r1_SHA512);
+ noParams.add(MiscObjectIdentifiers.id_MLDSA87_Ed448_SHA512);
+ noParams.add(MiscObjectIdentifiers.id_Falcon512_ECDSA_P256_SHA256);
+ noParams.add(MiscObjectIdentifiers.id_Falcon512_ECDSA_brainpoolP256r1_SHA256);
+ noParams.add(MiscObjectIdentifiers.id_Falcon512_Ed25519_SHA512);
+
//
// PKCS 1.5 encrypted algorithms
//
diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/AuthEnvelopedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/AuthEnvelopedDataTest.java
index 6d81c93fb6..1f6736766a 100644
--- a/pkix/src/test/java/org/bouncycastle/cms/test/AuthEnvelopedDataTest.java
+++ b/pkix/src/test/java/org/bouncycastle/cms/test/AuthEnvelopedDataTest.java
@@ -18,9 +18,11 @@
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.CMSAttributes;
+import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.GCMParameters;
import org.bouncycastle.asn1.cms.Time;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.cms.CMSAttributeTableGenerationException;
import org.bouncycastle.cms.CMSAttributeTableGenerator;
import org.bouncycastle.cms.CMSAuthEnvelopedData;
@@ -205,6 +207,59 @@ public AttributeTable getAttributes(Map parameters)
assertEquals("Hello, world!", Strings.fromByteArray(recData));
}
+ public void testGCMwithHKDF()
+ throws Exception
+ {
+ if (!CMSTestUtil.isAeadAvailable())
+ {
+ return;
+ }
+ byte[] message = Strings.toByteArray("Hello, world!");
+ OutputEncryptor candidate = new JceCMSContentEncryptorBuilder(NISTObjectIdentifiers.id_aes128_GCM)
+ .setEnableSha256HKdf(true)
+ .setProvider(BC).build();
+
+ assertEquals(CMSObjectIdentifiers.id_alg_cek_hkdf_sha256, candidate.getAlgorithmIdentifier().getAlgorithm());
+
+ AlgorithmIdentifier kdfParams = AlgorithmIdentifier.getInstance(candidate.getAlgorithmIdentifier().getParameters());
+
+ assertEquals(NISTObjectIdentifiers.id_aes128_GCM, kdfParams.getAlgorithm());
+ assertNotNull(GCMParameters.getInstance(kdfParams.getParameters()));
+
+ assertTrue(candidate instanceof OutputAEADEncryptor);
+
+ OutputAEADEncryptor macProvider = (OutputAEADEncryptor)candidate;
+
+ CMSAuthEnvelopedDataGenerator authGen = new CMSAuthEnvelopedDataGenerator();
+
+ authGen.setAuthenticatedAttributeGenerator(new CMSAttributeTableGenerator()
+ {
+ public AttributeTable getAttributes(Map parameters)
+ throws CMSAttributeTableGenerationException
+ {
+ Hashtable attrs = new Hashtable();
+ Attribute testAttr = new Attribute(CMSAttributes.signingTime,
+ new DERSet(new Time(new Date())));
+ attrs.put(testAttr.getAttrType(), testAttr);
+ return new AttributeTable(attrs);
+ }
+ });
+
+ authGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert));
+
+ CMSAuthEnvelopedData authData = authGen.generate(new CMSProcessableByteArray(message), macProvider);
+
+ CMSAuthEnvelopedData encAuthData = new CMSAuthEnvelopedData(authData.getEncoded());
+
+ RecipientInformationStore recipients = encAuthData.getRecipientInfos();
+
+ RecipientInformation recipient = (RecipientInformation)recipients.getRecipients().iterator().next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransAuthEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals("Hello, world!", Strings.fromByteArray(recData));
+ }
+
public void testCCM()
throws Exception
{
@@ -252,6 +307,58 @@ public AttributeTable getAttributes(Map parameters)
assertEquals("Hello, world!", Strings.fromByteArray(recData));
}
+ public void testCCMwithHKDF()
+ throws Exception
+ {
+ if (!CMSTestUtil.isAeadAvailable())
+ {
+ return;
+ }
+ byte[] message = Strings.toByteArray("Hello, world!");
+ OutputEncryptor candidate = new JceCMSContentEncryptorBuilder(NISTObjectIdentifiers.id_aes128_CCM)
+ .setEnableSha256HKdf(true).setProvider(BC).build();
+
+ assertEquals(CMSObjectIdentifiers.id_alg_cek_hkdf_sha256, candidate.getAlgorithmIdentifier().getAlgorithm());
+
+ AlgorithmIdentifier kdfParams = AlgorithmIdentifier.getInstance(candidate.getAlgorithmIdentifier().getParameters());
+
+ assertEquals(NISTObjectIdentifiers.id_aes128_CCM, kdfParams.getAlgorithm());
+ assertNotNull(GCMParameters.getInstance(kdfParams.getParameters()));
+
+ assertTrue(candidate instanceof OutputAEADEncryptor);
+
+ OutputAEADEncryptor macProvider = (OutputAEADEncryptor)candidate;
+
+ CMSAuthEnvelopedDataGenerator authGen = new CMSAuthEnvelopedDataGenerator();
+
+ authGen.setAuthenticatedAttributeGenerator(new CMSAttributeTableGenerator()
+ {
+ public AttributeTable getAttributes(Map parameters)
+ throws CMSAttributeTableGenerationException
+ {
+ Hashtable attrs = new Hashtable();
+ Attribute testAttr = new Attribute(CMSAttributes.signingTime,
+ new DERSet(new Time(new Date())));
+ attrs.put(testAttr.getAttrType(), testAttr);
+ return new AttributeTable(attrs);
+ }
+ });
+
+ authGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert));
+
+ CMSAuthEnvelopedData authData = authGen.generate(new CMSProcessableByteArray(message), macProvider);
+
+ CMSAuthEnvelopedData encAuthData = new CMSAuthEnvelopedData(authData.getEncoded());
+
+ RecipientInformationStore recipients = encAuthData.getRecipientInfos();
+
+ RecipientInformation recipient = (RecipientInformation)recipients.getRecipients().iterator().next();
+
+ byte[] recData = recipient.getContent(new JceKeyTransAuthEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+ assertTrue(java.util.Arrays.equals(authData.getMac(), recipient.getMac()));
+ assertEquals("Hello, world!", Strings.fromByteArray(recData));
+ }
+
public void testBcCCM()
throws Exception
{
diff --git a/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java b/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java
index 89af11290d..180056efb4 100644
--- a/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java
+++ b/pkix/src/test/java/org/bouncycastle/cms/test/NewEnvelopedDataTest.java
@@ -45,6 +45,7 @@
import org.bouncycastle.asn1.cms.Attribute;
import org.bouncycastle.asn1.cms.AttributeTable;
import org.bouncycastle.asn1.cms.CCMParameters;
+import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.cms.EncryptedContentInfo;
import org.bouncycastle.asn1.cms.EnvelopedData;
@@ -791,6 +792,57 @@ public void testKeyTrans()
assertTrue(collection.iterator().next() instanceof RecipientInformation);
}
+ public void testKeyTransWithHKDF()
+ throws Exception
+ {
+ byte[] data = "WallaWallaWashington".getBytes();
+
+ CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
+
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(_reciCert).setProvider(BC));
+ edGen.addRecipientInfoGenerator(new JceKeyTransRecipientInfoGenerator(ASN1OctetString.getInstance(ASN1OctetString.getInstance(_reciCert.getExtensionValue(Extension.subjectKeyIdentifier.getId())).getOctets()).getOctets(), _reciCert.getPublicKey()).setProvider(BC));
+
+ CMSEnvelopedData ed = edGen.generate(
+ new CMSProcessableByteArray(data),
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC)
+ .setEnableSha256HKdf(true)
+ .setProvider(BC).build());
+
+ RecipientInformationStore recipients = ed.getRecipientInfos();
+
+ assertEquals(ed.getEncryptionAlgOID(), CMSObjectIdentifiers.id_alg_cek_hkdf_sha256.getId());
+
+ AlgorithmIdentifier encAlgId = AlgorithmIdentifier.getInstance(ed.getContentEncryptionAlgorithm().getParameters());
+
+ assertEquals(encAlgId.getAlgorithm(), CMSAlgorithm.DES_EDE3_CBC);
+
+ Collection c = recipients.getRecipients();
+
+ assertEquals(2, c.size());
+
+ Iterator it = c.iterator();
+
+ while (it.hasNext())
+ {
+ RecipientInformation recipient = (RecipientInformation)it.next();
+
+ assertEquals(recipient.getKeyEncryptionAlgOID(), PKCSObjectIdentifiers.rsaEncryption.getId());
+
+ byte[] recData = recipient.getContent(new JceKeyTransEnvelopedRecipient(_reciKP.getPrivate()).setProvider(BC));
+
+ assertEquals(true, Arrays.equals(data, recData));
+ }
+
+ RecipientId id = new JceKeyTransRecipientId(_reciCert);
+
+ Collection collection = recipients.getRecipients(id);
+ if (collection.size() != 2)
+ {
+ fail("recipients not matched using general recipient ID.");
+ }
+ assertTrue(collection.iterator().next() instanceof RecipientInformation);
+ }
+
public void testKeyTransOAEPDefault()
throws Exception
{
@@ -1532,6 +1584,7 @@ public void testAES192KEK()
throws Exception
{
tryKekAlgorithm(CMSTestUtil.makeAESKey(192), NISTObjectIdentifiers.id_aes192_wrap);
+ tryKekAlgorithmWithHKdf(CMSTestUtil.makeAESKey(192), NISTObjectIdentifiers.id_aes192_wrap);
}
public void testAES256KEK()
@@ -1566,6 +1619,18 @@ public void testCamellia256KEK()
private void tryKekAlgorithm(SecretKey kek, ASN1ObjectIdentifier algOid)
throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
+ {
+ doTryKekAlgorithm(kek, algOid, false);
+ }
+
+ private void tryKekAlgorithmWithHKdf(SecretKey kek, ASN1ObjectIdentifier algOid)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
+ {
+ doTryKekAlgorithm(kek, algOid, true);
+ }
+
+ private void doTryKekAlgorithm(SecretKey kek, ASN1ObjectIdentifier algOid, boolean withKdf)
+ throws NoSuchAlgorithmException, NoSuchProviderException, CMSException
{
byte[] data = "WallaWallaWashington".getBytes();
CMSEnvelopedDataGenerator edGen = new CMSEnvelopedDataGenerator();
@@ -1576,14 +1641,23 @@ private void tryKekAlgorithm(SecretKey kek, ASN1ObjectIdentifier algOid)
CMSEnvelopedData ed = edGen.generate(
new CMSProcessableByteArray(data),
- new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC).setProvider(BC).build());
+ new JceCMSContentEncryptorBuilder(CMSAlgorithm.DES_EDE3_CBC)
+ .setEnableSha256HKdf(withKdf)
+ .setProvider(BC).build());
RecipientInformationStore recipients = ed.getRecipientInfos();
Collection c = recipients.getRecipients();
Iterator it = c.iterator();
- assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ if (withKdf)
+ {
+ assertEquals(ed.getEncryptionAlgOID(), CMSObjectIdentifiers.id_alg_cek_hkdf_sha256.getId());
+ }
+ else
+ {
+ assertEquals(ed.getEncryptionAlgOID(), CMSEnvelopedDataGenerator.DES_EDE3_CBC);
+ }
if (it.hasNext())
{
diff --git a/util/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java b/util/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
index 13cd14dfe1..c2e910bcef 100644
--- a/util/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
+++ b/util/src/main/java/org/bouncycastle/asn1/cms/CMSObjectIdentifiers.java
@@ -59,4 +59,10 @@ public interface CMSObjectIdentifiers
ASN1ObjectIdentifier id_ori = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.13");
ASN1ObjectIdentifier id_ori_kem = id_ori.branch("3");
+
+ /**
+ * id-alg-cek-hkdf-sha256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ * us(840) rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) alg(3) 31 }
+ */
+ ASN1ObjectIdentifier id_alg_cek_hkdf_sha256 = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.31");
}
From cae1829c506b0c2748be417d619a63cf24961c84 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sun, 24 Mar 2024 03:37:32 +1100
Subject: [PATCH 0184/1846] added import of java.logging (github #1608)
---
prov/src/main/ext-jdk1.9/module-info.java | 1 +
prov/src/main/jdk1.9/module-info.java | 1 +
2 files changed, 2 insertions(+)
diff --git a/prov/src/main/ext-jdk1.9/module-info.java b/prov/src/main/ext-jdk1.9/module-info.java
index 5b7cb1c5d2..87c7f33c1d 100644
--- a/prov/src/main/ext-jdk1.9/module-info.java
+++ b/prov/src/main/ext-jdk1.9/module-info.java
@@ -1,6 +1,7 @@
module org.bouncycastle.provider
{
requires java.sql;
+ requires java.logging;
requires java.naming;
provides java.security.Provider with org.bouncycastle.jce.provider.BouncyCastleProvider,org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
diff --git a/prov/src/main/jdk1.9/module-info.java b/prov/src/main/jdk1.9/module-info.java
index e6e3a34ee0..288e0d4a21 100644
--- a/prov/src/main/jdk1.9/module-info.java
+++ b/prov/src/main/jdk1.9/module-info.java
@@ -1,6 +1,7 @@
module org.bouncycastle.provider
{
requires java.sql;
+ requires java.logging;
requires java.naming;
provides java.security.Provider with org.bouncycastle.jce.provider.BouncyCastleProvider,org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
From d7d5e735abd64bf0f413f54fd9e495fc02400fb0 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sun, 24 Mar 2024 04:28:43 +1100
Subject: [PATCH 0185/1846] added new RSA mode for better TLS unwrap operation
relates to github #1528
---
.../provider/asymmetric/rsa/CipherSpi.java | 44 ++++++++++-
.../TLSRSAPremasterSecretParameterSpec.java | 19 +++++
.../JceDefaultTlsCredentialedDecryptor.java | 79 +++++++++++--------
3 files changed, 107 insertions(+), 35 deletions(-)
create mode 100644 prov/src/main/java/org/bouncycastle/jcajce/spec/TLSRSAPremasterSecretParameterSpec.java
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
index cfacb93b9a..a8f251b94c 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -31,9 +31,13 @@
import org.bouncycastle.crypto.encodings.OAEPEncoding;
import org.bouncycastle.crypto.engines.RSABlindedEngine;
import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.params.RSAKeyParameters;
+import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
+import org.bouncycastle.crypto.tls.TlsRsaKeyExchange;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
import org.bouncycastle.jcajce.provider.util.BadBlockException;
import org.bouncycastle.jcajce.provider.util.DigestFactory;
+import org.bouncycastle.jcajce.spec.TLSRSAPremasterSecretParameterSpec;
import org.bouncycastle.jcajce.util.BCJcaJceHelper;
import org.bouncycastle.jcajce.util.JcaJceHelper;
import org.bouncycastle.util.Strings;
@@ -49,6 +53,8 @@ public class CipherSpi
private boolean publicKeyOnly = false;
private boolean privateKeyOnly = false;
private ErasableOutputStream bOut = new ErasableOutputStream();
+ private TLSRSAPremasterSecretParameterSpec tlsRsaSpec = null;
+ private CipherParameters param = null;
public CipherSpi(
AsymmetricBlockCipher engine)
@@ -262,9 +268,12 @@ protected void engineInit(
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException
{
- CipherParameters param;
- if (params == null || params instanceof OAEPParameterSpec)
+ this.tlsRsaSpec = null;
+
+ if (params == null
+ || params instanceof OAEPParameterSpec
+ || params instanceof TLSRSAPremasterSecretParameterSpec)
{
if (key instanceof RSAPublicKey)
{
@@ -291,7 +300,7 @@ else if (key instanceof RSAPrivateKey)
throw new InvalidKeyException("unknown key type passed to RSA");
}
- if (params != null)
+ if (params instanceof OAEPParameterSpec)
{
OAEPParameterSpec spec = (OAEPParameterSpec)params;
@@ -324,6 +333,14 @@ else if (key instanceof RSAPrivateKey)
cipher = new OAEPEncoding(new RSABlindedEngine(), digest, mgfDigest, ((PSource.PSpecified)spec.getPSource()).getValue());
}
+ else if (params instanceof TLSRSAPremasterSecretParameterSpec)
+ {
+ if (!(param instanceof RSAPrivateCrtKeyParameters))
+ {
+ throw new InvalidKeyException("RSA private key required for TLS decryption");
+ }
+ this.tlsRsaSpec = (TLSRSAPremasterSecretParameterSpec)params;
+ }
}
else
{
@@ -403,6 +420,11 @@ protected byte[] engineUpdate(
int inputOffset,
int inputLen)
{
+ if (tlsRsaSpec != null)
+ {
+ throw new IllegalStateException("RSA cipher initialized for TLS only");
+ }
+
bOut.write(input, inputOffset, inputLen);
if (cipher instanceof RSABlindedEngine)
@@ -430,6 +452,11 @@ protected int engineUpdate(
byte[] output,
int outputOffset)
{
+ if (tlsRsaSpec != null)
+ {
+ throw new IllegalStateException("RSA cipher initialized for TLS only");
+ }
+
bOut.write(input, inputOffset, inputLen);
if (cipher instanceof RSABlindedEngine)
@@ -456,6 +483,12 @@ protected byte[] engineDoFinal(
int inputLen)
throws IllegalBlockSizeException, BadPaddingException
{
+ if (tlsRsaSpec != null)
+ {
+ ParametersWithRandom pWithR = (ParametersWithRandom)param;
+ return TlsRsaKeyExchange.decryptPreMasterSecret(input, (RSAKeyParameters)pWithR.getParameters(), tlsRsaSpec.getProtocolVersion(), pWithR.getRandom());
+ }
+
if (input != null)
{
bOut.write(input, inputOffset, inputLen);
@@ -487,6 +520,11 @@ protected int engineDoFinal(
int outputOffset)
throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
{
+ if (tlsRsaSpec != null)
+ {
+ throw new IllegalStateException("RSA cipher initialized for TLS only");
+ }
+
if (outputOffset + engineGetOutputSize(inputLen) > output.length)
{
throw new ShortBufferException("output buffer too short for input.");
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/spec/TLSRSAPremasterSecretParameterSpec.java b/prov/src/main/java/org/bouncycastle/jcajce/spec/TLSRSAPremasterSecretParameterSpec.java
new file mode 100644
index 0000000000..db23037e08
--- /dev/null
+++ b/prov/src/main/java/org/bouncycastle/jcajce/spec/TLSRSAPremasterSecretParameterSpec.java
@@ -0,0 +1,19 @@
+package org.bouncycastle.jcajce.spec;
+
+import java.security.spec.AlgorithmParameterSpec;
+
+public class TLSRSAPremasterSecretParameterSpec
+ implements AlgorithmParameterSpec
+{
+ private final int protocolVersion;
+
+ public TLSRSAPremasterSecretParameterSpec(int protocolVersion)
+ {
+ this.protocolVersion = protocolVersion;
+ }
+
+ public int getProtocolVersion()
+ {
+ return protocolVersion;
+ }
+}
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java
index 3cecb3b788..53c70f7d2d 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java
@@ -7,6 +7,7 @@
import javax.crypto.Cipher;
+import org.bouncycastle.jcajce.spec.TLSRSAPremasterSecretParameterSpec;
import org.bouncycastle.tls.Certificate;
import org.bouncycastle.tls.ProtocolVersion;
import org.bouncycastle.tls.TlsCredentialedDecryptor;
@@ -81,49 +82,63 @@ protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
* RFC 5246 7.4.7.1.
*/
ProtocolVersion expectedVersion = cryptoParams.getRSAPreMasterSecretVersion();
+ byte[] M;
- /*
- * Generate 48 random bytes we can use as a Pre-Master-Secret, if the PKCS1 padding check should fail.
- */
- byte[] fallback = new byte[48];
- secureRandom.nextBytes(fallback);
-
- byte[] M = Arrays.clone(fallback);
try
{
Cipher c = crypto.createRSAEncryptionCipher();
- c.init(Cipher.DECRYPT_MODE, rsaServerPrivateKey, secureRandom);
- byte[] m = c.doFinal(encryptedPreMasterSecret);
- if (m != null && m.length == 48)
- {
- M = m;
- }
+
+ c.init(Cipher.DECRYPT_MODE, rsaServerPrivateKey, new TLSRSAPremasterSecretParameterSpec(expectedVersion.getFullVersion()), secureRandom);
+ M = c.doFinal(encryptedPreMasterSecret);
}
- catch (Exception e)
+ catch (Exception ex)
{
+ // Fallback
+
/*
- * A TLS server MUST NOT generate an alert if processing an RSA-encrypted premaster secret message
- * fails, or the version number is not as expected. Instead, it MUST continue the handshake with a
- * randomly generated premaster secret.
+ * Generate 48 random bytes we can use as a Pre-Master-Secret, if the PKCS1 padding check should fail.
*/
- }
+ byte[] fallback = new byte[48];
+ secureRandom.nextBytes(fallback);
- /*
- * Compare the version number in the decrypted Pre-Master-Secret with the legacy_version field from
- * the ClientHello. If they don't match, continue the handshake with the randomly generated 'fallback'
- * value.
- *
- * NOTE: The comparison and replacement must be constant-time.
- */
- int mask = (expectedVersion.getMajorVersion() ^ (M[0] & 0xFF))
- | (expectedVersion.getMinorVersion() ^ (M[1] & 0xFF));
+ M = Arrays.clone(fallback);
+ try
+ {
+ Cipher c = crypto.createRSAEncryptionCipher();
+
+ c.init(Cipher.DECRYPT_MODE, rsaServerPrivateKey, secureRandom);
+ byte[] m = c.doFinal(encryptedPreMasterSecret);
+ if (m != null && m.length == 48)
+ {
+ M = m;
+ }
+ }
+ catch (Exception e)
+ {
+ /*
+ * A TLS server MUST NOT generate an alert if processing an RSA-encrypted premaster secret message
+ * fails, or the version number is not as expected. Instead, it MUST continue the handshake with a
+ * randomly generated premaster secret.
+ */
+ }
+
+ /*
+ * Compare the version number in the decrypted Pre-Master-Secret with the legacy_version field from
+ * the ClientHello. If they don't match, continue the handshake with the randomly generated 'fallback'
+ * value.
+ *
+ * NOTE: The comparison and replacement must be constant-time.
+ */
+ int mask = (expectedVersion.getMajorVersion() ^ (M[0] & 0xFF))
+ | (expectedVersion.getMinorVersion() ^ (M[1] & 0xFF));
- // 'mask' will be all 1s if the versions matched, or else all 0s.
- mask = (mask - 1) >> 31;
+ // 'mask' will be all 1s if the versions matched, or else all 0s.
+ mask = (mask - 1) >> 31;
- for (int i = 0; i < 48; i++)
- {
- M[i] = (byte)((M[i] & mask) | (fallback[i] & ~mask));
+ for (int i = 0; i < 48; i++)
+ {
+ M[i] = (byte)((M[i] & mask) | (fallback[i] & ~mask));
+ }
}
return crypto.createSecret(M);
From e5b46eabbb6f818a291c145bd716c57ef11b2b6a Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sun, 24 Mar 2024 04:32:12 +1100
Subject: [PATCH 0186/1846] widened RSA private key support - relates to github
#1528
---
.../jcajce/provider/asymmetric/rsa/CipherSpi.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
index a8f251b94c..7fa8168bac 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -32,7 +32,6 @@
import org.bouncycastle.crypto.engines.RSABlindedEngine;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.params.RSAKeyParameters;
-import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.crypto.tls.TlsRsaKeyExchange;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseCipherSpi;
import org.bouncycastle.jcajce.provider.util.BadBlockException;
@@ -335,10 +334,11 @@ else if (key instanceof RSAPrivateKey)
}
else if (params instanceof TLSRSAPremasterSecretParameterSpec)
{
- if (!(param instanceof RSAPrivateCrtKeyParameters))
+ if (!(param instanceof RSAKeyParameters) || !((RSAKeyParameters)param).isPrivate())
{
throw new InvalidKeyException("RSA private key required for TLS decryption");
}
+
this.tlsRsaSpec = (TLSRSAPremasterSecretParameterSpec)params;
}
}
From b5321b502cdb8b2849a4a7acf5d89f53916d3f0f Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sun, 24 Mar 2024 04:41:00 +1100
Subject: [PATCH 0187/1846] corrected repackaging issue.
---
.../{internal => }/asn1/misc/test/CMPUpdates16Test.java | 2 +-
.../{internal => }/asn1/misc/test/GetInstanceTest.java | 2 +-
.../src/test/java/org/bouncycastle/asn1/util/test/AllTests.java | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
rename util/src/test/java/org/bouncycastle/{internal => }/asn1/misc/test/CMPUpdates16Test.java (98%)
rename util/src/test/java/org/bouncycastle/{internal => }/asn1/misc/test/GetInstanceTest.java (99%)
diff --git a/util/src/test/java/org/bouncycastle/internal/asn1/misc/test/CMPUpdates16Test.java b/util/src/test/java/org/bouncycastle/asn1/misc/test/CMPUpdates16Test.java
similarity index 98%
rename from util/src/test/java/org/bouncycastle/internal/asn1/misc/test/CMPUpdates16Test.java
rename to util/src/test/java/org/bouncycastle/asn1/misc/test/CMPUpdates16Test.java
index 2831421ccc..4e760e1792 100644
--- a/util/src/test/java/org/bouncycastle/internal/asn1/misc/test/CMPUpdates16Test.java
+++ b/util/src/test/java/org/bouncycastle/asn1/misc/test/CMPUpdates16Test.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.internal.asn1.misc.test;
+package org.bouncycastle.asn1.misc.test;
import junit.framework.TestCase;
import org.bouncycastle.asn1.ASN1Encodable;
diff --git a/util/src/test/java/org/bouncycastle/internal/asn1/misc/test/GetInstanceTest.java b/util/src/test/java/org/bouncycastle/asn1/misc/test/GetInstanceTest.java
similarity index 99%
rename from util/src/test/java/org/bouncycastle/internal/asn1/misc/test/GetInstanceTest.java
rename to util/src/test/java/org/bouncycastle/asn1/misc/test/GetInstanceTest.java
index 4612f6206c..1cc8d17056 100644
--- a/util/src/test/java/org/bouncycastle/internal/asn1/misc/test/GetInstanceTest.java
+++ b/util/src/test/java/org/bouncycastle/asn1/misc/test/GetInstanceTest.java
@@ -1,4 +1,4 @@
-package org.bouncycastle.internal.asn1.misc.test;
+package org.bouncycastle.asn1.misc.test;
import java.lang.reflect.Method;
import java.math.BigInteger;
diff --git a/util/src/test/java/org/bouncycastle/asn1/util/test/AllTests.java b/util/src/test/java/org/bouncycastle/asn1/util/test/AllTests.java
index e6f4793325..637d40b206 100644
--- a/util/src/test/java/org/bouncycastle/asn1/util/test/AllTests.java
+++ b/util/src/test/java/org/bouncycastle/asn1/util/test/AllTests.java
@@ -6,7 +6,7 @@
import junit.framework.TestSuite;
import org.bouncycastle.asn1.cms.test.OctetStringTest;
import org.bouncycastle.asn1.cms.test.ParseTest;
-import org.bouncycastle.internal.asn1.misc.test.GetInstanceTest;
+import org.bouncycastle.asn1.misc.test.GetInstanceTest;
import org.bouncycastle.test.PrintTestResult;
import org.bouncycastle.util.test.SimpleTestResult;
From b4762c6bfa6cf7ad7fe53a55dcdeb48f98e2e934 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Mon, 25 Mar 2024 23:32:51 +1100
Subject: [PATCH 0188/1846] added missing copy statement
---
ant/bc+-build.xml | 1 +
1 file changed, 1 insertion(+)
diff --git a/ant/bc+-build.xml b/ant/bc+-build.xml
index c071660291..646282c01d 100644
--- a/ant/bc+-build.xml
+++ b/ant/bc+-build.xml
@@ -923,6 +923,7 @@
+
From bb879ff8f1e2947e43c4ae365a4db97495536714 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 26 Mar 2024 06:42:38 +1100
Subject: [PATCH 0189/1846] removed AllTests for keybox test
---
ant/bc+-build.xml | 1 +
1 file changed, 1 insertion(+)
diff --git a/ant/bc+-build.xml b/ant/bc+-build.xml
index 646282c01d..a8f811b2c5 100644
--- a/ant/bc+-build.xml
+++ b/ant/bc+-build.xml
@@ -954,6 +954,7 @@
+
From 93f8b3416b3285bb98dd845647a0c798fb02805a Mon Sep 17 00:00:00 2001
From: mwcw
Date: Tue, 26 Mar 2024 09:02:59 +1100
Subject: [PATCH 0190/1846] Added running ant build to CI.
---
.gitlab-ci.yml | 56 +++++++++++++++++++++++++++++--------------------
ci/build_1_8.sh | 15 +++++++++++++
2 files changed, 48 insertions(+), 23 deletions(-)
create mode 100644 ci/build_1_8.sh
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index eee7f79280..4f7b3f73fd 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,5 +1,6 @@
stages:
- check
+ - build
- test
check-code:
@@ -18,35 +19,44 @@ check-code:
- "mail/build/reports"
- "util/build/reports"
- "tls/build/reports"
- - "mls/build/reports"
-
+ - "mls/build/reports"
+
+ant-build:
+ stage: build
+ needs: [ "check-code" ]
+ script:
+ - "ecr_login"
+ - "ecr_pull vm_base_intel latest"
+ - "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/build_1_8.sh\""
+
+
test-code-8:
stage: test
- needs: ["check-code"]
+ needs: [ "check-code" ]
script:
- - "ecr_login"
- - "ecr_pull vm_base_intel latest"
- - "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_8.sh\""
+ - "ecr_login"
+ - "ecr_pull vm_base_intel latest"
+ - "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_8.sh\""
artifacts:
when: always
reports:
junit:
- - "core/build/test-results/**/*.xml"
- - "prov/build/test-results/**/*.xml"
- - "pg/build/test-results/**/*.xml"
- - "pkix/build/test-results/**/*.xml"
- - "mail/build/test-results/**/*.xml"
- - "util/build/test-results/**/*.xml"
- - "tls/build/test-results/**/*.xml"
- - "mls/build/test-results/**/*.xml"
+ - "core/build/test-results/**/*.xml"
+ - "prov/build/test-results/**/*.xml"
+ - "pg/build/test-results/**/*.xml"
+ - "pkix/build/test-results/**/*.xml"
+ - "mail/build/test-results/**/*.xml"
+ - "util/build/test-results/**/*.xml"
+ - "tls/build/test-results/**/*.xml"
+ - "mls/build/test-results/**/*.xml"
test-code-11:
stage: test
- needs: ["check-code"]
+ needs: [ "check-code" ]
script:
- - "ecr_login"
- - "ecr_pull vm_base_intel latest"
- - "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_11.sh\""
+ - "ecr_login"
+ - "ecr_pull vm_base_intel latest"
+ - "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_11.sh\""
artifacts:
when: always
reports:
@@ -63,11 +73,11 @@ test-code-11:
test-code-17:
stage: test
- needs: ["check-code"]
+ needs: [ "check-code" ]
script:
- - "ecr_login"
- - "ecr_pull vm_base_intel latest"
- - "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_17.sh\""
+ - "ecr_login"
+ - "ecr_pull vm_base_intel latest"
+ - "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_17.sh\""
artifacts:
when: always
reports:
@@ -84,7 +94,7 @@ test-code-17:
test-code-21:
stage: test
- needs: ["check-code"]
+ needs: [ "check-code" ]
script:
- "ecr_login"
- "ecr_pull vm_base_intel latest"
diff --git a/ci/build_1_8.sh b/ci/build_1_8.sh
new file mode 100644
index 0000000000..3a21b967d8
--- /dev/null
+++ b/ci/build_1_8.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+set -e
+
+#
+# This script is for running inside the docker container
+#
+
+cd /workspace/bc-java
+source ci/common.sh
+
+export JAVA_HOME=`openjdk_8`
+export export PATH=$JAVA_HOME/bin:$PATH
+export JDKPATH=$JAVA_HOME
+
+sh build1-8+
\ No newline at end of file
From ec31b821013127aabd45dbec37c69a653b9a02fb Mon Sep 17 00:00:00 2001
From: mwcw
Date: Tue, 26 Mar 2024 09:09:02 +1100
Subject: [PATCH 0191/1846] Added ant to path.
---
ci/build_1_8.sh | 2 ++
1 file changed, 2 insertions(+)
diff --git a/ci/build_1_8.sh b/ci/build_1_8.sh
index 3a21b967d8..d3413d74a8 100644
--- a/ci/build_1_8.sh
+++ b/ci/build_1_8.sh
@@ -12,4 +12,6 @@ export JAVA_HOME=`openjdk_8`
export export PATH=$JAVA_HOME/bin:$PATH
export JDKPATH=$JAVA_HOME
+export PATH=$PATH:`ant-bin-1-10`
+
sh build1-8+
\ No newline at end of file
From 1e9721fd114e7e4c436d468916a5f5687345bdd5 Mon Sep 17 00:00:00 2001
From: mwcw
Date: Tue, 26 Mar 2024 09:32:53 +1100
Subject: [PATCH 0192/1846] Update to pass multiple args to javadoc
---
ant/bc+-build.xml | 2 +-
ant/jdk18+.xml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/ant/bc+-build.xml b/ant/bc+-build.xml
index a8f811b2c5..8b6f7364d8 100644
--- a/ant/bc+-build.xml
+++ b/ant/bc+-build.xml
@@ -250,7 +250,7 @@
windowtitle="Bouncy Castle Library ${release.name} API Specification"
header="<b>Bouncy Castle Cryptography Library ${release.name}</b>">
-
+
diff --git a/ant/jdk18+.xml b/ant/jdk18+.xml
index ce9441866c..66e194ad90 100644
--- a/ant/jdk18+.xml
+++ b/ant/jdk18+.xml
@@ -9,7 +9,7 @@
-
+
From dc6640fe5603ca212a92866e60eec893b58c8b92 Mon Sep 17 00:00:00 2001
From: Megan
Date: Tue, 26 Mar 2024 03:59:01 +0000
Subject: [PATCH 0193/1846] Added call to gitlab_wait
---
.gitlab-ci.yml | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 4f7b3f73fd..774498d6ca 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -6,6 +6,7 @@ stages:
check-code:
stage: check
script:
+ - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/check_java.sh\""
@@ -25,6 +26,7 @@ ant-build:
stage: build
needs: [ "check-code" ]
script:
+ - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/build_1_8.sh\""
@@ -34,6 +36,7 @@ test-code-8:
stage: test
needs: [ "check-code" ]
script:
+ - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_8.sh\""
@@ -54,6 +57,7 @@ test-code-11:
stage: test
needs: [ "check-code" ]
script:
+ - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_11.sh\""
@@ -75,6 +79,7 @@ test-code-17:
stage: test
needs: [ "check-code" ]
script:
+ - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_17.sh\""
@@ -96,6 +101,7 @@ test-code-21:
stage: test
needs: [ "check-code" ]
script:
+ - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_21.sh\""
From 85a60581bebac35b891dce830bad989e5754f24e Mon Sep 17 00:00:00 2001
From: Megan
Date: Tue, 26 Mar 2024 04:27:27 +0000
Subject: [PATCH 0194/1846] Removed gitlab_wait.sh from jobs.
---
.gitlab-ci.yml | 6 ------
1 file changed, 6 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 774498d6ca..4f7b3f73fd 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -6,7 +6,6 @@ stages:
check-code:
stage: check
script:
- - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/check_java.sh\""
@@ -26,7 +25,6 @@ ant-build:
stage: build
needs: [ "check-code" ]
script:
- - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/build_1_8.sh\""
@@ -36,7 +34,6 @@ test-code-8:
stage: test
needs: [ "check-code" ]
script:
- - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_8.sh\""
@@ -57,7 +54,6 @@ test-code-11:
stage: test
needs: [ "check-code" ]
script:
- - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_11.sh\""
@@ -79,7 +75,6 @@ test-code-17:
stage: test
needs: [ "check-code" ]
script:
- - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_17.sh\""
@@ -101,7 +96,6 @@ test-code-21:
stage: test
needs: [ "check-code" ]
script:
- - "gitlab_wait.sh"
- "ecr_login"
- "ecr_pull vm_base_intel latest"
- "ci_docker_run \"vm_base_intel:latest\" \"bc-java\" \"/workspace/bc-java/ci/test_21.sh\""
From d884486e01a780d20fbcdeb576d2d4af9d0fd9d0 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 26 Mar 2024 16:15:28 +1100
Subject: [PATCH 0195/1846] added some explanatory comments.
---
.../impl/jcajce/JceDefaultTlsCredentialedDecryptor.java | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java
index 53c70f7d2d..a55935ab11 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceDefaultTlsCredentialedDecryptor.java
@@ -86,6 +86,9 @@ protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
try
{
+ // The use of the TLSRSAPremasterSecretParameterSpec signals to the BC provider that
+ // that the underlying implementation should not throw exceptions but return a random
+ // value on failures where the plaintext turns out to be invalid.
Cipher c = crypto.createRSAEncryptionCipher();
c.init(Cipher.DECRYPT_MODE, rsaServerPrivateKey, new TLSRSAPremasterSecretParameterSpec(expectedVersion.getFullVersion()), secureRandom);
@@ -93,7 +96,9 @@ protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
}
catch (Exception ex)
{
- // Fallback
+ // Fallback - note this will likely result in some level of a timing signal as traditionally
+ // JCE RSA providers will signal padding errors by throwing exceptions. The real answer to this
+ // problem is not to use RSA encryption based cipher suites.
/*
* Generate 48 random bytes we can use as a Pre-Master-Secret, if the PKCS1 padding check should fail.
From a84dffb2f6f28ff69be3555909bf13dca9f412f8 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Tue, 26 Mar 2024 16:24:35 +1100
Subject: [PATCH 0196/1846] minor changes to messages
---
.../main/java/org/bouncycastle/jcajce/CompositePublicKey.java | 2 +-
prov/src/main/jdk1.9/module-info.java | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
index ea26b64961..c55cb83dc5 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
@@ -52,7 +52,7 @@ public CompositePublicKey(ASN1ObjectIdentifier algorithmIdentifier, PublicKey...
if (keys == null || keys.length == 0)
{
- throw new IllegalArgumentException("At least one public key must be provided for the composite public key.");
+ throw new IllegalArgumentException("at least one public key must be provided for the composite public key");
}
List keyList = new ArrayList<>(keys.length);
diff --git a/prov/src/main/jdk1.9/module-info.java b/prov/src/main/jdk1.9/module-info.java
index 288e0d4a21..2b23fe2ed2 100644
--- a/prov/src/main/jdk1.9/module-info.java
+++ b/prov/src/main/jdk1.9/module-info.java
@@ -63,6 +63,7 @@
exports org.bouncycastle.jcajce;
exports org.bouncycastle.jcajce.io;
exports org.bouncycastle.jcajce.provider.asymmetric;
+ exports org.bouncycastle.jcajce.provider.asymmetric.compositesignatures;
exports org.bouncycastle.jcajce.provider.asymmetric.dh;
exports org.bouncycastle.jcajce.provider.asymmetric.dsa;
exports org.bouncycastle.jcajce.provider.asymmetric.dstu;
From 9c84c414fd9bed10bf2a171c29b95d221c77f74c Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Tue, 26 Mar 2024 19:20:36 +0700
Subject: [PATCH 0197/1846] Round out implementation of TLS RSA PreMasterSecret
---
.../crypto/tls/TlsRsaKeyExchange.java | 28 +++--
.../provider/asymmetric/rsa/CipherSpi.java | 116 +++++-------------
.../bc/BcDefaultTlsCredentialedDecryptor.java | 3 +-
3 files changed, 48 insertions(+), 99 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java b/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
index e9694247d0..477e94a4ab 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
@@ -16,18 +16,20 @@
public abstract class TlsRsaKeyExchange
{
+ public static final int PRE_MASTER_SECRET_LENGTH = 48;
+
private static final BigInteger ONE = BigInteger.valueOf(1);
private TlsRsaKeyExchange()
{
}
- public static byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret, RSAKeyParameters privateKey,
+ public static byte[] decryptPreMasterSecret(byte[] in, int inOff, int inLen, RSAKeyParameters privateKey,
int protocolVersion, SecureRandom secureRandom)
{
- if (Arrays.isNullOrEmpty(encryptedPreMasterSecret))
+ if (in == null || inLen < 1 || inLen > getInputLimit(privateKey) || inOff < 0 || inOff > in.length - inLen)
{
- throw new IllegalArgumentException("'encryptedPreMasterSecret' cannot be null or empty");
+ throw new IllegalArgumentException("input not a valid EncryptedPreMasterSecret");
}
if (!privateKey.isPrivate())
@@ -61,7 +63,7 @@ public static byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret, RSA
try
{
- BigInteger input = convertInput(modulus, encryptedPreMasterSecret);
+ BigInteger input = convertInput(modulus, in, inOff, inLen);
byte[] encoding = rsaBlinded(privateKey, input, secureRandom);
int pkcs1Length = (bitLength - 1) / 8;
@@ -92,6 +94,11 @@ public static byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret, RSA
return result;
}
+ public static int getInputLimit(RSAKeyParameters privateKey)
+ {
+ return (privateKey.getModulus().bitLength() + 7) / 8;
+ }
+
private static int caddTo(int len, int cond, byte[] x, byte[] z)
{
// assert cond == 0 || cond == -1;
@@ -140,17 +147,12 @@ private static int checkPkcs1Encoding2(byte[] buf, int pkcs1Length, int plaintex
return errorSign >> 31;
}
- private static BigInteger convertInput(BigInteger modulus, byte[] input)
+ private static BigInteger convertInput(BigInteger modulus, byte[] in, int inOff, int inLen)
{
- int inputLimit = (modulus.bitLength() + 7) / 8;
-
- if (input.length <= inputLimit)
+ BigInteger result = BigIntegers.fromUnsignedByteArray(in, inOff, inLen);
+ if (result.compareTo(modulus) < 0)
{
- BigInteger result = new BigInteger(1, input);
- if (result.compareTo(modulus) < 0)
- {
- return result;
- }
+ return result;
}
throw new DataLengthException("input too large for RSA cipher.");
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
index 7fa8168bac..a4a771d463 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -420,28 +420,12 @@ protected byte[] engineUpdate(
int inputOffset,
int inputLen)
{
- if (tlsRsaSpec != null)
+ if (inputLen > getInputLimit() - bOut.size())
{
- throw new IllegalStateException("RSA cipher initialized for TLS only");
+ throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
}
bOut.write(input, inputOffset, inputLen);
-
- if (cipher instanceof RSABlindedEngine)
- {
- if (bOut.size() > cipher.getInputBlockSize() + 1)
- {
- throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
- }
- }
- else
- {
- if (bOut.size() > cipher.getInputBlockSize())
- {
- throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
- }
- }
-
return null;
}
@@ -452,28 +436,7 @@ protected int engineUpdate(
byte[] output,
int outputOffset)
{
- if (tlsRsaSpec != null)
- {
- throw new IllegalStateException("RSA cipher initialized for TLS only");
- }
-
- bOut.write(input, inputOffset, inputLen);
-
- if (cipher instanceof RSABlindedEngine)
- {
- if (bOut.size() > cipher.getInputBlockSize() + 1)
- {
- throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
- }
- }
- else
- {
- if (bOut.size() > cipher.getInputBlockSize())
- {
- throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
- }
- }
-
+ engineUpdate(input, inputOffset, inputLen);
return 0;
}
@@ -483,30 +446,9 @@ protected byte[] engineDoFinal(
int inputLen)
throws IllegalBlockSizeException, BadPaddingException
{
- if (tlsRsaSpec != null)
- {
- ParametersWithRandom pWithR = (ParametersWithRandom)param;
- return TlsRsaKeyExchange.decryptPreMasterSecret(input, (RSAKeyParameters)pWithR.getParameters(), tlsRsaSpec.getProtocolVersion(), pWithR.getRandom());
- }
-
if (input != null)
{
- bOut.write(input, inputOffset, inputLen);
- }
-
- if (cipher instanceof RSABlindedEngine)
- {
- if (bOut.size() > cipher.getInputBlockSize() + 1)
- {
- throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
- }
- }
- else
- {
- if (bOut.size() > cipher.getInputBlockSize())
- {
- throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
- }
+ engineUpdate(input, inputOffset, inputLen);
}
return getOutput();
@@ -520,44 +462,41 @@ protected int engineDoFinal(
int outputOffset)
throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
{
+ int outputSize;
if (tlsRsaSpec != null)
{
- throw new IllegalStateException("RSA cipher initialized for TLS only");
+ outputSize = TlsRsaKeyExchange.PRE_MASTER_SECRET_LENGTH;
}
-
- if (outputOffset + engineGetOutputSize(inputLen) > output.length)
+ else
{
- throw new ShortBufferException("output buffer too short for input.");
+ outputSize = engineGetOutputSize(input == null ? 0 : inputLen);
}
- if (input != null)
+ if (outputOffset > output.length - outputSize)
{
- bOut.write(input, inputOffset, inputLen);
+ throw new ShortBufferException("output buffer too short for input.");
}
- if (cipher instanceof RSABlindedEngine)
+ byte[] out = engineDoFinal(input, inputOffset, inputLen);
+ System.arraycopy(out, 0, output, outputOffset, out.length);
+ return out.length;
+ }
+
+ private int getInputLimit()
+ {
+ if (tlsRsaSpec != null)
{
- if (bOut.size() > cipher.getInputBlockSize() + 1)
- {
- throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
- }
+ ParametersWithRandom pWithR = (ParametersWithRandom)param;
+ return TlsRsaKeyExchange.getInputLimit((RSAKeyParameters)pWithR.getParameters());
}
- else
+ else if (cipher instanceof RSABlindedEngine)
{
- if (bOut.size() > cipher.getInputBlockSize())
- {
- throw new ArrayIndexOutOfBoundsException("too much data for RSA block");
- }
+ return cipher.getInputBlockSize() + 1;
}
-
- byte[] out = getOutput();
-
- for (int i = 0; i != out.length; i++)
+ else
{
- output[outputOffset + i] = out[i];
+ return cipher.getInputBlockSize();
}
-
- return out.length;
}
private byte[] getOutput()
@@ -565,6 +504,13 @@ private byte[] getOutput()
{
try
{
+ if (tlsRsaSpec != null)
+ {
+ ParametersWithRandom pWithR = (ParametersWithRandom)param;
+ return TlsRsaKeyExchange.decryptPreMasterSecret(bOut.getBuf(), 0, bOut.size(),
+ (RSAKeyParameters)pWithR.getParameters(), tlsRsaSpec.getProtocolVersion(), pWithR.getRandom());
+ }
+
byte[] output;
try
{
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
index 46093002ac..7e0c4492dd 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.java
@@ -79,7 +79,8 @@ protected TlsSecret safeDecryptPreMasterSecret(TlsCryptoParameters cryptoParams,
ProtocolVersion expectedVersion = cryptoParams.getRSAPreMasterSecretVersion();
byte[] preMasterSecret = org.bouncycastle.crypto.tls.TlsRsaKeyExchange.decryptPreMasterSecret(
- encryptedPreMasterSecret, rsaServerPrivateKey, expectedVersion.getFullVersion(), crypto.getSecureRandom());
+ encryptedPreMasterSecret, 0, encryptedPreMasterSecret.length, rsaServerPrivateKey,
+ expectedVersion.getFullVersion(), crypto.getSecureRandom());
return crypto.createSecret(preMasterSecret);
}
From 97b1684dc570574077d0e9c236c5dcd8212026bf Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Tue, 26 Mar 2024 20:00:56 +0700
Subject: [PATCH 0198/1846] Refactoring
---
.../org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java b/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
index 477e94a4ab..7d57f126c0 100644
--- a/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
+++ b/core/src/main/java/org/bouncycastle/crypto/tls/TlsRsaKeyExchange.java
@@ -56,9 +56,9 @@ public static byte[] decryptPreMasterSecret(byte[] in, int inOff, int inLen, RSA
secureRandom = CryptoServicesRegistrar.getSecureRandom(secureRandom);
/*
- * Generate 48 random bytes we can use as a Pre-Master-Secret if the decrypted value is invalid.
+ * Generate random bytes we can use as a Pre-Master-Secret if the decrypted value is invalid.
*/
- byte[] result = new byte[48];
+ byte[] result = new byte[PRE_MASTER_SECRET_LENGTH];
secureRandom.nextBytes(result);
try
@@ -67,13 +67,13 @@ public static byte[] decryptPreMasterSecret(byte[] in, int inOff, int inLen, RSA
byte[] encoding = rsaBlinded(privateKey, input, secureRandom);
int pkcs1Length = (bitLength - 1) / 8;
- int plainTextOffset = encoding.length - 48;
+ int plainTextOffset = encoding.length - PRE_MASTER_SECRET_LENGTH;
- int badEncodingMask = checkPkcs1Encoding2(encoding, pkcs1Length, 48);
+ int badEncodingMask = checkPkcs1Encoding2(encoding, pkcs1Length, PRE_MASTER_SECRET_LENGTH);
int badVersionMask = -((Pack.bigEndianToShort(encoding, plainTextOffset) ^ protocolVersion) & 0xFFFF) >> 31;
int fallbackMask = badEncodingMask | badVersionMask;
- for (int i = 0; i < 48; ++i)
+ for (int i = 0; i < PRE_MASTER_SECRET_LENGTH; ++i)
{
result[i] = (byte)((result[i] & fallbackMask) | (encoding[plainTextOffset + i] & ~fallbackMask));
}
From ed8035bb701b845ecffa38931d85eb5fe7f1d217 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 27 Mar 2024 01:06:17 +1100
Subject: [PATCH 0199/1846] removed use of PQC provider.
---
.../openpgp/test/OperatorJcajceTest.java | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
index 9683ec2eb5..1dc3a46994 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
@@ -7,6 +7,7 @@
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
+import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.PKCS8EncodedKeySpec;
@@ -40,7 +41,6 @@
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter;
import org.bouncycastle.openpgp.operator.jcajce.JcePBESecretKeyEncryptorBuilder;
import org.bouncycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
-import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
@@ -109,7 +109,7 @@ private void testDigestCalc(PGPDigestCalculator digCalc, byte[] expected)
public void testJcaKeyFingerprintCalculator()
throws Exception
{
- final JcaKeyFingerprintCalculator calculator = new JcaKeyFingerprintCalculator().setProvider(new BouncyCastlePQCProvider());
+ final JcaKeyFingerprintCalculator calculator = new JcaKeyFingerprintCalculator().setProvider(new NullProvider());
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
kpGen.initialize(1024);
KeyPair kp = kpGen.generateKeyPair();
@@ -158,7 +158,7 @@ public void testJcePGPDataEncryptorBuilder()
public void testJcaPGPDigestCalculatorProviderBuilder()
throws Exception
{
- PGPDigestCalculatorProvider provider = new JcaPGPDigestCalculatorProviderBuilder().setProvider(new BouncyCastlePQCProvider()).build();
+ PGPDigestCalculatorProvider provider = new JcaPGPDigestCalculatorProviderBuilder().setProvider(new NullProvider()).build();
testException("exception on setup: ", "PGPException", () -> provider.get(SymmetricKeyAlgorithmTags.AES_256));
}
@@ -219,4 +219,12 @@ public void testX25519HKDF()
//isTrue(Arrays.areEqual(output, expectedDecryptedSessionKey));
}
+ private class NullProvider
+ extends Provider
+ {
+ NullProvider()
+ {
+ super("NULL", 0.0, "Null Provider");
+ }
+ }
}
From b03709529a81efc46246ef9cd1f97546c115ebdb Mon Sep 17 00:00:00 2001
From: royb
Date: Tue, 26 Mar 2024 11:09:51 -0400
Subject: [PATCH 0200/1846] NTRU KEMspi for jdk 21
---
.../pqc/jcajce/provider/NTRU.java | 43 ++++
.../provider/ntru/NTRUDecapsulatorSpi.java | 91 ++++++++
.../provider/ntru/NTRUEncapsulatorSpi.java | 108 +++++++++
.../pqc/jcajce/provider/ntru/NTRUKEMSpi.java | 62 +++++
.../jcacje/provider/test/AllTests21.java | 1 +
.../jcacje/provider/test/NTRUKEMTest.java | 216 ++++++++++++++++++
6 files changed, 521 insertions(+)
create mode 100644 prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/NTRU.java
create mode 100644 prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUDecapsulatorSpi.java
create mode 100644 prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUEncapsulatorSpi.java
create mode 100644 prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKEMSpi.java
create mode 100644 prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/NTRUKEMTest.java
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/NTRU.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/NTRU.java
new file mode 100644
index 0000000000..aa4377f28f
--- /dev/null
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/NTRU.java
@@ -0,0 +1,43 @@
+package org.bouncycastle.pqc.jcajce.provider;
+
+import org.bouncycastle.asn1.bc.BCObjectIdentifiers;
+import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.bouncycastle.pqc.jcajce.provider.ntru.NTRUKeyFactorySpi;
+
+public class NTRU
+{
+ private static final String PREFIX = "org.bouncycastle.pqc.jcajce.provider" + ".ntru.";
+
+ public static class Mappings
+ extends AsymmetricAlgorithmProvider
+ {
+ public Mappings()
+ {
+ }
+
+ public void configure(ConfigurableProvider provider)
+ {
+ provider.addAlgorithm("KeyFactory.NTRU", PREFIX + "NTRUKeyFactorySpi");
+ provider.addAlgorithm("KeyPairGenerator.NTRU", PREFIX + "NTRUKeyPairGeneratorSpi");
+
+ provider.addAlgorithm("KeyGenerator.NTRU", PREFIX + "NTRUKeyGeneratorSpi");
+
+ AsymmetricKeyInfoConverter keyFact = new NTRUKeyFactorySpi();
+
+ provider.addAlgorithm("Cipher.NTRU", PREFIX + "NTRUCipherSpi$Base");
+ provider.addAlgorithm("Alg.Alias.Cipher." + BCObjectIdentifiers.pqc_kem_ntru, "NTRU");
+
+ registerOid(provider, BCObjectIdentifiers.ntruhps2048509, "NTRU", keyFact);
+ registerOid(provider, BCObjectIdentifiers.ntruhps2048677, "NTRU", keyFact);
+ registerOid(provider, BCObjectIdentifiers.ntruhps4096821, "NTRU", keyFact);
+ registerOid(provider, BCObjectIdentifiers.ntruhps40961229, "NTRU", keyFact);
+ registerOid(provider, BCObjectIdentifiers.ntruhrss701, "NTRU", keyFact);
+ registerOid(provider, BCObjectIdentifiers.ntruhrss1373, "NTRU", keyFact);
+
+ provider.addAlgorithm("Kem.NTRU", PREFIX + "NTRUKEMSpi");
+ provider.addAlgorithm("Alg.Alias.Kem." + BCObjectIdentifiers.pqc_kem_ntru, "NTRU");
+ }
+ }
+}
\ No newline at end of file
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUDecapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUDecapsulatorSpi.java
new file mode 100644
index 0000000000..f51faf3509
--- /dev/null
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUDecapsulatorSpi.java
@@ -0,0 +1,91 @@
+package org.bouncycastle.pqc.jcajce.provider.ntru;
+
+import org.bouncycastle.jcajce.spec.KTSParameterSpec;
+
+import org.bouncycastle.jcajce.spec.KTSParameterSpec;
+import org.bouncycastle.pqc.crypto.ntru.NTRUKEMExtractor;
+import org.bouncycastle.pqc.jcajce.provider.Util;
+
+import javax.crypto.DecapsulateException;
+import javax.crypto.KEMSpi;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.InvalidKeyException;
+import java.util.Arrays;
+import java.util.Objects;
+
+public class NTRUDecapsulatorSpi
+ implements KEMSpi.DecapsulatorSpi
+{
+ BCNTRUPrivateKey privateKey;
+ KTSParameterSpec parameterSpec;
+ NTRUKEMExtractor kemExt;
+
+ public NTRUDecapsulatorSpi(BCNTRUPrivateKey privateKey, KTSParameterSpec parameterSpec)
+ {
+ this.privateKey = privateKey;
+ this.parameterSpec = parameterSpec;
+
+ this.kemExt = new NTRUKEMExtractor(privateKey.getKeyParams());
+ }
+
+ @Override
+ public SecretKey engineDecapsulate(byte[] encapsulation, int from, int to, String algorithm) throws DecapsulateException
+ {
+ Objects.checkFromToIndex(from, to, engineSecretSize());
+ Objects.requireNonNull(algorithm, "null algorithm");
+ Objects.requireNonNull(encapsulation, "null encapsulation");
+
+ if (encapsulation.length != engineEncapsulationSize())
+ {
+ throw new DecapsulateException("incorrect encapsulation size");
+ }
+
+ // if algorithm is Generic then use parameterSpec to wrap key
+ if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
+ algorithm.equals("Generic"))
+ {
+ algorithm = parameterSpec.getKeyAlgorithmName();
+ }
+
+ // check spec algorithm mismatch provided algorithm
+ if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
+ !parameterSpec.getKeyAlgorithmName().equals(algorithm))
+ {
+ throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm);
+ }
+
+ // Only use KDF when ktsParameterSpec is provided
+ // Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
+ boolean useKDF = parameterSpec.getKdfAlgorithm() != null;
+
+ byte[] secret = kemExt.extractSecret(encapsulation);
+
+ if (useKDF)
+ {
+ try
+ {
+ secret = Util.makeKeyBytes(parameterSpec, secret);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+ byte[] secretKey = Arrays.copyOfRange(secret, from, to);
+
+ return new SecretKeySpec(secretKey, algorithm);
+ }
+
+ @Override
+ public int engineSecretSize()
+ {
+ return parameterSpec.getKeySize() / 8;
+ }
+
+ @Override
+ public int engineEncapsulationSize()
+ {
+ return kemExt.getEncapsulationLength();
+ }
+}
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUEncapsulatorSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUEncapsulatorSpi.java
new file mode 100644
index 0000000000..81c94d49e4
--- /dev/null
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUEncapsulatorSpi.java
@@ -0,0 +1,108 @@
+package org.bouncycastle.pqc.jcajce.provider.ntru;
+
+import org.bouncycastle.crypto.SecretWithEncapsulation;
+import org.bouncycastle.jcajce.spec.KTSParameterSpec;
+import org.bouncycastle.pqc.crypto.ntru.NTRUKEMGenerator;
+import org.bouncycastle.pqc.jcajce.provider.Util;
+
+import javax.crypto.KEM;
+import javax.crypto.KEMSpi;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.InvalidKeyException;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Objects;
+
+public class NTRUEncapsulatorSpi
+ implements KEMSpi.EncapsulatorSpi
+{
+ private final BCNTRUPublicKey publicKey;
+ private final KTSParameterSpec parameterSpec;
+ private final NTRUKEMGenerator kemGen;
+
+ public NTRUEncapsulatorSpi(BCNTRUPublicKey publicKey, KTSParameterSpec parameterSpec, SecureRandom random)
+ {
+ this.publicKey = publicKey;
+ this.parameterSpec = parameterSpec;
+
+ this.kemGen = new NTRUKEMGenerator(random);
+ }
+
+ @Override
+ public KEM.Encapsulated engineEncapsulate(int from, int to, String algorithm)
+ {
+ Objects.checkFromToIndex(from, to, engineSecretSize());
+ Objects.requireNonNull(algorithm, "null algorithm");
+
+ // if algorithm is Generic then use parameterSpec to wrap key
+ if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
+ algorithm.equals("Generic"))
+ {
+ algorithm = parameterSpec.getKeyAlgorithmName();
+ }
+
+ // check spec algorithm mismatch provided algorithm
+ if (!parameterSpec.getKeyAlgorithmName().equals("Generic") &&
+ !parameterSpec.getKeyAlgorithmName().equals(algorithm))
+ {
+ throw new UnsupportedOperationException(parameterSpec.getKeyAlgorithmName() + " does not match " + algorithm);
+ }
+
+ // Only use KDF when ktsParameterSpec is provided
+ // Considering any ktsParameterSpec with "Generic" as ktsParameterSpec not provided
+ boolean useKDF = parameterSpec.getKdfAlgorithm() != null;
+
+ SecretWithEncapsulation secEnc = kemGen.generateEncapsulated(publicKey.getKeyParams());
+
+ byte[] encapsulation = secEnc.getEncapsulation();
+ byte[] secret = secEnc.getSecret();
+
+ byte[] secretKey;
+
+ if (useKDF)
+ {
+ try
+ {
+ secret = Util.makeKeyBytes(parameterSpec, secret);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ secretKey = Arrays.copyOfRange(secret, from, to);
+
+ return new KEM.Encapsulated(new SecretKeySpec(secretKey, algorithm), encapsulation, null); //TODO: DER encoding for params
+
+ }
+
+ @Override
+ public int engineSecretSize()
+ {
+ return parameterSpec.getKeySize() / 8;
+ }
+
+ @Override
+ public int engineEncapsulationSize()
+ {
+ //TODO: Maybe make parameterSet public or add getEncapsulationSize() in NTRUKEMGenerator.java
+ switch (publicKey.getKeyParams().getParameters().getName())
+ {
+ case "ntruhps2048509":
+ return 699;
+ case "ntruhps2048677":
+ return 930;
+ case "ntruhps4096821":
+ return 1230;
+ case "ntruhps40961229":
+ return 1843;
+ case "ntruhrss701":
+ return 1138;
+ case "ntruhrss1373":
+ return 2401;
+ default:
+ return -1;
+ }
+ }
+}
diff --git a/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKEMSpi.java b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKEMSpi.java
new file mode 100644
index 0000000000..77b7a2bf54
--- /dev/null
+++ b/prov/src/main/jdk21/org/bouncycastle/pqc/jcajce/provider/ntru/NTRUKEMSpi.java
@@ -0,0 +1,62 @@
+package org.bouncycastle.pqc.jcajce.provider.ntru;
+
+import org.bouncycastle.jcajce.spec.KTSParameterSpec;
+import org.bouncycastle.pqc.jcajce.provider.ntru.BCNTRUPrivateKey;
+import org.bouncycastle.pqc.jcajce.provider.ntru.NTRUDecapsulatorSpi;
+
+import javax.crypto.KEMSpi;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+public class NTRUKEMSpi
+ implements KEMSpi
+{
+
+ @Override
+ public EncapsulatorSpi engineNewEncapsulator(PublicKey publicKey, AlgorithmParameterSpec spec, SecureRandom secureRandom)
+ throws InvalidAlgorithmParameterException, InvalidKeyException
+ {
+ if (!(publicKey instanceof BCNTRUPublicKey))
+ {
+ throw new InvalidKeyException("unsupported key");
+ }
+ if (spec == null)
+ {
+ // Do not wrap key, no KDF
+ spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build();
+ }
+ if (!(spec instanceof KTSParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("NTRU can only accept KTSParameterSpec");
+ }
+ if (secureRandom == null)
+ {
+ secureRandom = new SecureRandom();
+ }
+ return new NTRUEncapsulatorSpi((BCNTRUPublicKey) publicKey, (KTSParameterSpec) spec, secureRandom);
+ }
+
+ @Override
+ public DecapsulatorSpi engineNewDecapsulator(PrivateKey privateKey, AlgorithmParameterSpec spec)
+ throws InvalidAlgorithmParameterException, InvalidKeyException
+ {
+ if (!(privateKey instanceof BCNTRUPrivateKey))
+ {
+ throw new InvalidKeyException("unsupported key");
+ }
+ if (spec == null)
+ {
+ // Do not unwrap key, no KDF
+ spec = new KTSParameterSpec.Builder("Generic", 256).withNoKdf().build();
+ }
+ if (!(spec instanceof KTSParameterSpec))
+ {
+ throw new InvalidAlgorithmParameterException("NTRU can only accept KTSParameterSpec");
+ }
+ return new NTRUDecapsulatorSpi((BCNTRUPrivateKey) privateKey, (KTSParameterSpec) spec);
+ }
+}
diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/AllTests21.java b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/AllTests21.java
index 5ab3df3a17..237f78986d 100644
--- a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/AllTests21.java
+++ b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/AllTests21.java
@@ -18,6 +18,7 @@ public static void main(String[] args)
public static Test suite()
{
TestSuite suite = new TestSuite("JDK21 Provider Tests");
+ suite.addTestSuite(NTRUKEMTest.class);
suite.addTestSuite(SNTRUPrimeKEMTest.class);
return suite;
}
diff --git a/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/NTRUKEMTest.java b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/NTRUKEMTest.java
new file mode 100644
index 0000000000..0b95b45d07
--- /dev/null
+++ b/prov/src/test/jdk21/org/bouncycastle/jcacje/provider/test/NTRUKEMTest.java
@@ -0,0 +1,216 @@
+package org.bouncycastle.jcacje.provider.test;
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.Security;
+
+import javax.crypto.KEM;
+import javax.crypto.SecretKey;
+
+import junit.framework.TestCase;
+import org.bouncycastle.jcajce.spec.KEMParameterSpec;
+import org.bouncycastle.jcajce.spec.KTSParameterSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.bouncycastle.pqc.jcajce.spec.NTRUParameterSpec;
+import org.bouncycastle.pqc.jcajce.interfaces.NTRUKey;
+import org.bouncycastle.util.Arrays;
+
+
+public class NTRUKEMTest
+ extends TestCase
+{
+ public void setUp()
+ {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null)
+ {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ }
+
+ // Test for no KDF
+// public void testKEMVec()
+// throws Exception
+// {
+// Security.addProvider(new BouncyCastlePQCProvider());
+//
+// // count 0
+//// byte[] seed = Hex.decode("061550234D158C5EC95595FE04EF7A25767F2E24CC2BC479D09D86DC9ABCFDE7056A8C266F9EF97ED08541DBD2E1FFA1");
+//// byte[] pk = Hex.decode("01031FE0C4328B956E9AFA7B5D86DE2CBF1F0728A1236F685DD2FD221ACDD05CAB64B01AF7A5F3C2837A5B7FE5FE31E366F7F04C5B77C1D6BD3B25A765A84CF9AA08FD9ABA3BB6A4B5C3504064D0803687A04F06B2BB5F7BB95AABF6CB823ACC6E74E98FC468C3E07BCAE284797221A8C8A16168A91A03D066F0EC93F26C8BB6E948BECB9919A72E0FB86F380F1F2C1A2EFCEF871D6ACE4F5E0AD226A80117F7CEEFE566193D872A9ABADB9873D3E9ABB0119CF4133D06F0DA9F0ECB6319CEE796F2FF5B85B4A6754AD4C94346E325BAFF9CC922561CF02B827E2A487ECE6A4AD9ABBDE1D81C218CD5D50A66B8E3EB9870C9F68457BC813A2D827EA7C87951439DD394DA1ED071E8AAEE175BDBFC5CE2ACDE12F78C9B82D9653B970F035A130A1DFBE5B2D4C186C909B9ADF4FB821B2FA21EC03D8D8E095D68F4CC12CEDBE1DE7428A201B04A9575BE758D58340E73602C3467876A4B18218C34A3126DBCC877144E4A42A45005217D9C50F38DBAFAC6477011DA1A1FC749F26B6C747DDADF1F1E4707440A34C22046A6145D3033408212254FBEFAE6A4FCF5AA41BA14EF3C6CA23F3E04CA53A5C2AA03C717A04E928E5DD392ADFBA921528E54944B4183ACBED4D21DFFA3F33D35B9679068B3711AC438F7CAF3042436A9C0BB296ED1C7891B7B782EAABFCE080BDC54CB4EAE3E75536171BF1235397ED37A4394D05D31D7274A1640C1B42912CD9AEBB6B323C370130A854E5BB2253D6F3CA7AFA061C241646C28A8D1EA7AACA73A028920C2BA5DC9EC21F1645B92B35FE810E024CB764CE53F611E61DFC62CEDD8BCD445870D50EBD4DD8021924CC366FADE330AC3826DBF43A328254C367B15718967D72EB4F7EC3BFB692B5BEF357BEF0974739400113F766922F3171964E303D255FE2453BE85AA7B9B9B6408D1655D475BE7EF0351273BC084C9E71B794FAC5C256E87CFEDE5FD8E03EC272B24675B947BB5C1711D894285E026221A152D19DDE65ED293710D195D31968D18E9E2ACF3A0BF5C9F4760B1C20DDCB49FD9A24A3027025A5C090C708E97CD0F273E89DD43180ABEAC4665478732683325406CFBF20BF3059AE57756FAF185612EC199424EC64EC444BC190F0FAA6B2E9A2D96E7814E2FC3BF673B87B7CEC8D6F3A814B5774CF95490E258F0B10269E1ADD8C1D1C4BDD5346ABD921CE3E02A2D051A95E56DFE9A0C655D926FCA45D445170498F6D0870BC8D3F444982E55DE23D59A385E1F18732F7D7F6526289C6659D4363009EBCDF2066411E49E3A8E3D6B312DDCC49169BBF9B13C827A88ACFD5B3E61A9116916F41052A3AAF50ABDA2E7CAA9DB7EA816F44C0F315CB86700F62E25E05C90294FBD55342D62BAFA8BA55BEE7B532D50CD947065E704E625");
+//// byte[] sk = Hex.decode("5515559645A956544158655545514489451621815999295514A25949655418096985596A011900615556598565956A6866A916555455214551995455460640548011661525945242549500A515565165659455A52545A6A5445050A2054599A4659591541906682494418654A68A969155864655419119405555105595842994525415591649A569515155058551859A565A8854655454848415444169519555149656009A284AA0664A42991A8809015AA6555A54AA551010460084421102809A028A940502189698410446514812188888644650A081288196648158A61261A94A50908918A5810846011A9925260685A244404A0A585A0289066611A85A5A12408668A6A6591565185058559A18658821104418281602A994A6505012A82A662412A40255690122299A0954295A946110669299104014952500529294624041461249AA142A0201031FE0C4328B956E9AFA7B5D86DE2CBF1F0728A1236F685DD2FD221ACDD05CAB64B01AF7A5F3C2837A5B7FE5FE31E366F7F04C5B77C1D6BD3B25A765A84CF9AA08FD9ABA3BB6A4B5C3504064D0803687A04F06B2BB5F7BB95AABF6CB823ACC6E74E98FC468C3E07BCAE284797221A8C8A16168A91A03D066F0EC93F26C8BB6E948BECB9919A72E0FB86F380F1F2C1A2EFCEF871D6ACE4F5E0AD226A80117F7CEEFE566193D872A9ABADB9873D3E9ABB0119CF4133D06F0DA9F0ECB6319CEE796F2FF5B85B4A6754AD4C94346E325BAFF9CC922561CF02B827E2A487ECE6A4AD9ABBDE1D81C218CD5D50A66B8E3EB9870C9F68457BC813A2D827EA7C87951439DD394DA1ED071E8AAEE175BDBFC5CE2ACDE12F78C9B82D9653B970F035A130A1DFBE5B2D4C186C909B9ADF4FB821B2FA21EC03D8D8E095D68F4CC12CEDBE1DE7428A201B04A9575BE758D58340E73602C3467876A4B18218C34A3126DBCC877144E4A42A45005217D9C50F38DBAFAC6477011DA1A1FC749F26B6C747DDADF1F1E4707440A34C22046A6145D3033408212254FBEFAE6A4FCF5AA41BA14EF3C6CA23F3E04CA53A5C2AA03C717A04E928E5DD392ADFBA921528E54944B4183ACBED4D21DFFA3F33D35B9679068B3711AC438F7CAF3042436A9C0BB296ED1C7891B7B782EAABFCE080BDC54CB4EAE3E75536171BF1235397ED37A4394D05D31D7274A1640C1B42912CD9AEBB6B323C370130A854E5BB2253D6F3CA7AFA061C241646C28A8D1EA7AACA73A028920C2BA5DC9EC21F1645B92B35FE810E024CB764CE53F611E61DFC62CEDD8BCD445870D50EBD4DD8021924CC366FADE330AC3826DBF43A328254C367B15718967D72EB4F7EC3BFB692B5BEF357BEF0974739400113F766922F3171964E303D255FE2453BE85AA7B9B9B6408D1655D475BE7EF0351273BC084C9E71B794FAC5C256E87CFEDE5FD8E03EC272B24675B947BB5C1711D894285E026221A152D19DDE65ED293710D195D31968D18E9E2ACF3A0BF5C9F4760B1C20DDCB49FD9A24A3027025A5C090C708E97CD0F273E89DD43180ABEAC4665478732683325406CFBF20BF3059AE57756FAF185612EC199424EC64EC444BC190F0FAA6B2E9A2D96E7814E2FC3BF673B87B7CEC8D6F3A814B5774CF95490E258F0B10269E1ADD8C1D1C4BDD5346ABD921CE3E02A2D051A95E56DFE9A0C655D926FCA45D445170498F6D0870BC8D3F444982E55DE23D59A385E1F18732F7D7F6526289C6659D4363009EBCDF2066411E49E3A8E3D6B312DDCC49169BBF9B13C827A88ACFD5B3E61A9116916F41052A3AAF50ABDA2E7CAA9DB7EA816F44C0F315CB86700F62E25E05C90294FBD55342D62BAFA8BA55BEE7B532D50CD947065E704E62500D57230D15E762228DA98178A193D7D95284B20E82D74228146FDF68D59B37C5E7F78C0E14E7C40BD4F4D9CF0B189B69983DD39E29AA6439ECAB0A5B294D2A1216CE31CAC6D1B2358D2B0476C4D8002519B6D63639B2D4564E2458C8E06BDEEBE82262570777780F43B110A96547415A69A38EF0ECE0C2AF16B9CF11FF8326E2DE6DD0333B2EDE445AA3A1057824478BFC71FD00DEE601938734810D816F4DADD35F4C152B10CF13957945F8CC47FEF0CE3BDD1F0C5D8CD24B07E3F6D2A5D01717CFD06");
+// byte[] ct = Hex.decode("BC60F537CD5FE3038DACE613B8819A0DC920B8FE092474F763A1BD05F69137A1A084AA1A45A5BF1055F9340368D60CE415217C2C382E7EFFCD289D62A0A9E1E7FA2EFD07EF4B75B02DD436535AED897AECD520763AC7F8DFAFEBC122594388F210DF28DE472E748CFB640E8899B07CB4514401DEF9E9C542DC89733F20F9605F641DD1DD6F332DC051C2E5B2C391ACE70FD00FBC251EE1EA2AB27D165F966DA338F8AA970AAF66931F7CC68E2846EE5AD7EAF8E15B9CA333AD1260163E2BE2324C03094E249D3418164A655BD469E506F5B8420BF4FF6080DA230373B18D74AF03F11C9B545E3791CCC9B3B9927B2222983B7A6DE620BE8520B215ECDA45302695C0229C2A9607260BFD3C6EB9D7EAFAB5E47FD5760FA23067BAC1E6A980C4727B0C187A5B6397AC43D3BE24C42A1D2FCFE43512494A7BFC5CC19455DF6AA6F2698A2903831CA2E5F4F84442E6A74BC9D3CC3D6FBEE97D5CF4B6C58D3DC9ADB359FB56CF35FE21F96E885624498ACDF0BAF3A52B7F2564D1EA384DDA7FD32167786C5E010C3BCF5D2E7164BD6ECE815366887250D184F8061E57C3935214F191B38E982132EF4262E91808FF1CFD902B5248F6E7C031A98234DE0D578D1234B7453F2F575A88B622B0F11902C2146F45912E9BDAFA0846AF7B6789E621ABE3C65A4D990A96488B6307BE210887E82BBADFB026B60CA7DF3C9D429D8FEFCCC93A82E345F3B17756F6341F5DB3151974B1B9C7AC4AA33E80923475FE38FFC0AE7F47529360787AC283008971D87FB07369BAD111F1B99FAA59F2E1B5C088A5F31A47ED6A8E30FF6465A7DC79967EA78891C8EBD462D2566A4EA30EDFB8B7BEDD3C4E2ABFEEE7B366125A19B6372CEE2EB2F85514648AE920D292F444E6F90346DF87FD7C107848796219027BA581B3D87704FA8605108CA88ACF262C5C07D9BFB42635A1944634AF0633B471D0D2B2E4D6284894E0E48D58AE5D07E95130C9FBA77A0F124F9348E1A570BA0D009B7B46E03CEB201B17114B935AA91691A7F830346636FD34ECE2CC295D0124AD8CA76CC81E942C1607699F0DFFD3BDB509392FAF8212363F562554B05F756FF252765E6FCAFB04C6F2CF6A76F2E59E14F5BD4EA8E2ECF50B17E632F346D697FFB7AEB82ADDEF5B4DEC0DEE73D2D96B1A33C6AB4BCF7A160B79114A48F224FA037315ADF0485AB63DC2BF09F02606DAD80F13F0ED0241E6F53B21BBBE584794F77D0B783A7093F53AC916A848FF0F9FA3FB08A053C4");
+// byte[] ss = Hex.decode("2FFCE8C89E97BBA86A7ECD68088FB116A20601B88B8E88A3783CF2D2ED439769");
+//
+// byte[] fixedRandomBytes = Hex.decode("7c9935a0912822144249e045d113b6e7cca2aa19b94d210a458e4c8dffc19aa7053095f130f12e7d79262cf801e5f36f63bf9ba079264c836bb02cd0a45a6dee06b7ccda4d18d429cfb5c7784eedcf12e28519d7da3ffcd65731b6d5b773204a55671a9d60940059720a74baa026a7777cd11dd3f81dbf836a06906d60aea820cdb70b606781805857448d6233a8e174b9c5e89cace15b40002c75a3b2c820a2846de5d6bf7c655a9b794d36e4eacbefaebadc20b9b7018c4fb60bb77f17d924db45bfbf74d2d052f8ec84b04cd70f6693f2eac613a0b55d9ad4d951d3808e66cd9d716ed9338a25aa41a9fdad9f7b46f10c6c8338bf52f8b4e2bf25e5e4071beb03e83b558e5db80a224da29951496268ae19980cea3c200e489eeeed9c16e2f0ac2d8daa9822958a84a0ba2fc08d4dba8fe84a3e60acab2183d1e795e74e58ee25a9e6d1fbcb30e564f9628bab26a674f9969d2625b7b7473c29bcc926486d1620bb9e9fcc107f1dded7c80189e7fa361fe8dd996b9c2d8f683847caa95d1542678bd200063bdb5757a4b6a72e8071b246df24fd5b30cf94eedef6ac59c892eebb3d4288fcf80182fc36db2946706dad5059ade4674341081ea63cd695aed3afcf51d66d01b5e61623d4fce329dc33835317f300dd58a9624153d0f8a25518c946046de3d55fb45a09396f4c8816c7f359a1999e32a4eba8d25920002f0bbf2e3b9850cd67f90fc11d1e3da7a9abf920d4007a952b77a9c9c1ac449abbdb1cd35ff17ef9182ed94b50e5b60c6400735362dfc37b59d23606e265aba4e88d617daff717c07b15d63c59e7e72aa19fe6f360ba4cae860c9045ad03dc845edaf2786583fb53bcdf05d21b336d25901204d7794cd3b7dddc30d28b5ac4563be1a6515d323d821ae873d0b6e5ff48dec06d8f9585ed64f0bcca2a353b64c7dcf0d6ae9084529a30db3a40163bf8acac48251c7f82b5ade896d66f15ed82850bb86689746b0144561a25634a8b2f5f62470990d4a67e105183d208ccfdb9ed024c52ffe5f0afd3219022e95d10289de8a31ce0666f8ab7ee89583ca70109d7bc4fde5922bbc35c31691d4874e0a3c9c2b9f3731029fb14c6533b650a31242a3b33002c01a2add52c76d828acfecb87193e28ea8fcc99f2cc2d51c7f512ace14f864749f20fa8c554db03c2d8fd1cb5a2274ec97a470e18783d2ba66165798d0b1c0652615e5b5cf9941474a66dda526c474c7c8d2189058db7f1cb6cc3687e5c6fe322aa8a615cefbf6abdf0a0c36cbb32a0a58183c460a692e2e89a21fa709aa3da00270c6e7368b1a0178459c96c2c539074a72f7d1867a6aa8d9f545cd270930bb05c99a8c394357b0377eb66f90529882093cb5cd5b8ad08f538966fab56c5a29883214009c76d69de18aabbbc4f5cb757e8b5422d5d7869e91e3850ddbec01bc40ed11b2134d40d109508d812e7b7be26278c585a1703e935737ae3bff4ebf9bfa383ebba7e2f7d0fb9f4b78479a70c6a6d1c0394919fd1cda8600fd284418d6f4d3cae2b213f4078df0de5a860a23738fd7f85450f3d7f9903b306f863c7808296419c06a4a12a6149a0b699719aa762ba72f0a052e971b58ac97185ec95a5b8784b60355f163c4dbea0b1fea3e8e5f23eef6abbfc155846052f396d5d97731678e48ad0668391935a6594fabd5b33440b647f343601e909a3926719bae73df1cd6af5904bce016a4934b27b01b45288ab1c13a3d72531ad31adc304e7d38291b35e2f8c3cfc153127d5465a8b953a3af7f7e5cdc22174919e50d7c195cf5a7463facc8f17baf75118259bbf5316369bd70c7211a240def65fa94dfb58f3984985b9815e32c3591c93cc9fc47e75ebac8aa0044681e34791a1b847068386520e36bdba90735c870a3cc9fc8b7be1c084d4200c5f02b7476cc7c406e1b8335c4b3e05a98f6567a942a0dddf9d0c4e26a700454b34a6f174c776978dbb7c18c40070ab899752040fa824ccf63d31f15f7f86c44905e4898f0ed731becc9d20b9b35b92a57de9f5e42c38842ae6c7d94c8b246825f8d722db09b138db117d112968ebd1ff4bb835bff94cfed81fe6f22915d2e0ce4bd1cd743788ac146fe4aa7e2ed023f88e8f96715c97548bbaf0549f1e38fc16ca351206745e7ebb59649e9e534c1633289f8cb0071bbdee509cb131bcc7f26d3b548c17fd413a3a3101583b18f3335e0380098a3cfba480f7e0ff0b606c03338790d6d2e5b2307edfc311721f1587ca55501f4b4b5aeab9773ef78f27c40e8a42bcb57c887f99a6d56be4647f12a52367936bf3b63bea50319990cb58436a5dfb819c09c27299e778a68347f40ef386c6ae97e25f9fdfb7da6b8c6efd04ec9eb83e6cf431b2661a29f4203b286d4dfd860aed5eb5456b8e4a5b9cba46fdfa83aea1e043b3182784c8cef3feeee0343be2ff4d5cfae8c202049a53a20b35fdc1c82e7b246ad7cc7e0a2b05368d873d948284a206d12ff366456ecb1123a121c8d2eaa53a423aa6b4e4c36257b7a18d1ebdb28c0f5a76a3938cbff7b0e1b43dc5237a3fa7b6266bcfba4ee44d7ca17a84e0a97d8f4baf6b9843af217d5275e07336413a3a0790856b8a25c67f6d2822dd85120dc18d70d6ffa1501b3880d036876322c1769f08bb767e9c6a7948e9e8d87ba0fad66ed655973ce1bccb8dedd9c7f2c80250769e247ce679126cb3f2fe64ae05110691ea91626d8ea26f4cf674626e62850e4523ebbfef5a926c90d9d33fa67f6bc50d35737801604e5f5b119e08c306ba7b0c09f79f871e10b2261cd8f489ccc14bc17ace710a407e0ae21732192ab6febcf4d58c53ca415f0d53e4746267874ee026106209cf1ca11099ef5e59122f4cf17d50131d0197d3b7a1fbde22d3d40635b106b27315e033e2d8e8a0cd45ba504848b470cfb1fc78d47f65226cf0968aa51fd62568b9108adffcc25193d747e735dd5e06766ee213f5ae9032ddb28cfcef714ade717c9d18b7d63e4fc057ef88fcc0894a23d36f2aa16dd530086239279cdbe14764656bc51f78f4d448c38320e32e110bbe4e90bbcf11d924563469001ea8561f5710352f44619ca1c2f108d021f520008b542071ca87c936bbd87cf42c3a06e10976cd82e074974601ad86662b283ef5d2fd63486a98acc91758160a5e008333ad3b365be36836a196643b4136fbec90ef50bb944cb17ee0b55adc5a60dd81809e74d3f4ab5751a4c1b94fe7082f86c6935b867d15bc27328c3a7d9e5215fc8a2fc7f3d088446353ec9c92d3b5d01fa372540d1de064ea02030a300eaf73eb4eb40e5b2ec2b0c6d3d52f63369bdcc63d268a065e18aeee15474393c08eebfcb9d2a795e5422fd50fd099f85759966ba28127bf5b1eae0851b5c567c23ac33469791cbf78e827f98c4269b997008ac745188aa2a77cddd83574858a7a321f46cb0db5b89b100318c818500dd4d5a8aaf16c38bf32831099cac8b121e191ea8c50573f395bc70753839643e602b3b2242eaba726ec243a643392df202c6fde7e8436609969436aa1707fee35a08e0aafdfcd6471db08b9814e4547689f04e5f8b918fc0a8fd82784865ef5cbcc53da7e2fb1adc45e5a429833003b159edd94f3e1400b784181c81a270517c22fcaa0fd7286adafe160b3b17495ca6186e7e15c878be4c228cb5f79a4d940dbdfaf94392aec9aaa252c9eb0b58dded996e081fc1bad2a7a229f715b4690d8871ae7b086961f7b7d44e1f9a2bd093042919d0543007e29e222c057540f0ead016575771f85811d93583af887ca5f8094c9274b4b933f528788661c9eac7d6f736024051df17028b8d06f4ca6d33dcef7fcb6cb4a063b764706fd0d457c6119b6ce77fe47d40881bbc41d5fc042717fe4b599132af01cdb6032fcec422410c071f3d83eae54264ac430927e85a468308f96dfa26ede5fa047df6d63fadfd3861bd3507ae199274d6e0b3e329a10a58cef6535747ee4a6c5ca9ec10a39f2acff29a33b82d09b899d6c4c1271ac8e6721c0c77dbb6af1b4b4cb7fca8dfb716a76f6f587950d2ae419c4bfcdfbfe4fc08605627964b126c39ded0e22260c7450b7ae8e9397a27ad0f614577524224eed1976a085dbc1889d2495ce1b94a32153d9e433b27beecbd7e87a411248aeadb5c6d155148336bb55f23bfec0efc2d32463b46c2293206137ded47fe3c1cc7f64e135222308209640dadff7c9da43f9939894b7a67c298d7a790a5ec56391076f8c9518d85aa1d5df44cf3043c15ceaf489e6b7eeaad05907373c4fd7a16a4982299b66791d3436ddbdf438bfd98e2d94f0d41835c604b992d69249d798fc66ff358905dc801c79d60ae1a498898a7faded0502cbb751bb56ec28ce4069b4531c7c20c7dcdba2b0f21691bc776d7eb4295124f8411832f8941229c43b0881aee44425f6eb418143ed19d1fe79fe55cb5744259a4bc13c3512227c06a8c42563c9951516327ea8e90b9f4313e146e8b452814a93fac4564ea1bcd51360c8d19bbc07331ee161bff595e330397dfa532b2b2d25a428a999bf9b357335196ad4a7d7d2db12ca056549223039379aaaf5f89d281e04e986f5dba96ecaee589032db3d66118e4ce169a6a3034394baec899bc5eab4385973728be47fbdaba1d6cf6db50d77d394306727244eca23f2b68af3e38d275799bc81c840fd425e06d516cc33ca100c0d704ba1606ef4199d1b47d9a756a171309746ba0cdf48e9a0ee457cfe19a99d4112405d3318968ca97e13f72f271df0a5b487b3c5869fdddc6d53c1e7190ebcccad22f5d52bb99780a1887ac2fa0b933a0ca708ab7f20e1bb46ec6238351ecfee46cb42bb574270b46f4a3626ba8af5b5b3c96ccb7f1acd772b13277412fdd4ea740f8c6ea0d2383377115f8d17c095b8325ffc82ce966150413de37d622bc426c3f8ceb1cde12069e3c41e90d248ac627be702482c4efb2f028e2b2a607e2bbff190ddb710d7e36a7811621baab0f134434c254cbef59e86af197b6289e72d24714ca1ea3784bacb250676a778bf9d6ce2549799af999b917c8df2db58ec799ad51f10d0bd3707aa5f3c3aca8b8a105914825e6b78709eed6190de883b34bfe6f4bd0c91001a5a5d168a5212c95ec4ba15c700c937fd359e401899e56e3db259da628943951e8b2a366c94ec46b9f6b5d4da72943ba738d662d2cdb4fef6091ead96cc74d272c4c89077765ab6e93cafc737c82ab30b13b40d14c595d7a5efe4e89cccfb81275776c2b8df49db7c37f8a149a1a53703a255095021c125679d6929d8b46de63254204b79f43bef2f2bd7f0e2143de50616e19346239acb7db9a980baf1f212d2c26c69fae7d759c46da0aa97f443031d06f8b6a85794ec9fc778d30f08a4292a5e13488767741ff120121e0037c3830d32b6181008b47a8d48126af48719a7e7396ca1d6e787fba426a54410364baf076426f4c72dbddf964e5dc617bebfe8d381320150ec065cdd87288245115a18ded71c70b06cc02bdae6d695cbbb5b3d8a2aa16cdf80d84d511ac1b754f472f66ea6c5e312b4c67a66067e1f9d32de4d1d14c4c4e2cab3f40c2895c18a56b94fa40b75641723e7c147a594c89511956f046f0fbd26f3d3814c13ab717c7e164bdc9f8c0e5ca120724989897db7def83513e8325176d04a774021ba934b174af4b063e8764a8cf7c81822f8eb2c5870ad4b876051fe5c18c352cc03b885f74c65d22a5f9eb0fa399782ad33639c0ade4a2c1ff3ceab622373b98410f25c3de2d570f847fcb8492ba5b06661287a4e09af59374ccd9d080fcbce8ece50bc61c96d3b5ecfada0a974f04329d6f245083c3e7d49e7c59e2cc437de2add8bde7518f0b8961c7565705cafa86ff93a9f3fe8d22a7f76446e4e26a7534f8714081433b4f5c95d68a1cd7bf0e5cd74adfadc851287f9ac437cf0c67d3c5e7bfd49fb44f4277b860d657035303cb2d872fe8530e406d3607e3e33b45f47a8a42a229362cb0208cd5de79a7c0069b7fa8263c606b2f80b66d7562d975b9f096fe599cd28ba85521cd123f665d6c101665af1d4f6c850e28b3ee8b8f74d2c63e7331a55edea8024059810071122e0f8ec7c3776a148a28a987e2db7eef4f493c4e69e20f2ce2caeb305a23bede1aff4bcd706f87be91340d48eee4f8ea2fa7f496e882ee68c9f60daac3ef08c95452d936a8762d15a47659e4a791b03ab52cd0407cbe3677b4cb3b9c2d3f19b8f21250b28abfe1eb6c4e4bc92014fc4f10b165a594c30131f571aceb009e5574219584e2fd3f3281bd6156697e8347bffb50c3b699807bff24fabf9a7ced1d796078dce628d3ae6445b81c8fb6a633b9f25dd4d25a5a6d64b8af3c71c5b392822aa9e5748f3ce90b0c44f7857ec8dbe90d15c9b31152430b245139da98c63cf1efb6d89c674b15e51d30a282f779a6dc4b23a5e546fcf8cb0bdabaf6640651b98b6e8c7afc5c084938ef0d099f87466cd1648cb9aff11054c70ebd8921e459d6245b89ea05cc218d48c331e3138a7613a1500dbdc8b5077e9063b39a4a6aa8971e910228f026d3437b1344dc8f746bcc34a94605fa855200afc964565df617bd3c04d4998c162623cc4975fdea827256f8f61da092fef0e4a3023a03c6aa606579111dc80c118a470b9a690409b125cee61d64472d40eec1c222cffe7c3a59f8a00fe2fe51b072644af0be728bbf948f2848d1371b34d09f0fcf3fcc31d084ad69d7edc2e1aff6651f7f0123e1a83c44891567a34357b114e060e82464d18cb73a2e7e2b5f604c09938eb06df26a0141a55e7fc84f219c7728b022ecba2f1c71266a5e6aa7bd784a8c6e0db32b53cc03aa500fff71b06855acf22b8335531655fa414693b3fe9a320a98781ca9f60b955b3817f54873915ad3fcc843b172a4cbc5d3091dc4b301b4417a391b66895ee37ab81a6fe186fcf6ee7f61fe3b89556edda3130153e2562aa190be6994ef738fab5c2dda559e63f4b5b1f08faecf5e3cd9afc5d6336c45273ad5f93dd26d0894e2dc587f7fc1b26ea6b2428e55f07d9e175fdf9d9e0b58df7e169079cf203f21e5aafcd3a7710a0259d87be594ba30bcb2a6a2e26b28f499c3145889198e5aef16fafdbd1c440c300d83100d11d0a0647f0066608e847b6b109e9853b2549ffae9498ab5042823f0fe0ab248ca6ef9de115ecec752dcd1bf2e4e55e79cc0d17866c97ddff73f7e35eb598e60ecc8ac4cab0db57c948aca8750b1543bc926d2cd7a6239a683cba85400d0bcad56e943a4f614bea94990bc426e1eae75046b6baed05a59bf0084eb777d824d0d212e9819e2ea7db881c44fbb85bc374a0d6235f8392a3d9a761a5747d75d96cdc3c8dd7272eade200d57230d15e762228da98178a193d7d95284b20e82d74228146fdf68d59b37c5e7f78c0e14e7c40bd4f4d9cf0b189b69983dd39e29aa6439ecab0a5b294d2a1216ce31cac6d1b2358d2b0476c4d8002519b6d63639b2d4564e2458c8e06bdeebe82262570777780f43b110a96547415a69a38ef0ece0c2af16b9cf11ff8326e2de6dd0333b2ede445aa3a1057824478bfc71fd00dee601938734810d816f4dadd35f4c130598b9678682552d0d9bbf0116e52f71e30f449c6e70b673af7186d562e4591cfb9fcc9c591cfa471b8e3ea987e8e6b5f57d6ea8dd522e74d63169f343b20f9816236320cb16a04fc7b629e6240bc1686651f69bf37db30dde39875d57beccdc24c9d5575b0bb0b86f6d2e06f857152874f3a9034cb6018c5f83c55665f22a4195cb93fde9d0294d0769969423c54cdea07300e6f2bcda80f8e35f2631ceddbe3d29cfbb81a94d60b576e5c471ae1dacac226e9178369177bae4f33fec7b710b587ce317d3781e5fa8bae55167b7b93cdd061782786fe574fb7296b7c338edcd16642149ef44e694f8d30eb602193457a9956acb38b8ffdbf22b7bd93bda15b79cf2ed4c8e4606052696fbf38a852bef0ef9e8cecc8faa42493ff945a0b6cf235f7a64b03e4cf567ffe3687b6208c42c7df3272008f9c57ef92801444faf4932120223aa8882a57ed3cd8fdce71fe4ac4ea41dec00b74c0310d25260e0f95a4b89b5cd96ae446b33bc433181db39d0b4e48de172186f9c50ef7ac72adaebb2202b358a1250070349c66516d7f5d895ecf2dec601759abe52e2c7fec904db0b8a4390a4f8367db536a6a1eedc4435a6de58b62b3d4a946061b77adc10d21535a026657ec07ce19d9e097f93da31ef963ec7cfb971edaa8acea7537f5280b51188d88de355a79408f5c1fac07234ef9629ee992abfc874b33572362b95722ff1714cc238c68be7850c3bfa7bb5bf2c41122192cea2783f79cb558a65198c93a6009fd3102ed3d7cf677c5c632ec1a31abc087e2ab717c9abd04caf709a3855ddbfb70a81099f22ec5f49f3122e6633882f813bb76e2597670e37f36240e00a75b4b90a132cf2b4a652269ab8be1697087fa262593a16639f496edb72b0c906eee57a219c51dd548a697295bfac80d400d834c486a7642aab0d12aa4617abf1f604b5d6c9cf40c57fc8454761ba7fe54cebd8ec43daa495a6feba2e7524b6b771348100b3af4eb145642d006c3acf26262f8de8a6465f4eef60bea55615c19c50790daa8a0a39d42d66f89e4e6e3a5029cda85b50bb256ce3c57ee6aed2ae47db1d10b05bea586992a0b3a282d36d7c8d254badfa4a8b7f91d0fef5bc971b99b7c2d0aaf904a42b11139cc22d6450b6467c9453f1392193fd16b9aa565c757fa9457a9723fbfc6ce3b2f8381f0393b4eb984068adb273a50ccbe4e8fb708902179e0b8d645481a7f3919e07f758cfd12a3496bdd5b063d99ef127cb36dffefc4a29c23e63da9f4ab05a20faf7d73d70c619d48a92c653d415b7a9aca0c499937fd2acc6b1e6842d5f15c00bfa3b1d1c1655f8601c13f94291bcf76979b2c45d30384e4ce99a60ec088c9328a393581a8bf247609e5f9f025d98df1ed6c25ed4d6dfc67c98ec93b9158e7ccb8e8a50f4548479444ca7386ae077140d8a26459123dc28c9bcd531e3287f74cea298cd4f475c45e51792e439ba4368171a5ff60656c1ec132ce5affd6814f5f0fd786b15479a8bd2d2d3874bae96ab58e3b603bb251746b67bd00bb210f3d00e3725ad2a9441a11c8d320aa18e83383815f1eae1a7f195034f9dfe7ff7c4fd84acb7c2e22ec131d928e425cf96b64b562de90593cd61f237c11e2a4fc33a7f5333e1c6085a8f0d393e346646f36b3c4767c3681ce53c75414d72c57121fb10ac3f0eb8b784794cf2dcafcf0fe0c7b003d6171c20a3d63b44d168ef4bb79da894b5555c6f69a4d6e82fa558526e1bb75c63dc8e0fcbe3b9d462c0933eec9f034d4e917f30d48e98a93755c7c8771648711b81e5cb6f4e30680b7ce662cee5c8a02df4d1cc8f6aef8e632eaa09474321f231b7ed4cc9ba2a993693f4169b7752402bea7309d0412c9269799914894ebfaa9785716406225a18101a6f393dad47dc052c45bcad6f8bad49f108d6d179588d1c08db51ec9a50ce2702c9ecc1f9ad68633060579801e2d131d1044effa20ac6fe815f15d64e900c7d72d57ce8a398ac34119490d71b1058ffc111e089617145d592119352203f341c0ba91941455c29d5c253bd219bfed0d556212098a969a38b6d561be89635273ae7e4531210dd7b0d0310f2806a6e7a46c9f908c19862f9e05206d8408b246f4b8a508b9e78824cb9da63e4b6fcc2bdc9c391f2d4b9e3008dba425a937e025130b7cdd946dafe43e3a18f7331c04e063df4ee19cdd09e2c652acf3f4ced146b3b38f0fb8f8dae0f9fb1f87881cb1e7cbe6c33da4b704f03921810fbf3368a11c3014d2a4bfca1396ed43b3c3a3c6de41ee3740d40eb28983b2967f74a5a2a0515f68f70f4746dc94f29607f14b671c088df491386a38cc6f9765cc9b2ac7e91d80a2506624a9b0864aea397eddf2a9647d6f42cbdc68f4e8667f3d5614faf151b94acde040329ebcacd4d6ad474306c990998423ad8fb307e4a47e4e73463d913c812e3316a77bf238b89f69178dc0924253c110ca5396095d7c1689526e1cbf8dadb924f19df73aa7c97b59e013d6c4ddc687e06e10f82c7aeb21011e931222a777ab3a87759cb893b380ce15a22491ef3dacf62512e3d0561a137aa294d981601813767e44decfff7e84b4c33d6d73022f20faea96ce49976f75c85b390bfdd508a8c2a1f77681add20cfb715fffef359dda3e824d607ae19f298d7323210b7bd3fa6db1bdbdf613d13b6b7ef349278eabd1ec4ae836ad0307e3f5956e753b39c5edb973a6f90012962e3bb75f673461c211e711109320152825f5c9fe4b516f85eb0ba33e8719843f1ca4c965bacdf870dcd53dc05ea444696c615be7cb9214235f008b4c458fd0cff1b313e3433eed9ac1495785a57c4da01fded6650a61d29cecd2462a84faea9b689d050021f4b7d883edb39ad74a5eeec5a898f73f40fff5b74948fbf96ad6afd14d48a2f4b15782d163f219b069f2da414905b5b97576f4486fea35e93d2aaa4b41afeff1db600782acd9658479c960603aaaccf3fdb10bbe916936ca4526e2a3751ecef7abe2500bf18512d52006bc80c2fe5481727125e0a27d4342f3046e626b753b40eb210dbd64c8f67059fbe0c93146d09f30550cd33f3d03986f842a9421f07fc94f09ca898526e4cd51ba9b268beffeaa5f381c59964b5ca8b04918433b9229080b54be25920c8c3ddfa2b98d5c095a6800c1d3d03c8b30e989198fc96c3c8dae0d8d2ca09365d23c9e46abb40591d30817eb8e33985dedd0387b3ddc66fb655d37e41efbad4c05af86ce280afa66e591a619bf9236e5b7b7b31bdc87f63257aa652630afbe9ad8363750c04042c43ad5f392076f7481b3ca6b3dd83d7e87c604f8b08b0f13234fe8d8e5ab60756ae91d0d69eb144a3db813dd6095bcbee564b04a713152e40cf86285c1d51088832d18184b90f8db1d7e7d55bc79a2178b833523e0af31c027172271477162fc13d848d082b37bd1fc5700383cbb36ccc550ee3ec492266f9a86075bb32171abab9a335317d47a85de18d44809c6fbdbe76d2e5a5aec7cf00250eb24f453038b89e6cddb09e646676419c252e14f0d661f85747cc17f67732ca487012c3bb8ca822a9518695e68620af1ee12d2c6e48e0775128992922364c7bef20448e44025d399918109fc3ecc93f1c57c04be4409df78823aa4f098e3883282d7f9cbdac7aaa49dc8795c67578c862a0e45097499bbdf0b0e37");
+// FixedSecureRandom fixedRandom = new FixedSecureRandom(fixedRandomBytes);
+//
+// // Receiver side
+// KeyPairGenerator g = KeyPairGenerator.getInstance("NTRU");
+// g.initialize(NTRUParameterSpec.sntrup653, fixedRandom);
+// KeyPair kp = g.generateKeyPair();
+// NTRUKey pkR = (NTRUKey)kp.getPublic();
+//
+// // Sender side
+// KEM kemS = KEM.getInstance("NTRU");
+// KTSParameterSpec ktsSpec = null;
+// KEM.Encapsulator e = kemS.newEncapsulator((PublicKey)pkR, ktsSpec, fixedRandom);
+// KEM.Encapsulated enc = e.encapsulate();
+// SecretKey secS = enc.key();
+// byte[] em = enc.encapsulation();
+// byte[] params = enc.params();
+//
+// assertTrue(Arrays.areEqual(em, ct));
+// assertTrue(Arrays.areEqual(enc.key().getEncoded(), ss));
+//
+// // Receiver side
+// KEM kemR = KEM.getInstance("NTRU");
+// KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec);
+// SecretKey secR = d.decapsulate(em);
+//
+// // secS and secR will be identical
+// assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
+// assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
+//
+// }
+ public void testKEM()
+ throws Exception
+ {
+ // Receiver side
+ KeyPairGenerator g = KeyPairGenerator.getInstance("NTRU", "BCPQC");
+
+ g.initialize(NTRUParameterSpec.ntruhrss701, new SecureRandom());
+
+ KeyPair kp = g.generateKeyPair();
+ PublicKey pkR = kp.getPublic();
+
+ // Sender side
+ KEM kemS = KEM.getInstance("NTRU");
+ KTSParameterSpec ktsSpec = null;
+ KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsSpec, null);
+ KEM.Encapsulated enc = e.encapsulate();
+ SecretKey secS = enc.key();
+ byte[] em = enc.encapsulation();
+ byte[] params = enc.params();
+
+ // Receiver side
+ KEM kemR = KEM.getInstance("NTRU");
+// AlgorithmParameters algParams = AlgorithmParameters.getInstance("NTRU");
+// algParams.init(params);
+// NTRUParameterSpec specR = algParams.getParameterSpec(NTRUParameterSpec.class);
+ KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsSpec);
+ SecretKey secR = d.decapsulate(em);
+
+ // secS and secR will be identical
+ assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
+ assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
+ }
+
+ public void testBasicKEMAES()
+ throws Exception
+ {
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null)
+ {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRU", "BC");
+ kpg.initialize(NTRUParameterSpec.ntruhps2048509, new SecureRandom());
+
+ performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
+ performKEM(kpg.generateKeyPair(),0, 16, "AES", new KEMParameterSpec("AES"));
+ performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES-KWP"));
+
+ try
+ {
+ performKEM(kpg.generateKeyPair(),0, 16, "AES-KWP", new KEMParameterSpec("AES"));
+ fail();
+ }
+ catch (Exception ex)
+ {
+ }
+
+ kpg.initialize(NTRUParameterSpec.ntruhps4096821, new SecureRandom());
+ performKEM(kpg.generateKeyPair(), new KEMParameterSpec("AES"));
+
+
+
+ }
+
+ public void testBasicKEMCamellia()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRU", "BCPQC");
+ kpg.initialize(NTRUParameterSpec.ntruhps2048509, new SecureRandom());
+
+ performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia", 256).build());
+ performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("Camellia-KWP", 256).build());
+ }
+
+ public void testBasicKEMSEED()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRU", "BCPQC");
+ kpg.initialize(NTRUParameterSpec.ntruhps2048509, new SecureRandom());
+
+ performKEM(kpg.generateKeyPair(), new KTSParameterSpec.Builder("SEED", 128).build());
+ }
+
+ public void testBasicKEMARIA()
+ throws Exception
+ {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("NTRU", "BCPQC");
+ kpg.initialize(NTRUParameterSpec.ntruhps2048677, new SecureRandom());
+
+ performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA"));
+ performKEM(kpg.generateKeyPair(), new KEMParameterSpec("ARIA-KWP"));
+ }
+
+ private void performKEM(KeyPair kp, int from, int to, String algorithm, KTSParameterSpec ktsParameterSpec)
+ throws Exception
+ {
+ PublicKey pkR = kp.getPublic();
+
+ // Sender side
+ KEM kemS = KEM.getInstance("NTRU");
+ KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
+ KEM.Encapsulated enc = e.encapsulate(from, to, algorithm);
+ SecretKey secS = enc.key();
+ byte[] em = enc.encapsulation();
+
+ // Receiver side
+ KEM kemR = KEM.getInstance("NTRU");
+ KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
+ SecretKey secR = d.decapsulate(em, from, to, algorithm);
+
+ // secS and secR will be identical
+ assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
+ assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
+ }
+
+ private void performKEM(KeyPair kp, KTSParameterSpec ktsParameterSpec)
+ throws Exception
+ {
+ PublicKey pkR = kp.getPublic();
+
+ // Sender side
+ KEM kemS = KEM.getInstance("NTRU");
+ KEM.Encapsulator e = kemS.newEncapsulator(pkR, ktsParameterSpec, null);
+ KEM.Encapsulated enc = e.encapsulate();
+ SecretKey secS = enc.key();
+ byte[] em = enc.encapsulation();
+
+ // Receiver side
+ KEM kemR = KEM.getInstance("NTRU");
+// KTSParameterSpec RktsParameterSpec = new KTSParameterSpec.Builder(
+// ktsParameterSpec.getKeyAlgorithmName(),
+// enc.key().getEncoded().length
+// ).withParameterSpec(ktsParameterSpec).build();
+ KEM.Decapsulator d = kemR.newDecapsulator(kp.getPrivate(), ktsParameterSpec);
+ SecretKey secR = d.decapsulate(em);
+
+ // secS and secR will be identical
+ assertEquals(secS.getAlgorithm(), secR.getAlgorithm());
+ assertTrue(Arrays.areEqual(secS.getEncoded(), secR.getEncoded()));
+ }
+}
From f7fa1c47f07fc6a35768989164c5856ada8ad05d Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 27 Mar 2024 17:40:07 +1100
Subject: [PATCH 0201/1846] digest name fix. added jdk1.5 compatibility
classes.
---
.../bcpg/ArmoredOutputStream.java | 49 +-
.../bouncycastle/bcpg/ExperimentalPacket.java | 3 +-
.../org/bouncycastle/openpgp/PGPUtil.java | 17 +-
.../operator/jcajce/OperatorHelper.java | 49 +-
.../org/bouncycastle/gpg/SExprParser.java | 562 ++++++++++++++
...PublicKeyKeyEncryptionMethodGenerator.java | 205 +++++
.../operator/jcajce/JcaPGPKeyConverter.java | 712 ++++++++++++++++++
...PublicKeyKeyEncryptionMethodGenerator.java | 259 +++++++
.../openpgp/test/OpenpgpTest.java | 12 +-
.../openpgp/test/OperatorJcajceTest.java | 21 +-
10 files changed, 1786 insertions(+), 103 deletions(-)
create mode 100644 pg/src/main/jdk1.5/org/bouncycastle/gpg/SExprParser.java
create mode 100644 pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
create mode 100644 pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
create mode 100644 pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java b/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java
index d41320042d..efedb5e9bc 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java
@@ -11,6 +11,8 @@
import java.util.List;
import java.util.Map;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.util.Strings;
/**
@@ -299,51 +301,14 @@ public void beginClearText(
sb.append(nl);
for (int hashAlgorithm : hashAlgorithms)
{
- String hash;
- switch (hashAlgorithm)
+ try
{
- case HashAlgorithmTags.MD5:
- hash = "MD5";
- break;
- case HashAlgorithmTags.SHA1:
- hash = "SHA1";
- break;
- case HashAlgorithmTags.RIPEMD160:
- hash = "RIPEMD160";
- break;
- case HashAlgorithmTags.MD2:
- hash = "MD2";
- break;
- case HashAlgorithmTags.SHA256:
- hash = "SHA256";
- break;
- case HashAlgorithmTags.SHA384:
- hash = "SHA384";
- break;
- case HashAlgorithmTags.SHA512:
- hash = "SHA512";
- break;
- case HashAlgorithmTags.SHA224:
- hash = "SHA224";
- break;
- case HashAlgorithmTags.SHA3_256:
- case HashAlgorithmTags.SHA3_256_OLD:
- hash = "SHA3-256";
- break;
- case HashAlgorithmTags.SHA3_384: // OLD
- hash = "SHA3-384";
- break;
- case HashAlgorithmTags.SHA3_512:
- case HashAlgorithmTags.SHA3_512_OLD:
- hash = "SHA3-512";
- break;
- case HashAlgorithmTags.SHA3_224:
- hash = "SHA3-224";
- break;
- default:
+ String hash = PGPUtil.getDigestName(hashAlgorithm);
+ sb.append(HASH_HDR).append(": ").append(hash).append(nl);
+ }
+ catch (PGPException e){
throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm);
}
- sb.append(HASH_HDR).append(": ").append(hash).append(nl);
}
sb.append(nl);
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java b/pg/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java
index 58a4b85d9b..927b1bade9 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/ExperimentalPacket.java
@@ -10,7 +10,6 @@
public class ExperimentalPacket
extends ContainedPacket implements PublicKeyAlgorithmTags
{
- private int tag;
private byte[] contents;
/**
@@ -45,6 +44,6 @@ public void encode(
BCPGOutputStream out)
throws IOException
{
- out.writePacket(tag, contents);
+ out.writePacket(getPacketTag(), contents);
}
}
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java b/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java
index 0f3da60664..76bad21f70 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java
@@ -103,19 +103,23 @@ public static String getDigestName(
case HashAlgorithmTags.RIPEMD160:
return "RIPEMD160";
case HashAlgorithmTags.SHA256:
- case HashAlgorithmTags.SHA3_256:
- case HashAlgorithmTags.SHA3_256_OLD:
return "SHA256";
case HashAlgorithmTags.SHA384:
- case HashAlgorithmTags.SHA3_384:
return "SHA384";
case HashAlgorithmTags.SHA512:
- case HashAlgorithmTags.SHA3_512:
- case HashAlgorithmTags.SHA3_512_OLD:
return "SHA512";
case HashAlgorithmTags.SHA224:
- case HashAlgorithmTags.SHA3_224:
return "SHA224";
+ case HashAlgorithmTags.SHA3_256:
+ case HashAlgorithmTags.SHA3_256_OLD:
+ return "SHA3-256";
+ case HashAlgorithmTags.SHA3_384:
+ return "SHA3-384";
+ case HashAlgorithmTags.SHA3_512:
+ case HashAlgorithmTags.SHA3_512_OLD:
+ return "SHA3-512";
+ case HashAlgorithmTags.SHA3_224:
+ return "SHA3-224";
case HashAlgorithmTags.TIGER_192:
return "TIGER";
default:
@@ -123,6 +127,7 @@ public static String getDigestName(
}
}
+
public static int getDigestIDForName(String name)
{
name = Strings.toLowerCase(name);
diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
index 2a552d1730..9afaaa950f 100644
--- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
+++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/OperatorHelper.java
@@ -36,58 +36,15 @@ class OperatorHelper
this.helper = helper;
}
- /**
- * Return an appropriate name for the hash algorithm represented by the passed
- * in hash algorithm ID number (JCA message digest naming convention).
- *
- * @param hashAlgorithm the algorithm ID for a hash algorithm.
- * @return a String representation of the hash name.
- */
- String getDigestName(
- int hashAlgorithm)
- throws PGPException
- {
- switch (hashAlgorithm)
- {
- case HashAlgorithmTags.SHA1:
- return "SHA-1";
- case HashAlgorithmTags.MD2:
- return "MD2";
- case HashAlgorithmTags.MD5:
- return "MD5";
- case HashAlgorithmTags.RIPEMD160:
- return "RIPEMD160";
- case HashAlgorithmTags.SHA256:
- return "SHA-256";
- case HashAlgorithmTags.SHA384:
- return "SHA-384";
- case HashAlgorithmTags.SHA512:
- return "SHA-512";
- case HashAlgorithmTags.SHA224:
- return "SHA-224";
- case HashAlgorithmTags.SHA3_256:
- case HashAlgorithmTags.SHA3_256_OLD:
- return "SHA3-256";
- case HashAlgorithmTags.SHA3_384: // OLD
- return "SHA3-384";
- case HashAlgorithmTags.SHA3_512:
- case HashAlgorithmTags.SHA3_512_OLD:
- return "SHA3-512";
- case HashAlgorithmTags.SHA3_224:
- return "SHA3-224";
- case HashAlgorithmTags.TIGER_192:
- return "TIGER";
- default:
- throw new PGPException("unknown hash algorithm tag in getDigestName: " + hashAlgorithm);
- }
- }
+
+
MessageDigest createDigest(int algorithm)
throws GeneralSecurityException, PGPException
{
MessageDigest dig;
- String digestName = getDigestName(algorithm);
+ String digestName = PGPUtil.getDigestName(algorithm);
try
{
dig = helper.createMessageDigest(digestName);
diff --git a/pg/src/main/jdk1.5/org/bouncycastle/gpg/SExprParser.java b/pg/src/main/jdk1.5/org/bouncycastle/gpg/SExprParser.java
new file mode 100644
index 0000000000..7cb00acc1e
--- /dev/null
+++ b/pg/src/main/jdk1.5/org/bouncycastle/gpg/SExprParser.java
@@ -0,0 +1,562 @@
+package org.bouncycastle.gpg;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.math.BigInteger;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves;
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParametersHolder;
+import org.bouncycastle.bcpg.BCPGKey;
+import org.bouncycastle.bcpg.DSAPublicBCPGKey;
+import org.bouncycastle.bcpg.DSASecretBCPGKey;
+import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
+import org.bouncycastle.bcpg.ECPublicBCPGKey;
+import org.bouncycastle.bcpg.ECSecretBCPGKey;
+import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
+import org.bouncycastle.bcpg.EdSecretBCPGKey;
+import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
+import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
+import org.bouncycastle.bcpg.PublicKeyPacket;
+import org.bouncycastle.bcpg.RSAPublicBCPGKey;
+import org.bouncycastle.bcpg.RSASecretBCPGKey;
+import org.bouncycastle.bcpg.S2K;
+import org.bouncycastle.bcpg.SecretKeyPacket;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.crypto.ec.CustomNamedCurves;
+import org.bouncycastle.math.ec.ECPoint;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPSecretKey;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
+import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory;
+import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculator;
+import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider;
+import org.bouncycastle.openpgp.operator.PGPSecretKeyDecryptorWithAAD;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+import org.bouncycastle.util.Strings;
+
+/**
+ * A parser for secret keys stored in SExpr
+ */
+public class SExprParser
+{
+ private final PGPDigestCalculatorProvider digestProvider;
+
+ /**
+ * Base constructor.
+ *
+ * @param digestProvider a provider for digest calculations. Used to confirm key protection hashes.
+ */
+ public SExprParser(PGPDigestCalculatorProvider digestProvider)
+ {
+ this.digestProvider = digestProvider;
+ }
+
+ private static final Map rsaLabels = new HashMap()
+ {{
+ put(ProtectionModeTags.OPENPGP_S2K3_OCB_AES, new String[]{"rsa", "n", "e", "protected-at"});
+ put(ProtectionModeTags.OPENPGP_S2K3_SHA1_AES_CBC, new String[]{"rsa", "n", "e", "d", "p", "q", "u", "protected-at"});
+ }};
+ private static final Map eccLabels = new HashMap()
+ {{
+ put(ProtectionModeTags.OPENPGP_S2K3_OCB_AES, new String[]{"ecc", "curve", "flags", "q", "protected-at"});
+ put(ProtectionModeTags.OPENPGP_S2K3_SHA1_AES_CBC, new String[]{"ecc", "curve", "q", "d", "protected-at"});
+ }};
+
+ private static final Map dsaLabels = new HashMap()
+ {{
+ put(ProtectionModeTags.OPENPGP_S2K3_OCB_AES, new String[]{"dsa", "p", "q", "g", "y", "protected-at"});
+ put(ProtectionModeTags.OPENPGP_S2K3_SHA1_AES_CBC, new String[]{"dsa", "p", "q", "g", "y", "x", "protected-at"});
+ }};
+
+ private static final Map elgLabels = new HashMap()
+ {{
+ //https://github.com/gpg/gnupg/blob/40227e42ea0f2f1cf9c9f506375446648df17e8d/agent/cvt-openpgp.c#L217
+ put(ProtectionModeTags.OPENPGP_S2K3_OCB_AES, new String[]{"elg", "p", "q", "g", "y", "protected-at"});
+ put(ProtectionModeTags.OPENPGP_S2K3_SHA1_AES_CBC, new String[]{"elg", "p", "q", "g", "y", "x", "protected-at"});
+ }};
+
+ private static final String[] rsaBigIntegers = new String[]{"n", "e"};
+ private static final String[] dsaBigIntegers = new String[]{"p", "q", "g", "y"};
+ private static final String[] elgBigIntegers = new String[]{"p", "g", "y"};
+
+ public interface ProtectionFormatTypeTags
+ {
+ int PRIVATE_KEY = 1;
+ int PROTECTED_PRIVATE_KEY = 2;
+ int SHADOWED_PRIVATE_KEY = 3;
+ int OPENPGP_PRIVATE_KEY = 4;
+ int PROTECTED_SHARED_SECRET = 5;
+ }
+
+ private interface ProtectionModeTags
+ {
+ int OPENPGP_S2K3_SHA1_AES_CBC = 1;
+ int OPENPGP_S2K3_OCB_AES = 2;
+ int OPENPGP_NATIVE = 3;
+ }
+
+ /**
+ * Parse a secret key from one of the GPG S expression keys associating it with the passed in public key.
+ *
+ * @return a secret key object.
+ */
+ public PGPSecretKey parseSecretKey(InputStream inputStream, PBEProtectionRemoverFactory keyProtectionRemoverFactory, PGPPublicKey pubKey)
+ throws IOException, PGPException
+ {
+ if (pubKey == null)
+ {
+ throw new NullPointerException("Public key cannot be null");
+ }
+ return parse(inputStream, keyProtectionRemoverFactory, null, pubKey);
+ }
+
+ /**
+ * Parse a secret key from one of the GPG S expression keys.
+ *
+ * @return a secret key object.
+ */
+ public PGPSecretKey parseSecretKey(InputStream inputStream, PBEProtectionRemoverFactory keyProtectionRemoverFactory,
+ KeyFingerPrintCalculator fingerPrintCalculator)
+ throws IOException, PGPException
+ {
+ return parse(inputStream, keyProtectionRemoverFactory, fingerPrintCalculator, null);
+ }
+
+ private PGPSecretKey parse(InputStream inputStream, PBEProtectionRemoverFactory keyProtectionRemoverFactory,
+ KeyFingerPrintCalculator fingerPrintCalculator, PGPPublicKey pubKey)
+ throws IOException, PGPException
+ {
+ final int maxDepth = 10;
+ SExpression keyExpression = SExpression.parseCanonical(inputStream, maxDepth);
+ int type = getProtectionType(keyExpression.getString(0));
+ if (type == ProtectionFormatTypeTags.PRIVATE_KEY || type == ProtectionFormatTypeTags.PROTECTED_PRIVATE_KEY ||
+ type == ProtectionFormatTypeTags.SHADOWED_PRIVATE_KEY)
+ {
+ SExpression expression = keyExpression.getExpression(1);
+ String keyType = expression.getString(0);
+ PublicKeyAlgorithmTags[] secretKey = getPGPSecretKey(keyProtectionRemoverFactory, fingerPrintCalculator,
+ pubKey, maxDepth, type, expression, keyType, digestProvider);
+ return new PGPSecretKey((SecretKeyPacket)secretKey[0], (PGPPublicKey)secretKey[1]);
+ }
+ throw new PGPException("unknown key type found");
+ }
+
+ public static PublicKeyAlgorithmTags[] getPGPSecretKey(PBEProtectionRemoverFactory keyProtectionRemoverFactory,
+ KeyFingerPrintCalculator fingerPrintCalculator, PGPPublicKey pubKey,
+ int maxDepth, int type, final SExpression expression, String keyType,
+ PGPDigestCalculatorProvider digestProvider)
+ throws PGPException, IOException
+ {
+ SecretKeyPacket secretKeyPacket;
+ if (keyType.equals("ecc"))
+ {
+ BCPGKey basePubKey = getECCBasePublicKey(expression);
+ if (pubKey != null)
+ {
+ assertEccPublicKeyMath(basePubKey, pubKey);
+ }
+ else
+ {
+ PublicKeyPacket pubPacket = null;
+ if (basePubKey instanceof EdDSAPublicBCPGKey)
+ {
+ pubPacket = new PublicKeyPacket(PublicKeyAlgorithmTags.EDDSA_LEGACY, new Date(), basePubKey);
+ }
+ else if (basePubKey instanceof ECPublicBCPGKey)
+ {
+ pubPacket = new PublicKeyPacket(PublicKeyAlgorithmTags.ECDSA, new Date(), basePubKey);
+ }
+ pubKey = new PGPPublicKey(pubPacket, fingerPrintCalculator);
+ }
+ secretKeyPacket = getSecKeyPacket(pubKey, keyProtectionRemoverFactory, maxDepth, type, expression, digestProvider, eccLabels,
+ new getSecKeyDataOperation()
+ {
+ @Override
+ public byte[] getSecKeyData(SExpression keyIn)
+ {
+ BigInteger d = BigIntegers.fromUnsignedByteArray(keyIn.getExpressionWithLabelOrFail("d").getBytes(1));
+ final String curve = expression.getExpressionWithLabel("curve").getString(1);
+ if (curve.startsWith("NIST") || curve.startsWith("brain"))
+ {
+ return new ECSecretBCPGKey(d).getEncoded();
+ }
+ else
+ {
+ return new EdSecretBCPGKey(d).getEncoded();
+ }
+ }
+ });
+ }
+ else if (keyType.equals("dsa"))
+ {
+ pubKey = getPublicKey(fingerPrintCalculator, pubKey, expression, PublicKeyAlgorithmTags.DSA, dsaBigIntegers, new getPublicKeyOperation()
+ {
+ public BCPGKey getBasePublicKey(BigInteger[] bigIntegers)
+ {
+ return new DSAPublicBCPGKey(bigIntegers[0], bigIntegers[1], bigIntegers[2], bigIntegers[3]);
+ }
+
+ public void assertPublicKeyMatch(BCPGKey k1, BCPGKey k2)
+ throws PGPException
+ {
+ DSAPublicBCPGKey key1 = (DSAPublicBCPGKey)k1;
+ DSAPublicBCPGKey key2 = (DSAPublicBCPGKey)k2;
+ if (!key1.getP().equals(key2.getP()) || !key1.getQ().equals(key2.getQ())
+ || !key1.getG().equals(key2.getG()) || !key1.getY().equals(key2.getY()))
+ {
+ throw new PGPException("passed in public key does not match secret key");
+ }
+ }
+ });
+ secretKeyPacket = getSecKeyPacket(pubKey, keyProtectionRemoverFactory, maxDepth, type, expression, digestProvider, dsaLabels,
+ new getSecKeyDataOperation()
+ {
+ @Override
+ public byte[] getSecKeyData(SExpression keyIn)
+ {
+ BigInteger x = BigIntegers.fromUnsignedByteArray(keyIn.getExpressionWithLabelOrFail("x").getBytes(1));
+ return new DSASecretBCPGKey(x).getEncoded();
+ }
+ });
+ }
+ else if (keyType.equals("elg"))
+ {
+ pubKey = getPublicKey(fingerPrintCalculator, pubKey, expression, PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, elgBigIntegers, new getPublicKeyOperation()
+ {
+ public BCPGKey getBasePublicKey(BigInteger[] bigIntegers)
+ {
+ return new ElGamalPublicBCPGKey(bigIntegers[0], bigIntegers[1], bigIntegers[2]);
+ }
+
+ public void assertPublicKeyMatch(BCPGKey k1, BCPGKey k2)
+ throws PGPException
+ {
+ ElGamalPublicBCPGKey key1 = (ElGamalPublicBCPGKey)k1;
+ ElGamalPublicBCPGKey key2 = (ElGamalPublicBCPGKey)k2;
+ if (!key1.getP().equals(key2.getP()) || !key1.getG().equals(key2.getG()) || !key1.getY().equals(key2.getY()))
+ {
+ throw new PGPException("passed in public key does not match secret key");
+ }
+ }
+ });
+ secretKeyPacket = getSecKeyPacket(pubKey, keyProtectionRemoverFactory, maxDepth, type, expression, digestProvider, elgLabels,
+ new getSecKeyDataOperation()
+ {
+ @Override
+ public byte[] getSecKeyData(SExpression keyIn)
+ {
+ BigInteger x = BigIntegers.fromUnsignedByteArray(keyIn.getExpressionWithLabelOrFail("x").getBytes(1));
+ return new ElGamalSecretBCPGKey(x).getEncoded();
+ }
+ });
+ }
+ else if (keyType.equals("rsa"))
+ {
+ // TODO: type of RSA key?
+ pubKey = getPublicKey(fingerPrintCalculator, pubKey, expression, PublicKeyAlgorithmTags.RSA_GENERAL, rsaBigIntegers, new getPublicKeyOperation()
+ {
+ public BCPGKey getBasePublicKey(BigInteger[] bigIntegers)
+ {
+ return new RSAPublicBCPGKey(bigIntegers[0], bigIntegers[1]);
+ }
+
+ public void assertPublicKeyMatch(BCPGKey k1, BCPGKey k2)
+ throws PGPException
+ {
+ RSAPublicBCPGKey key1 = (RSAPublicBCPGKey)k1;
+ RSAPublicBCPGKey key2 = (RSAPublicBCPGKey)k2;
+ if (!key1.getModulus().equals(key2.getModulus())
+ || !key1.getPublicExponent().equals(key2.getPublicExponent()))
+ {
+ throw new PGPException("passed in public key does not match secret key");
+ }
+ }
+ });
+ secretKeyPacket = getSecKeyPacket(pubKey, keyProtectionRemoverFactory, maxDepth, type, expression, digestProvider, rsaLabels,
+ new getSecKeyDataOperation()
+ {
+ @Override
+ public byte[] getSecKeyData(SExpression keyIn)
+ {
+ BigInteger d = BigIntegers.fromUnsignedByteArray(keyIn.getExpressionWithLabelOrFail("d").getBytes(1));
+ BigInteger p = BigIntegers.fromUnsignedByteArray(keyIn.getExpressionWithLabelOrFail("p").getBytes(1));
+ BigInteger q = BigIntegers.fromUnsignedByteArray(keyIn.getExpressionWithLabelOrFail("q").getBytes(1));
+ return new RSASecretBCPGKey(d, p, q).getEncoded();
+ }
+ });
+ }
+ else
+ {
+ throw new PGPException("unknown key type: " + keyType);
+ }
+ return new PublicKeyAlgorithmTags[]{secretKeyPacket, pubKey};
+ }
+
+ private interface getPublicKeyOperation
+ {
+ BCPGKey getBasePublicKey(BigInteger[] bigIntegers);
+
+ void assertPublicKeyMatch(BCPGKey key1, BCPGKey key2)
+ throws PGPException;
+ }
+
+ private static PGPPublicKey getPublicKey(KeyFingerPrintCalculator fingerPrintCalculator, PGPPublicKey pubKey, SExpression expression,
+ int publicKeyAlgorithmTags, String[] bigIntegerLabels, getPublicKeyOperation operation)
+ throws PGPException
+ {
+ int flag = 0, flag_break = (1 << bigIntegerLabels.length) - 1;
+ BigInteger[] bigIntegers = new BigInteger[bigIntegerLabels.length];
+ for (Object item : expression.getValues())
+ {
+ if (item instanceof SExpression)
+ {
+ SExpression exp = (SExpression)item;
+ String str = exp.getString(0);
+ for (int i = 0; i < bigIntegerLabels.length; ++i)
+ {
+ if ((flag & (1 << i)) == 0 && str.equals(bigIntegerLabels[i]))
+ {
+ bigIntegers[i] = BigIntegers.fromUnsignedByteArray(exp.getBytes(1));
+ flag |= 1 << i;
+ if (flag == flag_break)
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (flag != flag_break)
+ {
+ throw new IllegalArgumentException("The public key should not be null");
+ }
+ BCPGKey basePubKey = operation.getBasePublicKey(bigIntegers);
+ if (pubKey != null)
+ {
+ operation.assertPublicKeyMatch(basePubKey, pubKey.getPublicKeyPacket().getKey());
+ }
+ else
+ {
+ pubKey = new PGPPublicKey(new PublicKeyPacket(publicKeyAlgorithmTags, new Date(), basePubKey), fingerPrintCalculator);
+ }
+ return pubKey;
+ }
+
+ private interface getSecKeyDataOperation
+ {
+ byte[] getSecKeyData(SExpression keyIn);
+ }
+
+ private static SecretKeyPacket getSecKeyPacket(PGPPublicKey pubKey, PBEProtectionRemoverFactory keyProtectionRemoverFactory, int maxDepth, int type,
+ SExpression expression, PGPDigestCalculatorProvider digestProvider,
+ Map labels, getSecKeyDataOperation operation)
+ throws PGPException, IOException
+ {
+ byte[] secKeyData = null;
+ S2K s2K = null;
+ byte[] nonce = null;
+ SExpression keyIn;
+ if (type != ProtectionFormatTypeTags.SHADOWED_PRIVATE_KEY)
+ {
+ if (type == ProtectionFormatTypeTags.PROTECTED_PRIVATE_KEY)
+ {
+ SExpression protectedKey = expression.getExpressionWithLabel("protected");
+ if (protectedKey == null)
+ {
+ throw new IllegalArgumentException(type + " does not have protected block");
+ }
+ String protectionStr = protectedKey.getString(1);
+ int protection = getProtectionMode(protectionStr);
+ if (protection == ProtectionModeTags.OPENPGP_S2K3_OCB_AES || protection == ProtectionModeTags.OPENPGP_S2K3_SHA1_AES_CBC)
+ {
+ byte[] data;
+ SExpression protectionKeyParameters = protectedKey.getExpression(2);
+ SExpression s2kParams = protectionKeyParameters.getExpression(0);
+ // TODO select correct hash
+ s2K = new S2K(PGPUtil.getDigestIDForName(s2kParams.getString(0)), s2kParams.getBytes(1), s2kParams.getInt(2));
+ nonce = protectionKeyParameters.getBytes(1);
+ PBESecretKeyDecryptor keyDecryptor = keyProtectionRemoverFactory.createDecryptor(protectionStr);
+ byte[] key = keyDecryptor.makeKeyFromPassPhrase(SymmetricKeyAlgorithmTags.AES_128, s2K);
+ byte[] keyData = protectedKey.getBytes(3);
+ if (protection == ProtectionModeTags.OPENPGP_S2K3_SHA1_AES_CBC)
+ {
+ data = keyDecryptor.recoverKeyData(SymmetricKeyAlgorithmTags.AES_128, key, nonce, keyData, 0, keyData.length);
+ keyIn = SExpression.parseCanonical(new ByteArrayInputStream(data), maxDepth);
+ if (digestProvider != null)
+ {
+ PGPDigestCalculator digestCalculator = digestProvider.get(HashAlgorithmTags.SHA1);
+ OutputStream dOut = digestCalculator.getOutputStream();
+ byte[] aad = SExpression.buildExpression(expression, keyIn.getExpression(0), labels.get(protection)).toCanonicalForm();
+ dOut.write(aad);
+ byte[] check = digestCalculator.getDigest();
+ byte[] hashBytes = keyIn.getExpression(1).getBytes(2);
+ if (!Arrays.constantTimeAreEqual(check, hashBytes))
+ {
+ throw new PGPException("checksum on protected data failed in SExpr");
+ }
+ }
+ keyIn = keyIn.getExpression(0);
+ }
+ else //ProtectionModeTags.OPENPGP_S2K3_OCB_AES
+ {
+ String[] filter = labels.get(protection);
+ if (filter == null)
+ {
+ // TODO could not get client to generate protected elgamal keys
+ throw new IllegalStateException("no decryption support for protected elgamal keys");
+ }
+ byte[] aad = SExpression.buildExpression(expression, filter).toCanonicalForm();
+ data = ((PGPSecretKeyDecryptorWithAAD)keyDecryptor).recoverKeyData(SymmetricKeyAlgorithmTags.AES_128, key,
+ nonce, aad, keyData, 0, keyData.length);
+ keyIn = SExpression.parseCanonical(new ByteArrayInputStream(data), maxDepth).getExpression(0);
+ }
+ }
+ else
+ {
+ // openpgp-native is not supported for now
+ throw new PGPException("unsupported protection type " + protectedKey.getString(1));
+ }
+ }
+ else
+ {
+ keyIn = expression;
+ }
+ secKeyData = operation.getSecKeyData(keyIn);
+ }
+ return new SecretKeyPacket(pubKey.getPublicKeyPacket(), SymmetricKeyAlgorithmTags.NULL, s2K, nonce, secKeyData);
+ }
+
+ private static BCPGKey getECCBasePublicKey(SExpression expression)
+ {
+ byte[] qoint = null;
+ String curve = null;
+ int flag = 0;
+ for (Object item : expression.getValues())
+ {
+ if (item instanceof SExpression)
+ {
+ SExpression exp = (SExpression)item;
+ String label = exp.getString(0);
+ if (label.equals("curve"))
+ {
+ curve = exp.getString(1);
+ flag |= 1;
+ }
+ else if (label.equals("q"))
+ {
+ qoint = exp.getBytes(1);
+ flag |= 2;
+ }
+ if (flag == 3)
+ {
+ break;
+ }
+ }
+ }
+ if (flag != 3)
+ {
+ throw new IllegalArgumentException("no curve expression");
+ }
+ else if (curve.startsWith("NIST"))
+ {
+ curve = curve.substring("NIST".length()).trim();
+ }
+ String curve_lowercase = Strings.toLowerCase(curve);
+ if (curve_lowercase.equals("ed25519"))
+ {
+ return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed25519, new BigInteger(1, qoint));
+ }
+ else if (curve_lowercase.equals("ed448"))
+ {
+ return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, qoint));
+ }
+ else
+ {
+ ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(curve);
+ X9ECParametersHolder holder = CustomNamedCurves.getByNameLazy(curve);
+ if (holder == null && oid != null)
+ {
+ holder = TeleTrusTNamedCurves.getByOIDLazy(oid);
+ }
+ if (holder == null)
+ {
+ throw new IllegalStateException("unable to resolve parameters for " + curve);
+ }
+ ECPoint pnt = holder.getCurve().decodePoint(qoint);
+ return new ECDSAPublicBCPGKey(oid, pnt);
+ }
+ }
+
+ private static void assertEccPublicKeyMath(BCPGKey key1, PGPPublicKey key2)
+ throws PGPException
+ {
+ if (key1 instanceof ECDSAPublicBCPGKey)
+ {
+ ECPublicBCPGKey assocPubKey = (ECPublicBCPGKey)key2.getPublicKeyPacket().getKey();
+ if (!((ECDSAPublicBCPGKey)key1).getCurveOID().equals(assocPubKey.getCurveOID())
+ || !((ECDSAPublicBCPGKey)key1).getEncodedPoint().equals(assocPubKey.getEncodedPoint()))
+ {
+ throw new PGPException("passed in public key does not match secret key");
+ }
+ }
+ else if (key1 instanceof EdDSAPublicBCPGKey)
+ {
+ EdDSAPublicBCPGKey assocPubKey = (EdDSAPublicBCPGKey)key2.getPublicKeyPacket().getKey();
+ if (!((EdDSAPublicBCPGKey)key1).getCurveOID().equals(assocPubKey.getCurveOID())
+ || !((EdDSAPublicBCPGKey)key1).getEncodedPoint().equals(assocPubKey.getEncodedPoint()))
+ {
+ throw new PGPException("passed in public key does not match secret key");
+ }
+ }
+ else
+ {
+ throw new PGPException("unknown key type: " + (key1 != null ? key1.getClass().getName() : "null"));
+ }
+ }
+
+ public static int getProtectionType(String str)
+ {
+ if (str.equals("private-key"))
+ {
+ return ProtectionFormatTypeTags.PRIVATE_KEY;
+ }
+ else if (str.equals("protected-private-key"))
+ {
+ return ProtectionFormatTypeTags.PROTECTED_PRIVATE_KEY;
+ }
+ else if (str.equals("shadowed-private-key"))
+ {
+ return ProtectionFormatTypeTags.SHADOWED_PRIVATE_KEY;
+ }
+ // The other two types are not supported for now
+ return -1;
+ }
+
+ private static int getProtectionMode(String str)
+ {
+ if (str.equals("openpgp-s2k3-sha1-aes-cbc"))
+ {
+ return ProtectionModeTags.OPENPGP_S2K3_SHA1_AES_CBC;
+ }
+ else if (str.equals("openpgp-s2k3-ocb-aes"))
+ {
+ return ProtectionModeTags.OPENPGP_S2K3_OCB_AES;
+ }
+ // The other mode is not supported for now
+ return -1;
+ }
+}
\ No newline at end of file
diff --git a/pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
new file mode 100644
index 0000000000..b36972c9e3
--- /dev/null
+++ b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/bc/BcPublicKeyKeyEncryptionMethodGenerator.java
@@ -0,0 +1,205 @@
+package org.bouncycastle.openpgp.operator.bc;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
+import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
+import org.bouncycastle.bcpg.HashAlgorithmTags;
+import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
+import org.bouncycastle.bcpg.PublicKeyPacket;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.crypto.AsymmetricBlockCipher;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import org.bouncycastle.crypto.InvalidCipherTextException;
+import org.bouncycastle.crypto.KeyGenerationParameters;
+import org.bouncycastle.crypto.RawAgreement;
+import org.bouncycastle.crypto.Wrapper;
+import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
+import org.bouncycastle.crypto.agreement.X25519Agreement;
+import org.bouncycastle.crypto.agreement.X448Agreement;
+import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
+import org.bouncycastle.crypto.generators.X25519KeyPairGenerator;
+import org.bouncycastle.crypto.generators.X448KeyPairGenerator;
+import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
+import org.bouncycastle.crypto.params.ECPublicKeyParameters;
+import org.bouncycastle.crypto.params.KeyParameter;
+import org.bouncycastle.crypto.params.ParametersWithRandom;
+import org.bouncycastle.crypto.params.X25519KeyGenerationParameters;
+import org.bouncycastle.crypto.params.X25519PublicKeyParameters;
+import org.bouncycastle.crypto.params.X448KeyGenerationParameters;
+import org.bouncycastle.crypto.params.X448PublicKeyParameters;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.operator.PGPPad;
+import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator;
+import org.bouncycastle.openpgp.operator.RFC6637Utils;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+
+/**
+ * A method generator for supporting public key based encryption operations.
+ */
+public class BcPublicKeyKeyEncryptionMethodGenerator
+ extends PublicKeyKeyEncryptionMethodGenerator
+{
+ private static final byte X_HDR = 0x40;
+
+ private SecureRandom random;
+ private BcPGPKeyConverter keyConverter = new BcPGPKeyConverter();
+
+ /**
+ * Create a public key encryption method generator with the method to be based on the passed in key.
+ *
+ * @param key the public key to use for encryption.
+ */
+ public BcPublicKeyKeyEncryptionMethodGenerator(PGPPublicKey key)
+ {
+ super(key);
+ }
+
+ /**
+ * Provide a user defined source of randomness.
+ *
+ * @param random the secure random to be used.
+ * @return the current generator.
+ */
+ public BcPublicKeyKeyEncryptionMethodGenerator setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
+ throws PGPException
+ {
+ try
+ {
+ AsymmetricKeyParameter cryptoPublicKey = keyConverter.getPublicKey(pubKey);
+ PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
+ if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.ECDH)
+ {
+ ECDHPublicBCPGKey ecPubKey = (ECDHPublicBCPGKey)pubKeyPacket.getKey();
+ byte[] userKeyingMaterial = RFC6637Utils.createUserKeyingMaterial(pubKeyPacket, new BcKeyFingerprintCalculator());
+ if (ecPubKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
+ {
+ AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(new X25519KeyPairGenerator(), new X25519KeyGenerationParameters(random));
+
+ byte[] secret = BcUtil.getSecret(new X25519Agreement(), ephKp.getPrivate(), cryptoPublicKey);
+
+ byte[] ephPubEncoding = new byte[1 + X25519PublicKeyParameters.KEY_SIZE];
+ ephPubEncoding[0] = X_HDR;
+ ((X25519PublicKeyParameters)ephKp.getPublic()).encode(ephPubEncoding, 1);
+ return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm());
+ }
+ else
+ {
+ AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(new ECKeyPairGenerator(),
+ new ECKeyGenerationParameters(((ECPublicKeyParameters)cryptoPublicKey).getParameters(), random));
+
+ ECDHBasicAgreement agreement = new ECDHBasicAgreement();
+ agreement.init(ephKp.getPrivate());
+ BigInteger S = agreement.calculateAgreement(cryptoPublicKey);
+ byte[] secret = BigIntegers.asUnsignedByteArray(agreement.getFieldSize(), S);
+
+ byte[] ephPubEncoding = ((ECPublicKeyParameters)ephKp.getPublic()).getQ().getEncoded(false);
+
+ return encryptSessionInfo(sessionInfo, secret, userKeyingMaterial, ephPubEncoding, ecPubKey.getHashAlgorithm(), ecPubKey.getSymmetricKeyAlgorithm());
+ }
+ }
+ else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
+ {
+ return encryptSessionInfo(pubKeyPacket, sessionInfo, HashAlgorithmTags.SHA256, SymmetricKeyAlgorithmTags.AES_128, "X25519",
+ new X25519KeyPairGenerator(), new X25519KeyGenerationParameters(random), new X25519Agreement(), cryptoPublicKey, X25519PublicKeyParameters.KEY_SIZE,
+ new ephPubEncodingOperation()
+ {
+ @Override
+ public void getEphPubEncoding(AsymmetricKeyParameter publicKey, byte[] ephPubEncoding)
+ {
+ ((X25519PublicKeyParameters)publicKey).encode(ephPubEncoding, 0);
+ }
+ });
+ }
+ else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
+ {
+ return encryptSessionInfo(pubKeyPacket, sessionInfo, HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256, "X448",
+ new X448KeyPairGenerator(), new X448KeyGenerationParameters(random), new X448Agreement(), cryptoPublicKey, X448PublicKeyParameters.KEY_SIZE,
+ new ephPubEncodingOperation()
+ {
+ @Override
+ public void getEphPubEncoding(AsymmetricKeyParameter publicKey, byte[] ephPubEncoding)
+ {
+ ((X448PublicKeyParameters)publicKey).encode(ephPubEncoding, 0);
+ }
+ });
+ }
+ else
+ {
+ AsymmetricBlockCipher c = BcImplProvider.createPublicKeyCipher(pubKey.getAlgorithm());
+
+ c.init(true, new ParametersWithRandom(cryptoPublicKey, random));
+
+ return c.processBlock(sessionInfo, 0, sessionInfo.length);
+ }
+ }
+ catch (InvalidCipherTextException | IOException e)
+ {
+ throw new PGPException("exception encrypting session info: " + e.getMessage(), e);
+ }
+ }
+
+ @FunctionalInterface
+ private interface ephPubEncodingOperation
+ {
+ void getEphPubEncoding(AsymmetricKeyParameter publicKey, byte[] ephPubEncoding);
+ }
+
+ private byte[] encryptSessionInfo(byte[] sessionInfo, byte[] secret,
+ byte[] userKeyingMaterial, byte[] ephPubEncoding, int hashAlgorithm, int symmetricKeyAlgorithm)
+ throws IOException, PGPException
+ {
+ RFC6637KDFCalculator rfc6637KDFCalculator = new RFC6637KDFCalculator(
+ new BcPGPDigestCalculatorProvider().get(hashAlgorithm), symmetricKeyAlgorithm);
+ KeyParameter key = new KeyParameter(rfc6637KDFCalculator.createKey(secret, userKeyingMaterial));
+
+ byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
+
+ return getSessionInfo(ephPubEncoding, getWrapper(symmetricKeyAlgorithm, key, paddedSessionData));
+ }
+
+ private byte[] encryptSessionInfo(PublicKeyPacket pubKeyPacket, byte[] sessionInfo, int hashAlgorithm, int symmetricKeyAlgorithm, String algorithmName,
+ AsymmetricCipherKeyPairGenerator gen, KeyGenerationParameters parameters, RawAgreement agreement, AsymmetricKeyParameter cryptoPublicKey,
+ int keySize, ephPubEncodingOperation ephPubEncodingOperation)
+ throws PGPException, IOException
+ {
+ AsymmetricCipherKeyPair ephKp = getAsymmetricCipherKeyPair(gen, parameters);
+ byte[] secret = BcUtil.getSecret(agreement, ephKp.getPrivate(), cryptoPublicKey);
+ byte[] ephPubEncoding = new byte[keySize];
+ ephPubEncodingOperation.getEphPubEncoding(ephKp.getPublic(), ephPubEncoding);
+ KeyParameter key = new KeyParameter(RFC6637KDFCalculator.createKey(hashAlgorithm, symmetricKeyAlgorithm,
+ Arrays.concatenate(ephPubEncoding, pubKeyPacket.getKey().getEncoded(), secret), "OpenPGP " + algorithmName));
+ //No checksum and padding
+ byte[] sessionData = new byte[sessionInfo.length - 3];
+ System.arraycopy(sessionInfo, 1, sessionData, 0, sessionData.length);
+
+ return getSessionInfo(ephPubEncoding, sessionInfo[0], getWrapper(symmetricKeyAlgorithm, key, sessionData));
+ }
+
+ private byte[] getWrapper(int symmetricKeyAlgorithm, KeyParameter key, byte[] sessionData)
+ throws PGPException
+ {
+ Wrapper c = BcImplProvider.createWrapper(symmetricKeyAlgorithm);
+ c.init(true, new ParametersWithRandom(key, random));
+ return c.wrap(sessionData, 0, sessionData.length);
+ }
+
+ private AsymmetricCipherKeyPair getAsymmetricCipherKeyPair(AsymmetricCipherKeyPairGenerator gen, KeyGenerationParameters parameters)
+ {
+ gen.init(parameters);
+ return gen.generateKeyPair();
+ }
+}
\ No newline at end of file
diff --git a/pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
new file mode 100644
index 0000000000..2c7de0af68
--- /dev/null
+++ b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java
@@ -0,0 +1,712 @@
+package org.bouncycastle.openpgp.operator.jcajce;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.DSAPublicKey;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.DSAPrivateKeySpec;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.ECGenParameterSpec;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPrivateKeySpec;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.InvalidParameterSpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.RSAPrivateCrtKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
+
+import javax.crypto.interfaces.DHPrivateKey;
+import javax.crypto.interfaces.DHPublicKey;
+import javax.crypto.spec.DHParameterSpec;
+import javax.crypto.spec.DHPrivateKeySpec;
+import javax.crypto.spec.DHPublicKeySpec;
+
+import org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.DEROctetString;
+import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
+import org.bouncycastle.asn1.edec.EdECObjectIdentifiers;
+import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
+import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.ECNamedCurveTable;
+import org.bouncycastle.asn1.x9.X9ECParameters;
+import org.bouncycastle.asn1.x9.X9ECParametersHolder;
+import org.bouncycastle.asn1.x9.X9ECPoint;
+import org.bouncycastle.bcpg.BCPGKey;
+import org.bouncycastle.bcpg.DSAPublicBCPGKey;
+import org.bouncycastle.bcpg.DSASecretBCPGKey;
+import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
+import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
+import org.bouncycastle.bcpg.ECPublicBCPGKey;
+import org.bouncycastle.bcpg.ECSecretBCPGKey;
+import org.bouncycastle.bcpg.Ed25519PublicBCPGKey;
+import org.bouncycastle.bcpg.Ed25519SecretBCPGKey;
+import org.bouncycastle.bcpg.Ed448PublicBCPGKey;
+import org.bouncycastle.bcpg.Ed448SecretBCPGKey;
+import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
+import org.bouncycastle.bcpg.EdSecretBCPGKey;
+import org.bouncycastle.bcpg.ElGamalPublicBCPGKey;
+import org.bouncycastle.bcpg.ElGamalSecretBCPGKey;
+import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
+import org.bouncycastle.bcpg.PublicKeyPacket;
+import org.bouncycastle.bcpg.RSAPublicBCPGKey;
+import org.bouncycastle.bcpg.RSASecretBCPGKey;
+import org.bouncycastle.bcpg.X25519PublicBCPGKey;
+import org.bouncycastle.bcpg.X25519SecretBCPGKey;
+import org.bouncycastle.bcpg.X448PublicBCPGKey;
+import org.bouncycastle.bcpg.X448SecretBCPGKey;
+import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
+import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
+import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
+import org.bouncycastle.math.ec.ECPoint;
+
+import org.bouncycastle.math.ec.rfc7748.X25519;
+import org.bouncycastle.math.ec.rfc8032.Ed25519;
+import org.bouncycastle.openpgp.PGPAlgorithmParameters;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPKdfParameters;
+import org.bouncycastle.openpgp.PGPPrivateKey;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
+import org.bouncycastle.openpgp.operator.PGPKeyConverter;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.BigIntegers;
+
+public class JcaPGPKeyConverter
+ extends PGPKeyConverter
+{
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private KeyFingerPrintCalculator fingerPrintCalculator = new JcaKeyFingerprintCalculator();
+
+ public JcaPGPKeyConverter setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ return this;
+ }
+
+ public JcaPGPKeyConverter setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ return this;
+ }
+
+ /**
+ * Convert a PrivateKey into a PGPPrivateKey.
+ *
+ * @param pub the corresponding PGPPublicKey to privKey.
+ * @param privKey the private key for the key in pub.
+ * @return a PGPPrivateKey
+ * @throws PGPException
+ */
+ public PGPPrivateKey getPGPPrivateKey(PGPPublicKey pub, PrivateKey privKey)
+ throws PGPException
+ {
+ BCPGKey privPk = getPrivateBCPGKey(pub, privKey);
+
+ return new PGPPrivateKey(pub.getKeyID(), pub.getPublicKeyPacket(), privPk);
+ }
+
+ /**
+ * Create a PGPPublicKey from the passed in JCA one.
+ *
+ * Note: the time passed in affects the value of the key's keyID, so you probably only want
+ * to do this once for a JCA key, or make sure you keep track of the time you used.
+ *
+ *
+ * @param algorithm asymmetric algorithm type representing the public key.
+ * @param algorithmParameters additional parameters to be stored against the public key.
+ * @param pubKey actual public key to associate.
+ * @param time date of creation.
+ * @throws PGPException on key creation problem.
+ */
+ public PGPPublicKey getPGPPublicKey(int algorithm, PGPAlgorithmParameters algorithmParameters, PublicKey pubKey, Date time)
+ throws PGPException
+ {
+ BCPGKey bcpgKey = getPublicBCPGKey(algorithm, algorithmParameters, pubKey);
+
+ return new PGPPublicKey(new PublicKeyPacket(algorithm, time, bcpgKey), fingerPrintCalculator);
+ }
+
+ /**
+ * Create a PGPPublicKey from the passed in JCA one.
+ *
+ * Note: the time passed in affects the value of the key's keyID, so you probably only want
+ * to do this once for a JCA key, or make sure you keep track of the time you used.
+ *
+ *
+ * @param algorithm asymmetric algorithm type representing the public key.
+ * @param pubKey actual public key to associate.
+ * @param time date of creation.
+ * @throws PGPException on key creation problem.
+ */
+ public PGPPublicKey getPGPPublicKey(int algorithm, PublicKey pubKey, Date time)
+ throws PGPException
+ {
+ return getPGPPublicKey(algorithm, null, pubKey, time);
+ }
+
+ public PrivateKey getPrivateKey(PGPPrivateKey privKey)
+ throws PGPException
+ {
+ if (privKey instanceof JcaPGPPrivateKey)
+ {
+ return ((JcaPGPPrivateKey)privKey).getPrivateKey();
+ }
+
+ PublicKeyPacket pubPk = privKey.getPublicKeyPacket();
+ BCPGKey privPk = privKey.getPrivateKeyDataPacket();
+
+ try
+ {
+ switch (pubPk.getAlgorithm())
+ {
+ case PublicKeyAlgorithmTags.DSA:
+ {
+ DSAPublicBCPGKey dsaPub = (DSAPublicBCPGKey)pubPk.getKey();
+ DSASecretBCPGKey dsaPriv = (DSASecretBCPGKey)privPk;
+ DSAPrivateKeySpec dsaPrivSpec = new DSAPrivateKeySpec(dsaPriv.getX(), dsaPub.getP(), dsaPub.getQ(),
+ dsaPub.getG());
+ return implGeneratePrivate("DSA", dsaPrivSpec);
+ }
+
+ case PublicKeyAlgorithmTags.ECDH:
+ {
+ ECDHPublicBCPGKey ecdhPub = (ECDHPublicBCPGKey)pubPk.getKey();
+ ECSecretBCPGKey ecdhK = (ECSecretBCPGKey)privPk;
+
+ if (CryptlibObjectIdentifiers.curvey25519.equals(ecdhPub.getCurveOID()))
+ {
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return implGeneratePrivate("XDH", new Operation()
+ {
+ @Override
+ public PrivateKeyInfo getPrivateKeyInfos()
+ throws IOException
+ {
+ return getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519,
+ Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX())));
+ }
+ });
+ }
+ else
+ {
+ return implGetPrivateKeyEC("ECDH", ecdhPub, ecdhK);
+ }
+ }
+ case PublicKeyAlgorithmTags.X25519:
+ {
+ return implGeneratePrivate("XDH", new Operation()
+ {
+ @Override
+ public PrivateKeyInfo getPrivateKeyInfos()
+ throws IOException
+ {
+ return getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519,
+ X25519SecretBCPGKey.LENGTH, Arrays.reverseInPlace(privPk.getEncoded()));
+ }
+ });
+ }
+ case PublicKeyAlgorithmTags.X448:
+ {
+ return implGeneratePrivate("XDH", new Operation()
+ {
+ @Override
+ public PrivateKeyInfo getPrivateKeyInfos()
+ throws IOException
+ {
+ return getPrivateKeyInfo(EdECObjectIdentifiers.id_X448,
+ X448SecretBCPGKey.LENGTH, Arrays.reverseInPlace(privPk.getEncoded()));
+ }
+ });
+ }
+ case PublicKeyAlgorithmTags.ECDSA:
+ {
+ return implGetPrivateKeyEC("ECDSA", (ECDSAPublicBCPGKey)pubPk.getKey(), (ECSecretBCPGKey)privPk);
+ }
+ case PublicKeyAlgorithmTags.EDDSA_LEGACY:
+ {
+ return implGeneratePrivate("EdDSA", new Operation()
+ {
+ @Override
+ public PrivateKeyInfo getPrivateKeyInfos()
+ throws IOException
+ {
+ return getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519,
+ BigIntegers.asUnsignedByteArray(Ed25519.SECRET_KEY_SIZE, ((EdSecretBCPGKey)privPk).getX()));
+ }
+ });
+ }
+ case PublicKeyAlgorithmTags.Ed25519:
+ {
+ return implGeneratePrivate("EdDSA", new Operation()
+ {
+ @Override
+ public PrivateKeyInfo getPrivateKeyInfos()
+ throws IOException
+ {
+ return getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519,
+ Ed25519SecretBCPGKey.LENGTH, privPk.getEncoded());
+ }
+ });
+ }
+ case PublicKeyAlgorithmTags.Ed448:
+ {
+ return implGeneratePrivate("EdDSA", new Operation()
+ {
+ @Override
+ public PrivateKeyInfo getPrivateKeyInfos()
+ throws IOException
+ {
+ return getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed448,
+ Ed448SecretBCPGKey.LENGTH, privPk.getEncoded());
+ }
+ });
+ }
+ case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
+ case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
+ {
+ ElGamalPublicBCPGKey elPub = (ElGamalPublicBCPGKey)pubPk.getKey();
+ ElGamalSecretBCPGKey elPriv = (ElGamalSecretBCPGKey)privPk;
+ DHPrivateKeySpec elSpec = new DHPrivateKeySpec(elPriv.getX(), elPub.getP(), elPub.getG());
+ return implGeneratePrivate("ElGamal", elSpec);
+ }
+
+ case PublicKeyAlgorithmTags.RSA_ENCRYPT:
+ case PublicKeyAlgorithmTags.RSA_GENERAL:
+ case PublicKeyAlgorithmTags.RSA_SIGN:
+ {
+ RSAPublicBCPGKey rsaPub = (RSAPublicBCPGKey)pubPk.getKey();
+ RSASecretBCPGKey rsaPriv = (RSASecretBCPGKey)privPk;
+ RSAPrivateCrtKeySpec rsaPrivSpec = new RSAPrivateCrtKeySpec(rsaPriv.getModulus(),
+ rsaPub.getPublicExponent(), rsaPriv.getPrivateExponent(), rsaPriv.getPrimeP(), rsaPriv.getPrimeQ(),
+ rsaPriv.getPrimeExponentP(), rsaPriv.getPrimeExponentQ(), rsaPriv.getCrtCoefficient());
+ return implGeneratePrivate("RSA", rsaPrivSpec);
+ }
+
+ default:
+ throw new PGPException("unknown public key algorithm encountered: " + pubPk.getAlgorithm());
+ }
+ }
+ catch (PGPException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PGPException("Exception constructing key", e);
+ }
+ }
+
+ public PublicKey getPublicKey(PGPPublicKey publicKey)
+ throws PGPException
+ {
+ PublicKeyPacket publicPk = publicKey.getPublicKeyPacket();
+
+ try
+ {
+ switch (publicPk.getAlgorithm())
+ {
+ case PublicKeyAlgorithmTags.DSA:
+ {
+ DSAPublicBCPGKey dsaK = (DSAPublicBCPGKey)publicPk.getKey();
+ DSAPublicKeySpec dsaSpec = new DSAPublicKeySpec(dsaK.getY(), dsaK.getP(), dsaK.getQ(), dsaK.getG());
+ return implGeneratePublic("DSA", dsaSpec);
+ }
+
+ case PublicKeyAlgorithmTags.ECDH:
+ {
+ ECDHPublicBCPGKey ecdhK = (ECDHPublicBCPGKey)publicPk.getKey();
+
+ if (ecdhK.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
+ {
+ return get25519PublicKey(ecdhK.getEncodedPoint(), EdECObjectIdentifiers.id_X25519, "XDH", "Curve");
+ }
+ else
+ {
+ return implGetPublicKeyEC("ECDH", ecdhK);
+ }
+ }
+ case PublicKeyAlgorithmTags.X25519:
+ {
+ return implGetPublicKeyX509(publicPk.getKey().getEncoded(), 0, EdECObjectIdentifiers.id_X25519, "XDH");
+ }
+ case PublicKeyAlgorithmTags.X448:
+ {
+ return implGetPublicKeyX509(publicPk.getKey().getEncoded(), 0, EdECObjectIdentifiers.id_X448, "XDH");
+ }
+ case PublicKeyAlgorithmTags.ECDSA:
+ return implGetPublicKeyEC("ECDSA", (ECDSAPublicBCPGKey)publicPk.getKey());
+
+ case PublicKeyAlgorithmTags.EDDSA_LEGACY:
+ {
+ return get25519PublicKey(((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint(), EdECObjectIdentifiers.id_Ed25519, "EdDSA", "Ed");
+ }
+ case PublicKeyAlgorithmTags.Ed25519:
+ {
+ BCPGKey key = publicPk.getKey();
+ if (key instanceof Ed25519PublicBCPGKey)
+ {
+ return implGetPublicKeyX509(BigIntegers.asUnsignedByteArray(new BigInteger(1, publicPk.getKey().getEncoded())),
+ 0, EdECObjectIdentifiers.id_Ed25519, "EdDSA");
+ }
+ else
+ {
+ return implGetPublicKeyX509(BigIntegers.asUnsignedByteArray(((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint()),
+ 0, EdECObjectIdentifiers.id_Ed25519, "EdDSA");
+ }
+ }
+ case PublicKeyAlgorithmTags.Ed448:
+ {
+ return implGetPublicKeyX509(BigIntegers.asUnsignedByteArray(new BigInteger(1, publicPk.getKey().getEncoded())),
+ 0, EdECObjectIdentifiers.id_Ed448, "EdDSA");
+ }
+ case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
+ case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
+ {
+ ElGamalPublicBCPGKey elK = (ElGamalPublicBCPGKey)publicPk.getKey();
+ DHPublicKeySpec elSpec = new DHPublicKeySpec(elK.getY(), elK.getP(), elK.getG());
+ return implGeneratePublic("ElGamal", elSpec);
+ }
+
+ case PublicKeyAlgorithmTags.RSA_ENCRYPT:
+ case PublicKeyAlgorithmTags.RSA_GENERAL:
+ case PublicKeyAlgorithmTags.RSA_SIGN:
+ {
+ RSAPublicBCPGKey rsaK = (RSAPublicBCPGKey)publicPk.getKey();
+ RSAPublicKeySpec rsaSpec = new RSAPublicKeySpec(rsaK.getModulus(), rsaK.getPublicExponent());
+ return implGeneratePublic("RSA", rsaSpec);
+ }
+
+ default:
+ throw new PGPException("unknown public key algorithm encountered: " + publicPk.getAlgorithm());
+ }
+ }
+ catch (PGPException e)
+ {
+ throw e;
+ }
+ catch (Exception e)
+ {
+ throw new PGPException("exception constructing public key", e);
+ }
+ }
+
+ private ECParameterSpec getECParameterSpec(ASN1ObjectIdentifier curveOid, X9ECParameters x9Params)
+ throws InvalidParameterSpecException, NoSuchProviderException, NoSuchAlgorithmException
+ {
+ AlgorithmParameters params = helper.createAlgorithmParameters("EC");
+
+ params.init(new ECGenParameterSpec(ECNamedCurveTable.getName(curveOid)));
+
+ return params.getParameterSpec(ECParameterSpec.class);
+ }
+
+ private BCPGKey getPrivateBCPGKey(PrivateKey privKey, BCPGKeyOperation operation)
+ throws PGPException
+ {
+ PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(privKey.getEncoded());
+
+ try
+ {
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return operation.getBCPGKey(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets());
+ }
+ catch (IOException e)
+ {
+ throw new PGPException(e.getMessage(), e);
+ }
+ }
+
+ private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey)
+ throws PGPException
+ {
+ switch (pub.getAlgorithm())
+ {
+ case PublicKeyAlgorithmTags.DSA:
+ {
+ DSAPrivateKey dsK = (DSAPrivateKey)privKey;
+ return new DSASecretBCPGKey(dsK.getX());
+ }
+
+ case PublicKeyAlgorithmTags.ECDH:
+ {
+ if (privKey instanceof ECPrivateKey)
+ {
+ ECPrivateKey ecK = (ECPrivateKey)privKey;
+ return new ECSecretBCPGKey(ecK.getS());
+ }
+ else
+ {
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return getPrivateBCPGKey(privKey, new BCPGKeyOperation()
+ {
+ @Override
+ public BCPGKey getBCPGKey(byte[] pInfoEncoded)
+ {
+ return new ECSecretBCPGKey(new BigInteger(1, Arrays.reverse(pInfoEncoded)));
+ }
+ });
+ }
+ }
+ case PublicKeyAlgorithmTags.X25519:
+ {
+ // 'reverse' because the native format for X25519 private keys is little-endian
+ return getPrivateBCPGKey(privKey, new BCPGKeyOperation()
+ {
+ @Override
+ public BCPGKey getBCPGKey(byte[] pInfoEncoded)
+ {
+ return new X25519SecretBCPGKey(Arrays.reverse(pInfoEncoded));
+ }
+ });
+ }
+ case PublicKeyAlgorithmTags.X448:
+ {
+ // 'reverse' because the native format for X448 private keys is little-endian
+ return getPrivateBCPGKey(privKey, new BCPGKeyOperation()
+ {
+ @Override
+ public BCPGKey getBCPGKey(byte[] pInfoEncoded)
+ {
+ return new X448SecretBCPGKey(Arrays.reverse(pInfoEncoded));
+ }
+ });
+ }
+ case PublicKeyAlgorithmTags.ECDSA:
+ {
+ return new ECSecretBCPGKey(((ECPrivateKey)privKey).getS());
+ }
+ case PublicKeyAlgorithmTags.EDDSA_LEGACY:
+ {
+ return getPrivateBCPGKey(privKey, new BCPGKeyOperation()
+ {
+ @Override
+ public BCPGKey getBCPGKey(byte[] pInfoEncoded)
+ {
+ return new EdSecretBCPGKey(new BigInteger(1, pInfoEncoded));
+ }
+ });
+ }
+ case PublicKeyAlgorithmTags.Ed25519:
+ {
+ return getPrivateBCPGKey(privKey, Ed25519SecretBCPGKey::new);
+ }
+ case PublicKeyAlgorithmTags.Ed448:
+ {
+ return getPrivateBCPGKey(privKey, Ed448SecretBCPGKey::new);
+ }
+ case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT:
+ case PublicKeyAlgorithmTags.ELGAMAL_GENERAL:
+ {
+ DHPrivateKey esK = (DHPrivateKey)privKey;
+ return new ElGamalSecretBCPGKey(esK.getX());
+ }
+ case PublicKeyAlgorithmTags.RSA_ENCRYPT:
+ case PublicKeyAlgorithmTags.RSA_GENERAL:
+ case PublicKeyAlgorithmTags.RSA_SIGN:
+ {
+ RSAPrivateCrtKey rsK = (RSAPrivateCrtKey)privKey;
+ return new RSASecretBCPGKey(rsK.getPrivateExponent(), rsK.getPrimeP(), rsK.getPrimeQ());
+ }
+ default:
+ throw new PGPException("unknown key class");
+ }
+ }
+
+ private BCPGKey getPublicBCPGKey(int algorithm, PGPAlgorithmParameters algorithmParameters, PublicKey pubKey)
+ throws PGPException
+ {
+ if (pubKey instanceof RSAPublicKey)
+ {
+ RSAPublicKey rK = (RSAPublicKey)pubKey;
+ return new RSAPublicBCPGKey(rK.getModulus(), rK.getPublicExponent());
+ }
+ else if (pubKey instanceof DSAPublicKey)
+ {
+ DSAPublicKey dK = (DSAPublicKey)pubKey;
+ DSAParams dP = dK.getParams();
+ return new DSAPublicBCPGKey(dP.getP(), dP.getQ(), dP.getG(), dK.getY());
+ }
+ else if (pubKey instanceof DHPublicKey)
+ {
+ DHPublicKey eK = (DHPublicKey)pubKey;
+ DHParameterSpec eS = eK.getParams();
+ return new ElGamalPublicBCPGKey(eS.getP(), eS.getG(), eK.getY());
+ }
+ else if (pubKey instanceof ECPublicKey)
+ {
+ SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+
+ // TODO: should probably match curve by comparison as well
+ ASN1ObjectIdentifier curveOid = ASN1ObjectIdentifier.getInstance(keyInfo.getAlgorithm().getParameters());
+
+ X9ECParametersHolder params = ECNamedCurveTable.getByOIDLazy(curveOid);
+
+ ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes());
+ X9ECPoint derQ = new X9ECPoint(params.getCurve(), key);
+
+ if (algorithm == PGPPublicKey.ECDH)
+ {
+ PGPKdfParameters kdfParams = implGetKdfParameters(curveOid, algorithmParameters);
+
+ return new ECDHPublicBCPGKey(curveOid, derQ.getPoint(), kdfParams.getHashAlgorithm(),
+ kdfParams.getSymmetricWrapAlgorithm());
+ }
+ else if (algorithm == PGPPublicKey.ECDSA)
+ {
+ return new ECDSAPublicBCPGKey(curveOid, derQ.getPoint());
+ }
+ else
+ {
+ throw new PGPException("unknown EC algorithm");
+ }
+ }
+ else if (algorithm == PGPPublicKey.Ed25519)
+ {
+ return getPublicBCPGKey(pubKey, Ed25519PublicBCPGKey.LENGTH, Ed25519PublicBCPGKey::new);
+ }
+ else if (pubKey.getAlgorithm().regionMatches(true, 0, "ED2", 0, 3))
+ {
+ return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, getPointEncUncompressed(pubKey, Ed25519.PUBLIC_KEY_SIZE)));
+ }
+ else if (algorithm == PGPPublicKey.X25519)
+ {
+ return getPublicBCPGKey(pubKey, X25519PublicBCPGKey.LENGTH, X25519PublicBCPGKey::new);
+ }
+ else if (pubKey.getAlgorithm().regionMatches(true, 0, "X2", 0, 2))
+ {
+ PGPKdfParameters kdfParams = implGetKdfParameters(CryptlibObjectIdentifiers.curvey25519, algorithmParameters);
+
+ return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, getPointEncUncompressed(pubKey, X25519.SCALAR_SIZE)),
+ kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm());
+ }
+ else if (algorithm == PGPPublicKey.Ed448)
+ {
+ return getPublicBCPGKey(pubKey, Ed448PublicBCPGKey.LENGTH, Ed448PublicBCPGKey::new);
+ }
+ else if (algorithm == PGPPublicKey.X448)
+ {
+ return getPublicBCPGKey(pubKey, X448PublicBCPGKey.LENGTH, X448PublicBCPGKey::new);
+ }
+ else
+ {
+ throw new PGPException("unknown key class");
+ }
+ }
+
+ @FunctionalInterface
+ private interface BCPGKeyOperation
+ {
+ BCPGKey getBCPGKey(byte[] key);
+ }
+
+ private BCPGKey getPublicBCPGKey(PublicKey pubKey, int keySize, BCPGKeyOperation operation)
+ {
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+ byte[] pointEnc = new byte[keySize];
+
+ System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 0, pointEnc.length);
+ return operation.getBCPGKey(pointEnc);
+ }
+
+ private byte[] getPointEncUncompressed(PublicKey pubKey, int publicKeySize)
+ {
+ SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded());
+ byte[] pointEnc = new byte[1 + publicKeySize];
+
+ pointEnc[0] = 0x40;
+ System.arraycopy(pubInfo.getPublicKeyData().getBytes(), 0, pointEnc, 1, pointEnc.length - 1);
+ return pointEnc;
+ }
+
+ @FunctionalInterface
+ private interface Operation
+ {
+ PrivateKeyInfo getPrivateKeyInfos()
+ throws IOException;
+ }
+
+ private PrivateKey implGeneratePrivate(String keyAlgorithm, Operation operation)
+ throws GeneralSecurityException, PGPException, IOException
+ {
+ PKCS8EncodedKeySpec pkcs8Spec = new PKCS8EncodedKeySpec(operation.getPrivateKeyInfos().getEncoded());
+ KeyFactory keyFactory = helper.createKeyFactory(keyAlgorithm);
+ return keyFactory.generatePrivate(pkcs8Spec);
+ }
+
+ private PrivateKey implGeneratePrivate(String keyAlgorithm, KeySpec keySpec)
+ throws GeneralSecurityException, PGPException
+ {
+ KeyFactory keyFactory = helper.createKeyFactory(keyAlgorithm);
+ return keyFactory.generatePrivate(keySpec);
+ }
+
+ private PublicKey implGeneratePublic(String keyAlgorithm, KeySpec keySpec)
+ throws GeneralSecurityException, PGPException
+ {
+ KeyFactory keyFactory = helper.createKeyFactory(keyAlgorithm);
+ return keyFactory.generatePublic(keySpec);
+ }
+
+ private PublicKey implGetPublicKeyX509(byte[] pEnc, int pEncOff, ASN1ObjectIdentifier algorithm, String keyAlgorithm)
+ throws IOException, PGPException, GeneralSecurityException
+ {
+ return implGeneratePublic(keyAlgorithm, new X509EncodedKeySpec(new SubjectPublicKeyInfo(
+ new AlgorithmIdentifier(algorithm), Arrays.copyOfRange(pEnc, pEncOff, pEnc.length)).getEncoded()));
+ }
+
+ private PrivateKey implGetPrivateKeyEC(String keyAlgorithm, ECPublicBCPGKey ecPub, ECSecretBCPGKey ecPriv)
+ throws GeneralSecurityException, PGPException
+ {
+ ASN1ObjectIdentifier curveOid = ecPub.getCurveOID();
+ ECPrivateKeySpec ecPrivSpec = new ECPrivateKeySpec(ecPriv.getX(), getECParameterSpec(curveOid, JcaJcePGPUtil.getX9Parameters(curveOid)));
+ return implGeneratePrivate(keyAlgorithm, ecPrivSpec);
+ }
+
+ private PublicKey implGetPublicKeyEC(String keyAlgorithm, ECPublicBCPGKey ecPub)
+ throws GeneralSecurityException, IOException, PGPException
+ {
+ ASN1ObjectIdentifier curveOID = ecPub.getCurveOID();
+ X9ECParameters x9Params = JcaJcePGPUtil.getX9Parameters(curveOID);
+ ECPoint ecPubPoint = JcaJcePGPUtil.decodePoint(ecPub.getEncodedPoint(), x9Params.getCurve());
+ ECPublicKeySpec ecPubSpec = new ECPublicKeySpec(
+ new java.security.spec.ECPoint(
+ ecPubPoint.getAffineXCoord().toBigInteger(),
+ ecPubPoint.getAffineYCoord().toBigInteger()),
+ getECParameterSpec(curveOID, x9Params));
+ return implGeneratePublic(keyAlgorithm, ecPubSpec);
+ }
+
+ private PublicKey get25519PublicKey(BigInteger x, ASN1ObjectIdentifier algorithm, String keyAlgorithm, String name)
+ throws PGPException, GeneralSecurityException, IOException
+ {
+ byte[] pEnc = BigIntegers.asUnsignedByteArray(x);
+
+ // skip the 0x40 header byte.
+ if (pEnc.length < 1 || 0x40 != pEnc[0])
+ {
+ throw new IllegalArgumentException("Invalid " + name + "25519 public key");
+ }
+ return implGetPublicKeyX509(pEnc, 1, algorithm, keyAlgorithm);
+ }
+}
diff --git a/pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
new file mode 100644
index 0000000000..80bdca4a6a
--- /dev/null
+++ b/pg/src/main/jdk1.5/org/bouncycastle/openpgp/operator/jcajce/JcePublicKeyKeyEncryptionMethodGenerator.java
@@ -0,0 +1,259 @@
+package org.bouncycastle.openpgp.operator.jcajce;
+
+import java.io.IOException;
+import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.Provider;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.AlgorithmParameterSpec;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers;
+import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import org.bouncycastle.asn1.x9.X962Parameters;
+import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
+import org.bouncycastle.bcpg.PublicKeyAlgorithmTags;
+import org.bouncycastle.bcpg.PublicKeyPacket;
+import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags;
+import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec;
+import org.bouncycastle.jcajce.spec.UserKeyingMaterialSpecWithPrepend;
+import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
+import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
+import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
+import org.bouncycastle.openpgp.PGPException;
+import org.bouncycastle.openpgp.PGPPublicKey;
+import org.bouncycastle.openpgp.PGPUtil;
+import org.bouncycastle.openpgp.operator.PGPPad;
+import org.bouncycastle.openpgp.operator.PublicKeyKeyEncryptionMethodGenerator;
+import org.bouncycastle.openpgp.operator.RFC6637Utils;
+import org.bouncycastle.util.Arrays;
+
+public class JcePublicKeyKeyEncryptionMethodGenerator
+ extends PublicKeyKeyEncryptionMethodGenerator
+{
+ private static final byte X_HDR = 0x40;
+
+ private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
+ private SecureRandom random;
+ private JcaPGPKeyConverter keyConverter = new JcaPGPKeyConverter();
+
+ /**
+ * Create a public key encryption method generator with the method to be based on the passed in key.
+ *
+ * @param key the public key to use for encryption.
+ */
+ public JcePublicKeyKeyEncryptionMethodGenerator(PGPPublicKey key)
+ {
+ super(key);
+ }
+
+ public JcePublicKeyKeyEncryptionMethodGenerator setProvider(Provider provider)
+ {
+ this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
+
+ keyConverter.setProvider(provider);
+
+ return this;
+ }
+
+ public JcePublicKeyKeyEncryptionMethodGenerator setProvider(String providerName)
+ {
+ this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
+
+ keyConverter.setProvider(providerName);
+
+ return this;
+ }
+
+ /**
+ * Provide a user defined source of randomness.
+ *
+ * @param random the secure random to be used.
+ * @return the current generator.
+ */
+ public JcePublicKeyKeyEncryptionMethodGenerator setSecureRandom(SecureRandom random)
+ {
+ this.random = random;
+
+ return this;
+ }
+
+ protected byte[] encryptSessionInfo(PGPPublicKey pubKey, byte[] sessionInfo)
+ throws PGPException
+ {
+ try
+ {
+ PublicKey cryptoPublicKey = keyConverter.getPublicKey(pubKey);
+
+ if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.ECDH)
+ {
+ ECDHPublicBCPGKey ecKey = (ECDHPublicBCPGKey)pubKey.getPublicKeyPacket().getKey();
+ String keyEncryptionOID = RFC6637Utils.getKeyEncryptionOID(ecKey.getSymmetricKeyAlgorithm()).getId();
+ PublicKeyPacket pubKeyPacket = pubKey.getPublicKeyPacket();
+ if (ecKey.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519))
+ {
+ return getEncryptSessionInfo(pubKeyPacket, "X25519", cryptoPublicKey, keyEncryptionOID,
+ ecKey.getSymmetricKeyAlgorithm(), sessionInfo, RFC6637Utils.getXDHAlgorithm(pubKeyPacket),
+ new KeyPairGeneratorOperation()
+ {
+ @Override
+ public void initialize(KeyPairGenerator kpGen)
+ throws GeneralSecurityException, IOException
+ {
+ kpGen.initialize(255, random);
+ }
+ },
+ new EphPubEncoding()
+ {
+ @Override
+ public byte[] getEphPubEncoding(byte[] ephPubEncoding)
+ {
+ return Arrays.prepend(ephPubEncoding, X_HDR);
+ }
+ });
+ }
+ else
+ {
+ return getEncryptSessionInfo(pubKeyPacket, "EC", cryptoPublicKey, keyEncryptionOID,
+ ecKey.getSymmetricKeyAlgorithm(), sessionInfo, RFC6637Utils.getAgreementAlgorithm(pubKeyPacket),
+ new KeyPairGeneratorOperation()
+ {
+ @Override
+ public void initialize(KeyPairGenerator kpGen)
+ throws GeneralSecurityException, IOException
+ {
+ AlgorithmParameters ecAlgParams = helper.createAlgorithmParameters("EC");
+ ecAlgParams.init(new X962Parameters(ecKey.getCurveOID()).getEncoded());
+ kpGen.initialize(ecAlgParams.getParameterSpec(AlgorithmParameterSpec.class), random);
+ }
+ },
+ new EphPubEncoding()
+ {
+ @Override
+ public byte[] getEphPubEncoding(byte[] ephPubEncoding)
+ {
+ if (null == ephPubEncoding || ephPubEncoding.length < 1 || ephPubEncoding[0] != 0x04)
+ {
+ ephPubEncoding = JcaJcePGPUtil.getX9Parameters(ecKey.getCurveOID()).getCurve().decodePoint(ephPubEncoding).getEncoded(false);
+ }
+ return ephPubEncoding;
+ }
+ });
+ }
+ }
+ else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X25519)
+ {
+ return getEncryptSessionInfo(pubKey, "X25519", cryptoPublicKey, NISTObjectIdentifiers.id_aes128_wrap.getId(),
+ SymmetricKeyAlgorithmTags.AES_128, sessionInfo, "X25519withSHA256HKDF", 255);
+ }
+ else if (pubKey.getAlgorithm() == PublicKeyAlgorithmTags.X448)
+ {
+ return getEncryptSessionInfo(pubKey, "X448", cryptoPublicKey, NISTObjectIdentifiers.id_aes256_wrap.getId(),
+ SymmetricKeyAlgorithmTags.AES_256, sessionInfo, "X448withSHA512HKDF", 448);
+ }
+ else
+ {
+ Cipher c = helper.createPublicKeyCipher(pubKey.getAlgorithm());
+
+ c.init(Cipher.ENCRYPT_MODE, cryptoPublicKey, random);
+
+ return c.doFinal(sessionInfo);
+ }
+ }
+ catch (IllegalBlockSizeException e)
+ {
+ throw new PGPException("illegal block size: " + e.getMessage(), e);
+ }
+ catch (BadPaddingException e)
+ {
+ throw new PGPException("bad padding: " + e.getMessage(), e);
+ }
+ catch (InvalidKeyException e)
+ {
+ throw new PGPException("key invalid: " + e.getMessage(), e);
+ }
+ catch (IOException e)
+ {
+ throw new PGPException("unable to encode MPI: " + e.getMessage(), e);
+ }
+ catch (GeneralSecurityException e)
+ {
+ throw new PGPException("unable to set up ephemeral keys: " + e.getMessage(), e);
+ }
+ }
+
+ @FunctionalInterface
+ private interface KeyPairGeneratorOperation
+ {
+ void initialize(KeyPairGenerator kpGen)
+ throws GeneralSecurityException, IOException;
+ }
+
+ @FunctionalInterface
+ private interface EphPubEncoding
+ {
+ byte[] getEphPubEncoding(byte[] publicKeyData);
+ }
+
+ private byte[] getEncryptSessionInfo(PublicKeyPacket pubKeyPacket, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
+ int symmetricKeyAlgorithm, byte[] sessionInfo, String agreementName, KeyPairGeneratorOperation kpOperation,
+ EphPubEncoding getEncoding)
+ throws GeneralSecurityException, IOException, PGPException
+ {
+ KeyPairGenerator kpGen = helper.createKeyPairGenerator(algorithmName);
+ kpOperation.initialize(kpGen);
+ KeyPair ephKP = kpGen.generateKeyPair();
+ UserKeyingMaterialSpec ukmSpec = new UserKeyingMaterialSpec(RFC6637Utils.createUserKeyingMaterial(pubKeyPacket,
+ new JcaKeyFingerprintCalculator()));
+ Key secret = JcaJcePGPUtil.getSecret(helper, cryptoPublicKey, keyEncryptionOID, agreementName, ukmSpec, ephKP.getPrivate());
+ byte[] ephPubEncoding = getEncoding.getEphPubEncoding(SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes());
+ byte[] paddedSessionData = PGPPad.padSessionData(sessionInfo, sessionKeyObfuscation);
+
+ return getSessionInfo(ephPubEncoding, getWrapper(symmetricKeyAlgorithm, sessionInfo, secret, paddedSessionData));
+ }
+
+ /**
+ * Note that unlike ECDH, no checksum or padding are appended to the
+ * session key before key wrapping. Finally, note that unlike the other
+ * public-key algorithms, in the case of a v3 PKESK packet, the
+ * symmetric algorithm ID is not encrypted. Instead, it is prepended to
+ * the encrypted session key in plaintext. In this case, the symmetric
+ * algorithm used MUST be AES-128, AES-192 or AES-256 (algorithm ID 7, 8
+ * or 9).
+ */
+ private byte[] getEncryptSessionInfo(PGPPublicKey pgpPublicKey, String algorithmName, PublicKey cryptoPublicKey, String keyEncryptionOID,
+ int symmetricKeyAlgorithm, byte[] sessionInfo, String agreementAlgorithmName, int keySize)
+ throws GeneralSecurityException, IOException, PGPException
+ {
+ KeyPairGenerator kpGen = helper.createKeyPairGenerator(algorithmName);
+ kpGen.initialize(keySize, random);
+ KeyPair ephKP = kpGen.generateKeyPair();
+
+ byte[] ephPubEncoding = SubjectPublicKeyInfo.getInstance(ephKP.getPublic().getEncoded()).getPublicKeyData().getBytes();
+ UserKeyingMaterialSpecWithPrepend ukmSpec = JcaJcePGPUtil.getUserKeyingMaterialSpecWithPrepend(ephPubEncoding, pgpPublicKey.getPublicKeyPacket(), algorithmName);
+ Key secret = JcaJcePGPUtil.getSecret(helper, cryptoPublicKey, keyEncryptionOID, agreementAlgorithmName, ukmSpec, ephKP.getPrivate());
+ //No checksum or padding
+ byte[] sessionData = new byte[sessionInfo.length - 3];
+ System.arraycopy(sessionInfo, 1, sessionData, 0, sessionData.length);
+
+ return getSessionInfo(ephPubEncoding, sessionInfo[0], getWrapper(symmetricKeyAlgorithm, sessionInfo, secret, sessionData));
+ }
+
+ private byte[] getWrapper(int symmetricKeyAlgorithm, byte[] sessionInfo, Key secret, byte[] sessionData)
+ throws PGPException, InvalidKeyException, IllegalBlockSizeException
+ {
+ Cipher c = helper.createKeyWrapper(symmetricKeyAlgorithm);
+ c.init(Cipher.WRAP_MODE, secret, random);
+ return c.wrap(new SecretKeySpec(sessionData, PGPUtil.getSymmetricCipherName(sessionInfo[0])));
+ }
+}
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OpenpgpTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OpenpgpTest.java
index 67ba2d3467..c5e9659987 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OpenpgpTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OpenpgpTest.java
@@ -132,15 +132,15 @@ public void testPGPUtil()
isEquals("MD5", PGPUtil.getDigestName(HashAlgorithmTags.MD5));
isEquals("RIPEMD160", PGPUtil.getDigestName(HashAlgorithmTags.RIPEMD160));
isEquals("SHA256", PGPUtil.getDigestName(HashAlgorithmTags.SHA256));
- isEquals("SHA256", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_256));
- isEquals("SHA256", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_256_OLD));
+ isEquals("SHA3-256", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_256));
+ isEquals("SHA3-256", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_256_OLD));
isEquals("SHA384", PGPUtil.getDigestName(HashAlgorithmTags.SHA384));
- isEquals("SHA384", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_384));
+ isEquals("SHA3-384", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_384));
isEquals("SHA512", PGPUtil.getDigestName(HashAlgorithmTags.SHA512));
- isEquals("SHA512", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_512));
- isEquals("SHA512", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_512_OLD));
+ isEquals("SHA3-512", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_512));
+ isEquals("SHA3-512", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_512_OLD));
isEquals("SHA224", PGPUtil.getDigestName(HashAlgorithmTags.SHA224));
- isEquals("SHA224", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_224));
+ isEquals("SHA3-224", PGPUtil.getDigestName(HashAlgorithmTags.SHA3_224));
isEquals("TIGER", PGPUtil.getDigestName(HashAlgorithmTags.TIGER_192));
testException("unknown hash algorithm tag in getDigestName: ", "PGPException", () -> PGPUtil.getDigestName(HashAlgorithmTags.MD4));
diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
index 1dc3a46994..98a1f9211c 100644
--- a/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
+++ b/pg/src/test/java/org/bouncycastle/openpgp/test/OperatorJcajceTest.java
@@ -66,6 +66,7 @@ public String getName()
public void performTest()
throws Exception
{
+ testCreateDigest();
testX25519HKDF();
testJcePBESecretKeyEncryptorBuilder();
testJcaPGPContentVerifierBuilderProvider();
@@ -184,6 +185,24 @@ public void testJcePBESecretKeyEncryptorBuilder()
testException("s2KCount value outside of range 0 to 255.", "IllegalArgumentException", () -> new JcePBESecretKeyEncryptorBuilder(PGPEncryptedData.AES_256, sha1Calc, -1));
}
+ public void testCreateDigest()
+ throws Exception
+ {
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA1).getAlgorithm(), HashAlgorithmTags.SHA1);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.MD2).getAlgorithm(), HashAlgorithmTags.MD2);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.MD5).getAlgorithm(), HashAlgorithmTags.MD5);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.RIPEMD160).getAlgorithm(), HashAlgorithmTags.RIPEMD160);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA256).getAlgorithm(), HashAlgorithmTags.SHA256);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA224).getAlgorithm(), HashAlgorithmTags.SHA224);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA384).getAlgorithm(), HashAlgorithmTags.SHA384);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA512).getAlgorithm(), HashAlgorithmTags.SHA512);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA3_256).getAlgorithm(), HashAlgorithmTags.SHA3_256);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA3_224).getAlgorithm(), HashAlgorithmTags.SHA3_224);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA3_384).getAlgorithm(), HashAlgorithmTags.SHA3_384);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.SHA3_512).getAlgorithm(), HashAlgorithmTags.SHA3_512);
+ isEquals(new JcaPGPDigestCalculatorProviderBuilder().build().get(HashAlgorithmTags.TIGER_192).getAlgorithm(), HashAlgorithmTags.TIGER_192);
+ }
+
public void testX25519HKDF()
throws Exception
{
@@ -201,7 +220,7 @@ public void testX25519HKDF()
KeyAgreement agreement = KeyAgreement.getInstance("X25519withSHA256HKDF", "BC");
agreement.init(privKey, new HybridValueParameterSpec(Arrays.concatenate(ephmeralKey, publicKey), true, new UserKeyingMaterialSpec(Strings.toByteArray("OpenPGP X25519"))));
agreement.doPhase(pubKey, true);
- Key secretKey= agreement.generateSecret(NISTObjectIdentifiers.id_aes128_wrap.getId());
+ Key secretKey = agreement.generateSecret(NISTObjectIdentifiers.id_aes128_wrap.getId());
// agreement.init(ephmeralprivateKeyParameters);
// byte[] secret = new byte[agreement.getAgreementSize()];
From 68d6e77f1a28db78e89f96539c81002382c21655 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 27 Mar 2024 18:01:17 +1100
Subject: [PATCH 0202/1846] fixed checkstyle issue
---
.../main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java b/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java
index efedb5e9bc..274889ab18 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java
@@ -306,7 +306,8 @@ public void beginClearText(
String hash = PGPUtil.getDigestName(hashAlgorithm);
sb.append(HASH_HDR).append(": ").append(hash).append(nl);
}
- catch (PGPException e){
+ catch (PGPException e)
+ {
throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm);
}
}
From 72081fd3ab213b3e7caf8f704a5aacc6fdd5879e Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 27 Mar 2024 18:15:09 +1100
Subject: [PATCH 0203/1846] reverted PGPUtil inclusion
---
.../bcpg/ArmoredOutputStream.java | 50 ++++++++++++++++---
1 file changed, 42 insertions(+), 8 deletions(-)
diff --git a/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java b/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java
index 274889ab18..d41320042d 100644
--- a/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java
+++ b/pg/src/main/java/org/bouncycastle/bcpg/ArmoredOutputStream.java
@@ -11,8 +11,6 @@
import java.util.List;
import java.util.Map;
-import org.bouncycastle.openpgp.PGPException;
-import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.util.Strings;
/**
@@ -301,15 +299,51 @@ public void beginClearText(
sb.append(nl);
for (int hashAlgorithm : hashAlgorithms)
{
- try
- {
- String hash = PGPUtil.getDigestName(hashAlgorithm);
- sb.append(HASH_HDR).append(": ").append(hash).append(nl);
- }
- catch (PGPException e)
+ String hash;
+ switch (hashAlgorithm)
{
+ case HashAlgorithmTags.MD5:
+ hash = "MD5";
+ break;
+ case HashAlgorithmTags.SHA1:
+ hash = "SHA1";
+ break;
+ case HashAlgorithmTags.RIPEMD160:
+ hash = "RIPEMD160";
+ break;
+ case HashAlgorithmTags.MD2:
+ hash = "MD2";
+ break;
+ case HashAlgorithmTags.SHA256:
+ hash = "SHA256";
+ break;
+ case HashAlgorithmTags.SHA384:
+ hash = "SHA384";
+ break;
+ case HashAlgorithmTags.SHA512:
+ hash = "SHA512";
+ break;
+ case HashAlgorithmTags.SHA224:
+ hash = "SHA224";
+ break;
+ case HashAlgorithmTags.SHA3_256:
+ case HashAlgorithmTags.SHA3_256_OLD:
+ hash = "SHA3-256";
+ break;
+ case HashAlgorithmTags.SHA3_384: // OLD
+ hash = "SHA3-384";
+ break;
+ case HashAlgorithmTags.SHA3_512:
+ case HashAlgorithmTags.SHA3_512_OLD:
+ hash = "SHA3-512";
+ break;
+ case HashAlgorithmTags.SHA3_224:
+ hash = "SHA3-224";
+ break;
+ default:
throw new IOException("unknown hash algorithm tag in beginClearText: " + hashAlgorithm);
}
+ sb.append(HASH_HDR).append(": ").append(hash).append(nl);
}
sb.append(nl);
From 02b98eb08d013c1c6b560c311144e889b884b53f Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 27 Mar 2024 18:26:03 +0700
Subject: [PATCH 0204/1846] Fix various bitstring usages
---
.../mozilla/SignedPublicKeyAndChallenge.java | 2 +-
.../jcajce/JcaContentVerifierProviderBuilder.java | 2 +-
.../test/java/org/bouncycastle/cert/test/PKCS10Test.java | 2 +-
.../asymmetric/compositesignatures/SignatureSpi.java | 3 ++-
.../jcajce/provider/asymmetric/x509/X509CRLImpl.java | 8 ++++----
.../provider/asymmetric/x509/X509CertificateImpl.java | 8 ++++----
.../bouncycastle/jce/netscape/NetscapeCertRequest.java | 5 ++---
.../jce/provider/ProvOcspRevocationChecker.java | 2 +-
.../org/bouncycastle/jce/provider/test/EdECTest.java | 2 +-
.../jce/provider/test/PKCS10CertRequestTest.java | 9 ++++-----
10 files changed, 21 insertions(+), 22 deletions(-)
diff --git a/pkix/src/main/java/org/bouncycastle/mozilla/SignedPublicKeyAndChallenge.java b/pkix/src/main/java/org/bouncycastle/mozilla/SignedPublicKeyAndChallenge.java
index 44d5954237..8be439cdd3 100644
--- a/pkix/src/main/java/org/bouncycastle/mozilla/SignedPublicKeyAndChallenge.java
+++ b/pkix/src/main/java/org/bouncycastle/mozilla/SignedPublicKeyAndChallenge.java
@@ -121,7 +121,7 @@ public boolean verify(String provider)
{
sig.update(spkacSeq.getPublicKeyAndChallenge().getEncoded());
- return sig.verify(spkacSeq.getSignature().getBytes());
+ return sig.verify(spkacSeq.getSignature().getOctets());
}
catch (Exception e)
{
diff --git a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
index 063f4fecc7..0c28215d3c 100644
--- a/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
+++ b/pkix/src/main/java/org/bouncycastle/operator/jcajce/JcaContentVerifierProviderBuilder.java
@@ -434,7 +434,7 @@ public boolean verify(byte[] expected)
{
if (sigs[i] != null)
{
- if (!sigs[i].verify(ASN1BitString.getInstance(sigSeq.getObjectAt(i)).getBytes()))
+ if (!sigs[i].verify(ASN1BitString.getInstance(sigSeq.getObjectAt(i)).getOctets()))
{
failed = true;
}
diff --git a/pkix/src/test/java/org/bouncycastle/cert/test/PKCS10Test.java b/pkix/src/test/java/org/bouncycastle/cert/test/PKCS10Test.java
index 2ea4ef749c..c9052928ed 100644
--- a/pkix/src/test/java/org/bouncycastle/cert/test/PKCS10Test.java
+++ b/pkix/src/test/java/org/bouncycastle/cert/test/PKCS10Test.java
@@ -259,7 +259,7 @@ private void createECRequest(String algorithm, ASN1ObjectIdentifier algOid, ASN1
sig.update(req.toASN1Structure().getCertificationRequestInfo().getEncoded());
- if (!sig.verify(req.toASN1Structure().getSignature().getBytes()))
+ if (!sig.verify(req.toASN1Structure().getSignature().getOctets()))
{
fail("signature not mapped correctly.");
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
index e95b0d6ecd..29d9f3970c 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
@@ -14,6 +14,7 @@
import java.util.Collections;
import java.util.List;
+import org.bouncycastle.asn1.ASN1BitString;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Encoding;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
@@ -250,7 +251,7 @@ protected boolean engineVerify(byte[] signature)
{
this.componentSignatures.get(i).update(this.OIDBytes);
this.componentSignatures.get(i).update(digestResult); //in total, "OID || digest(message)" is the message fed into each component signature
- if (!this.componentSignatures.get(i).verify(DERBitString.getInstance(signatureSequence.getObjectAt(i)).getBytes()))
+ if (!this.componentSignatures.get(i).verify(ASN1BitString.getInstance(signatureSequence.getObjectAt(i)).getOctets()))
{
fail = true;
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java
index 719e129761..f113cbe2e4 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java
@@ -242,7 +242,7 @@ private void doVerify(PublicKey key, SignatureCreator sigCreator)
{
List pubKeys = ((CompositePublicKey)key).getPublicKeys();
ASN1Sequence keySeq = ASN1Sequence.getInstance(c.getSignatureAlgorithm().getParameters());
- ASN1Sequence sigSeq = ASN1Sequence.getInstance(ASN1BitString.getInstance(c.getSignature()).getBytes());
+ ASN1Sequence sigSeq = ASN1Sequence.getInstance(c.getSignature().getOctets());
boolean success = false;
for (int i = 0; i != pubKeys.size(); i++)
@@ -264,7 +264,7 @@ private void doVerify(PublicKey key, SignatureCreator sigCreator)
checkSignature(
(PublicKey)pubKeys.get(i), signature,
sigAlg.getParameters(),
- ASN1BitString.getInstance(sigSeq.getObjectAt(i)).getBytes());
+ ASN1BitString.getInstance(sigSeq.getObjectAt(i)).getOctets());
success = true;
}
catch (SignatureException e)
@@ -286,7 +286,7 @@ private void doVerify(PublicKey key, SignatureCreator sigCreator)
else if (X509SignatureUtil.isCompositeAlgorithm(c.getSignatureAlgorithm()))
{
ASN1Sequence keySeq = ASN1Sequence.getInstance(c.getSignatureAlgorithm().getParameters());
- ASN1Sequence sigSeq = ASN1Sequence.getInstance(ASN1BitString.getInstance(c.getSignature()).getBytes());
+ ASN1Sequence sigSeq = ASN1Sequence.getInstance(c.getSignature().getOctets());
boolean success = false;
for (int i = 0; i != sigSeq.size(); i++)
@@ -303,7 +303,7 @@ else if (X509SignatureUtil.isCompositeAlgorithm(c.getSignatureAlgorithm()))
checkSignature(
key, signature,
sigAlg.getParameters(),
- ASN1BitString.getInstance(sigSeq.getObjectAt(i)).getBytes());
+ ASN1BitString.getInstance(sigSeq.getObjectAt(i)).getOctets());
success = true;
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java
index 5390d2e025..5dff8bf601 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java
@@ -624,7 +624,7 @@ private void doVerify(
{
List pubKeys = ((CompositePublicKey)key).getPublicKeys();
ASN1Sequence keySeq = ASN1Sequence.getInstance(c.getSignatureAlgorithm().getParameters());
- ASN1Sequence sigSeq = ASN1Sequence.getInstance(ASN1BitString.getInstance(c.getSignature()).getBytes());
+ ASN1Sequence sigSeq = ASN1Sequence.getInstance(c.getSignature().getOctets());
boolean success = false;
for (int i = 0; i != pubKeys.size(); i++)
@@ -645,7 +645,7 @@ private void doVerify(
checkSignature(
(PublicKey)pubKeys.get(i), signature,
sigAlg.getParameters(),
- ASN1BitString.getInstance(sigSeq.getObjectAt(i)).getBytes());
+ ASN1BitString.getInstance(sigSeq.getObjectAt(i)).getOctets());
success = true;
}
catch (SignatureException e)
@@ -667,7 +667,7 @@ private void doVerify(
else if (X509SignatureUtil.isCompositeAlgorithm(c.getSignatureAlgorithm()))
{
ASN1Sequence keySeq = ASN1Sequence.getInstance(c.getSignatureAlgorithm().getParameters());
- ASN1Sequence sigSeq = ASN1Sequence.getInstance(ASN1BitString.getInstance(c.getSignature()).getBytes());
+ ASN1Sequence sigSeq = ASN1Sequence.getInstance(c.getSignature().getOctets());
boolean success = false;
for (int i = 0; i != sigSeq.size(); i++)
@@ -684,7 +684,7 @@ else if (X509SignatureUtil.isCompositeAlgorithm(c.getSignatureAlgorithm()))
checkSignature(
key, signature,
sigAlg.getParameters(),
- ASN1BitString.getInstance(sigSeq.getObjectAt(i)).getBytes());
+ ASN1BitString.getInstance(sigSeq.getObjectAt(i)).getOctets());
success = true;
}
diff --git a/prov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java b/prov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
index a72e94c4cd..c05c9a3671 100644
--- a/prov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
+++ b/prov/src/main/java/org/bouncycastle/jce/netscape/NetscapeCertRequest.java
@@ -112,8 +112,7 @@ public NetscapeCertRequest (ASN1Sequence spkac)
SubjectPublicKeyInfo pubkeyinfo = SubjectPublicKeyInfo.getInstance(pkac.getObjectAt(0));
- X509EncodedKeySpec xspec = new X509EncodedKeySpec(new DERBitString(
- pubkeyinfo).getBytes());
+ X509EncodedKeySpec xspec = new X509EncodedKeySpec(pubkeyinfo.getEncoded(ASN1Encoding.DER));
keyAlg = pubkeyinfo.getAlgorithm();
pubkey = KeyFactory.getInstance(keyAlg.getAlgorithm().getId(), "BC")
@@ -207,7 +206,7 @@ public boolean verify(String challenge) throws NoSuchAlgorithmException,
Signature sig = Signature.getInstance(sigAlg.getAlgorithm().getId(),
"BC");
sig.initVerify(pubkey);
- sig.update(content.getBytes());
+ sig.update(content.getOctets());
return sig.verify(sigBits);
}
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java b/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
index b172f62107..1d697023f0 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/ProvOcspRevocationChecker.java
@@ -431,7 +431,7 @@ static boolean validatedOcspResponse(BasicOCSPResponse basicResp, PKIXCertRevoca
sig.update(basicResp.getTbsResponseData().getEncoded(ASN1Encoding.DER));
- if (sig.verify(basicResp.getSignature().getBytes()))
+ if (sig.verify(basicResp.getSignature().getOctets()))
{
if (nonce != null)
{
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java
index 630024287b..6069675087 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/EdECTest.java
@@ -158,7 +158,7 @@ public void performTest()
// yes, the demo certificate is invalid...
sig.update(x25519Seq.getObjectAt(0).toASN1Primitive().getEncoded(ASN1Encoding.DL));
- isTrue(sig.verify(x25519Cert.getSignature().getBytes()));
+ isTrue(sig.verify(x25519Cert.getSignature().getOctets()));
CertificateFactory certFact = CertificateFactory.getInstance("X.509", "BC");
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS10CertRequestTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS10CertRequestTest.java
index 84303eee6b..a8e07d73ce 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS10CertRequestTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS10CertRequestTest.java
@@ -41,7 +41,6 @@
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
-import org.bouncycastle.math.ec.ECConstants;
import org.bouncycastle.math.ec.ECCurve;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;
@@ -215,7 +214,7 @@ private void createECRequest(String algorithm, ASN1ObjectIdentifier algOid, ASN1
sig.update(req.getCertificationRequestInfo().getEncoded());
- if (!sig.verify(req.getSignature().getBytes()))
+ if (!sig.verify(req.getSignature().getOctets()))
{
fail("signature not mapped correctly.");
}
@@ -294,7 +293,7 @@ private void createECRequest(String algorithm, ASN1ObjectIdentifier algOid)
sig.update(req.getCertificationRequestInfo().getEncoded());
- if (!sig.verify(req.getSignature().getBytes()))
+ if (!sig.verify(req.getSignature().getOctets()))
{
fail("signature not mapped correctly.");
}
@@ -344,7 +343,7 @@ private void createECGOSTRequest()
sig.update(req.getCertificationRequestInfo().getEncoded());
- if (!sig.verify(req.getSignature().getBytes()))
+ if (!sig.verify(req.getSignature().getOctets()))
{
fail("signature not mapped correctly.");
}
@@ -401,7 +400,7 @@ private void createPSSTest(String algorithm)
sig.update(req.getCertificationRequestInfo().getEncoded());
- if (!sig.verify(req.getSignature().getBytes()))
+ if (!sig.verify(req.getSignature().getOctets()))
{
fail("signature not mapped correctly.");
}
From 937d9c26ddcbe21a4a684f108cdc1376c5937a3d Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 27 Mar 2024 18:39:16 +0700
Subject: [PATCH 0205/1846] Fix engineGetOutputSize and add some TODOs
---
.../provider/asymmetric/rsa/CipherSpi.java | 20 +++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
index a4a771d463..abad97187c 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/rsa/CipherSpi.java
@@ -134,6 +134,11 @@ else if (key instanceof RSAPublicKey)
protected int engineGetOutputSize(
int inputLen)
{
+ if (tlsRsaSpec != null)
+ {
+ return TlsRsaKeyExchange.PRE_MASTER_SECRET_LENGTH;
+ }
+
try
{
return cipher.getOutputBlockSize();
@@ -334,6 +339,7 @@ else if (key instanceof RSAPrivateKey)
}
else if (params instanceof TLSRSAPremasterSecretParameterSpec)
{
+ // TODO Restrict mode to DECRYPT_MODE (and/or UNWRAP_MODE)
if (!(param instanceof RSAKeyParameters) || !((RSAKeyParameters)param).isPrivate())
{
throw new InvalidKeyException("RSA private key required for TLS decryption");
@@ -353,6 +359,7 @@ else if (params instanceof TLSRSAPremasterSecretParameterSpec)
}
else
{
+ // TODO Remove after checking all AsymmetricBlockCipher init methods?
param = new ParametersWithRandom(param, CryptoServicesRegistrar.getSecureRandom());
}
@@ -446,6 +453,7 @@ protected byte[] engineDoFinal(
int inputLen)
throws IllegalBlockSizeException, BadPaddingException
{
+ // TODO Can input actually be null?
if (input != null)
{
engineUpdate(input, inputOffset, inputLen);
@@ -462,16 +470,8 @@ protected int engineDoFinal(
int outputOffset)
throws IllegalBlockSizeException, BadPaddingException, ShortBufferException
{
- int outputSize;
- if (tlsRsaSpec != null)
- {
- outputSize = TlsRsaKeyExchange.PRE_MASTER_SECRET_LENGTH;
- }
- else
- {
- outputSize = engineGetOutputSize(input == null ? 0 : inputLen);
- }
-
+ // TODO Can input actually be null?
+ int outputSize = engineGetOutputSize(input == null ? 0 : inputLen);
if (outputOffset > output.length - outputSize)
{
throw new ShortBufferException("output buffer too short for input.");
From 966eed3c196cfc79a6eaed5de8d562c20b2b1581 Mon Sep 17 00:00:00 2001
From: Alexander Scheel
Date: Wed, 27 Mar 2024 09:28:53 -0400
Subject: [PATCH 0206/1846] Add regression tests for Ed448 loop
See also: 02f1fb441b6b72826ea892aea4a741403d9562f3
Signed-off-by: Alexander Scheel
---
.../bouncycastle/crypto/test/Ed448Test.java | 1075 +++++++++++++++++
1 file changed, 1075 insertions(+)
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Ed448Test.java b/core/src/test/java/org/bouncycastle/crypto/test/Ed448Test.java
index 4316fae005..07e0295406 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Ed448Test.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Ed448Test.java
@@ -12,6 +12,7 @@
import org.bouncycastle.crypto.signers.Ed448phSigner;
import org.bouncycastle.math.ec.rfc8032.Ed448;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
@@ -164,4 +165,1078 @@ private void testConsistency(int algorithm, byte[] context) throws Exception
}
}
}
+
+ private void testRegressionInfiniteLoop() throws Exception
+ {
+ String[] testCases = new String[]{
+ "pub=MEMwBQYDK2VxAzoAgZiVkEoqFULqfNRJUnq5Fu1OsZRExw1AxI5dAjzLFbcb+krjKjKA81DKnED3+iN6aQ7QlK2PsvGA priv=MEcCAQAwBQYDK2VxBDsEOeZPlP0NUeEuIOnJOE6PccUigEvDNtUtfWEyc27WyIgFwD2BqKGdJNHVHJe5Gws66Y9CMHZK54RCZg== msg=5k+U/Q1R4S4g6ck4To9xxSKAS8M21S19YTJzbtbIiAXAPYGooZ0k0dUcl7kbCzrpj0IwdkrnhEJm5l5p+g54eg== sig=RfExPil6ytaGVcLbC7Z+98YGgEceUtKP4YOkFQxKOcdzo92jTtgn24hZMhfJJfvUmPYW0L8w1F+AXpI+homRI5H99ZuSUBW9SoXGa3XeyHbH2cnB+gU1BYSJt418+K0WeluuaRotEoHkj2klG2vc/zUA e=found last=27 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhnn8NJQ4lJeTojTiZY3QxFhsv3UlfCh7kUz6pC9le9EB9mqwOhZd4PUGtVDXvVMbEgWBqpSKS46A priv=MEcCAQAwBQYDK2VxBDsEOcuWqeEhJ89KpaG7GuUKJz+2k+CXSTrrTGIU+sKHHOETLcGrrvJBiOgTTfa+9CPv1V+UbUl9edhe5w== msg=y5ap4SEnz0qlobsa5QonP7aT4JdJOutMYhT6wocc4RMtwauu8kGI6BNN9r70I+/VX5RtSX152F7nnB7zQei8qQ== sig=dAKGHOOLmdiqdgBs2rvJlG7Xwn6cN+PpbhGbcEIczKdwxMzTJTc9sxlGXNT5TrfSl1hpuzuCoAGAsVSE0N9FmntBGfX+nJ3qSG5A7Zj0RsTuq8F9oalpMjWQw/CaQSDU5olgwHcz52OgekBivfI74iAA e=found last=27 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA515DzkzTyiFq0By7UCpcd/iGyTWm8n4eCZ5Lmgwqq8WeLXN69nTitfiRxEXR43PaQt20vaC4SB+A priv=MEcCAQAwBQYDK2VxBDsEOVZwRWJ1s60j0ExUJUf+4q7mWimTA3v78XoZ8SdvNGUhxPHcW32wnroI0e3Og7IAuxxZBcFYu+Zb6Q== msg=VnBFYnWzrSPQTFQlR/7iruZaKZMDe/vxehnxJ280ZSHE8dxbfbCeugjR7c6DsgC7HFkFwVi75lvpGpr8fzMKCQ== sig=Fs7BsuOmQAglqYnwtddH3//1xz8DQ/MFW8CxgNWSG9sOo4gpdc24T/0ORYEL+JWe/FD/oiuiHUoAQ79vTyoHZIhJCmozuzHB7Yk8Eu42egehlz2kYaJNVmcq2DuiVfWx5y6jzP3eYbpoXLs/oKqCfh4A e=found last=26 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFFIH79iGjW4RppqmcrknuabK9ix9tKfEv0DoSJnK7obnAiQVECfLPhj+oTa0sMNEKDQaiEm2va2A priv=MEcCAQAwBQYDK2VxBDsEOSScY3x+NmvgStzAA7JXDNuMfXtyZsd5FFvyzumGmosWrg9KfoUOF0gzrwbc4ILpWif39MrQmBhQgA== msg=JJxjfH42a+BK3MADslcM24x9e3Jmx3kUW/LO6YaaixauD0p+hQ4XSDOvBtzggulaJ/f0ytCYGFCA9xNrnOgqUQ== sig=hvheMugthdwgTHlJqYFnDRBrYq4jJnY/0j6t8dIn6TWtmOg4ovtIrS9F0Tl4vZXVUo8KNnuyGvWA93+7jcMRXRq68qbyPx6fH2uYDm72/hSPAESu8LrZOgUvO+VxQR874H1PKdib402WEqv/Gg9ViwUA e=found last=27 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbsdgKdEQ1sul8g8on0VqFpHDOUeNTkiNuMSqG0vIl+IznqqWSPAXUUBoq7k6ARX+6S3EUS8XFy2A priv=MEcCAQAwBQYDK2VxBDsEOcbZbtIQHwHdcmlNU4AS933i0kEoJ1tZt+bErVhsjmNQ32ybroh+f/LMAiCTYM1I/4JDbQLSb6mueA== msg=xtlu0hAfAd1yaU1TgBL3feLSQSgnW1m35sStWGyOY1DfbJuuiH5/8swCIJNgzUj/gkNtAtJvqa543uSJs2S+zg== sig=ekw6WqqH7Nt5zMdbOA4QrmmYsnrW+MgpiGljDPth45gI55wjs4bAxIBpSRFim9OPhKKOuovYzigAhTYKHeNCBouAmBgkdsmHJDUTE6oFDIOXYI6KEFSwNZTQ8izwcV+nEoSGtFCFTWUioXQkJnOhSxUA e=found last=27 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAcmhnjr0eGus/TMsrnhZvXRrIFbVPi9R1FLjwueY0AIXrH15mkdfreSVXBzwxwkK71SNQY/ZL8LIA priv=MEcCAQAwBQYDK2VxBDsEOenkZu/cy5G8gMHlJwaD6DI06gxHu7KVyfx5r+svT7kze5+bFYeeIZptlJ4YED6zjhsy/hCAxUoR0Q== msg=6eRm79zLkbyAweUnBoPoMjTqDEe7spXJ/Hmv6y9PuTN7n5sVh54hmm2UnhgQPrOOGzL+EIDFShHRUboKGmcuJg== sig=v0ShF3C6zpZlH1OEs/+2VtV045pefEr4mDYxHC9gwM7vIdNMduqv+ORTR/kfsO+rqr+aNsNi7XmASqLakn3Vbt4KSWYpguzpHtPF0h4ITs1WsPH4tfwxBEoR/FGqNaVdATRy6KIxLBOyHUf4UzanZBIA e=found last=27 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1V5GjmIS9RvRthCq70wH7KT7W9QXaYHnjo+iJqMbh9qDU9O+KozH3zxGgrIb4lCogAzILmichasA priv=MEcCAQAwBQYDK2VxBDsEOY+z51GP/xLrgARJWwB+tDAmAKDFAR+eQ/JJ8LRZ6Yrk4B+kMM76wIF44e0H+FxOLOWUasLqQzqv5w== msg=j7PnUY//EuuABElbAH60MCYAoMUBH55D8knwtFnpiuTgH6QwzvrAgXjh7Qf4XE4s5ZRqwupDOq/n/NCGP+uv/A== sig=xPhIEJ7GaSmnz6yBJEh8vUfReqVYtrftCzwX8YbTyQZtoqVofQm+1ZKd61je3OUWI4bWfNCixT6AfI4pt2cJe3PE9N/DjfAZI0B6WleqQVmMVphcNBuMLb9KyuYrmZYAyCOTv8U7bqLzqPRFaSRQLhcA e=found last=26 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoArt2zBdtE07d3p1FA/U2u6LmaI4Sr+0qsVygHDqvhIobotKmJXCQTPqq8SfVl5EXLaWBf310RDc6A priv=MEcCAQAwBQYDK2VxBDsEOUkDZInSe8hUewSVDODlxf0IErKrmqBJcfFh52G73QWhLj1vH7NOgF/fC9KnZ318Qdgudl/3QT1vRQ== msg=SQNkidJ7yFR7BJUM4OXF/QgSsquaoElx8WHnYbvdBaEuPW8fs06AX98L0qdnfXxB2C52X/dBPW9F4U0VE85uvQ== sig=eOCfk68n2BDT6EPpvtc5GLTxo2guiiy4eT0Lw/sQr2glzO0r+WFaLnAhtH9AX6OmhaJvFyIHH1GA434ZqDn+aJpmk/jYldHtLH1wSsCm1VI1F75c6BAvDRIDpVtptVOEvI0+D6BQz640sVxtVRqk5SQA e=found last=27 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoArjp0KCuyGHeDpr+dc7F+AAtbfazXQIJVKiMqzz29IS4y4oY7BcefdpgmAf5jqzNjtxQ24t/ShwwA priv=MEcCAQAwBQYDK2VxBDsEOeSG+lyikZdnyutY2bFB3rFrsYOXNdWDEgJoQfoOET+q8IBsX8AveISGDBM3n/y6PklalbU3a8990Q== msg=5Ib6XKKRl2fK61jZsUHesWuxg5c11YMSAmhB+g4RP6rwgGxfwC94hIYMEzef/Lo+SVqVtTdrz33R3oiWFE2y+Q== sig=bs7/WGV1Rdq6rdIm+jQJR29uruw4ISePDFbvm+gZqYzjZquEPnAHawDwJ8qXL07WTWrm3pJJBhUA7EpcSb2SKlH3VEAy5TvCCJhaFMHCpLPJtxMAUwhGvL4JSp+ChUoszYdVx84gEk+7wLa5YjCZuhIA e=found last=26 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwUu5MbjncRAg4DtlyPIlk2Kp0+vQFgObzQO5FWmf5k05ReW7K3XoXa9SD3pdmaSf9Lv3DAFYpU2A priv=MEcCAQAwBQYDK2VxBDsEOQd2sw/fIyaBlKc7N5lz7z9gejiWjXN49ug3N4Ey3PrIg+DzeKTGRQUPan5OJWurIgIVEzRsxH7SIQ== msg=B3azD98jJoGUpzs3mXPvP2B6OJaNc3j26Dc3gTLc+siD4PN4pMZFBQ9qfk4la6siAhUTNGzEftIhCpgczPuR8g== sig=xsB+vY7y8uGOtDkK731DpVtytNXSu/01HI/3CLZNrU80Im9VWOstb0Bx7IRAXxREPr7Yad+fo0oAVNLs9chh3nAKx0fA4IxKPin4R4P6WDEWh+YfMDzsLa7wrmoCq2Zazp64kiQEjk0hoAIjO/kD/xYA e=found last=27 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMpVnXq53scujnvFZUGZAkbPpZRjv6PB1HUtqnZDHARwVlREGMDt5T353e7rgchm7DRw4baOBq34A priv=MEcCAQAwBQYDK2VxBDsEOQ842J5En8P0hcwVwRokVZ7Wv3bF6WcRZfi0g/PsAMIXwPn8DDSqQLDjTZGaJcsYoF1hMcxK0T0tbg== msg=DzjYnkSfw/SFzBXBGiRVnta/dsXpZxFl+LSD8+wAwhfA+fwMNKpAsONNkZolyxigXWExzErRPS1usySFpLUyxg== sig=2tL36Y9TEj9M4cIf5fGfB/ujkREMkazw3CG2r1Vng0u3w1acPtdZQEpC1fMn46zO89joc1wxXscAPDy8hoUpscekmZdaqpLlvBs9oNGcvwuonuC8Io11mP8YqlxTqOrOVyOZ6LjqYtlDbEFEp6/dPwcA e=found last=26 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAcnfkW4NjaWBvn72ZVV23vafJ2WC/5RX3oGsD90qedadMPwEqGSanvw7itysPmQJ/QVTIMpZGkuAA priv=MEcCAQAwBQYDK2VxBDsEOR2PvP00KafP3gVUwVzhDZ+GRMh5uY2pQNHFW6Qe4xrjwgUhjclnfdxaohxhyMwcjxl89HZVU0ioiQ== msg=HY+8/TQpp8/eBVTBXOENn4ZEyHm5jalA0cVbpB7jGuPCBSGNyWd93FqiHGHIzByPGXz0dlVTSKiJz+Z455qsMQ== sig=fu1a6on+zdYPw6CGepibQxS0VABDf4ihTjGFms/cxn8DsTCcoyElQbsj1DnaWZtjrkZTRZonsBaAf3qC4eTuNBdwQGN9rl2Fq6JXE50KO64TCvZq7i8G09frb5EznpwibBj5/eRpuFXfO873QUeTyisA e=found last=27 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAl4gxCreiBS0uWDhqOG57TSsX44rxwUpkfqzJ8j4BPOgpRBvIURJcQ1SbMNovZrEx50OdC+fw1NSA priv=MEcCAQAwBQYDK2VxBDsEOXJh+fT2exH/KVm2WJusOy1WN4qHEwclf4exbpGqUJQtwDBZ5r7hJDt6QrobpnKjzO1CzHqlqKCtnQ== msg=cmH59PZ7Ef8pWbZYm6w7LVY3iocTByV/h7FukapQlC3AMFnmvuEkO3pCuhumcqPM7ULMeqWooK2dHXFWH4YNzQ== sig=ypvSeR61KBMGo44yoppt3Rgw7Zw2oyLEZNUyzcpCQCl7C0tlpj5MFZMSLqNdx5IzahYG25/v9DOA3RgtcrQhLSgvZWFesc5iaaxLrb+ybD3+DyGY548J52YuxXfi81cqQSgKWpP2kM8zxkIlvf180DcA e=found last=26 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAQcX2/eajEGs6s8FRRRNdesX4wR20Wiseg7bccA6rlBmsfI165gUTbynD/B6+QOKH1eHq45Glh5wA priv=MEcCAQAwBQYDK2VxBDsEORpSHJsqnfgxarjFGgZFNcC5+XJp4TmFx4M26ENCZuhjNddqPFMBS0iuFq1y76QbXkCUjRu94CYIgw== msg=GlIcmyqd+DFquMUaBkU1wLn5cmnhOYXHgzboQ0Jm6GM112o8UwFLSK4WrXLvpBteQJSNG73gJgiDGCqlYQfPug== sig=GemEMDVr0QbJ/xGNFSUu9AtjBsZFOlsSAb1BokzRdxuKfBqKUTZAyD6jdJ9L3DQoHiV/E4eSvNcAro6BsVL3/zzPsjbfUBya0HsHePZfpSaruX4r0cT34ggaphdV+e5reoF4ijlpB7cDkyeCElR9CyAA e=found last=26 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAaRO77yJwuC3mdvWOeU74bs2RBArdrKgk1abcI4IbdssOSYKlxu6SsjhFu/NVEuBmzonnx2oyWLSA priv=MEcCAQAwBQYDK2VxBDsEOeAuFLzBnbwT0LuucrtlqXx8/0+dVatgpT+JMq3qyy8UcvxsXeXWDIYIb6cjDOVV99GydpVgONA8xA== msg=4C4UvMGdvBPQu65yu2WpfHz/T51Vq2ClP4kyrerLLxRy/Gxd5dYMhghvpyMM5VX30bJ2lWA40DzEpO4UWhJDxA== sig=8BRApKdGu7AOPTYJhduTp+ZLjAZRKnewWd6aM8vsQRVPJ1JKE1V/JXL+lSQdHfaH266FNgmvGOSAgTnkiqpa6S3oI62+fTkB/YLHSS0obgA4ZLx/13enJ2yfaPQta8WXGVWfWJWP+Jhze8T5+IcYeRsA e=found last=26 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9j+NRCuIpeVRILKe62ubhhsKZxdUMh0OtQ0fop51MN609qg9qX3WsP4TjYWAVZ69MKfPlD/K4D2A priv=MEcCAQAwBQYDK2VxBDsEOcszViNOvqgdLnJ0ZegCBJaGnPFF00081A4pt0d/moRWnfq1j6nEDqD3ZLV8RDyyxP6JWOP2/WT+Eg== msg=yzNWI06+qB0ucnRl6AIEloac8UXTTTzUDim3R3+ahFad+rWPqcQOoPdktXxEPLLE/olY4/b9ZP4S+KFrEFD5vw== sig=rGIzh8Jmeo3VFLqPheaWwgxh/z+4UQNdLwlbkiWXbnLhRM/mX+KL1PKoaHcICGF72RvXNxHYk2uAG9t7Lpa7FTJPK71mpiZZou+gc0nHjFVnoA2EdbBq1fh2E35BPdN49iciO0CjmwGAJpXTYpzuDDMA e=found last=27 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABpqdNL4pYviG8T7EwnBU2wuIX0Hh68q3tO+keC4Iwz9r6yVTSvYwitBtzZXXps0IEc6djpb/nLKA priv=MEcCAQAwBQYDK2VxBDsEOTCbmYW4XJPlaGpc9dRamLEsHytlLP4A4KGCsB/7BwDxBxGUinjXyYAjKFYsnwNaG48FWpxIkyjjKw== msg=MJuZhbhck+Voalz11FqYsSwfK2Us/gDgoYKwH/sHAPEHEZSKeNfJgCMoViyfA1objwVanEiTKOMrd4PpbG4SNQ== sig=E6NG9fyW6bPCFognNvFweQCqNKWEY7rY4lQVYb9EYzGM5EfTHO1d79f3TUOwWp3eYqd8a1NnoloAUTPj2sOv6snLRwdnrWR3aaaAJscWLd0Na++82SIDVGNtin7gUMzkjVDfUcmmG2BoSvM8qZuAGCgA e=found last=27 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGuAEliEdqZpPXrRnlZ6di5b2/DniM/GlaTSJbLvQFwzWE5/x6dpJFUfw3sKIRGgoAji6udH/+ZiA priv=MEcCAQAwBQYDK2VxBDsEOVdJ2NhdXRt0hxuwuiit1u12zaDSWQV0ejcEfGxjkEpGOD5kgTFWZ9kFNj6MZviCqr3QB4VKYffhdQ== msg=V0nY2F1dG3SHG7C6KK3W7XbNoNJZBXR6NwR8bGOQSkY4PmSBMVZn2QU2Poxm+IKqvdAHhUph9+F1JhQUCAkTLg== sig=I0V5Oik45aAedV/NIi4hX+RRjBb7pdkKC9EeLKMiv3jINBWrNpYCGh0RI12W3Ia31LfZNqrsEFoAoiQLfqB/DIAY43zfiRsambMjUnyGI+Y3mJqr18dHQn9azromvHxYtuUmp9K2ceqR+X44UsT/Aj0A e=found last=27 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7r30W9/z4F5kQWc2Upen+tRo9RidWuDDOq8yVNa72sgjCsZJhgInwapv2W/9O4/fBnjFnwYcqmwA priv=MEcCAQAwBQYDK2VxBDsEOaP1fS92daKp9NQZJ5Zac3Ts1+I5PZJmJshwpcttwhaN2aj8rkKxvonUuwi6SfriY8HOWm5Be3YE6g== msg=o/V9L3Z1oqn01BknllpzdOzX4jk9kmYmyHCly23CFo3ZqPyuQrG+idS7CLpJ+uJjwc5abkF7dgTqEHTKTM2pUQ== sig=/bvJH3E4LOvajAbaUrzmOXoPs6NzeTPhizI3RQmK1HQyDFVltIWW69i1Jzs2GXUJnXDGwnEE6QSAQSueyyBElClkndbDr+i3BPVNLXMD6gpgJIh2rAc1dxqRFBD93C6BRHx5B3wtesqA00PgjlaiqS8A e=found last=27 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfVsHrLO4pqvKpKFh9MokO9rs9RQH9WzaoRhDD7xY/xmjY3Y1vT0uJYGB90ELSKq/cx50fjDqV8mA priv=MEcCAQAwBQYDK2VxBDsEORvtd+K44eD0Cxw2JjbKJbM+HGu8oe/gVpVLKqkehypIW7n2pUhn0p4L05m0L7PeoYi/UWBqImmO3A== msg=G+134rjh4PQLHDYmNsolsz4ca7yh7+BWlUsqqR6HKkhbufalSGfSngvTmbQvs96hiL9RYGoiaY7c3RKOuqpI6A== sig=lo6Wwa9MT0BLQefNqAiGFRPhfQPON3m6dDDeyynvtMmRyMsolzHkanmoWDNzPU2uZw234o9KU1MA6f8fq7kbTBJLsoMA0Us0WR+DTidn7zgw3IWSqj451RANL6jWxBRl3wsScvFAmhmkuqS2w+n02iYA e=found last=26 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApPFQYj2Mh7sLd77pdTG83ctJZp+srgikgdVGtHV7q5kwCSJDCcAHEBDb1bDiXpJqwFyJudTc9uoA priv=MEcCAQAwBQYDK2VxBDsEORfTwIwCpQk+NNA5nQVMKn7XYOalpag/psGupSOt6JCx0hnwqbZquQQNytwXp6qX2dakLttzSSswSw== msg=F9PAjAKlCT400DmdBUwqftdg5qWlqD+mwa6lI63okLHSGfCptmq5BA3K3BenqpfZ1qQu23NJKzBLRh03Jc4OXQ== sig=5JYZQdYOb7lwm3J9bEGsMFl9uch6WIRdshubSOyaNBP/R+TTFaRVWlaH7koCSx0Ab9q4gYGKq5cAWFfTttcWT3hEu/ziOjLF6uffuYZ6ue+y+YiuzUtl4B664IfhiuLytlVJCCiFygt/duF5eqjvXQ8A e=found last=26 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4Fe3M11Jb//a7ZXRMtXvmR59nkahuD/6z9lZilHGRIIG77cpiEZ61KwPF5KB1FKN2WyqtrERbkYA priv=MEcCAQAwBQYDK2VxBDsEOc+Ugy+i3gKBohdZRHciZAre2X/qy0ZiBnyduwh1xV2hlD3bqAu/yHmQ6fLGXE0n0S3Cq+TY57W62g== msg=z5SDL6LeAoGiF1lEdyJkCt7Zf+rLRmIGfJ27CHXFXaGUPduoC7/IeZDp8sZcTSfRLcKr5Njntbraaa8E8Sc20g== sig=X2b9cu5l5bzaacSLNHQWQbQghT9B16vc2ukWLEfn63Ye8f3nB5qJAv4yu5BxVukMKO97rzw1HSSAmcYAK7sG9XLOR0DBZk8OmbmJKDtsLEc2OBOL6SQPK4AGPTwPt1SkAK/8UD4f8eQutAz7oE/g6AQA e=found last=27 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAzjQ+8MSGU6w8beYCHNwkblvVAzgRD4bfc7ZbIALBFShF3ZBa/ml9domDaG7W6HUcs38vGWGjrFqA priv=MEcCAQAwBQYDK2VxBDsEOcYeuTk7RPdIVmRIqUGSFylWf4oU5k350sd7N3KFZof+6LeglVjXrk52tWNDepmwG6s1e1nmCIyQRw== msg=xh65OTtE90hWZEipQZIXKVZ/ihTmTfnSx3s3coVmh/7ot6CVWNeuTna1Y0N6mbAbqzV7WeYIjJBHCMYAx6tchg== sig=wO1obSahf7aSUQDJkANK3xBhuV+IZYuxvPTY3OBVJeGvSbSv+jKluQSEfcB2QmrbfjbBVeQC1uwAxboiZ9KhXiFfsg8ZyecAk6bGGerMoHrZUhu6+mwzL62sv9uoC9uWx+Sltwkn83DlV3iVkGaLIwEA e=found last=26 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAiJ+WiK5KnJ15u5VmgtlfbooCDFPLN+MPxQajmX9wf9jXYZOZLtd/zhnirLD2DPCueQY8ef4lxBUA priv=MEcCAQAwBQYDK2VxBDsEOVXzHroDaMbzTkYJwDOaPSVsNnkfiTC1iZp3nisUlqKFZQxW7n06tVPZSt1vQ7Kr7MKmOBkd4I76xA== msg=VfMeugNoxvNORgnAM5o9JWw2eR+JMLWJmneeKxSWooVlDFbufTq1U9lK3W9DsqvswqY4GR3gjvrEuf4WvJlg8A== sig=Gx37ALzn4oIpFO2st8AQ64DAdJR3wx6UDOaeXK1HcHWGAZjQhriuT/fQZ7v2yBYs+8Dp4QiFyNaAgDaoFcRJlcPVBOMScygQJcLF/BWwRUSMAHP25sTiDxAtiWDcMGOt0o9BpAJr6eo3hYja6I1Zrz0A e=found last=27 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9hbuwtphQBr8Ty00m3GLFgyn/Q9oeE9NMNYgM/gcrjNWkWSATCJx7BgA3RYF90VfMRcUNrgCR2uA priv=MEcCAQAwBQYDK2VxBDsEOSUzv3U49bzdz97GYKI4tsDWXrpP0Xhaohy/HVlI1WsNjNabmWSzYy8Ic46ZmsH8jc3okkgtOxB7WQ== msg=JTO/dTj1vN3P3sZgoji2wNZeuk/ReFqiHL8dWUjVaw2M1puZZLNjLwhzjpmawfyNzeiSSC07EHtZOy0PxtK8uQ== sig=m0vSY4S6Wx+N2YS4auf5GpBthIXMIf78tIMntA3SUV/d5iy/fv7/yNfctz0WQJJJwmv17ckJYL4A6QXxDNTafUvXfhffVUYYLb+UqTpj5AvCXTwsFp9ZvszR82BJ16leKO0GlSbT53clA8NkyEy9YCAA e=found last=26 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA8NuTEeSbwGTl3IRr9Xn8Tj1Ma3r0Icw6O7nH6PEJnea6e/fGPp1Z2fGPTb4XIefDKWknCW/TZWeA priv=MEcCAQAwBQYDK2VxBDsEOcgdpOskbwI5NbwKlVwQBS5thN+3pvV0oumg5G1eUKWRpu/IMJBu6cpXNqJxuRSdndGxMIOLq625pQ== msg=yB2k6yRvAjk1vAqVXBAFLm2E37em9XSi6aDkbV5QpZGm78gwkG7pylc2onG5FJ2d0bEwg4urrbmlwBRLjsWq5w== sig=/sbcSVbL2l+CDemfJemx78t326mFMvpLNNxcyJtqsCTi3GqiMZyJuvznRXG5byQAPyKKDQjvShmABpZblmFq4tWlE/7mEEB0Pzb0pivhcLfg/UK6xdBI4qYU6c0LT3lwe/xCOWvqJ4vDUZZHO3dscTkA e=found last=27 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAcH3/X0gEViMWnugcutNIiTMEun7v9bRGuYYwpjEtMycpgZsu1CyajHp/VbzVube27dOVuNfUnueA priv=MEcCAQAwBQYDK2VxBDsEOWnuDqTBP+tRVdBeqs3IANV+QKI4KmNuQi0MQmMQPqv/hzDZksXY/2Af7jvC0JefW3C4gh0Mg3qwUA== msg=ae4OpME/61FV0F6qzcgA1X5AojgqY25CLQxCYxA+q/+HMNmSxdj/YB/uO8LQl59bcLiCHQyDerBQLrHHbC+7ug== sig=PKZCMEssQ8nbUQxhPzlw0s6+EjEdSv2rVLAN/658yu0jhiaro8sKtDEGV/voKeNXwqX7NETM8fgAhT3rW94FGjHjbZDSn41xiO3sBUEWq7EZ+A9efZfPJPfSZuLCVFVIpfqIngGlhfJCO6UC82Fw5QsA e=found last=26 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOGDwDvXn81ziT5xILalvQZz9uug5DRiyX/du1qhb8uScd8FdT1yK1a0hXgJXofQG3C0IQuilks2A priv=MEcCAQAwBQYDK2VxBDsEOdv/BaSqZA30UNFtzewbTDMMNinfQzV2ldHcG7GxwXveyTl1tml4MNtk3CNx0w3SsQg2BYuPDSmrxw== msg=2/8FpKpkDfRQ0W3N7BtMMww2Kd9DNXaV0dwbsbHBe97JOXW2aXgw22TcI3HTDdKxCDYFi48NKavH99vHgJtnCg== sig=0IgrlAyj7VFbPPep16LHnbKtbvRGhQ5/9o4DxZSsxsW2BNWLas9NMp4arAfjdpPQPbUg5I6N0WeAcrk7l61VIMKjTNpdqzlFQTWD+6xUXVzSfq+t9G6QeErncjmDI0PmlfhbyrffNRXoTvukyEvDYgcA e=found last=25 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoARxIt7qDzz/zv8hdUhVZTlfzp1l8GeF23FTugbrkiA8Z6QecUq1YhTzBqwVGPwMN0nmE+SHxcv7GA priv=MEcCAQAwBQYDK2VxBDsEOTv89Y4GNcnoIwe2xjZ1S/uKdkv5mE4MD11GfOPwUIZj2H+youmAg35vhGiWSuhubhNXeOmrEPFOfA== msg=O/z1jgY1yegjB7bGNnVL+4p2S/mYTgwPXUZ84/BQhmPYf7Ki6YCDfm+EaJZK6G5uE1d46asQ8U58TRmYgdLETA== sig=TuBFmVCNEs8P251m26iXXTaHq6F7HyJu+oi847vgGxeZwmCBuUUthVDP7nUhfyhUB+oJgHrTTG6AvJDp04+BhEj5CPdO/tVkO88o658eHV8GEOzxEgx/afY2zq658S0NpRIehPlWuc3WtOAViQ5ByAQA e=found last=27 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAywAoGNiPkk86ininOVTAKhT7rLHI7g6f3oG10Tem+UrRXKpcWQ74aV9/EpKga9ev0BSunASoOjmA priv=MEcCAQAwBQYDK2VxBDsEOX/T5adh6unS+qMyyrG3hQd4htEsvSVnrUi4WZufrzrnhSKUKVOXXTuIrB/GNVjn/1Mw5ePUjylpBA== msg=f9Plp2Hq6dL6ozLKsbeFB3iG0Sy9JWetSLhZm5+vOueFIpQpU5ddO4isH8Y1WOf/UzDl49SPKWkEvVUlIdmRkQ== sig=Bk5STgBOhiARXA4ej15FvFlpCn2ZoFODlM/2SqPbcxEwKfDJ+2RTRgOp+E4SigP/lfZoFZjgPcEA2/ngoHGRTUUzHfgDDIaMm9D3XatSMskAHSBHJJfXPmzsHl2uXSV0/Mz/UbXiXvD8lN6YsBlhMCkA e=found last=27 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA+zbCepL0k3LucihSC4cgEUlqb5qlyBVniI00MxfUyk7XiYR90O00Qt6Nx6MivezUSMdYmpp4M4CA priv=MEcCAQAwBQYDK2VxBDsEOTPNUFITSWGDbRJN2uvjUS4PI/WC80fSFqfUNwa8csaFV6a00Bo3lQp1XIL9UB3kZWl5SMasuRzBRw== msg=M81QUhNJYYNtEk3a6+NRLg8j9YLzR9IWp9Q3BrxyxoVXprTQGjeVCnVcgv1QHeRlaXlIxqy5HMFHCv6LQxQRag== sig=JkxooMctW+TQWIGLpHMks9bJpujOryJDoE8ciYWFOORYO/OQXbEMU2LyPX/wMPeO0YMMpzZIcFsAM08SvOFm21CgH5OZzOiqoGkpmT4YdxhU2Ee0jq1V3LKloHaJsCuyeo2dMSphDiH83nYe2GxEySUA e=found last=25 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAnXzNeySkWkvNCpyzPvlFo7pebiEBIvZBbRDy82xeATwSj+TaDJmn44pG8qVab2VgJhOa4GWwmV8A priv=MEcCAQAwBQYDK2VxBDsEORMZn7q15K/2Zp/bP2SPXyRs/3hEJCoErRqL/Ytt+ZS71gt4QxmoA40SOed02Dg42A8S5rdXYKlnNQ== msg=ExmfurXkr/Zmn9s/ZI9fJGz/eEQkKgStGov9i235lLvWC3hDGagDjRI553TYODjYDxLmt1dgqWc1RZXuMprS9g== sig=6aObndh7bSpmomJZyOAsPLHEKViaqPySBpAFX5zSE+amwUiBTnkkwTE4+SWG/DIY3KrUPxi1XueAg0lBPQKbP6K6c9qbLLDMmV1O9Tnhm9ioXusjhovJ7vNLFcYPgOI2ov0uRUSmID1fB91vV9U4HRYA e=found last=26 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABq8Mt2BEGyL2b3Hotasq9/r0ZBfzlF+ztBtnFCBN3JT21qRQTIuH9/UV4Wjm7kWXoXhLyFesmhaA priv=MEcCAQAwBQYDK2VxBDsEOaSkKCqP4SzY6wzruYa/EQwpraGSuci4TfiUBSPiufVW5S8oHlk8JkhKYzuBYbT+YGlXXism4ywASg== msg=pKQoKo/hLNjrDOu5hr8RDCmtoZK5yLhN+JQFI+K59VblLygeWTwmSEpjO4FhtP5gaVdeKybjLABKb1U4Kh0AGg== sig=HTEliiGwpAOTcA0JPbxRnKm+wpFl8ycFhOWdee/P3SnDDVTOsH5xvBX2gAJ7+wkkok4UemT9zeSAet3JCOe8gECX3cUHXhZWPJ5lQ0vjjzmZ21guXa7eWJqOl4pnAufpGS09TixD6lT5B7XMSuCyBBoA e=found last=25 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqMX1wloMBK1XnPVSdQ8rZcwjbOVvFX1idlLvXv7omRH4da35CLKbO/Hgzew/qXml+MfrbspQ73sA priv=MEcCAQAwBQYDK2VxBDsEOb3bQbXtHp/JqLuhyb2I7gQV2sUap2dtX+MGu4QCUiBNJROc6ibfnGdUQCU5Wgx9kIhvNvOyygGIHw== msg=vdtBte0en8mou6HJvYjuBBXaxRqnZ21f4wa7hAJSIE0lE5zqJt+cZ1RAJTlaDH2QiG8287LKAYgfssFD4I5iAQ== sig=+kVkht/xdkVOW8CcSjAfuCmrcWvbF7atd+v2sVGvWidWrMdWqBIuPJgsF8kRTGCj10yHVOtUN1aAZnA/nUwfzLsuEV/pe+ZhH8Mi1EEkGLEUMXC+ziB7qjxHzOKO6eaqZkuSUI5J2bQlRg2W46uPQiUA e=found last=26 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUL/SFcMnq8dcQ86Nr6kmDPDbab21ZaiAOgnvZGNHEftJvAY9re8/PS4CwISoWiGj6bO+oeC7WO0A priv=MEcCAQAwBQYDK2VxBDsEOTwzFYgNHJvBLSdVPuxeMXVzC71psC6VeG5vz5dE9aq2qTUlKqVDK5YcsYqBEkhM1KdMZ8yrNTfkag== msg=PDMViA0cm8EtJ1U+7F4xdXMLvWmwLpV4bm/Pl0T1qrapNSUqpUMrlhyxioESSEzUp0xnzKs1N+RqN46FwvuGfw== sig=yNxXCRbmOXPeMpZ8oI51wEjCCxQCeqlyllaeYYURRsg9z1CvZJT1fEoJwdTEqMUR/mj+xhJSM/KA3Rfjoo+tSZdbcqsBvtaG5TYlLYB992YW9yfFiO96/Z9sUu2+S36llxBJvyXZGFhb5UWtccDNryEA e=found last=25 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAb7WGT/R9LvlAW5O5LkIOu8DEsUOpiedWqQc2HFqHbcERi9zmrO+vn7J5tBH9Pji6uLpxjNVNTecA priv=MEcCAQAwBQYDK2VxBDsEOS2o0pCuV9eWBLlhobmDkfTn5PfgXPl1ncOirJMr6ME8t31Vi0vpABg9Y/mqiR+IpNIhdh/iuOOn1A== msg=LajSkK5X15YEuWGhuYOR9Ofk9+Bc+XWdw6KskyvowTy3fVWLS+kAGD1j+aqJH4ik0iF2H+K446fUfVdJr5ndNQ== sig=T/gdY5BgWBwEoaYhDTzr9RJ1C8XUoiL8oIbtDuO1G65tigAYKXq8qrKMc1gdKbKUv/iBInUSdauA26bWs3M5cydAYn1rk+hdcYdiGOkJAF68l1P+JmIfMa1O5V9/nvGFrKOj2W7SCoC2/iXyLfe4CDcA e=found last=26 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAKsOK7PepW+05fIy2I3vM7BtFM2L9k/ygjImA8B1sl2gAm1G0V80oTJb881GRrB5CnspczpbFZ28A priv=MEcCAQAwBQYDK2VxBDsEOWxNxl2FpP6kdavbhe122VkuYScpYD4bGm7TbjOqAhCq6LIB7yLBQ/vpbly8Mm3rdEe22khk8WXcLA== msg=bE3GXYWk/qR1q9uF7XbZWS5hJylgPhsabtNuM6oCEKrosgHvIsFD++luXLwybet0R7baSGTxZdwsZDcpGchFBw== sig=LvJrAZ44qQnMEZCeBfCL9/3mWFPyWX6cffOeAmXwmaeKYefueae308pvOiX432aoygqP0pxWBG6AsbDs+n17YHQgxv/mTi3MTrOZY9RNpT5W/B3mgQevqW3uQIPbjcYwTW+e1IEjtfS7dbDsy7hxmiQA e=found last=27 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAjaCt8xBHtDssrE7A/S/0xVBXgr9EV+GT4ge0fqrLWei60vzK40+Ji3dQj567NKB1qAxzMrRRJLyA priv=MEcCAQAwBQYDK2VxBDsEOUeO/aVbBT8M8PxyNQuP0isdAfvBb9S/kc0r1ueyOzwv7EaJZ3Imch5y+D7Z+sbQWoRJEpCfjgXsiw== msg=R479pVsFPwzw/HI1C4/SKx0B+8Fv1L+RzSvW57I7PC/sRolnciZyHnL4Ptn6xtBahEkSkJ+OBeyLiocVYw+e5A== sig=YcJ3InrqaoUKwfuqSRf1NU9YSc60Hlkeng+UdjUbiSc8hMc7eEjfzVerCOs7lwQOs+D2a29CboIAE/27aKohkIgCPKFGXjxfNbHBCLDE+gQMSY2g40sQ2woyKzQlAANg5akVvl8dyGQXrimudPLTABsA e=found last=26 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAjy5gTE5rGZA9aSyKk9Y1M096JQSEFvB63wZI5XnfIJtC4PW85359cMoGIdzd5rappgqF/osKp24A priv=MEcCAQAwBQYDK2VxBDsEOf1+cimNciS+LPdqk0a67LVVb5l9Q8fxEHmNqM9AMZlnzIzIH0sSr4Es9uSVa5EjuW+TRwZkvGS9nQ== msg=/X5yKY1yJL4s92qTRrrstVVvmX1Dx/EQeY2oz0AxmWfMjMgfSxKvgSz25JVrkSO5b5NHBmS8ZL2dmymGlCDinQ== sig=Nr6+LH6AwZAy+3u922ZvHFMjSJxnKIxcvpUvGsNxOQbn5g9OL8b6CFBLrrfiEB9NGhAY37o+EsMAUc0yce672oSSbBo+rbaHa0mpiIJDQ556h6NsXwKl92AntGgmZIylrFnYt90fERbdFo4RLTR7JQAA e=found last=25 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA22tw1JzmICBZ19L9UaHwGbmEUIo9jAPZcbyKW6xwlv7touBNVl62mrUUkJLWCf8voTeBnggHP9GA priv=MEcCAQAwBQYDK2VxBDsEOWZO/U6s94qbEDR+eysG34Y36F9dvOxbLaJCzbVbu62n/ogegSoK0TNIndwCy9tIKeTvV+PbFdj1Kg== msg=Zk79Tqz3ipsQNH57KwbfhjfoX1287FstokLNtVu7raf+iB6BKgrRM0id3ALL20gp5O9X49sV2PUqJ9cXiFdQoQ== sig=PfkWXg47XIwwZxaZzSVCjHq0gTwP/8nCrF0ZURRhSVFDyi2tasPAaNARXHo4zZPCqNbCBcMfuO2AWA7WsIaY2qAyKR3w9ftv1PYJsXxWDMbmZhYk0NavJo8Zv2tIdpBSFaXXQ1v5zAIYy1/ZXOl6rCYA e=found last=27 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWhTHH9QTQP8hxMR/tbQpLRPJopS1aveeDmkdh1ENjt8f4MRhu4exGDV4ajAOk5v/+j0R0tvQra8A priv=MEcCAQAwBQYDK2VxBDsEOUE3W2LE6Py9VSbPDNwNgcO8mzyLp05aTrCHMgzbEWWN37xGhFR3moxN6HSS3rBRIGjpR4aKdRTaYw== msg=QTdbYsTo/L1VJs8M3A2Bw7ybPIunTlpOsIcyDNsRZY3fvEaEVHeajE3odJLesFEgaOlHhop1FNpjEbZwnsukZw== sig=S6c+4m36qqqWxly1eKGZ8TWIzamifR1RIsGhXMfdCYXAR7KXaUt4y9oc9jDQKBop6HnBVCQagKEAHLAqImRSTswpANQ5Gip4MTOy9tQ0dKLV4vxgnA21ES/ofNjUVFHdQhoTQh9JiVKEqPJliofxWBgA e=found last=25 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAnhrKa48vr4t62alkewDt192cJKTcmNxG/PqtcW2AKLnmsdX3yYv/0ksNmCBVTmcWUAclzxIYvm6A priv=MEcCAQAwBQYDK2VxBDsEOY2DdqLiWKV6/qh9mjdW15DGTpZk4eCel6sPdZAWnTE4CtcqbKjnaFY05m6rFqfI3kjVMfB9FxHqnw== msg=jYN2ouJYpXr+qH2aN1bXkMZOlmTh4J6Xqw91kBadMTgK1ypsqOdoVjTmbqsWp8jeSNUx8H0XEeqfDlWpczLQHQ== sig=JeGc0yvoT2zrbO1hL3Ml02BStEtPOWDSxeUaqY6Hgr0lDT8t1KTI4gEdIuQvqbhdVWZPR9iBmTeASY2sHm5EtDz7HixLmNwA+YN2HEZKtioGX7Q51KRnBCZfzGA1GvD1ZxQ2bHwgFw/Nlgu479pbxQIA e=found last=25 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWSeFyQ7XoevL2Q5rg5pI/eUQXYjU0PnRsCN/fXH4oMACVFDbbNl9gXZC1njY+ZPv/cYdFhKXGhSA priv=MEcCAQAwBQYDK2VxBDsEOfChTyU4Tcg/NolyQc/5fG+sn5SNIf3HzojmfXUR2Yxk8eFUFZOUJT983W9+I3JdfcHV682XXOpgpw== msg=8KFPJThNyD82iXJBz/l8b6yflI0h/cfOiOZ9dRHZjGTx4VQVk5QlP3zdb34jcl19wdXrzZdc6mCnraRnDOaIBQ== sig=Ht1Xg9ZTYR0N0FfmXFVNEkT2h1AJjcxsl6vINhRJulW2dd2VMipDZHYa5E52j2F2Dmv7V+FKtWqALdC5cZ0xGP3Ro5j2rDL9lxy+VSAgy6wtOuIBTr4kPc8Kl6ndJ70wJyCEIidFlTvC9rE+Z5R98RMA e=found last=25 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJQZfP7SRmZP89iJl0b2Vx5c35S46QDHr99nzJ70YvLvQwIgRqNjp5odZjmSYAQYrJlsXABrZWH+A priv=MEcCAQAwBQYDK2VxBDsEOYhPI8cYeyQm8kJSEHWHh8dnhY/8Q0STCZmw4r+a3SFofE2WzE/6KZAk+1Yg4ka60VH8lmkItwYEmA== msg=iE8jxxh7JCbyQlIQdYeHx2eFj/xDRJMJmbDiv5rdIWh8TZbMT/opkCT7ViDiRrrRUfyWaQi3BgSYiki4DbBRzg== sig=RkfRV+mcUN5qGSarscGSOpJETXgZZLzCOewwkKhyPGApV/9Yer+UcwVwaqj5dhFZN/HqebAhONkAA/0vARiUKtCFmGlFlmhGZAWmN6WLckuDSOW5rK/KBCk9tkU8rcaACKZHwG7DNZiLyZVX5aGhGDwA e=found last=25 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoArC+6X5b4DcbtxG5rgmJSFDQW29KFc6GoN9gwbzEVIfi2rkI1AZP5MhZHx4dwl1iJHHOJV4dG7aUA priv=MEcCAQAwBQYDK2VxBDsEOUxAOzGNQkzae8c8WdyCA+vo7Zd9rfALc09glf+rNqgcBByjEJwDhi+KRs6WPttEtoCPDZhYnV1+HA== msg=TEA7MY1CTNp7xzxZ3IID6+jtl32t8AtzT2CV/6s2qBwEHKMQnAOGL4pGzpY+20S2gI8NmFidXX4cVUoeOYy+cg== sig=/cHlo9R3Yod3oeDrsSZ2VCyiv8oH6VmQl4JTw5BVPtLODnGn0g+/HeSd+ZIayGzqOfHcE6zz60IARk6Vn7mvyPORFM//dCIJgoCZeJsTZSN6fcLgr/4YXCejtf4isVgCHakvI5NzstttwzxKGOPRMS4A e=found last=25 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPXCt+cLZ+R/vNQnl5bm9VxDdSP87Gdxcc+NTf5TTfw6LeNpyNHF/XI4+TPqg1n36rkOhLxCoZ4yA priv=MEcCAQAwBQYDK2VxBDsEOZdJF0JEIhYTvkHuvDOzSjkqzicymk4Bsh8BTDyeFcqTjJRL3fKLnYFWtHcI4PUbRggt33jOd/d8jQ== msg=l0kXQkQiFhO+Qe68M7NKOSrOJzKaTgGyHwFMPJ4VypOMlEvd8oudgVa0dwjg9RtGCC3feM5393yNcgh/h1NPPQ== sig=NNvHO8P6EjUYnMpzaTNZyC+2J0BzCw9eGz7nHUfSQ+hrQ68rJR1XTlkH8/1/jHmgd2dpssStAFAAj29N0fSoRxm6xOKERByCNAztAMPVDJLdyw89uBxvNf28Xk66nFWgfWzHATS2HOpYlScsQtsKUjsA e=found last=25 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAh2wxr7WW9H/2/ikz2pUYD7t5Ta3ZW0sTz00Q2oUw1U9DSZiFuXF2Z31beKTJY9PNTHYlrv/c9suA priv=MEcCAQAwBQYDK2VxBDsEObCQSnVqMHsW0JMNkOM0+jQIhL8+PwBxwwvC4ngsb3VYbwgS0jLFiRshm72CE2uFm5Kd1jLoP8pmXQ== msg=sJBKdWowexbQkw2Q4zT6NAiEvz4/AHHDC8LieCxvdVhvCBLSMsWJGyGbvYITa4Wbkp3WMug/ymZdVAvCH7aWXw== sig=/D2vKRGgJ1a0GU1H4YVKn/vr9eTLFuKEpEMufRu85bV91csf7JXbUXeHAXIAp4doxa8SRePJPEKAZIJAyWvmFnLDMpEDpyqV1ZNFeBKU25fd/5iPB6kH6UFo2S+u3/8QVbiP98oSkAmUlbRBPEBWeiEA e=found last=25 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoArR/A6/wuM6IKhhAxzyk3zBia1BDOqDA1xKEz0+aF0DYonq/Mxltid9t49f5wl8OersadNsGweUOA priv=MEcCAQAwBQYDK2VxBDsEOTcsFa77WL7MRJ+6107dX/a6CP/fKsruOmsz3nhTe0U61dNAMz6J6yHK2iGVYoaIhYBbVk4bzNT4VQ== msg=NywVrvtYvsxEn7rXTt1f9roI/98qyu46azPeeFN7RTrV00AzPonrIcraIZVihoiFgFtWThvM1PhV2PoJeq4vaw== sig=Fui+RIJT3RLb8UTkPJl6GuFh25YYunboAQ+dWzAtVkxsDhovFdnmai+UpbvHAJGIw3onMbO+RA6AhunVn6tIdW17KjPpfDWNZ2iHSa2JKIaPNtNjF3ATaW5ZccjiPC44WLSRCWurMiNaYG9udl+qZTUA e=found last=25 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXuSE5382pAP0wxCeAu56KT68jjwpoSjHOVqogGzEDh0mojmPb0bXV2hGp9mJ59cNvpMShfY6/j8A priv=MEcCAQAwBQYDK2VxBDsEOcLlohV9V1dYZSv1rl7XE9cNZEaBAPJVwukaO8XbT8jfFUOGZlgO1myXcBvl4XbTvQ6kC5SD3do6xA== msg=wuWiFX1XV1hlK/WuXtcT1w1kRoEA8lXC6Ro7xdtPyN8VQ4ZmWA7WbJdwG+XhdtO9DqQLlIPd2jrE0HXipLVa4w== sig=WAEBqGG7Bxcv5X6FzUGAOVRHDkPQdxH5ng4QslJ4gHQ7UxHbktsYmXFIPuZdBl5jtGky4NHMJw6A1vVNpSKz/4lW5gynBUav1E1w6Q733iwaKW7oI2ohjV81+9Arm67KIslHmPa3BPbroBz/UZd/cxUA e=found last=27 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAaE30nPcGew5RG4YeWtrA0xP6V3Ml0AztQ7M6l4Tha5JR1dHzsZRYys4SlV4IWx7Cb5vNKHGLx6CA priv=MEcCAQAwBQYDK2VxBDsEOc57hRn2lQLfqGOuxC4XFlsz1NQibGCLO2wFSPnn2uG5+jvpDi3csp79ySIahfkaeWfpk1ElZMO2og== msg=znuFGfaVAt+oY67ELhcWWzPU1CJsYIs7bAVI+efa4bn6O+kOLdyynv3JIhqF+Rp5Z+mTUSVkw7aildSy//pNRQ== sig=Mhlr1VSfkCWXRvzDiKCKkgetdTz58DMqHi3k2JmikS/4r8w/Px2X+WXCe3zougAEn6voaQEb74SAjNxiSpCnc3if2O7QN3ZJmNdHQdO8hV1L8cMTarzyD95RM4qmc4dyhCU/6hY90UvAJwcdWKocSAkA e=found last=27 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAvHrVSPYcmQ8BgNX4Dv4eIzYG4slU4FGgOegyzRjWm2kRhiX2PIxO6Vi8N82/iLhFMDMSXdGqVnkA priv=MEcCAQAwBQYDK2VxBDsEORwxLhyd+zzp6T5LUJizc987CUBjw0NkVE0lpWzEAnYWZhMM2STfsN+hdqAVSQRHJOcFG8kPvpRLOQ== msg=HDEuHJ37POnpPktQmLNz3zsJQGPDQ2RUTSWlbMQCdhZmEwzZJN+w36F2oBVJBEck5wUbyQ++lEs54LQuwqBXVQ== sig=ZTZMIGEazvo6QtfOA5LLqCCA5pwtFo84jV5tmi0daWr6/8MSCYoqsB/P4WppYaHcXApXp1sWQYAARLumWUchbLjAE3zAXXcjswpP0ezSytQoza8JsbxLWNit6JXDtjigdyJcoUjwlcBjBocFHlZnvxoA e=found last=26 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtC9bfaZqHrUgN4PALTi0mWAHLUrInAuChgsunNl78dJbchV4XdzaBRlr8v6QspLIeJhfiPr3QJsA priv=MEcCAQAwBQYDK2VxBDsEOSp9nqdYD2PJaF0RrEXMr+kJWRw0m3SFdkJMjPlFcXo294RdYbnkWnHGQpNBMVSura8J9J15z9BMMQ== msg=Kn2ep1gPY8loXRGsRcyv6QlZHDSbdIV2QkyM+UVxejb3hF1hueRaccZCk0ExVK6trwn0nXnP0EwximxoHhp4Gg== sig=sTDlVqdRV5fg/sX1xMlCBhIbzLnEAuYg5W5zak3AQyau4BE+sZnh6R7ye//G/Q/gBuAKPxlVk+QAdyBmNRoxVRgoJ5qSRShGrMxp5YDmkTqhDgNEuOON9BEqXoLawPsh6QC5bZQApyDdlApoJol9qSgA e=found last=24 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFIM777rsNvfmfh+wsaJ2VqfNStU+OWP+mnYjjLL3OMsIBjsdwoFjKBOVepRnNahOky5Z018vwyeA priv=MEcCAQAwBQYDK2VxBDsEOXyze29hh547Gk3Ok8BR4ER1mZOqWxOFx8joUsKc+jjTrn8AK9c0aREwc3it3qCyTHGrBe16rm0Pyw== msg=fLN7b2GHnjsaTc6TwFHgRHWZk6pbE4XHyOhSwpz6ONOufwAr1zRpETBzeK3eoLJMcasF7XqubQ/Lykvf41AlYw== sig=yzoEVOvY33+l9mdQ0uGSZ0cuaX6oM5tKE5db4V2qxbt3FzCAVbkYonE4ULVmfQ4KbLSdc0h4JxQAxG4zQqA+icEyaw0yvMVfEPfLpLJg1F+dfrrY8T292OnQRlfl3jOjW/ihDuevzDwrRf1SxkR8YyEA e=found last=24 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2ACq27s4chtYQIwlmPRdaRCNPcpVIonK50FJPMYejbco8RXCuI8DMOlHB8ahx4TzAwsiQ6lm9v4A priv=MEcCAQAwBQYDK2VxBDsEOdsdat8udM03wfjloFejCSH9w53AZbRFTmdf/Ao+2ienleBGS3phUts20V8J5jdoCiYdB+f3ZfoelA== msg=2x1q3y50zTfB+OWgV6MJIf3DncBltEVOZ1/8Cj7aJ6eV4EZLemFS2zbRXwnmN2gKJh0H5/dl+h6UekTOQymwRg== sig=4a682EFm73iGIkpglMjeRvIBRli6LRYJk/32W9JnfdgvZ8FjxJ7E5r/LTEwfEKwirJ68Yza5opsA/W+B06xFvGq91tdeW6HrRXbWD7NEWYETmbVSbGzR6MEUWlxYdSA2eTTdImGubnVABchAfuk2lhIA e=found last=24 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9T9iqE6lOBXOQ3XE0W7J1fQM4r+0g4LyZootplGpIEHGe+X6n+Nw2Ali+n8ixokeEzCSXt4mcpKA priv=MEcCAQAwBQYDK2VxBDsEOePpu2A0KkDo403jGp+q+gMrw12OPmYMOjth9bCl8OhFs9A4aUeKNWZ7jOlxZt/hiB2xF1LmAZv0Hw== msg=4+m7YDQqQOjjTeMan6r6AyvDXY4+Zgw6O2H1sKXw6EWz0DhpR4o1ZnuM6XFm3+GIHbEXUuYBm/QfTsL/D0RsmQ== sig=FIvBSNq3ulJDWOfYUU/hkZRE30umwWWhiuLKpAnHDG+kJ6RMQFVI23nZO4Are9KYuHevQXE6TKKAb8csh+XheDX/7wsCBDHwelUlLZEPLskD7MNVgpn6rNGGfGtcYbhwamD/2i/5P9iLeScvj0SNqh8A e=found last=25 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOZQtHt6WI0h8lI9NXGwh9x3bPYMcA7Bbw4AGJaJ1RkZVv9ZLiic4ifgjPh/vjqRVfIMGuJzYrG4A priv=MEcCAQAwBQYDK2VxBDsEOfUBFfTzp6DFxVjzVPi2GUMiu8iqchDcsf4WCoBQJ9VTH0J6GUwYn6udxpx+qt7F00MNJKDHnCaItg== msg=9QEV9POnoMXFWPNU+LYZQyK7yKpyENyx/hYKgFAn1VMfQnoZTBifq53GnH6q3sXTQw0koMecJoi2VcpY3lkVvg== sig=u+1hiIgudvg9MdYI35Zl6FJalqiiP/W3mbhWQYvbpNTKUwgnjfcFaFolqdPJuQ6fJqNl7W5hD8wAQ06bJ7HIHgmvisAfUaAYQfGCMZBxpa+C7+kgUSuCawCCiCQWlqmklBA3BLRCckIpDbnB2QgIfTUA e=found last=24 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtuyFq6SMZvPnkiEfCH+jB9UqjSrYHpSIOE0+9EOzHVn3RExlMgqo0Jf+pr9iLt6rs+A0Mem6gMgA priv=MEcCAQAwBQYDK2VxBDsEOby01MLlBxcroDMETNGo3D3/86TxvTGXxwkFj9mq5aZlG905jZ0m/6P7si2r7hFQJIT50DM1H/SPaQ== msg=vLTUwuUHFyugMwRM0ajcPf/zpPG9MZfHCQWP2arlpmUb3TmNnSb/o/uyLavuEVAkhPnQMzUf9I9p2afApmxOFg== sig=Lj14xgwyjhNONi72xf6DEt7/G8ood7WBmv1w2kYIfZ2OjmU1vNekg/dDN7NM1kNbs1xDl1e5krEAx0lOsBlWwzbyPiS7fuhl/f7OTOlRhUlYIE572zi8W4cm3AD7GVDWK9PrNOe+SH1z5S1j+l6YBQcA e=found last=25 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5X2lHOcsZ6VlIm1a8sP6GTajQ1Gwi0fsXaU2rYIrg3W+uZYNhhfWh1RNs4MBhhbRCvdMnl9PsquA priv=MEcCAQAwBQYDK2VxBDsEObZDnPYO+J5ALQ5NT5J9BvE1xPXFd6AvYaD1t1aul8V/Jfg0x62DIKi69TWI/WSpLsxR+WozV1w5Wg== msg=tkOc9g74nkAtDk1Pkn0G8TXE9cV3oC9hoPW3Vq6XxX8l+DTHrYMgqLr1NYj9ZKkuzFH5ajNXXDlagQo1fKjO/Q== sig=UJq0noKiKT4NomFZMdrbjEjoguXl2NSanlk3vKLnQLdmHlfVWBqsTndfLkVMofrl1cxLnQYedEEAAHlijLhT9Dz7hv+k0vbL896QvNyOJozum3pb4Ov75NTKJyXfgPoJJH4iVFPrTH33cq0/LIvIJi0A e=found last=24 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJvKJ5cBAWBO8UpWI9ZGBBLdvs7W1dapRvdizFrFrDZq74m96A1JV32l8FsTJ1l3HLbFsSTITK2UA priv=MEcCAQAwBQYDK2VxBDsEOcecarvPdPAi0UPej5n9hmrNVofle8ldsmVc1j+Q2iiXk3CGYKFZDOEXHwBMUQ+7EsnNOj10/EYIBA== msg=x5xqu8908CLRQ96Pmf2Gas1Wh+V7yV2yZVzWP5DaKJeTcIZgoVkM4RcfAExRD7sSyc06PXT8RggEo00l6EFqKw== sig=IbjQFkQEBu5RwaQh3ngaDOCXil9z/8FuNhiKkjgfoNWmENYC1uMBTV8oprASY1a7Aj7kt945gjcA49yBqlRgvUVij1ebpZQrbtn8tjy0Df4N6EGV2wxXom9AsRIhqhsd9PJolTL708Dvr8hkJfYSLhYA e=found last=24 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWshCGSbbp52DYMcOluIXB8XK35VVOPpTLpaZQAdQvdMjXRC4sqZ3OlmHHxXjecwyL/3nqO1JiZsA priv=MEcCAQAwBQYDK2VxBDsEOXSaCXlY/XPI3nBCVOJcbvDsVoqaXBq6itvyeXCcY65nU611xZ8N+EU03YvPfZR+GAtFFD1THKBHXg== msg=dJoJeVj9c8jecEJU4lxu8OxWippcGrqK2/J5cJxjrmdTrXXFnw34RTTdi899lH4YC0UUPVMcoEde1SsWX77ykA== sig=dbjCP8a8zUkzffqW2qQ55TALxaQfbFqY/5/yIXq9nsw0PdkzcWhiRpy7LZ+DFlIXZWXl0kRdWtOA38xkbQYROTrPdkci+3gr38TIiRktag4CmmP3on4qNtioOOwW4kcduGlbLx+y4oTbk4W10bfhfxMA e=found last=24 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuP0wDFhZfisaP5FMZ6/EdzM6LehnZ8laogWviRoH7mZ8t7Kx3ugJPf4wA3Oilqg24Uh8irqMbTqA priv=MEcCAQAwBQYDK2VxBDsEORxNCa+k6EszXWc5G6b0ifhw6TYvYnYo8NpbCr6lV/Ix2+VyDycE9NUyB2+bgHs8QjyfP43n5NGJ6g== msg=HE0Jr6ToSzNdZzkbpvSJ+HDpNi9idijw2lsKvqVX8jHb5XIPJwT01TIHb5uAezxCPJ8/jefk0YnqHfrcdXkX5A== sig=K2oIW36whU94A4yVI8TVpUckanOiyuSOHxObYjVvXrx0+v3aGTVeqayNKBdXjoOxIsP347qx46GAa47lB/BkQ+6QMVs6Z3vk8eJ9JI4yxg6nK8hgn7SSNDWfiqVVgxMq5cCFGnm0S+OeesHcIUfruSEA e=found last=24 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAT5Fy3QCrd3PswSm3rxnAuLdGOYRKo8xRhtPRzc8QP7QEdtM2xJGBuPQVFR2wO41KqjVYyomvAtcA priv=MEcCAQAwBQYDK2VxBDsEOScDmiAgxvDKaXWHshp2UjV2fmu8Lv0SPjg9JGsZVshgsSZKGfDbM0XP0uZj5m48Mjjwqre2FziPbA== msg=JwOaICDG8MppdYeyGnZSNXZ+a7wu/RI+OD0kaxlWyGCxJkoZ8NszRc/S5mPmbjwyOPCqt7YXOI9sfOmkdTYW9A== sig=RCyoSle5WbcqZzYzG6SNFfRVaapm9ZgatKa8vM5OUlSMmnbI+a4oyQloNym1K4fi0gBszS/TT8yAbk8Fd559Rs6bMOsb2wRkhJzdQPqGG0jyjBJMqaYNJUc1RU2x8q+D/rIfte7c+ZhHc0isPuUVfhQA e=found last=24 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZpY9vLamaRdTO4rwxjrYhZt9A6auFu4xa7nI1lHM9FRtC3iQHV/9lhVL77izwGcwcUXeYNz+J4QA priv=MEcCAQAwBQYDK2VxBDsEOUYmodwSxRTdkm866XMoU1fg7FjjsyBNVMM4svnMpn5qRYkHxOYoGcIP9xrr7NRuMfgJL/Q0DwXNlQ== msg=Riah3BLFFN2SbzrpcyhTV+DsWOOzIE1Uwziy+cymfmpFiQfE5igZwg/3Guvs1G4x+Akv9DQPBc2VndzfR1ukcw== sig=vVs5XBOOJJMNXhfqCWNqz5E2Cmtafq+AJOkdSZEGSU9UXSOMzoE8vRhth5NzTChPlByayNfBDf6A2KCcqnE0YPlYF08fAFzrYfYR7rkYNZy+agNGv0URT5mnEURMqD7vgzZ3vZiofA8IuKz/4aEEixQA e=found last=24 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAKpe5fFpl+3treGBl7Kt7W/8PzGS2RuEvDL0w128NEcYf33R9nWYemykknIovkZNICE4cML4wDEmA priv=MEcCAQAwBQYDK2VxBDsEOcWifeL270utSTeet/UsMdlbmFZL9+a8i2q5WmOi+1c52Zw2XrVFqA/PdcIFWKr0fN94PSUKzJNoKQ== msg=xaJ94vbvS61JN5639Swx2VuYVkv35ryLarlaY6L7VznZnDZetUWoD891wgVYqvR833g9JQrMk2gpyVhb/auHow== sig=S+FLRElcvocsakyjDTjF3h66r1LZJ7WbJ5CuHmAsLGJrS5huZenwmnsq8ODIVeFv6gnKpA7hYRKAIcgT4NcpQJe1Gsc4lWL4KipPbwSyQ5FKJCDR+1W9ewkpsLBU5ESzOqi8jwjoCIB5gKfZK5m30S4A e=found last=24 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAK08f4O9EpkWzWpq1AKJhc13tID8ESO11Cfn7FxQB3FLnWAV11XOTqgPBMaugYDYM98l7/51wxLiA priv=MEcCAQAwBQYDK2VxBDsEOd3x1joUEt9gYRrDGP5FcOFrHs4TDl7mUKTtcSyxKjnurl8WDUl+6XgeMbqg9rkBya7YBxY0BiErQw== msg=3fHWOhQS32BhGsMY/kVw4WsezhMOXuZQpO1xLLEqOe6uXxYNSX7peB4xuqD2uQHJrtgHFjQGIStDe32xD9UDxw== sig=ohJZUJ97hlDs3ek+9xbNPfG7BjRnFLKK9mJEFm8JgQQU3Db+/h44SONVsexnnwVtn38J1ATxTvKAGpRBxZIZy4dLKiRb2bNM+eoGpzL5vC8+3p1lYLUa9Gp9PtlSIr2jfos8Mn4piqGCnWSYKl3yvCEA e=found last=24 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAf+IxRuk2cFH+IEwQBdCL7dhH5KIIHod32aOgZvDMMraSa6EdbiWWI2PwVRxS9MguWHZKJyOjv1YA priv=MEcCAQAwBQYDK2VxBDsEOXxOF+vZn4aZU7rMfKWP0jeiwLCDZI5SbVevPJmkEaVwRNWHK+53wdX0jlgXaLozZLt93VGZsNz0dQ== msg=fE4X69mfhplTusx8pY/SN6LAsINkjlJtV688maQRpXBE1Ycr7nfB1fSOWBdoujNku33dUZmw3PR13XDwhqnkAg== sig=ZnCKEM6GTcjg5n92xVHMEdnMaUQS6EdokVrjBIBKO4Qu0ZZxqFV9A2K0C3T+l5w6bgBHv8SRNNWAWMTFJKelU9XDqBrJxPT9KTas37quAfwO4NgvhBZuKTYYz4DHZALE8VbXrzD7g7/BgMv2KBPsVjMA e=found last=24 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPPPBDxEmRsx9Mv2iGUPv/iYF/C+gEBMx2h9p9k8FH6nmqo3RTJO9gqdaBwZMFsZSR982dVqVvl6A priv=MEcCAQAwBQYDK2VxBDsEOfdeuLYN1mJYKuDHy72/s7hfoEyWJ3Lvm4aV/A0PRItuLgH6TBnLazP/HGNE45LfULLAn9Q0j1CahQ== msg=9164tg3WYlgq4MfLvb+zuF+gTJYncu+bhpX8DQ9Ei24uAfpMGctrM/8cY0Tjkt9QssCf1DSPUJqFzQp/STpx8g== sig=d3KgKwK4B0dOEGYm6+lDtdgd4HEwQ7zWoVSeTsmz6eaUGrbkdEBUD598iOqn64djE6h97cIJoCSA7sXyZP0aAfFB+uDnTKHC+o9Eg0T1s3M6Tgc+FCYy/OYaG4SJcmnHSNqlUD18Vx15IDPy+jgHVikA e=found last=24 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXskZaFvFU7BMIzjxRedI0YFDZcw+GkhnB7pJcJgXLt6MTfSopjhBOfhJJKQzNHW135dWOx6hWYCA priv=MEcCAQAwBQYDK2VxBDsEOaMzHNCqUFevtqvUlh5uhMMkd+CrBYBXgcW123dbKel4cJtdLp+88H2OgeEsW3sDagF4mg8loHtvfw== msg=ozMc0KpQV6+2q9SWHm6EwyR34KsFgFeBxbXbd1sp6Xhwm10un7zwfY6B4SxbewNqAXiaDyWge29/eUh1slkJOA== sig=Z3t40m2XGfA0TXknG4bqdlxkY6FNnAIrz4Y0RjyXO2duTkrxBq9ozxPjJ3E8y2KfMAo8rkQGX+0ASU0VylvrFehMMk6kUhx8mVw4uzIxU10F2neNHR+BXxlKZ9ttiq70lC+Lraocee4F4JnLB2K4iAoA e=found last=23 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdp4XIYapgQKHeQJRocW4BnktB5Xq2B0qwGz5iQhk0Ui908MDeNMxEI3jTTxxPPR5pXiUIHNmNNqA priv=MEcCAQAwBQYDK2VxBDsEOeSgZHjuzb0uZ9eUYKFk6HyM/kgaSxeHRI4qbupwLMzXNnDPs2VNQ5Fm2cJ0ELbFeG/f4tJVLFjd8A== msg=5KBkeO7NvS5n15RgoWTofIz+SBpLF4dEjipu6nAszNc2cM+zZU1DkWbZwnQQtsV4b9/i0lUsWN3wwmHsPXDRyw== sig=05qf+GAS2b23Hu1aBindcxuiUpF8yDJ4uu9BRKxtWDzTaZ87PGqpjZMYJ3KjtnPJMow1bnIauUuAOCOJfL5GbhP9K6xcpge54kKDRyIL5ZR3LkvFhJaXtVmEWszGOZsOUtmyjTOSt1wZSy8jGiSjFgIA e=found last=23 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAe2z2oxZf2ALNBqOZcSW0wcecBF4dnUFApgwMTKFUp5wBouT0TGKyAxftR66d/Dw+g/RFDge+O0KA priv=MEcCAQAwBQYDK2VxBDsEOSu5BQeazB5tV2CXyjFnA9TJmWL/fa6mxvYLn9uRoWykrTPoayvOEbpZj4GOdyaqV2icPOPfxuCHBg== msg=K7kFB5rMHm1XYJfKMWcD1MmZYv99rqbG9guf25GhbKStM+hrK84RulmPgY53JqpXaJw849/G4IcG4iQP1whjkA== sig=YXUQohq2KH2FtfCkpCjR3APYFaXTqXw/9lHtu2tFVBWnyhJ6oqKD3kXCIAwaDhR+xzGnBIkriFUAEJ7Aya92GJqKWLn7Qxav1Zxoga31GhklX7/mz5jUFI4yYVzuNHj/h6j/+R81qQQ4J4nVo5O9SA0A e=found last=23 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApQCLxB9HZb8owpeZ1EKyUWqz1k4ywwLcAU7OVA2IRBQwHe054aKinphYpocPOsR/930Ou3xfx9CA priv=MEcCAQAwBQYDK2VxBDsEOcQI+qYifoHJGffFUpMHn+cBOsP9+wRNbsEX85sr6iVnUAT+AZzdfQjoGb0daCFOq8J1QOM6iz7/rQ== msg=xAj6piJ+gckZ98VSkwef5wE6w/37BE1uwRfzmyvqJWdQBP4BnN19COgZvR1oIU6rwnVA4zqLPv+ttATSYxFkBQ== sig=GqETvHNH+qKtROXXnTFFG1UQymtauG6kt7RuvfkQrLIGseZIbn/SlaKk7qUP7kDoahpmc4x/qf6AAQB8I9C3fDOoplWOdAw/ImL0RyGpRpZpKxjZALBQdBhDKlCPoSVNHyjgOythGCWm/bpLGM/kITYA e=found last=23 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADeiE/NcjaOU8fvAidCHCDg0jtjrMAc1qt2UTM9XpOib8I4eMXZEy09nPON89zmVzyTk2fAz4qTqA priv=MEcCAQAwBQYDK2VxBDsEOS3uHRdlQRjKDMEA7mZUk034rLYuLmayXHpJYmoez2yS6ME+WPsZz7agk+kZ45oFNCXAhgZ9GqO5uQ== msg=Le4dF2VBGMoMwQDuZlSTTfisti4uZrJcekliah7PbJLowT5Y+xnPtqCT6RnjmgU0JcCGBn0ao7m5prHtk66BAw== sig=hFn2ORHBBHCf55Eb6aa+4xf7BtHmQeSzkEEV3V9U4DLofyX/1LBClnZ+jHytaU8awc4+GHewMUqAcG5keR9OfIEwgXaGkJhEKZcC+KuuG/QinRB+sRbQRu8bXIqEVIH9dwP/+ddCzvvo5EVbzZzsPxEA e=found last=24 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAcDZopI4WfVzq6br3c4HIapx3Ay0E+R4u0XThOsVEamn+RXqOCXX24aschPTOkrV/7adg+6b9AvCA priv=MEcCAQAwBQYDK2VxBDsEOf73EHWv4ZJi7NDfDmYdVUynmUx0YfcZgFIVx3//vQF3AXLCYFaBYoRkx/xyPGU9rHqVEXVvfB1UhA== msg=/vcQda/hkmLs0N8OZh1VTKeZTHRh9xmAUhXHf/+9AXcBcsJgVoFihGTH/HI8ZT2sepURdW98HVSEzk6wFj/x+Q== sig=iOn1ClRhR1gyC3E17FCkdZYOWBmPxPfkjfoLpxKUGJWiiICILzkU1FLjlWbplXLbTQ+qy74ki6SAcu5b3srBFIAs+2uya6f+xGhzaJsuCkqHgmlC7m0IjTTZVdSPr1pCDmMWeL3xiUlVkYJ+PIsv/zgA e=found last=23 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAR28gOd8+97T2GNAIi9FLbvGZOuE+khX2mUsNXkpjd2bFKCbk4X491fzVX/Iw3iMV9Zmyket/R6YA priv=MEcCAQAwBQYDK2VxBDsEOXuaug8709+pztlieM/7UhqJt7/JbPz5MMWODJwfFYR9heHdZXvlTMW5+sWX8BcLj9unsyEhfnkcBA== msg=e5q6DzvT36nO2WJ4z/tSGom3v8ls/PkwxY4MnB8VhH2F4d1le+VMxbn6xZfwFwuP26ezISF+eRwEdymFPBrI0A== sig=x2+2+zS9GfsBYLQG8M5LuGjBysq2aiVYH1ABz+LUcVA/64BbVqAzpNBv7c7ygwrFatzWBFk+ZkMA0GPrZmqoumgjtATOMaUxnE0JGLYZJk9L2dC/MOUoluL1dwuo7sxJ9loWW5YOy8+RtFZU54CfLRkA e=found last=23 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbkzYn/Q5R6qsW48SHB88dVF0hKgxieSbYpjqum2AMufjupz1ikTCJxime3X8T4LEwahUVD2OMqSA priv=MEcCAQAwBQYDK2VxBDsEObMaUo05vJPehvoUz7WoOXPC3VFhx75OmbE5QfbH5ROxugJQmFNF/pDH6S7YASoSIl+s8y4mSlPa6Q== msg=sxpSjTm8k96G+hTPtag5c8LdUWHHvk6ZsTlB9sflE7G6AlCYU0X+kMfpLtgBKhIiX6zzLiZKU9rpGSVage71AA== sig=b7yxvs8fVuH2tP08b7j1QHVJT85i3dEAlAnya8RBuPHGYamSc8R15hUkWPGnl8blzF+YlmqHFJgAyjqCj4sIsVu0NgJIYByRY95AiUiBgXNmTwbXbpWoQpO0bhOpAoxqdgfqvDL/mu/gWJGJm0cT+AoA e=found last=23 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXjiGE0LOVnjN6X4mcpZQKiNs3SRGSJnkmiYUqcV080vRz8P0JqlZgrBkFLycxckqYwIvElRhmjWA priv=MEcCAQAwBQYDK2VxBDsEOb3xsuy9Q2Xnej4IdSGln92AL0iT4AQqe6OujxidB7tfuF243DuV+OC3vE1n1XjqT+dUslnGwOrZ+w== msg=vfGy7L1DZed6Pgh1IaWf3YAvSJPgBCp7o66PGJ0Hu1+4XbjcO5X44Le8TWfVeOpP51SyWcbA6tn70er8KqLV0w== sig=7lPGVnH5++t9TDPih5umfkkOr9GjukHv6f7bM2e1satpIb041IMyW9tCi59dGuOeJq8VP3kQ+ayA+frPEbaUUScetOgBWWgmQ29xy6tzIY8DHF3dWGlpNBnSGFph87pYnD9V/rJ8blZver5vC5b5cikA e=found last=23 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoARrMSVa601qMd46EvQzz4abPzfVqfmr2vU9wqjjmCkKctbPhLOLW/cSt3nEAarMrXqHwb2oERbMwA priv=MEcCAQAwBQYDK2VxBDsEOa9dXO7fhblxMjts8YWLh0MnJETaaE/CAL0xhVws67VdYXBUclbIl5F5TdE/1yJVo3wgFLbmOX0Rhg== msg=r11c7t+FuXEyO2zxhYuHQyckRNpoT8IAvTGFXCzrtV1hcFRyVsiXkXlN0T/XIlWjfCAUtuY5fRGGIrLZOk9GFA== sig=K+KnjfeH29Y6UzIFyokm8CADQ5ZsGD0ntHBmZyKFuMK+i5dHjj/E6N0RV/+dAMYrYZ9COHWgCsEAo1vGwusJc9OgkQ9iynNmAaP1Om1X3FvlyR3Pg29txFjotpgdVd4nt/Bv8zkEgRwnLCWyzyx67B0A e=found last=27 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5M2bYbb12st0aakEb6Elkq7kh4BpZppGbiMk3Ba+MBjEmERPkLJ6d4G5gEXMj1PTrW7V7JIi3oGA priv=MEcCAQAwBQYDK2VxBDsEObN1QgYhBMTS/9dC1KMj4V8MLPLLbF8xNadweEQzn0ne4Cy8v5ryQo1/8wNvDb1Awytfa7e2g+zWPg== msg=s3VCBiEExNL/10LUoyPhXwws8stsXzE1p3B4RDOfSd7gLLy/mvJCjX/zA28NvUDDK19rt7aD7NY+SPlX2RawlQ== sig=UD3+onB4AC4R121Ew3M6uhGAGJMD7tVEqZim9yqAEcVk/stS6CYtdN651WC7mcb9J2yd+BhrPbUAhlL/6p6tJRPdFqTDZJmY3x5LrKzhPD4E4qaFIlm5vU+YbxA+ZeIqywr0JGx2rLJoHa5kLt6wQxwA e=found last=23 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAlqV7W8WOiiL91SI6xkJDkPCmLdBXM7RF58oCAoek5UYJ48TvP8WKo+hMHvCvjMqOlgicE+qv43oA priv=MEcCAQAwBQYDK2VxBDsEOdpgsoHKdIEMy3qY6Nhxd+xQCRzo423h3HhkBEjEjODdcbv4N49B2Qj6c9T/ErU/pVj0BPmwInJejQ== msg=2mCygcp0gQzLepjo2HF37FAJHOjjbeHceGQESMSM4N1xu/g3j0HZCPpz1P8StT+lWPQE+bAicl6Np3It0IxvOw== sig=Wv1xVlXmkcEJ0/556tHBJzOi4z2g2pZ4Je2UdhvrqZURqxqzYy9IzJ97VCnkzTyInCNfbYG6gOMAZqPoJVr7JXigL3U5XLfmq4yZ4fpHCnNitagjphPYiO1M7kp6IGGqvMby/DHn0b25qVXw16xkRBUA e=found last=23 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAq30EjRUn4iEbl0RpNpyx/K+JieW41F7WWcuqcuV6i56WvrqGxUqwqHf40i0fAmC/tmRKl8PxvgYA priv=MEcCAQAwBQYDK2VxBDsEOYVopxBvR6G2ghS1wbY0P5CMKVZgJU3icYmYYMGru2/KpRD9CbQEbPSg0mi/LlNIvjfJglGG7ZxYow== msg=hWinEG9HobaCFLXBtjQ/kIwpVmAlTeJxiZhgwau7b8qlEP0JtARs9KDSaL8uU0i+N8mCUYbtnFijVxGjdJWyJQ== sig=QmdF/xjNRkaeEm8wTJnzh8e2+mSR4u57yCU/9aoFq458WQRlUDauxS0q/73Ymh14Y+L3zm3WBZ0A7BJZ5nZYVxHfXnzCKYGysA78Q/htMFZWy5TLfKGg89LbFXsW/r+TfLJ6dlwEw8+qTdvrmOdNsx4A e=found last=22 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGrk/pNQxn7T5YwGWNRu9SQCpJgWnQV9D+2Hp4bdmxlXluDTcvNsItFlvmvtwq5TwPvkkxzMnGsOA priv=MEcCAQAwBQYDK2VxBDsEOcw3iEY5zqoCEGU9iBKPJX1wjhOHIPQWXbPROAYaWACiENdfJpw2+LwObg1q2ZV9sMQJM4vDVTgtPA== msg=zDeIRjnOqgIQZT2IEo8lfXCOE4cg9BZds9E4BhpYAKIQ118mnDb4vA5uDWrZlX2wxAkzi8NVOC08SwcWbzurZg== sig=4jbZEcAHggeNdq9oD5y5K8KgIvbj8OSgsXteJebuk05N0LOuC5oYwJSqMVCIx5wFqfraN/VEzwYAZ/+/+G8C+eYpb9v5U1ZoaD83b7N+p+3gZKlz+6qjkszkwJbPa5S+T19zAxEMcnUlSBJX/V9ZrjQA e=found last=26 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAApe28XlHk90J1sjzLXmXimRFTsKF6LIRU73sGGejPaCDHJ9EJgNltPlleozE/MR0ah9RIl7quX6A priv=MEcCAQAwBQYDK2VxBDsEOdUE6MsdcLtTA3gKKdYziuRDBdAI9tMx6Bf+rQT848LQprEwuN/6ZlSC8wigej5z7iJbK1wza39U4Q== msg=1QToyx1wu1MDeAop1jOK5EMF0Aj20zHoF/6tBPzjwtCmsTC43/pmVILzCKB6PnPuIlsrXDNrf1ThaiSamS72TA== sig=9Pl8oVFqDHm+rTG0NPdxOlyM+qny4d06EBpkLtjogsvYb85qB2Vo7GOYIj4P8zHF0M7qOdsGVKEA7N0YzoElCc8BAWLN+9GRpgsC2YXSjpyH6OkD3Hd3owcWVJbA0GoZf49wnHSMt8WShp+WvGNQUQUA e=found last=24 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAnodQ38KxDm7BiqjZ85M4prnnlTZ4+lwltTcTGBe4rO/jVKNWVNglkbWOH5XU1MwSZcOQnH4AkIqA priv=MEcCAQAwBQYDK2VxBDsEOe55NkeorfF1fz08cQstdcmjvvo0YE4sS20k/gHO1u0738yrMtnKkySmjh0xH4awycZ6KVavmaA08w== msg=7nk2R6it8XV/PTxxCy11yaO++jRgTixLbST+Ac7W7TvfzKsy2cqTJKaOHTEfhrDJxnopVq+ZoDTzPoP6Nl/0eQ== sig=SGdCIwFT6KFU7F3x/c3Exu4LfWWM6njSeI4ZiJ1phwhkbEYP6JDmB4IGiHqxqRi26+0WP1EMESoAtV0UDrV0JymJZHEbhji29BmhWvsPmxObyMZ2ra3vU1yL15XrAP0ySNEAtGnjYhaVdpyrVP5xqwsA e=found last=24 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAYSm4ifAK0oGIgFkogiUAVWZB4WsyD30jd4JIG384lvkZzsDHGhKcaBYgM2LTqNB5p4DitES8qTuA priv=MEcCAQAwBQYDK2VxBDsEOV1luKD91lIXy+5Oudsb+uav+Zs07XGp4/mVRsNiRDjdBy65gtkuAwvvAiRjzS5G0ANbms8F4rPJHg== msg=XWW4oP3WUhfL7k652xv65q/5mzTtcanj+ZVGw2JEON0HLrmC2S4DC+8CJGPNLkbQA1uazwXis8keaUymKYP2ZQ== sig=QcgnVxuRr5fEI2BO2E5efwuHeUkFKJQknNaRjbNN1KMPd3w4bpOwdEtkH6ajJ5tUPRO00qPwqoiAzHLPgHW1p2JfDFZbvjcXDaAuq4+gC4PQRRdKykBcUFvSrIPts1WIA1rxm7ElsT4yZp9bo6u2szAA e=found last=23 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAlvBCZYQ5lvzLChSzb/Mh2xj3kIfPNAi/L0Fv34LJlCPJDM1IK3Aa0T0NH6QlWjMPVbzygVp7DySA priv=MEcCAQAwBQYDK2VxBDsEOSF0c5OykIl6JTY0Gza6PLuAp6srfbf2m7ZP3cQ+yg9NCHpa5mMhXx9P+SA+VCjVPybfKg+zyYXI6w== msg=IXRzk7KQiXolNjQbNro8u4Cnqyt9t/abtk/dxD7KD00IelrmYyFfH0/5ID5UKNU/Jt8qD7PJhcjrWVVTeZ0j6Q== sig=a9GAgi79DRehN+DhGjxKa5LYfIJHnmgPttr1sIANUkN5YlEAcCo8+1RGctICeyL2U4GWGT6KG5KAx3Tc6scbOgSR6EDupzOlPXQtJ+yg4MfxJv9plwCFfT+K9t0AsTcbE5qBmTes9bTpdIcdidyXJzQA e=found last=24 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWS8Yg66lAJBnz3XYk0k/GH4dLOYRhFSSHaNPSJZ6l4zg/qJvJ71sSjtvu0r2/YCxbD48yG7myDUA priv=MEcCAQAwBQYDK2VxBDsEOaXe3eOwGa2GPHZwnt4pgiDgqATwhHTzg+LIg9NRnFEOG4CudXVaZDmJdn1n5KgdjDMDsBKUA7Sreg== msg=pd7d47AZrYY8dnCe3imCIOCoBPCEdPOD4siD01GcUQ4bgK51dVpkOYl2fWfkqB2MMwOwEpQDtKt6c5d+DhA8Zw== sig=7ppONXIgxNUbKkVdPrETLPpqcLrcuH6xopxdb5rl2dFDDb0Eo8oofDT1VdT8A0pYPvtL0UYEVggAgYw/QpYioXOaZsvBqT7/aRPYSyD5w1MtbolWUTsGE+pwkOlAVOdSCKGs1R+iwj8pt2fok+NEDCAA e=found last=22 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5n6tpqdeTIxXCoI1spKHWXWCkDhatQs6PBbgCJFHUEFoukSEARm9B9ud5F8gqtpBusLyIz/fhcQA priv=MEcCAQAwBQYDK2VxBDsEOREeNvT3Ko/9DJMJ2O+5dM9TgaimK04eiiUvwRMDRuKay2f10f2wgOgMCPMdqpy286AZh9DwXqYXlw== msg=ER429Pcqj/0MkwnY77l0z1OBqKYrTh6KJS/BEwNG4prLZ/XR/bCA6AwI8x2qnLbzoBmH0PBepheXxco0BOmiQA== sig=pdbb41AsVXIXTPL162eNWCqgpH99qbOCurjE4gnq8kTgbg6omDZAT97Mqr25oQTe+ZE+8LfUJUEAgKYTi+EkHo/erfSgSSdeiAtFllgb73NoxCUSZIUzBCRZqeeKuKLiACyNqAI7Rh2y1XaORGIhuTUA e=found last=25 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAB5bwZ8mhkgIsVEEjV9JB4Pt1lyMAB44IlLpuw9yAKp/SDnihKaWyvYxQ4eQ8o9ckHGCn1t/qLYOA priv=MEcCAQAwBQYDK2VxBDsEObDDUhTLfG9EgWi2Fs47sdkbCHPo5C51Dj330+5ezMAjEN89GVVvlCSetjgDz5fu5jLj0GJa7yMqAw== msg=sMNSFMt8b0SBaLYWzjux2RsIc+jkLnUOPffT7l7MwCMQ3z0ZVW+UJJ62OAPPl+7mMuPQYlrvIyoDTkm02WyvWA== sig=iu8bFJsZq0wKtHHBK7cEekAJlwC/0xpoIV2eg1tc5vrRC+Jyr8DiOrjD3vA/X1r2uQ8jjcOzEbwAzemNVGvWDeRjmMIBr/9pOYIyS42NXHdotOKTO+nNAEkv2dbX/QM/Cigh6FHHx318dv3b3ztY3TMA e=found last=22 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADfDUEip0PS9DuatDmFdWkr9hlkExW0uQ19+bOhPikYG0YrJfEOfhKW6SGlqL7lEuawomnLgpPakA priv=MEcCAQAwBQYDK2VxBDsEOVKbDNv+JNvmBzDdrPHJjIKCRQAit/G9vhKqHM/cITdNKq7OXBmsf+PGdxtKPr1GvkHwevdbdmQbKw== msg=UpsM2/4k2+YHMN2s8cmMgoJFACK38b2+Eqocz9whN00qrs5cGax/48Z3G0o+vUa+QfB691t2ZBsrr0cNGcd4ew== sig=qACSMaIPNSVEJ2q/qTxrIHBlzCvg6hFx0bmeHSqqlD30lq8mri+szxDZ+Ma1HVz/nVizxKQlR/sA2ABV3ytaClKhXk/iIqTbxR3K6XOIGzOkLWAy/0Ei3e0HUicT/IRuTB84rAOXGno5gVPw+gqVqSAA e=found last=23 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA31Vw3TrI/khsdKVj3fw18/OuGJV2/nAQVwoY5D64NsAz5JUEkvi4zBiyhakngjZllBZxltoXlXsA priv=MEcCAQAwBQYDK2VxBDsEORdkZzYf5W1bhuxzWaKKd0O6bCnWyOqTYbe2L/0k7fynjFz/4XG3tAtCBHOSVFBTrbN3BXIAaorjvw== msg=F2RnNh/lbVuG7HNZoop3Q7psKdbI6pNht7Yv/STt/KeMXP/hcbe0C0IEc5JUUFOts3cFcgBqiuO/vBb5TPSH8g== sig=AIqRIowpQ6T9oZeE2v8iv3RwsZf1SM5pftq6N+wz/6YHhASLuoPsflIx5zTS6ao6ePfbmv3ZIOwARus0qegwCvAeS/Uu1bRkURkH2EN9EnaYYadOzXrcqOrZPUtNiQiLZXUg8FF5XSey/z2YdEvoXQoA e=found last=23 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAx6Xp6HPCWLg9h4Ir7C8848O4/Yat0BqVRPxyaPP7hU3UUZ2DoPw11ryUmEl+GeveKrs+HaNKJumA priv=MEcCAQAwBQYDK2VxBDsEOY/AXDgnwdb0rGkLo9oMW7svPBKMrlqMgX3yReWp8G75nW/ybvwas9R3/rVortmA3JhMy3HzVKqbMA== msg=j8BcOCfB1vSsaQuj2gxbuy88EoyuWoyBffJF5anwbvmdb/Ju/Bqz1Hf+tWiu2YDcmEzLcfNUqpswDmJnqEHBWQ== sig=EZVPi5KZZPqnVdkttX1SKw8kW8TbVFSJVVwQuy0yilZnjh5l5pg8KL7zjstmoXFP57u66TVvzugAvyAkTaqmylKm7jNzbsXwESN+FckbP43GfDpKkuVomv8rUIyPZesRs1Nn1K5rCFWoIA2+7lFvsSEA e=found last=22 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtDFYwMNWf+irCs5oTvZ/t55nQ/bdJQwvY+dhm05UTGktTrFWY2KNQTpUxhoaQWUBJu7fDLOtNpGA priv=MEcCAQAwBQYDK2VxBDsEOYtTwq24XEwr3NhZT4OVOzffmYNMV7cTr6m5nMFQYqROluv1cKGQh2WRREIeHegHzQGg2+K5Ol+IrA== msg=i1PCrbhcTCvc2FlPg5U7N9+Zg0xXtxOvqbmcwVBipE6W6/VwoZCHZZFEQh4d6AfNAaDb4rk6X4isSDPnw6tVeQ== sig=Yf4BHNC4o0sMU61BI1uYpsOfQzOx8SrDBaI+11vkkpb4jdbQ2BzWKAcXFZKHFos5YxCKswdaWqSAF+wfUd+WYJmeGs7J5Db+m9Z/WY3a4bwH9dfwbSPjShXJyuWpGt0uGXBR0u6XDs9ucbWvbpz7aSEA e=found last=22 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA0smWnjsBC1NBmYoFkspyJpizc+vU9scyUJWU4YSPgXAF3be5PvCUZnCAMeyagVN/gnmZS++AUOQA priv=MEcCAQAwBQYDK2VxBDsEOQi+aAzUZyEFXWPMFthDxcC7zCAuyDAmPObGUuhJadM4+lSjSyYc4KMGL8iF/mjo5Gp0Az3fMHM4IQ== msg=CL5oDNRnIQVdY8wW2EPFwLvMIC7IMCY85sZS6Elp0zj6VKNLJhzgowYvyIX+aOjkanQDPd8wczghmy4RTZRMxg== sig=odXPK7ZctqDYvQjTfU02J7DLxoxPzfc51vf5rvfcyQ5u9wO6ipTwi8+29ox3GM6d76+YLdta+bsA7UScOnW2Nh3lW5RYkRm6Yxh7e/JKX8hygP9oX/W4E142y4rWmHHz0ia/3aihdKJdYj+mnQo5PTAA e=found last=23 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAurkU00eMdWqPcqScM+Jx2SHcBM0nY19C0Xpn0qls6tgy1TkwZ/1S8WzKdakzR1w1g5KtP3VJSMkA priv=MEcCAQAwBQYDK2VxBDsEOdV3eD2wO6zz3XTonQP/dSf4YU3QTpe4bDgv7yKzlmYgvIZuZBVfBVZu4ETdeJdVhmOOTcDzBZNCbw== msg=1Xd4PbA7rPPddOidA/91J/hhTdBOl7hsOC/vIrOWZiC8hm5kFV8FVm7gRN14l1WGY45NwPMFk0JvZZaRT3QPDQ== sig=+WdUloHys69zLnjq+xPwbAYlznm/vJa+xVAp2yXEILVUOlokkX9gSnwFJG9NUwXQBW4ID3lhC+4ATnvQwLDaSJv/uwkL4xklnaV6W1adn9VkPGllfS0twD7fg1WlGJwh7Sl8FIEt25jPpwFkQtxXDA4A e=found last=26 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMAEC2bZrtsu5zWYl/yIaTRzdhO92aIz/TLuCKobk85vGtsZWn7+Q+oapHuVMBIK+f/wLy5yhl2SA priv=MEcCAQAwBQYDK2VxBDsEOVSK2wpaL43SanxIIuClLDalBt1j3vs3m3NMacbYGM5KWa/45tD/HCEBravJ0R3tU4TSXqGetZC4LQ== msg=VIrbClovjdJqfEgi4KUsNqUG3WPe+zebc0xpxtgYzkpZr/jm0P8cIQGtq8nRHe1ThNJeoZ61kLgtQlKLqk8obw== sig=GnL9scRKU+HXZ/iiHHwx9A2Mdgbbn9gGq3MPkdBlDGx7o1KQrayv20BSivxZnVOIoEfz8DOStk8A1YaeA8F31PDG9wK0xHNB48dMptggYUiG9wdrkfxzRRKSmx3LuzT4QtrnopE4Cjtchxk302toOj8A e=found last=22 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAHngW5pL4VhdMjE7LJstNoATtQuK5DGrMFT0ORxHVAW/5wA4W8Gfvw4Y69xKP/xAkyNWsag8LFw6A priv=MEcCAQAwBQYDK2VxBDsEOdRpmQGiLesYPtq3+ON9tecan1IIToeWA00fkmdd8TUMd2yzJW81TigbfEL93LfOQIYRMuZfKkBgSg== msg=1GmZAaIt6xg+2rf443215xqfUghOh5YDTR+SZ13xNQx3bLMlbzVOKBt8Qv3ct85AhhEy5l8qQGBKwFaq3sRftg== sig=n9UfZld+A6lXTmqrwR40gSgdlvFIvvPmr89wo69mFZs4r3IjuZaq9XY8abrdDwkeM0LG8lmVj3GAVK5BDF1mZm9bWDn76tUjke3mROO5TLUfM//UKq1Gai5jdPLcRAkiB9Gvc5l7uGByOn4HLxB5VBMA e=found last=22 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmkCmK/b7TD10/qOCbaLl/3wZ+P4VTuGpJKCO7sZtpg4RGeRlbxiv2xzzo4Dt5ykDA1RQ1sNRYQ+A priv=MEcCAQAwBQYDK2VxBDsEOZan0/tXTtzcfDdQSeVv/SUPrpjscJuOyPFUHVo6SvHgXm+h2S1rKdJSKohmEPBJfqPo3xTyThfDhw== msg=lqfT+1dO3Nx8N1BJ5W/9JQ+umOxwm47I8VQdWjpK8eBeb6HZLWsp0lIqiGYQ8El+o+jfFPJOF8OHkxuo4EJnPA== sig=+65VcHiydI4TIavpVRjucS7ILSPbAjt+Lf7kU/XLJEU6xUW02K8kTS5aBzaUeuX4YTKQd289rXQAtpZjqSHKinGl/mjwVdyNT/1baLUltj9gYbVyekuSXHfdsIIHtArnwFd0WwZ92N9vpIrlG0BUxCAA e=found last=22 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmiBaZr/XGS1HOmBJ79HWF4fQGCfW168M3ZJlau7BqHMf6EK3coREbJoajGMv9CZlJzaUv0twlKMA priv=MEcCAQAwBQYDK2VxBDsEOTkwZNIkeomCbUGLHHVaeC5A+Oi8XZFnx7Jqu0SezKKGyzt47m6s+qrVi+24AcYasQeCgCKyzJP76w== msg=OTBk0iR6iYJtQYscdVp4LkD46LxdkWfHsmq7RJ7MoobLO3jubqz6qtWL7bgBxhqxB4KAIrLMk/vr5+Mr1GjieA== sig=BMv22VQZrXuqa7PATSB/rXLOEoy8Evo+S4z9DuwtFUZyfznVof3qr6yYUj/Wo05a2QFMFyR97yeAYGa1odoDV0e1h5lNXsrQwXgjaeorZQqh5NlHYIVfTmAH6Ouh54m1P4IyMKZPY9ieAp5RKbtkETAA e=found last=22 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMOhkaL60Aa3yoiAdtlMqc4hek7/s2e20p/lwvxsPt2Eg0gCAB5V/ymUdU5aiinAfY+oLfgB+E+aA priv=MEcCAQAwBQYDK2VxBDsEOTiHEvh89nAhN3vsBCNiu+RuJgPa+4ki+7kRvi8VgETBpzvlg6v0uwwCxkMjQ3gHYSxwUzkhu3qCog== msg=OIcS+Hz2cCE3e+wEI2K75G4mA9r7iSL7uRG+LxWARMGnO+WDq/S7DALGQyNDeAdhLHBTOSG7eoKiXQ0kTv91sg== sig=glzaTjRE5q9uhpnjO+zsm2cq0F5UODCKuT5nH5zo8XBlM3Nu/PEnhbM/rCtzekGABUNZTSbxHhCAbKCZh6Cg8H6giHBvaLPUMsQoGweqg0A7XrtFBiaUUV5pLS4K8+he05iVkhIskku6p4Sw64xpvz8A e=found last=25 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAHrjiL40T8+P9v0eybS5UI+iJjyyZockesIYleAMtVc+e1Ea7mG75btrHNkHgw2dKuyDrQYQorDAA priv=MEcCAQAwBQYDK2VxBDsEOT0GwH3dGvuBKzbjx/AB5n9oKSArEScmz9kymPmvctlGTgrapZmvazziunftbVyzM6MN7BVvd4yQgA== msg=PQbAfd0a+4ErNuPH8AHmf2gpICsRJybP2TKY+a9y2UZOCtqlma9rPOK6d+1tXLMzow3sFW93jJCAqEAn+Uqf7Q== sig=qJB8yuie8qYHp5AD8ujxHWpvxKrMRw6N5DTDSQEQcH+sPlS9Z3h+mBk7i2ct0tF3P5rHEhGuuSaA8vSNHSnH5xyF3iZvQdatA3gmbJWiRIaUIUmfHzKb1m6iaFBTQoS/PV8Dy2cOAM4n4E7nNwDydRQA e=found last=25 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAS4+BmXkFsidt9jcmiiqC3vlJc042dyNgouRiy+1gEGop9dK0eZK3uoTUiHNu9pcP7IYoy480cXqA priv=MEcCAQAwBQYDK2VxBDsEOTmNv4In7xlfErM+uOx44s4NNAS/urTxMNEREJ8Pn0NxZSLTfayWCmpxxShjo/yO+eSXF50WhqO6FA== msg=OY2/gifvGV8Ssz647Hjizg00BL+6tPEw0REQnw+fQ3FlItN9rJYKanHFKGOj/I755JcXnRaGo7oUBh214SlUvg== sig=f+zQ2zwKiOkqzQH7PjRD2XJELlvUWe+IuXutcepjDlnGpVB5XHatFbIHS5Nhsd9V1njIo6L5LhoA2ULD5G1gyNGRha0Nl6GavQQ8GkIDLBvV2BfR9njJOuh10z4xO9zxFw1uN+fNtTfzTBCybIYBojMA e=found last=22 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFwl3yr+BZTKZ44uPGLbNGgFVwKY3Se9wL3RlASw0wV3B9mFZlEkWYR6pHJdHaAkWRrsOp8QxwMCA priv=MEcCAQAwBQYDK2VxBDsEOcsbATifUFSibtKt8VMT/jXwzfSZdlq1NOmUTO425SkEBWCA2VnNJ4b5bvRMKX8HGzR7vJuH6Jpgbw== msg=yxsBOJ9QVKJu0q3xUxP+NfDN9Jl2WrU06ZRM7jblKQQFYIDZWc0nhvlu9EwpfwcbNHu8m4fommBvHal+oZpbMg== sig=dbmB3qtIhw1tG8d4oq1tyeUQ/5+ZNP+wVDATwzUtnlWKKpGG2wjEMSOjB/Ka8qt/Z2FHBhca/FCAWt5ITbMRasZ1keM8SnBvFcEuVbJOSDrE30sJ/sD17NjXUkdNSypjfu5i+BzRpRFE0Wf04T6zvhUA e=found last=21 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATDzuqRAdb+4IjIz9VOm3gVh/8V0w8cOEKbm8JAtp+PLiFzEASlQ7O3yrRDAyGdYSxSGlYhnTVceA priv=MEcCAQAwBQYDK2VxBDsEOSaqWHHbtayuJ4Rr059jUaEYMkKfGVSspWFQjtH03P08KA2RjS1RJd+iw25FTqglwgp0J6vYYa0nsg== msg=JqpYcdu1rK4nhGvTn2NRoRgyQp8ZVKylYVCO0fTc/TwoDZGNLVEl36LDbkVOqCXCCnQnq9hhrSeyvIprHu22GA== sig=KgblGAEyYszMBQezn5qoPAeLs/s0Pp6y5pEv/SxQzQATUgVWpr7XUYVqUPSjM5u+L1YNSAPN6AUAMDa3GIxScECluzpyRk42rbYA6+rNIGqIrLPG8MzNB6b5iTdeIu97Qc3NJVIx2gPCwqJiXVxQtToA e=found last=21 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbLC7N8RW4ihSFRSOYZQSWM8T9za7pAr9D3GkDkB3rkcfgqElYWymDgnulStpn/UJkZxJwZUxcPMA priv=MEcCAQAwBQYDK2VxBDsEOW2flzUfIpYdlD88SBjbpuceJ85CejDpoihNiIWfcqtp6zdixkOcSwafqqHCmm3MReTPtfgb2rs8uw== msg=bZ+XNR8ilh2UPzxIGNum5x4nzkJ6MOmiKE2IhZ9yq2nrN2LGQ5xLBp+qocKabcxF5M+1+Bvauzy73hvIe729Gg== sig=fYCCW1Oixin07OoFQkbtwATrsHRdm1Vl6ySdrlnSVr6UHtCSDupD5K0RXvctTdq6ftR0n81sAnsAuey3uC1HyQ/P06gW4OeOrzweR6DLbmFqee3ACzYuMeteNO73eoC4ASW/KxCkOQVet95dyj29DgoA e=found last=22 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfj005evobBESDYfGyVIdKZXNcdUgbr/ffMSTWb7Km7tNmli71E2KyIIca3VDoFU6B6U99IDGdWMA priv=MEcCAQAwBQYDK2VxBDsEOc2dOzqOQsrIczxKyKpBkHlZnIX7oAvKBdVuTinqD62DW503iIgNawgib5ghaWXvxHIzoL4UpJlSgg== msg=zZ07Oo5CyshzPErIqkGQeVmchfugC8oF1W5OKeoPrYNbnTeIiA1rCCJvmCFpZe/EcjOgvhSkmVKChVOsa6rcZw== sig=P5Fq8fX4t/Op7c2Uxcs9t2YyW7aKBoY5OPAeczEYkibNTShZs3d/WsLPflM2KJrLnDWWBCXIYJQAWazVn10SWuBEgmwuIgW+9u+mzqS97S9M24klGFdnwq7BCWjxcpvVbNuMBnTeHS/bUsXs/r2WKDoA e=found last=25 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfazuILAunQV90LcwiYitA7m0WY4/9r3xEsI/O6xMw2UFBtqjZr6IZ8GdopDOo+RQXX/uY0yakS6A priv=MEcCAQAwBQYDK2VxBDsEOSQMV12pC3ReBye9xXHFS7d8rlhZiNf8NEOVuF6qd647daSvprju2hRQbLHa2WBYz9fxwknSxsk/Mw== msg=JAxXXakLdF4HJ73FccVLt3yuWFmI1/w0Q5W4Xqp3rjt1pK+muO7aFFBssdrZYFjP1/HCSdLGyT8z1uMouyPl9w== sig=pQ6xHkmx7wJ1E8F2Wg8PUS66MnbmiZr/gkhxtmtlLXZEn1oTh2WwEJeyUmaPJznGSiJvkzLw0FSAZ16yxDZeJRDUtVb4C0WHJNXXH5/YzrG6iV3rQA9z9KxsQW5am/Z6HEJP/if1tMtbvN0jKxiKCAYA e=found last=21 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoArVmBz5drHd1b+js1iENhf+Gw1tFGonxXYyDOxEezUe3pjk19MVUzI3XUKIePL6zCQ+7KiYeMWoyA priv=MEcCAQAwBQYDK2VxBDsEOSS0Sh1xJv1RhHJ281aVgR9XhLLN9fgR8rn3fjvf8eiGBDsWPFK/5TqmDME71aIZnsg4a5nNRslmgg== msg=JLRKHXEm/VGEcnbzVpWBH1eEss31+BHyufd+O9/x6IYEOxY8Ur/lOqYMwTvVohmeyDhrmc1GyWaCZve3meIrig== sig=qMPS6fsBFsVT0lvNhUVahmg+umw9REVQ/wIJYWIWRJPptOXBK79HiI2+a67xhDIKZedzXL82jpAA+YZ/lY5RwUlgLfNJDjRuEwtQwyfn5HqyjTOCVs3l5hrYRVhdJiBQT3Je7yHe4HTiiCdFVGhKrhUA e=found last=22 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABh77HcxU1qpI23SByTP7Y/kAfHFgdw+Nyo69sQcVhPWnlaItx2w8tOqAy+KHUgxJTMrfX0bCFQQA priv=MEcCAQAwBQYDK2VxBDsEOcr2czkd51+DDcqbx/K7Xby9YF63Fd5+MGkWuuotr54pbUV6ellKD9+dPQKNFc6FEeLX5OCRaTfm+A== msg=yvZzOR3nX4MNypvH8rtdvL1gXrcV3n4waRa66i2vniltRXp6WUoP3509Ao0VzoUR4tfk4JFpN+b445WR4RKW9w== sig=DAIxQt4lR2Ovrwm7Ha2AHZt3E+v6E4HWYNJ0vmIIjVmis/homZ/+pPJSSjMwzekSIha4L5GhbIWADlqpsQ+21I8GbPfEXpIlqOXH8MAj1VmUEfkcGPb5/Hnn6nn39xWMKC09HQFUgh9TNBsJec4WMjcA e=found last=21 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALh7MPQXsxZW4KbJtfofNYJ5sVoGqE3Xwy4nxlWYDBFGhYJX8tPp0HXyW7RxhmExZkQHYKZkWpSAA priv=MEcCAQAwBQYDK2VxBDsEObL6LCiexqrwAX11c4JbZu4r7SBT6PaMlqPxK9NvUrKm6K8yWqvDE35uAqrkOjapJLvdE80O0j/OSA== msg=svosKJ7GqvABfXVzgltm7ivtIFPo9oyWo/Er029SsqborzJaq8MTfm4CquQ6Nqkku90TzQ7SP85Ilc0JABsXLQ== sig=B2KCV3GUwrMyd05fawxIp9m0pOOH/M2BiZhMqDZIqLesrhPlfvbaHEHoFVgLO90Ol6ycS7ER5RyAqleAGCH4DQ9bg5KBniWXDbXR7P0jHcVylW+pogrd/UZtRx2Ahb/6VYsZxTgyC4su0r+/Es59LCwA e=found last=22 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAr4efpbsoaguktH8OeLCftHk6BvqgpDhDK0WRtpICFM/wUyLtgDvf0T2CLunJJoB0OK46ONNULduA priv=MEcCAQAwBQYDK2VxBDsEOQYlVugqyd1gx0j0lJM9qDLKsUopXopsdACEhluint9b+o4OCxUtYjDSqlpofDwD9vasyQ5L7R2iqA== msg=BiVW6CrJ3WDHSPSUkz2oMsqxSileimx0AISGW6Ke31v6jg4LFS1iMNKqWmh8PAP29qzJDkvtHaKoYyT7rlezlQ== sig=eMRbZbTozBuQm6rTm02hkHWzK8iXCOOxox7kDPfha6J9hUH+sOYvoPUtpcxtC8zt8qakhsUJ89gAefwq3/tdpjmGo8ZQFGpFgYdQVSCjoctOJ/j3eVzGKrhU/y/Z3BRXPTMfAGyc8iEzlCqX5ZrLBBMA e=found last=26 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwQT4iS6kZ9gkEXJAILafy7Txd/vfvmpk2ND/zBLqqKAH9aIl31+baDTk6kgUfLF6CEz4m2q8xZqA priv=MEcCAQAwBQYDK2VxBDsEOVBedwf7Ubiva5GyVyl2BdWlf09xiwMI+Nlz2zA8N5MH2Q562EFgqKTirfawV5Z6wejusS321ivcyQ== msg=UF53B/tRuK9rkbJXKXYF1aV/T3GLAwj42XPbMDw3kwfZDnrYQWCopOKt9rBXlnrB6O6xLfbWK9zJnY1ztaNegg== sig=H2OQOLy2CBGYdxvWNY/v+YZ8bcSA3TzaDvMhn9KeiRdsBe8MNLFx5ny40sF/1S7JYPMEqvrWwMOAht+d+fcuqe5cpFkWXAP9tmDS5S0oHQedPK0xbXqw2dOHSFPTKendpsFKLWVfSD97QevfnrlF/QgA e=found last=23 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADq7TvgXaEnj4Fy21xAy+449VOWXyYo6tMjL1n9xPATCCZXgiQ9zBbeQvwLrn2X7W2Hc529uX9a6A priv=MEcCAQAwBQYDK2VxBDsEORPjAT74uaemZ45SA6F6FagE36YN6DlZVfRJC/2Z/TYsAjvKQYWOstnRvNQKtAi5xQHLTYlekqs17g== msg=E+MBPvi5p6ZnjlIDoXoVqATfpg3oOVlV9EkL/Zn9NiwCO8pBhY6y2dG81Aq0CLnFActNiV6SqzXuUZIa1V28rw== sig=ORNNbz5BvzypBm32J+hX1Y65cjDkJdaspmq8WHHVGvdv2kQTEb56Yj6gTgKkLPvJm0Y7gt/wqNgAo7U2qonrrBySReVLHFGLhPN7lDzTyHV7tinqVVh1tS4caqZeyDp1Xfn9xFj8mVPt6UCoiyDOejQA e=found last=27 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAQEWeJ3N8qpN5ciPrXDPf6nYb1sTwFE5uSXSOOVCdDQzvONEtT/Nk1o/4zU7eDW9H6wDrgUoeB1GA priv=MEcCAQAwBQYDK2VxBDsEOViruV7fz4TblpSbZbea97MyNP0WtjB6G+sjJF3r1TORgwdmeKwHynJ+I36m4GjLDrMl8gyftSwfLg== msg=WKu5Xt/PhNuWlJtlt5r3szI0/Ra2MHob6yMkXevVM5GDB2Z4rAfKcn4jfqbgaMsOsyXyDJ+1LB8urGxYm9u4yA== sig=fdY8IVXha388l+q/EbdaN/rWlh9kd8x5S9VRvbold0HcLdScKInWQhkBjrFbA4sofL4BNpZ0++sAZOKFR4fU2ZSmcS0m1G30/IV6c8rQG48v3rDfqF6S8vT57NzNNUhiY+CNjYBKLxUjyteRRP07UD8A e=found last=26 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAiEp7QwAw0un8rMZbRvXYWSvpHMmYUEipXpi0uEsWO51dz4mKx64bpg7NPmcrIz2Y3QANcdRyatIA priv=MEcCAQAwBQYDK2VxBDsEOecSF6ZQfP3GK+WZcNGQFX1XOXYcmTUGBM5wIO9fWpFVPkWBDUQbbrJunynp489M1qdtofmSZ9ZtzQ== msg=5xIXplB8/cYr5Zlw0ZAVfVc5dhyZNQYEznAg719akVU+RYENRBtusm6fKenjz0zWp22h+ZJn1m3NW9FxwOegHw== sig=6Yu5IMvukjYE4Y3m96pcCk448VxnXYgkzX6+6+4BVrPONfKJWrkwZwCAn6P4B9sXOLRKNmZ0wceAj1coqx5oNEsfTvx1ShkzZpbgE4cqyuPl6quMyP8+58eGVcnAeCqTC3K+Q866FZG8RbsQ1OGBOB4A e=found last=25 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAYxZzv9JLeH6SNw3eB0cgpqNF8Q1QSjufGIQRonGD+yUd/10O/HMJ5L13sgAGvQVNJFe8fegHbDmA priv=MEcCAQAwBQYDK2VxBDsEOW03S36Kd75y/fDtWciP8zKDQc1o7DQcSWSP6wZVxSVwtDdo3d8dcSwygahdyS2MsYN5qsCK/zbt9A== msg=bTdLfop3vnL98O1ZyI/zMoNBzWjsNBxJZI/rBlXFJXC0N2jd3x1xLDKBqF3JLYyxg3mqwIr/Nu30QXjy/tFePQ== sig=bPuW8/FiiZsMscqIep7otJRrmwcQFzX3XtsB/z6BbHrxWfNcb94tSar8CFDNjSLi1Sw0mmDpmliADFggwsX9B9N3OiOvuXH2/PNyvvxWzUl2GfAIfbaZ9SgPhPGJahZHpZK+9AUiN6tmgTyGneF3pxkA e=found last=21 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3UuOzUmp7h1Fv79JKcrboT5aeSwR4oueNNmtVe7C9DaXs1OB2vQlod4iGsMEyUrmRPJ3zKrGutqA priv=MEcCAQAwBQYDK2VxBDsEOQhH2tN0pw2ky5VsIAoCTC86QmWceCMaO2kk2Fad3utkY/xbrIcew+Z260gEqdgM6qzMrlvwLNinHA== msg=CEfa03SnDaTLlWwgCgJMLzpCZZx4Ixo7aSTYVp3e62Rj/Fushx7D5nbrSASp2AzqrMyuW/As2KcchAqZqGzAUA== sig=ksFFrDLL9qpilVHgDVEnhhay4g7qlob57aECU0tZAynmZFj+Mtb93QUiK95FbAcjwfLhdHTX9vqA/KVNdMSMNM8mMTLP4132vMICkL48a/t/jIuXJVlyb1y9F2Yk9dNBK3ySn5yn5baGr9XDSTo9dzYA e=found last=21 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADcSKgWClFr6V2Ufd2FTqUtvMbjliJ8aW0GUY7RQ2lOv364veGEK/syqsFgYZTivnLxy7chFPmEwA priv=MEcCAQAwBQYDK2VxBDsEOQIHKj7IpRT9fv8OHn0xDqfsQYum/pWWUtv6UYulAf47KLSq3Fbue+fVltTl6UtG1Bh1iVnWLEGQhg== msg=AgcqPsilFP1+/w4efTEOp+xBi6b+lZZS2/pRi6UB/jsotKrcVu5759WW1OXpS0bUGHWJWdYsQZCG4xuy/ke3aA== sig=qCKyxt0h/dJzsOKxl1adzUaxiTyg+XxveHzJZpOTzf7pPlwuVon6Blp50bAOVoCBOguWANM/HeYAIFk7NUJDKUleyWEbOTwjmohWIpwrrxEsD0o42imfOOt/kIPG+UzxDoqyYTR6J6i8KZgJpo8WdjEA e=found last=21 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIye6H9D9Ga8IZOZNiaksgXF8pw58NlZayJ6BPgjghCYoLL3Tgp6TO0dIWro+iJk62+7K4IX72l8A priv=MEcCAQAwBQYDK2VxBDsEOREHJ1feomkYvW/IajlmMhzv8ZFCNlEY/mXnBRkI0YfvIFdt6DfDmNbdx20RB0V0Jrv4OpNl6SYvPg== msg=EQcnV96iaRi9b8hqOWYyHO/xkUI2URj+ZecFGQjRh+8gV23oN8OY1t3HbREHRXQmu/g6k2XpJi8+qU8BF1KYHg== sig=r9tb2+ZmFBFxMI8SXUi2zyWTypsVtFNiyYEjxKXXnQSpbrq3IGJ3xw2PVHOCqpOZg3kUozJ8fjqA3FPUmeSXHFSG5FRsoe74j76Yy5WLOkSdfe6P1AvmjQ+1a5xsoPFYLGk3jKcYf7r4kO37c6HtQy8A e=found last=21 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhckeTX3pV2n8Tb6OaBYtrVv5X6LlznAUJGNTXW5aJW+83d1GNfKRtCR9AXHxtpdc98sbmtOMEykA priv=MEcCAQAwBQYDK2VxBDsEOQ6vgD1tFaGJpYf9R0UDNCo8qXhMNUdASiZlYjyxF0QtinKKOwqSDBNqpJ6MmoVCz8dE4nFGAYoqqA== msg=Dq+APW0VoYmlh/1HRQM0KjypeEw1R0BKJmViPLEXRC2Kcoo7CpIME2qknoyahULPx0TicUYBiiqoiO33nEhhGg== sig=2znsouZNhw8WQKOJVHJQ1cFPrqWj3oviD1IAbleA/0AwEj+shqy9M+KTfYHsNg240WI6XHp7+HmAfI/nrlKfpgK1LaaTeM2MJBdqXVzb4PKzD9yAHD6TV3/vUuXf3UAgDEYpH5WtVs5uJP3L9X059g8A e=found last=24 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsSwtZmipHH3Dkr52794i0D48JJdGNdSAmJUR/RUAK2GKn00ySW/mZi3UVsVJyLKO2ULCkFeiVXaA priv=MEcCAQAwBQYDK2VxBDsEOSSX4WGFcP8FvMAKhhcmeA8WnjsbF9/qQU1piLcKhveozFLrHAhVXLyRhHiXrppfvJLdHx5K7Rf1NA== msg=JJfhYYVw/wW8wAqGFyZ4DxaeOxsX3+pBTWmItwqG96jMUuscCFVcvJGEeJeuml+8kt0fHkrtF/U0DoqAohv1xw== sig=m1XDHBM+lTTaaJUBpIAQ6TAIpYRvVptBktenrRpm9ZULI3FgvIJPdA9heTWtV5MylqfXmP0ny7oAsVHYaTfeHD9GSLVSRAvzIlyUjkKsVt7NDd67DPED+UBqOcY7mtKlp05WjeJ/9c2hQOnk6fzYjyMA e=found last=21 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVv4JJaO47VdAftlorZlVbd86HUt93Bv/WbT7yY3PcvUp2hHnHZh5CAj6CWNaoByBFRYxDKOx1T+A priv=MEcCAQAwBQYDK2VxBDsEOYa7nnY+xk/4M76sK+/M6x4R0RqBiRpmauRnuo5G0GwyprUKsfy4gW3ZXlRqsEZoR+aUeUo3xrCC+w== msg=hruedj7GT/gzvqwr78zrHhHRGoGJGmZq5Ge6jkbQbDKmtQqx/LiBbdleVGqwRmhH5pR5SjfGsIL7N41BvPMCxg== sig=C0sFEEUohBb4M44CERMN7DmQoVKFs9A4zQGYLjbnN3Hy+FUahL1/9TZzyWhfYewEc/J3T0LC1nyAY3slTPhkzEcXNPgTk8cn4ljY/oDUh8HQbp/ZDFXxUGq2a7UhLHx+ocsu337vLdk9OXJUM+uVaBkA e=found last=21 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmaR9E5rEFU623CyhdcXSXas5xb3EK8/sM5J3XfS5uCZP1KXuHs1WNh0GXUKBWB/LH4awiJ6nzlEA priv=MEcCAQAwBQYDK2VxBDsEOR8wNQS8nKLW00Kee2RGrhZYamqpQeBuxN/3reb1YqO8l2MruNOZA7KISpp6W3kPAty+zFcxLsDuMg== msg=HzA1BLycotbTQp57ZEauFlhqaqlB4G7E3/et5vVio7yXYyu405kDsohKmnpbeQ8C3L7MVzEuwO4yk7veG3jMMw== sig=GaA37AWqdkl6T/KGtgV9WdubWPatGsMjUayzPmUf22O6Pv97O1NV47nVr2uqWLZPzlXchuGB8NoA9GhDP2Mwh3C6/fnZ2SiZmLQ50l8keHV/hgf/RFOX/ElX/R0WyoygSV3xA+iwHF1ldTHBdAC7fgoA e=found last=22 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAlcEkhFKjOq8zRFrMI3eTJtMpKA8uxm8LHwL7zJEpZWYQiJPxqglWKLldXrMBBTxt8FkTPqOrEkqA priv=MEcCAQAwBQYDK2VxBDsEOWXoNjtzFsP0/CJtHRXNtVv8c+TaY+QdKOYhJbuoM63Rmfjj3FGdcAdMoN67b/jF4HDDvOckknPVGg== msg=Zeg2O3MWw/T8Im0dFc21W/xz5Npj5B0o5iElu6gzrdGZ+OPcUZ1wB0yg3rtv+MXgcMO85ySSc9UaDk+tN7Sbag== sig=KUxGU6Xx15YhnfAnCgYBdzvGDGSJYHaQnzuPWtkFIokVycHG+qSZMWdg+VObgAX30C3iqrDJQP2Aht0GREne7N1F/dQs7OHldw8qGoDFqLWP4pSeSM8bx9S7enSS3QJi52d80a36tGI+ep4iw9+QPx0A e=found last=21 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoANZNPGKCwN5u/T3Pq0Tull5B2yU8wRuBDIDGVf3DEGF+Qb3QqERrL9lE5rm015nV8g/p4iIqWJLMA priv=MEcCAQAwBQYDK2VxBDsEOfFm/iLFe+KoiKwkvBJ8aQEtPRIgEXh7Pe+c2vGmjtGGB26Y5v9/W2xqCeL/9LgzW6OlvRthK7ItDw== msg=8Wb+IsV74qiIrCS8EnxpAS09EiAReHs975za8aaO0YYHbpjm/39bbGoJ4v/0uDNbo6W9G2Ersi0Pc7VXPyq3Zg== sig=9SSlfNDRyI18+Sb3crdeOYsR9apjEdSmut5FDTrqPP7dlW2eLeUIZYb105X8MDu8GT1LEzbMNg6ATVVhs81W8TyCq9DNv8aHmp6Zv9FIlfN6JwW+qYmsv6kuqi3R7roxk8Fgba5KXZY0JR2YoCQDxAIA e=found last=24 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAQXFQlUOFqxVlaOsgwncS1OVqForlVgyWzlgP+5Uvd5qfgXGt0woFg/9Kf3TyJl1x+rYjg7JLf7CA priv=MEcCAQAwBQYDK2VxBDsEOY9w2rTUPV8mBbVD2vn401h5PJw2K7oAAr5rVt/BnWkF1PrfeyTqwo/NS/xAiJ045IFir7n0a5RNPg== msg=j3DatNQ9XyYFtUPa+fjTWHk8nDYrugACvmtW38GdaQXU+t97JOrCj81L/ECInTjkgWKvufRrlE0+TKLdTWMvLQ== sig=wfm8KJhab2tsw1r5pZnMoqmZ4F51cWeH7NRNpYzsCdIbBrfQZAu42wrvHhJjMY1QtDPdaqVqHNiADogy+rb8BZV350MAQ4bULln//xparA5BFLrTA0wULN/Z7VOltDkTlsqUodgOWFTpp3S0yCcm0SsA e=found last=21 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOkYtakSJIw8sAICb20yjJcp9SGlWhQJYPVTu6oH2l9duqIy4SxL9OyXXsYtAVyjsLTe993nV6f4A priv=MEcCAQAwBQYDK2VxBDsEOeAFKoPxS4/UVif/Z5kCT63s6NNTboPN0jaFOat6vdnl7/VPLnjsf7Yc8d8YTXB2YaZxXn2K6vFasQ== msg=4AUqg/FLj9RWJ/9nmQJPrezo01Nug83SNoU5q3q92eXv9U8ueOx/thzx3xhNcHZhpnFefYrq8VqxDNrASsnchA== sig=XRUI7NoHCvGKfLYAMytpxJWCh9+GTGuHz32hKiiD0L7WYMvQjO9RMb0XBRglMSZAvR4PMDJgBxqA+BiQ6JB4eQepz7t3WUEXfSA04/6Cq+dl6V3pvy8fEyMSVVpbBFCXmpDzvfrqCe2wnriNpF+XLjYA e=found last=20 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA+LtQ02o5JTn2g9UPDgBfMhNEAChLqAJSwqH7A0WFvCDgYgLNgGM01TPIep9umwcbYGs/EpVIdp4A priv=MEcCAQAwBQYDK2VxBDsEOeq4at9LqUFKmjwOUaz3AgBwbofRq/rWeLupnvrIQ6QD4ci9a1/q6FlubsHwVJAkCek4azuK59sVGw== msg=6rhq30upQUqaPA5RrPcCAHBuh9Gr+tZ4u6me+shDpAPhyL1rX+roWW5uwfBUkCQJ6ThrO4rn2xUbOWabkZTwbA== sig=4g6ag+eL+0Gl8tKCBD64FHShofg4pbt/Ajk59yvp+FItjw9wGD7XebrHyx6PCEsxtnZ0Q0lYFKSANFfvbKH6O8M9rmd4UoehVSB7OfAejPVV952Hp2q4xRf219EQlI6HXqPgsGF2VKSmEmdmWn70mRgA e=found last=21 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwMg2tQF1CdacKfzVUWCRzjO4J0mDeh1FXXzHtCBfg1x05kEb9NdDVHCuUGTCpBU8a61oo0AcP/IA priv=MEcCAQAwBQYDK2VxBDsEOWf+QjxG5wplkbkUHW26mkHXk/Pw7zpeNzIGiosbyKYJ7vDsbY37kvAvrDWitexOV+jitkDL0cMO8g== msg=Z/5CPEbnCmWRuRQdbbqaQdeT8/DvOl43MgaKixvIpgnu8OxtjfuS8C+sNaK17E5X6OK2QMvRww7y74E2xSueAA== sig=M6dL4OCFZarEdECPy3BN+ZZtyLVNiwHVY0QyPmy6ftau2J80Pv9nkaQ+EAXYRwpkC7bHbjxviUMAR2atYyJ5WRbIY0/7RhnHB85cFtq+i1ozZfGybV++NLaG16eKRNrOHSCZvf18cCjYv2NFK96yQzcA e=found last=20 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAr7lmcD7a1ry0iaKyuhG+Jflv+5gHuRVR8xsuJnS7rb/isqpsu6DwO3i+wV879oQe1R6/spx7yXWA priv=MEcCAQAwBQYDK2VxBDsEORdSVKo8hB+JTo+pQuzyg4Stv5jw7789SKQ6oUCJWTgwnG99BNtCFx54L1rgS7BI+oPeHuIHq4GPSg== msg=F1JUqjyEH4lOj6lC7PKDhK2/mPDvvz1IpDqhQIlZODCcb30E20IXHngvWuBLsEj6g94e4gergY9KVvBLfkWDow== sig=6uN9VzTj7WiNVq6JH7C4hgLepkkYjqOY5UHwEb8H8lQ6pJ9t7K2qb54Zn8XNMpIOyu94N+WQaUcAWorX3hLosKkmEIJgT3AP2k0crddeT6/q8zoqU/+ftAaG3YoXMZ+/uDTeVOnlxBggLrI6tmiwWQ4A e=found last=20 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAriuEEX+b9AfLM613eZ+hOt06Lrts/zOy0QnjeT9An1cOyEHWPWnR1IGO7F1uNtUrCWXN6V+5al0A priv=MEcCAQAwBQYDK2VxBDsEObBaHYdbFk/3+D4WSzyHm07NCie54UqPbiFpGAlep3aKNfanp/tu7zx/WhAUro+zPm2QTSlbAZbSnw== msg=sFodh1sWT/f4PhZLPIebTs0KJ7nhSo9uIWkYCV6ndoo19qen+27vPH9aEBSuj7M+bZBNKVsBltKf0zY2cbm/tw== sig=vp1IZy8b4zujsjIQcp65hidZHXFl1Yr/B6VbvmqfqLMXMbbrO9zLYNfWG7GyBJ6cAAnrWniV1GyA8bl9YqXP30MPXxoByyfxN8tva9ZRuExdOUdCGSO5UZOhCVQF1ncKFRriLOXuXUfiK84THknnxyYA e=found last=21 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIe9dlQt3uUuSjKNSQdiH4KJOk91oTFFGriPiCq/EWiwO7EjJVmHUz1CzU3mK7JV+07zl5SlcCc4A priv=MEcCAQAwBQYDK2VxBDsEOTxclqMplrQRja9Ehev0ijavNVAmhnV8qkrivkB5CRldP35lOMJ72sf2+Zfm8X0ORikWOoqPYK3Fgw== msg=PFyWoymWtBGNr0SF6/SKNq81UCaGdXyqSuK+QHkJGV0/fmU4wnvax/b5l+bxfQ5GKRY6io9grcWDeJjM3tuvtg== sig=f4Aq71/zWpj9dpWAg/lh5xRm1JCNY6XH8w0yjGRWcYcW0WkalCY6KVxIapYPQfNyt4OEvUxTp58Aylvr/EPiToWtvH93qCOrrh8yaMJ/g/QP3Q9SzB3S4gvtQNAdkf/xtLLb8xpnvtaxJJvVw9PrKwoA e=found last=22 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWkExplp1iwQKL3e4jiidF5rUsPESS+fcmddpGL+4uZ+BRBGN/PAVR8Mf4wgvlnHA0zx2HebkpTYA priv=MEcCAQAwBQYDK2VxBDsEOdzE6tjfQws7/oU6iJkOTHQzzPaahNV57E3NPyeELaFXFweSB+TBfGooXuezIKrnTBS6uLTJIQlqmg== msg=3MTq2N9DCzv+hTqImQ5MdDPM9pqE1XnsTc0/J4QtoVcXB5IH5MF8aihe57MgqudMFLq4tMkhCWqaWkSQQG/HxA== sig=Tt2cNrNGdI9r8adPqpsaAUV3qRASq9iz/tss2crHoNPdlWuuKyalG6NiZoauHR+7lYKkmgsbAXUA45O5baYs/58PQx5jPipFb4x3Vh4DYsBiZ8GAsCMPVUC4QSAOh4EOL/h0xdaFt+PO8uDbZe8K9hwA e=found last=20 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOJA+a2im1iK0Bhl1nfgXMX8atUyPITyXMhcDxmo+h1iLLvfajjZWGESOBkq2QHD1fF468/SQ73kA priv=MEcCAQAwBQYDK2VxBDsEOcSbk98XJslUW3FD69Qr7rYb6Yr9hvLr3dOVff1cQTqdzF/ezM4uqyiI6YfVCAbTcc40HpN/WFp/Uw== msg=xJuT3xcmyVRbcUPr1Cvuthvpiv2G8uvd05V9/VxBOp3MX97Mzi6rKIjph9UIBtNxzjQek39YWn9T+2VDXtmO6A== sig=iwUCGLklcWnet7T4TkegFtsXH5UDg8Y1twkC6d3RVTas1Y2KTyQC9H2TtSJcpm+r7Tjz6K/VrA+Ad+NwGXvTAJ8dqn9M7OwJ2mTe5UkGUrEwG1cpa5p2Qx7Hxz8S0jsYo89kTtHHuEG0OdYZj7iUmAQA e=found last=20 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA264jtZg/SLil+f3cWjw+7F49vfYsTKJ3T/ccZyw5fiHVY2FvZMJ1BdLUYcpOKdfd46SVbNcPSSEA priv=MEcCAQAwBQYDK2VxBDsEObCkAdl9ZVFdRIvtnaBQY2G22CmXnQ0XTmPuJPykfcXtZPww68odAycBqxFuI8uOk1TiQ+CITM4mcA== msg=sKQB2X1lUV1Ei+2doFBjYbbYKZedDRdOY+4k/KR9xe1k/DDryh0DJwGrEW4jy46TVOJD4IhMziZwcOS6yV5Vxw== sig=i+IKlEdkxiS56zcT2FfLD3QuFzQmlEija+scrtS8n4pRZr1UpkLMi/TMyiqPBll62mM/qJz2PUwADRL3TqsOzLmDN4/ieWcveuQG2zb4tvtkoewIyIpAoHheC5bolAcdr1akGweUWyvf1NT3/sfxwzEA e=found last=20 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAvXUbNYR/6BkI4jsESONW+3w8qRd+DCp8a5KI2zsmw1yy7mgEOACTCOwQ54BG40tjzc1IXkTJLKGA priv=MEcCAQAwBQYDK2VxBDsEOQgxAJF7gl8ot/4yzniq7lJdBk4Jv5GWjc2nYfvM5dd54LhZHJayz691wNGHicBKMxE2chZC0gZnuw== msg=CDEAkXuCXyi3/jLOeKruUl0GTgm/kZaNzadh+8zl13nguFkclrLPr3XA0YeJwEozETZyFkLSBme7dVfvBCd6KQ== sig=N6Fz5aijQTyyk78LtytlL2SaUH9NR5H9XwDt/lYkjHO8mzDJ+zWrRj4+HUBfjPvmYX6/dGpxaqqA22LIOUN461HFrrI/Gymi+gbRgeSOxFBv5XVutczkpkMtVxtRchuVq/9aZG+n4khoGyi1H8Ts6S0A e=found last=21 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3WuOi10sWJgsAxR7B0GhotKYcVT2HoMsLZwz71lRvOvrzgmOvGmXDvfcgzXTEURPNyiH+1I9LncA priv=MEcCAQAwBQYDK2VxBDsEOf9wKoo/teR2GPD21wHwRRyD/OzzY9tdRH972Rbpyhol8SXkxBP8uc5R1R+twU/XatlauY3frU5NHQ== msg=/3Aqij+15HYY8PbXAfBFHIP87PNj211Ef3vZFunKGiXxJeTEE/y5zlHVH63BT9dq2Vq5jd+tTk0dbxCtSFAzmA== sig=oCi9PF6FTbMp9IkF76bSbPBnSCqbUMJGwatQGRgYBoxjkZYd9Xg9IKs+9NiMXdWRcQ8iIafDzJkAspBYqLiuezJD8chT98Hh5jGz7ahzWcfpoHEvNHwSpba3rCBnn9cJC1Zm2/QUn0j7w4wtvomXzzQA e=found last=20 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAk6H0bCrEvMQ4nYy7S2nLnTno9jfjYHQg2/ubCp8mzLy1vJlrHw0tstVSyMEBzDTlnAQCgQ9UsvEA priv=MEcCAQAwBQYDK2VxBDsEORIP3/h2iKMb+4yxu3IUwCHwqsjH0qS0jmgqieulbqMFgDTuOLTstMMPX7gEZAS4yf8LgCvBMWtmXA== msg=Eg/f+HaIoxv7jLG7chTAIfCqyMfSpLSOaCqJ66VuowWANO44tOy0ww9fuARkBLjJ/wuAK8Exa2ZcQ/KK9/oJJg== sig=3qcHgW+y3cPPJQsT8wSLl8LuJ+wYKwjukqtjcuqPyYJzZClCz3EpyERYT5UtSksA4PRevWDGyimAiZohmff+CRuMzQPdr8UZ6TCuFRkx+k/thM+Ga3hfvXrBziBBHdr0n/4Bkz5TK+PC9SzdLlXLFiUA e=found last=20 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuIWJsaJ1/7emBnUOZllRBGLMgo0rmJf3HSe9kgF9gF50wEJy7KFW8gUj4scC9aYp1nR/w4aXBRGA priv=MEcCAQAwBQYDK2VxBDsEORVr9oBbZWNrvQ3jGRf12Q1ZKMU0f2TCOWjaWKn+1M5/z0dRu8Qgv17c/B7/iJdkvUkSohUujZhq4g== msg=FWv2gFtlY2u9DeMZF/XZDVkoxTR/ZMI5aNpYqf7Uzn/PR1G7xCC/Xtz8Hv+Il2S9SRKiFS6NmGriN3GwFGbzEw== sig=RFWNbJsUIFqMPGD1/q9ChliudKZDamjPdapfnp7vA/aGP+Q4TYH1C+FJwGlX6OWUcdKyngqXK4yA0E2KiDJxu/EdfaHOuwCXN02H2A+nBybeqvKEUy28PVJBCjUC1BpYdcexHYUbXYDpphLi0UyRNwYA e=found last=22 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAN8SfT6hD4EvmFRxb7C0gE7F60twMb9dcNFbgcdMzSmW7EkFHTC36585Rl0zVNOD2SbsyZouCBW2A priv=MEcCAQAwBQYDK2VxBDsEOQV4yQDw/8pwjW6aPCuqcAEZyGSMljpIZCAENRilP71OWvODvW9s0JOI6NCU4byTymT7nPi4HbauMw== msg=BXjJAPD/ynCNbpo8K6pwARnIZIyWOkhkIAQ1GKU/vU5a84O9b2zQk4jo0JThvJPKZPuc+Lgdtq4zWFv+66ezLw== sig=v+MunUnDJbS1S6uPD2OKiXmJl6zGFi0kJdgLqjbqiNIxVt22R1gNpnVPCrgzB9tIVhqqbnuqRYgA/oh/LK+L69vkRCyszyo2rIqshWSUPaVlAax/Hq6gj27Wk/U175gtaIb6gGcUMvWyAzQAR6SfRQYA e=found last=25 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAgLr16p1dyMOXTZvnF5Q7SY4ne/lv/UUEXoAVNvCZdO6JebgGszTwhBYyLY8ZjedNsLseBCLxEHYA priv=MEcCAQAwBQYDK2VxBDsEOZvyuMZJo2BRltzOQ7z71Dxm2w8+1NUyHw3paekZmRErixc3VkO5r21F40G641FvkAI2z3h8oGN3bg== msg=m/K4xkmjYFGW3M5DvPvUPGbbDz7U1TIfDelp6RmZESuLFzdWQ7mvbUXjQbrjUW+QAjbPeHygY3dudGYJ6tXigw== sig=zltFfApek3jsx4dK8vM4FIRmIYB/J67bUtzSqbPVd6sdya+CFBa9EkA+1B3o4XI8qxHSuaiSkNyAoTFNfOKl670sIvN2DOx/r63DcnlWagtBiDoQ3GZZ4R6DgvKeuUfpS1cgQfaFh4Y4O5wUkZRUlT0A e=found last=24 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAiCMn3mYNZ7EWUCOmlx9KQWFQTcWQFCMFQX6GP2TkClVoGDcftMph68Jik+2/EiXvwxM0pHdwDeGA priv=MEcCAQAwBQYDK2VxBDsEOaciSxz4sHdb3SVbXEDOiAYyKRbUep9H5BQwJVhA3/cDycLucziLhz6xrXENJ1sW5JIrm5TKnEXJYQ== msg=pyJLHPiwd1vdJVtcQM6IBjIpFtR6n0fkFDAlWEDf9wPJwu5zOIuHPrGtcQ0nWxbkkiublMqcRclh6fl/mO18NQ== sig=AwCgpdlayS5Itb+RZI4CNMO6jhfzwJ85ULEyfpEhMPmcoY/a/A3YT1qfOQ1P4rvZbFvHX9u+L60Adxc+9wcnu9aaw8fWqHgAlrlmu0zCJ/8vkm+rRufRPvBk6kQuZ4t4CQ8o8/din8+Z2CzGQY2whRIA e=found last=20 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZJM6zRTXdrdkSv3ti5s7l64yyXQsxx/JzXmt0wJKb4713u4Lm2HANAqdIXoigaesd8wXcU5tSYmA priv=MEcCAQAwBQYDK2VxBDsEOdvoZ2cQcgrHNkIy3J9A3Pp8GkYm/aML0rRNryvgp827FDyyqvCxtmlsAaAyODPPxJubaFUw5CJ89w== msg=2+hnZxByCsc2QjLcn0Dc+nwaRib9owvStE2vK+CnzbsUPLKq8LG2aWwBoDI4M8/Em5toVTDkInz3tZZ2L7gHsg== sig=pEjt6RR5uKwOQSamJ+ERRSWqFObCL3j8cnmnUrgVy5GUFzCl4D4rNFtcmlDregBCQbwyKIcHOtoAEM6ajoeJzZDEm5tg8MiNO5TKmdjMGQHG/ezsqVd8q4LY7e5x7T4/I21ijDvUjWyoXC7QJ/8ukxMA e=found last=24 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAh/LZX5EFQYglkzVFUGoQbum2T4C4iovpuC3wLzp+HoP5xGNdARwnDYzD9Mg5UC5/UHtB7GJADOUA priv=MEcCAQAwBQYDK2VxBDsEOZ1QY5UEXi9et70/ar1QNVpT4IkfRCTpxJ3GVj9+1YZVJzmMP0hWHrWFCy48PxfwVHAm+QqjnAx/iw== msg=nVBjlQReL163vT9qvVA1WlPgiR9EJOnEncZWP37VhlUnOYw/SFYetYULLjw/F/BUcCb5CqOcDH+LtACoY9HgNw== sig=G02BZ5LA2+vaN3sOwvFNYB6gy8jaLsqQKYVjzi3dfmmM+8AhcASF2q7kO42rhhCxJUd8n3b9x7IAHbDTpukq/jwjjIdqRb27Otox8BJCjVFzzxMqLCPoOpVjoGOZ5JxazLRAZB9w/zOf7LX1RowsfQcA e=found last=20 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUb2ZIWDkoxDyNGTXQ4I4JprAb1bo40uswgPARhdBsw6WJh49WsL7zKtgEj455z6Gl5q5/MQrwWkA priv=MEcCAQAwBQYDK2VxBDsEOQUsQ5NQ3O2+oOYTs4XH7grZGpjV1PU7CnP0XXjmxe70YhDxltlYykxMGYDy3qiNjZWt1Sh6gHER7w== msg=BSxDk1Dc7b6g5hOzhcfuCtkamNXU9TsKc/RdeObF7vRiEPGW2VjKTEwZgPLeqI2Nla3VKHqAcRHvLuXsAZsNTg== sig=9A6GS+ueFnYlX6QzX81mrDZRpAqar4wAdILN1IPpTUSVqc5HiXAYGE35ZqaMnKnPka9F6K1IFWoAWrvSmEVzUWo7aMKwRmt5NTkRlbt+GfgQ38iW6rvnIyNIG+sBvNxO8XujAZbJqD03PJsNVi8KHRgA e=found last=21 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADnOe576GsMo64I/WM04xTIsU8g19CZXRkqkZET6GhKhZE0PQ16backkhCoKLIdqtXkU9zg/LBY6A priv=MEcCAQAwBQYDK2VxBDsEOXMmPZm6TJdGmug57pikL/tpnmCzBlngXxdzaw7r8cVrVT/cVuVddqehiidCupw4uZujh9/r0l4D/Q== msg=cyY9mbpMl0aa6DnumKQv+2meYLMGWeBfF3NrDuvxxWtVP9xW5V12p6GKJ0K6nDi5m6OH3+vSXgP9pVI7FtZFOQ== sig=u0h3RluieIrIqGgkCfTdxeHaLWrZa8kqI3Ti0IeUtboypZJ7JfZ7DuVjkY8rtSTHfdcywFgjl3IAn6OQnh51wDniEIYk6Az61/xlBUtaCdVYZD8S5vY3sRF7OOwZaBhxdIlLWPU/RUEeytHg5PgC2jUA e=found last=25 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA+jc+4+asKW2XZizUS/DkbOeOS8PhkCgwH20CueZOcfD9quFD84kDaLoo6OZpP+/46wuvAt+JSVQA priv=MEcCAQAwBQYDK2VxBDsEOVdHW3ENL7fR7RDhA10AFFQQaSL/bADRDsRoet4+rpY6BR1/PyfObFa1AdSWcBQhmapnfC1RiUY0WQ== msg=V0dbcQ0vt9HtEOEDXQAUVBBpIv9sANEOxGh63j6uljoFHX8/J85sVrUB1JZwFCGZqmd8LVGJRjRZfWCKsNsB5g== sig=F+jkC1bulf7GPpJ4WSs4VsD5pEPADzrNaOzP1VEpYGfVT20X15uq39Wp69DQ65hTxD2sbHI7HBMAfhuSi5B2x4KdGqBfbcQABHw26Xl6n+2uvvnapOkOKp/dJaqJlpaaJpYdAXK8xcWGyA9az9EwrTwA e=found last=21 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPBTpBmig4YcA+Q973hmwUZHuOi5DVZf3H1nsymrKjVqa3QyNLMDYuy2Tar3HuWoC9j3YI2BPGu6A priv=MEcCAQAwBQYDK2VxBDsEOZ7ja/E4RJPRo2gcTpzNcM45pbluJdwYvkZ7FwXH3GV2JZSfMOXrFMHjxBoGF2cwe6P3dBDpENWoGA== msg=nuNr8ThEk9GjaBxOnM1wzjmluW4l3Bi+RnsXBcfcZXYllJ8w5esUwePEGgYXZzB7o/d0EOkQ1agYL1aZEWLD4w== sig=xHK3nb00WflhpB58ksFh68GW+27tDy1qbWUgfu9VOrcbfjOu/bcNoKE3Xzunze14ONHptlaPFzAAxSJULoDEsijG9cOXJdpUpX8R5Z1z1IQdxuHq4pzHM/0msXOu4Ks0G6+i/SGjoCAjuwxcekN/NhcA e=found last=26 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1iTMfku+wnpzmb+9I0yriUcKpJqejjz6gPjV5dCsIRGTGG/lcKE8M8beknKNddt5z+a4ymUD6qsA priv=MEcCAQAwBQYDK2VxBDsEOatqQXKZo48BjqGrXnsXBEGhgxCURwdG5LmjWYdrDlUmjJ7id2+H2WuCUbnJfstkXBHmzihZfLHI3g== msg=q2pBcpmjjwGOoateexcEQaGDEJRHB0bkuaNZh2sOVSaMnuJ3b4fZa4JRucl+y2RcEebOKFl8scjeJuoFRxqdKg== sig=hUkB2Rm9uFDI4tW3fkGIn77Je8q3R7mziH+2zwLGRQM56MTZObAhYCADzovXJL4uTg2MgDZOl5+ADQcnd3sJ12W7TO88mPxwOKxA/DfiBdct8/e32SgYDt5BBTWmPW3Qc6fa4ma86lQsX8qYEMHFdAoA e=found last=22 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbfxLYH6rv8IfjvEh6U4IePUtBqKgz4PoIqD07jpJYnrnZgXhFQejU9hHXT2y7oDkJFlLZwir/3YA priv=MEcCAQAwBQYDK2VxBDsEOVOIr5yY/Cl6hhoUh8J7q8Dst23+ugK5e28eux9OdiIw0xXRlYi54xCNbb0qe2/43O0/fmLq4gNP1A== msg=U4ivnJj8KXqGGhSHwnurwOy3bf66Arl7bx67H052IjDTFdGViLnjEI1tvSp7b/jc7T9+YuriA0/Uj93uyYOBOQ== sig=3+nuf8dhc9ksDkjOaX0LZULTK7oSwspWGZ4MGShOWGiUrGqAnKJuNy2JtBq6ygkk87cHD9hqnZGAzovv4odIgt8Jmewf7h6Wvs+8H4TmnurHBu2Bz7TYX1Jj08BNnHKJ2gVQv9ob7vQeu0Np48GKNBAA e=found last=25 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9PJ9h73qrbR1lC/MoI5Vt1hsjrN42ffI9jmzld2JmCR2hdZ9R+tmeJ1iYgbDQMURWq6kAS9UF0mA priv=MEcCAQAwBQYDK2VxBDsEOd3r2UphtZBd0qEvt6vRWwEp38tsDzOBtx/EumnumJXtcgAqK1laQv85jmuyx7/nZmM1KlFd3yctvA== msg=3evZSmG1kF3SoS+3q9FbASnfy2wPM4G3H8S6ae6Yle1yACorWVpC/zmOa7LHv+dmYzUqUV3fJy281S3w8FS9Hw== sig=iHA6/8sosbr7Mec7QHF5vn5MIyk38g2KHi7u7lIw7aME85thd4hpwi7lfuEtgA21Au8v3sQotn+Aw/HZo0I90CDNpJl5kvpE0hprVMJqj132dSnBV/E+zJopS5NIfx1PvKQSu2DrsxJ80UmIIz2p7xEA e=found last=20 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIZDMxzWE6/GhZGIftnY9uuQXMzlmD9IAdC7IJegpQJWw+9i93/pLDAwo0EQ2RjlC93aHxA+WnbSA priv=MEcCAQAwBQYDK2VxBDsEOa9VAlzmFZghy5kQF7wnFhjWdEeqdNKGWqiKY7tAfRSE7bLXFxDQ1dYRtlK8hkG4nzDUDX16rpNw4Q== msg=r1UCXOYVmCHLmRAXvCcWGNZ0R6p00oZaqIpju0B9FITtstcXENDV1hG2UryGQbifMNQNfXquk3DhCJFofqJg/A== sig=vtWGIvDknbtHgAhOaTu9f7jbGXjmfUrVCQvzZlvQokteuD3wTNf0TNtaAU+EcO1MDw8diEJ+bACACxVYMJgxZee4zE9rmA/nQ7n8PoqRCMHvWn3HLqscZFdcNSyJkRJ5gYE0nGI+DGxe7stW9RmJxxMA e=found last=20 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoARZVAHaw60EdVVBqqcc2g6Q+YwVyHFKKvnVvERSyu4Z14H92dI8H3nAdBI0R/0Mmr8uTqxjik4EAA priv=MEcCAQAwBQYDK2VxBDsEObmJc+Pj1murdmsO39Au+F/lmWbovDPak0adzw5Cpcd3Wz4AWLfsNtBT0laIdvOPZGxlD306Dsu1DA== msg=uYlz4+PWa6t2aw7f0C74X+WZZui8M9qTRp3PDkKlx3dbPgBYt+w20FPSVoh2849kbGUPfToOy7UMOGinL/4RQg== sig=rRRQMyivIoZ3XCK2wUrww49vVm8OoYUfaovzVO80ynAel43Sr/Tp1ODKPicku+Z4mcKVlnMvUn6ANeLEYWJl6C0Ogn6CwfAKZp9CtSKfbKYCINfta0Tucb7NaAyjx8VSbTXW35Hx/LDxuMK6YRxyyTUA e=found last=20 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAE32XaykN4j5sYY2ptmLVUkXIdqj5qTQvPS36AYoXpx/5GzpnbLlCwBGYXyLN56mCALmeO/X0MngA priv=MEcCAQAwBQYDK2VxBDsEOfMeHZfUM3bax+F69/n8i1+/Ueo0DLDgbFZjSylY6cBbtcb3dPMBkBKLODTVpnN031Yrc0i7bPiGkQ== msg=8x4dl9QzdtrH4Xr3+fyLX79R6jQMsOBsVmNLKVjpwFu1xvd08wGQEos4NNWmc3TfVitzSLts+IaRmlw2elWjlQ== sig=Hcznej5Tw02Z4ur5EFd/LTAe0QIsvH52GQJ8j05PzCHz3pRGjJPHIGzoP5X7stI5l44vd+rUm/uAaLymfp2aN80+gsErTyPnVRxjbamMP64Q3GArpdJzlRNcM4xOYo/KqNRwcDm6xByYmhjVtpNLVSkA e=found last=19 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2Xo4oeCsR5/1w0sBFfa+8Qy/gOkETl4hhz6eADFx5qnPVjwMDV+mxJxSjgM8WJqjeIMOOF7/w4kA priv=MEcCAQAwBQYDK2VxBDsEOftMIbz6BwZ3hfm8aUh9Ber6OiMj7MpgisrJYQsmTdsmCNywrwlzVJliZPiGa2Tdeo/Rok+OFviWHA== msg=+0whvPoHBneF+bxpSH0F6vo6IyPsymCKyslhCyZN2yYI3LCvCXNUmWJk+IZrZN16j9GiT44W+JYcRPLE5U/0YA== sig=aAcZ8k6kJ+WTgyCVxpxIiS+cuz8SapN0YehS0oQU53btSkEFRbemxUYSWKjH73B2F+j9+HTjpG4AVUu8RseoMhumHF3Mg+HO44lZE19ZH8X8NKAw1hY2X5PWXHDZRTSfBiUGzHIaOD21WP5Mh57nuQsA e=found last=23 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqHuV7va6e3z64TR5d3YvjwYKTaO9w8AUp9LrKVfWCHHe9+EiOHIbiWfkY3kMmbBkkGj7+KMqBkEA priv=MEcCAQAwBQYDK2VxBDsEOWaKKVUDN8gw9JfQ139IZgmwPqTsBW+lhW3JLnVgJIjl9InG5roDony2YvJJwWP/2/hwO2D+OHy75g== msg=ZoopVQM3yDD0l9DXf0hmCbA+pOwFb6WFbckudWAkiOX0icbmugOifLZi8knBY//b+HA7YP44fLvmq9/6ipzuBA== sig=73mM8VemmbpTVyZ/kGirl5reNiO/JNii6dWfHxSUe/Mq9U2J/UWCApy4C07vDG6hfulb7R+8vquAamUtGrBrj5xH+F4Rsp0F4y+JhKL7Ks+9veQ7obEAjQwAYEdOrckmFgdqVY7iGGlYg+TOpT4UgwMA e=found last=22 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOZZ2lQmPK+LnaQrCH8lKRBWhBoXPmiTDQgd7jBAiAV/YHgB/A7ZfF52ZIjUK2mBmUNToqkJ6I98A priv=MEcCAQAwBQYDK2VxBDsEOTjeWYJBP9zRlVA2kRCHdpVO+B+UY3EMq4KWEzMgKDwdh7V6s6MuEpi0DdWJIEJC0NngxJHqrnOEqQ== msg=ON5ZgkE/3NGVUDaREId2lU74H5RjcQyrgpYTMyAoPB2HtXqzoy4SmLQN1YkgQkLQ2eDEkequc4SpMrAcsqflIA== sig=JzCN2DEQg+KJmbEwqv5u80+y753rU8aUvRoylNnrvm/fbsbes9bwGcjocKdmd1ZSU6ZaoLx2W4IAbaU2XgkAL+/2EY5ECuSaiP56kk6z0Oy2rugf18O0D7Cpx+xAVFjI3+ozeNfojVpfDaKMzBGKoREA e=found last=19 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAjrG4tN4CSbvvGRl/58yxffsgxTnWj9sOdr6ZYU80PT7BoC+FjhKSgpljMlJG56obqNrOZlQdZDQA priv=MEcCAQAwBQYDK2VxBDsEOfn+T2Igw8dvmtF0u6R9a4943WtSGvQfp87+nU0QLkqAvdYohB/M257FfksP5w2av928fpGZj6LBpQ== msg=+f5PYiDDx2+a0XS7pH1rj3jda1Ia9B+nzv6dTRAuSoC91iiEH8zbnsV+Sw/nDZq/3bx+kZmPosGlpfeO+YdOqw== sig=T7MXsk6RwvEY36Z40GU6i3yO9/0lHGFd5YK9vmBgU5bcVWTQToGGRBFXnnA6PRRMWsq9MXKXEB8A6HG12Hwy9VeONZdaNyzl45bjR+o56zxrUoqnWSds2sQGqI+Sh67HASyw6EXaSa6hnTQJCTDvriAA e=found last=20 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAkfBsZhPW8SHYBbClynq6Vth679gzK+juIcKKrJzXyj/uvfDv7TQQyFCQBqcwIk8uvJ4DTc1ElacA priv=MEcCAQAwBQYDK2VxBDsEOdpQPYAad3bEt67L1tUfpnqCgRwNmOMwMfpyYi/SzLpT3qE8keZuvk/9GN9CWVOdal9XPJC/urYCzg== msg=2lA9gBp3dsS3rsvW1R+meoKBHA2Y4zAx+nJiL9LMulPeoTyR5m6+T/0Y30JZU51qX1c8kL+6tgLOHfbRdp0sEg== sig=aTzHp0FdBhoXNV8UUFqBzaufyHcpDgXbR6bGV1Ywl1oRCo0oDF/UVhFBqbsLUGBcoK+8+uMtd9UA60WMJfiDrJykRB5x6kNpfmzue1Dp40eyZM/XEV++o7nLo+wG4rP9//0emQ7WaZ6Zo6jeYEg5yhcA e=found last=19 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1EFwgKG0zNorG+bZE4mpTqFsYc299zA8S9FKESoXFMaiE0H1TXza5LRr6VfbhZbD1oUjg9k/hvaA priv=MEcCAQAwBQYDK2VxBDsEOXo0Xnwx8MXUKuxdcNCliAsC214DbaNMsgle6VpR6MM4pG62otKflKwp8r979eXNzTQ2BoPxipNjrw== msg=ejRefDHwxdQq7F1w0KWICwLbXgNto0yyCV7pWlHowzikbrai0p+UrCnyv3v15c3NNDYGg/GKk2OvZiu9Po8jjg== sig=0vRx8acft+oSnoIcGDxV8DNcTlY0VwHzjCGbreGZAzX1Tnz8LPvqn8/144n01a91mqPqdkOMBZYANGIWMe6EVVxhHwReAuBkXyXN4G8TV6NqWiRBAk7IzMXgJ5dZtiiIOq98cUIIarI83fBfWCWxzQUA e=found last=20 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAgZxD+g+BVA9zW/rlG10DB3z66N+LOy93hzZ9eEmULXR7kZ/3zETPZ2U3f1jDil+kFGcW7GpNuMUA priv=MEcCAQAwBQYDK2VxBDsEOcasyC5lI5F1AvLcYv+N2GBkO3mlGA1SRrrcDq3QLlHzkpwrenAzotecPi6fmy5sMauRLisNKt0kbQ== msg=xqzILmUjkXUC8txi/43YYGQ7eaUYDVJGutwOrdAuUfOSnCt6cDOi15w+Lp+bLmwxq5EuKw0q3SRtqUb2r11eVw== sig=tubU0Cbc34/RExNjlBG5mL/2vK4lziuG68KuDweutC3tWDEUNz0rihovpJlzz1gNY/hcMn5NQmsAcnzMUiZEQfRUiInJbCI9duTNVvQDjy+5gAf0u2v1pePpvqTAb7Z13FFvJV/7jy+nKFb6OVuBlCYA e=found last=19 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAnN6Cn84g1I4FVkEx1/O0f3M6Wyqlv3bGGtS5omK2NcA6KN9NSu+nHHZxlV8/eeV4W4KzNggStjoA priv=MEcCAQAwBQYDK2VxBDsEOSDmLy1yuoOyHBi9yvbso5GhyiAR+JN4wr+r0A/6ViyJW0w/32ZGxmHPkQzieAxbdnCDkYJcpP7USg== msg=IOYvLXK6g7IcGL3K9uyjkaHKIBH4k3jCv6vQD/pWLIlbTD/fZkbGYc+RDOJ4DFt2cIORglyk/tRKpNDrecefKQ== sig=8h7+pMitaO2NzauHDo82VK88vlxFEVuu9s9P4u/K3EfaVf5h5/d0Jr1TrG21uldNxhEUMoc9LeeATi80cDvK9YqDqlFXJncS7QaD8vsreaz1Z9OC5D8EO2t87KRERdkYJzhYpA8wDdEEremb1cKVMwMA e=found last=23 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGHqDG2/mVmi4Nw3Lo99cGxHKdUaI1ww8rcIi4ni5YwAYTRMGGQCvVHz4tjXpF92NPsHFVxYZmkeA priv=MEcCAQAwBQYDK2VxBDsEOQAZv9xKBWtq1f3oPDroU85qcAlgFk8qFTXElWUc2Oyter4GMXSZyn9xFxp6SXrgT8RJ+QEPa6zD8w== msg=ABm/3EoFa2rV/eg8OuhTzmpwCWAWTyoVNcSVZRzY7K16vgYxdJnKf3EXGnpJeuBPxEn5AQ9rrMPzLQVaBoDpVg== sig=0mjqOhYaxrUOWwecZ3dmd5dkXShMWwvnv6Rs5qVcpom1e8A0LC9ecIHcQyrm+K4lpNItm+FPD6wAUiOpBExJ1eHYyUJ1kcJsB7z9V679jPHJekOSv43L5uHAKL2g+sBCVeqVyf7a2POlLYwEddvSKjwA e=found last=21 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoACdazrEvZM/xoiXdwVG7QmE7VD3Ykn4Lp6m2aJhrgCLSHaG/fy2wC4m/4rsSZo4SsOwqtP2/XRi8A priv=MEcCAQAwBQYDK2VxBDsEOW84iU3k3hJUhQpP3QshemonFBbxzOQ9PGelVmkZPkC+KRofKY9EQoB0AE8nqsEczEtdOq5+xcvEmA== msg=bziJTeTeElSFCk/dCyF6aicUFvHM5D08Z6VWaRk+QL4pGh8pj0RCgHQATyeqwRzMS106rn7Fy8SYjJ8NidtRBQ== sig=wO7+yX3fVqyg97rTXuk2IN1Ni6w93BKB1GGbLudXdRbP3wfMArJ75jqc1eea6/1U4YwNE3cTMkYAZYfX6AwjvPrOSRUo1+GGBaY5j/a4OqO6TRQ0rpLclnp1yFJoCIHn9Iw+x3qvcxslGOSyQDnbwzAA e=found last=27 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADvABfkxzXlQRtnh/2o+Dq4Dsz8TaMafcgv6O/1JnauTWw68+kQ1iJCZJ5Uw/XLrTQvnEKn/kFNOA priv=MEcCAQAwBQYDK2VxBDsEORQKoc7dfqaXVC4CSrx6VAOj26vQIHat0wW5T5uhUHsGO8n1DHJu/Z5pb18XdYpnEat5gF3h5uiHuA== msg=FAqhzt1+ppdULgJKvHpUA6Pbq9Agdq3TBblPm6FQewY7yfUMcm79nmlvXxd1imcRq3mAXeHm6Ie4ELsVxF2V4g== sig=awKRNikB6wxU3hFm7HN3GaSmAhVpSWfvCnoQK/cvy/5OHiCv3izCPTPCiXvP3jieZHy9OjWPvh8AiEp+Vugq5hZHnxYDVoCN+OEQMks3BvAGSPtRe/5Pg2QaqhPy17M0rs4/NPiNKvRug+qet/b7YCAA e=found last=20 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIksuNKlOavKqrP8+d4Ayc0lvvfH2UIRag+SFoBJDF0r4tzBMddKLHIEMenI2wpYVdJgGWkh5YDYA priv=MEcCAQAwBQYDK2VxBDsEOUnDGPnKOFcwzsKRAHMztRULdwb4NfyyR1bHp0q2x0dz6OmzfJJbaAwbhYVETl8nqj6dVtcZiF8W5g== msg=ScMY+co4VzDOwpEAczO1FQt3Bvg1/LJHVsenSrbHR3Po6bN8kltoDBuFhUROXyeqPp1W1xmIXxbmb19ARt2wyA== sig=QMdHifUOFRbngXeuNJ2YrsbXlYivSo9QpMwdzlMDczf/SenITen/7JhOqG18f0O0x+I7zkJne/wAoEK/ysXosSNOj2iuAyI4TrmbyOYmxM7LGJMWxSbDEZ/Dqw553ai246wetXgmwxrdH1T1WkcrXSMA e=found last=20 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA8DjQwQol0koNLpFgje9/aD7XhupbumRYuqdfQxGzCVfgGpcoXmNRlhwkJY2nAWbIomO/wZcO0uuA priv=MEcCAQAwBQYDK2VxBDsEOcZhyisU1uGbW4a9yWbvoNUOLFKo/vgmOg6JjA03Ik+hDzXNz0ZHrVSEcVaeQ31dtuUdlw9thSY1wA== msg=xmHKKxTW4Ztbhr3JZu+g1Q4sUqj++CY6DomMDTciT6EPNc3PRketVIRxVp5DfV225R2XD22FJjXA0ll7FNHIMw== sig=rD0wzKiGKxsQeJVVnK448Tp6KOEibUKXNYbYkg90jU5RWGrT1mj3+d2zF9ktwH6K3CVHPF74xL2AvYVoQNl4zuf4mCM3wWefcZNOuYR2cktAHrjDgpdtXZXlGCw5YyzhuT8aBMiTCnf0oH90E2MDuhkA e=found last=19 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAa6bpPP3iOAFKutKMt3YB6tVZGa8MpFqPirAtqusZJrddNYHMRDC4Z5468cgXdopp2GUSer6zU6sA priv=MEcCAQAwBQYDK2VxBDsEOfPWx8CjmYGaZlQVKMzARuFAM+vlqzaBlAdAN1+1hXvL9iXjXjHCuZlPtYwUq1o7DRyqi4T2OMd0Ew== msg=89bHwKOZgZpmVBUozMBG4UAz6+WrNoGUB0A3X7WFe8v2JeNeMcK5mU+1jBSrWjsNHKqLhPY4x3QTyyKWPN2xyA== sig=TvC9ExgnAzHhw2nXJrkQwuZTWSeYXEegCTiqi3BF4ay0GHUz2CaUFgO6rOzI559NhBSWNuP+M7SAwsi7TlnPlnWXv8jh3iIoda2sa6b9BruzOGdjuqHWU01K5F2ZuQUNmiJ1RXfBJp1+O6HLABOeGhEA e=found last=19 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9gAifn9J1dfXBsUkLHHCYN7Z1jd/vMRJuAP+BVqYMR17M0W66hn5j0tOdUUhGOGlsoAF065ZFPYA priv=MEcCAQAwBQYDK2VxBDsEOWwBeLRwWkBG9loa80MK7EsgB4rXAf7H17wk3XvCcTixwQ2y3Fx0fNMEeZK6/vmA/49Q2rmUicgVNQ== msg=bAF4tHBaQEb2WhrzQwrsSyAHitcB/sfXvCTde8JxOLHBDbLcXHR80wR5krr++YD/j1DauZSJyBU1mGiQkDLCMg== sig=fxMm22lcaojZMSGffLYnLWoWsNaTR1rxW9I5CW9FOZBo7HwTKzL7TjtIiUvbw9b0YBQIyp1+dpQA5ytH4swcPRNGTFdi5MVsxq3tuOjJdYeWcOCK4qoW1y+/vlMLx9lJXxwdEKHlJEQmEY5kOgbecjAA e=found last=25 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApyxoTQDCGAB/faWE0F265jwXyxuN2LWm+jN/+saH2g9W8jpcaU+cnRuDhfO6ts9cmzjQWKhvtoGA priv=MEcCAQAwBQYDK2VxBDsEOYxDIm56AEXwu1hQocRoOTOfwxHA/nSO74DA7xCgXuvEDx3eRCDb80vQetZORNhn/EHHMBx9iZ9A7w== msg=jEMibnoARfC7WFChxGg5M5/DEcD+dI7vgMDvEKBe68QPHd5EINvzS9B61k5E2Gf8QccwHH2Jn0Dvw3m0lTwNoQ== sig=lR7rbni+Peeend85N2RIInTpde5bgT0NukMiMea9hQarFvRYum+JNWMrSNaUoraO/V+1F5IYIg8ARruSju1WvAO6BphLL1NgVFgS5VCy+l6oBDbH+9yq90aMRgdzEr0P+LhnahON8XfNJBbkLx7RfwwA e=found last=19 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5iLLy47l4+0xpL+6MVjpmIkfBaBYkG/JPIV2cJbs46Bp2h+sodGt8l7PEwaUAfi1oOg8Itq6MfoA priv=MEcCAQAwBQYDK2VxBDsEOTix6zskouM6lvq/Ie6ZLFmkUNNjQ6IyB4PnFVlvUn0IINzLgf82BvNboNj0PvNqO0y43+4986OXZg== msg=OLHrOySi4zqW+r8h7pksWaRQ02NDojIHg+cVWW9SfQgg3MuB/zYG81ug2PQ+82o7TLjf7j3zo5dmuOfLf3JZZA== sig=sc8u3akqY3mOp6KcFOJecJ5BIksiHzXH/R8L/vz+CaAgoPlfFvm+5WnkxUyyjiosSAFCT50N6hOA8jEses/iJ91TZYTwwNbUS6flAbipIquvaGP8yLKK/MgHIdZAcRfKg6IoKi/9sMxLZ9mk8ZZb0RAA e=found last=25 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAgxXFB1FYRn1aLattNITrBzHCN1Tcg60tiPN6m8UDyIsMZUzSbSfRUy3UgRh5Q5S4hsfCKF06DKsA priv=MEcCAQAwBQYDK2VxBDsEOUTfCH4vQYRzYXfSZ0OqM/S/S82xEUsguKNMy6vaOZ8PYdPZ1iMqxUvcCbUQoxzoiS8eB9rBOuSVcA== msg=RN8Ifi9BhHNhd9JnQ6oz9L9LzbERSyC4o0zLq9o5nw9h09nWIyrFS9wJtRCjHOiJLx4H2sE65JVwaNhkX6zttQ== sig=g0HehijesMyjtMSui0dDKVHaoyl67BKDSvAQyuO8bs1S4OUqfGTbjRU+F16prq3X+3qmoZsBY6cACNdrkIMzpp3t12dVP+OgOulkNmQJLjLO1BdJAgUnT2HLK7xeFkSk53h+GQb5P6e7OLfAY2D/xDQA e=found last=19 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAkOUR4IrUuH6XD3zvEdA5RGOR2J5EUNWGtUOMec9uLl7HtWnoVWxVp/Bf1LXAdA+nIyoGKjG2YPUA priv=MEcCAQAwBQYDK2VxBDsEOT3nwF37M4AbWbKuuSqy0+ZcWN8T+BFxpdFwSReXMEdocdB0k9te5bPvdj4osKZP38ICRaw1NNMCmw== msg=PefAXfszgBtZsq65KrLT5lxY3xP4EXGl0XBJF5cwR2hx0HST217ls+92Piiwpk/fwgJFrDU00wKby05FwGbSLA== sig=XG+xEpXbma3+9Ot5hRN6gRp7F+hFcIiajZlsV2MQ6mK+xf0FhgKw+0v1/31c2lhNpgbHrjN7VMKAlxOvvPoBJEEOGweDxVbNRLS9UJqMQdRwwNQM8hZZZoQfRiJPhc/ddZOm6rZclqIQu6MKBPLply4A e=found last=19 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAh6uqMpq3LkSQDOJ0LjpYeI8k/jWSrsnwd8Mr/jLc9DOSXtMBM44PDwqJdHNrRAJJkCiorrYOwhCA priv=MEcCAQAwBQYDK2VxBDsEOatMM99UUs/8lLTxKqyvAihyh4NtDMJ8CM6VJqoi6EiER2FTMC5xOG3ROAGjOcbXcAbMXcYLHeokuA== msg=q0wz31RSz/yUtPEqrK8CKHKHg20MwnwIzpUmqiLoSIRHYVMwLnE4bdE4AaM5xtdwBsxdxgsd6iS4M4yhktbO3Q== sig=N7G/gLc5bk57KE1g0yhb4XZzDLZBb91nJwfT2CLLUcysrRoP+VMYQanc3pLEzl14Ohi/N2gsrmeAQAa54TgTTjfXYB+vZTv3NfJXz83QaPfSr+WSgCp9s+rZtnLBzYyhkCZbRiNAWlF9HrQtrdIJqw0A e=found last=19 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWHQ+UGqtknhzT6WPCG37Er+Qx8u5Rx+18md/J90R1TFeDScAHFgaoy4qbQHfkTPR0k6f6DHBD4wA priv=MEcCAQAwBQYDK2VxBDsEOc4dtGze7HIkEAnnZVvIqoSaq/+PsTyMXT/Kgirux4efOkf4klPu1u52O7+sezp/q8VXCrKkAtHwjQ== msg=zh20bN7sciQQCedlW8iqhJqr/4+xPIxdP8qCKu7Hh586R/iSU+7W7nY7v6x7On+rxVcKsqQC0fCNFO5XFxuMQg== sig=OvBM1yf0ztz6s3L7dF7foQdaw28MvqgKvqBZukqJz9Z4dIxjubOwm7yPSnyPprPt4viI9AR/q72ADYiLhYrY1sJN1/09ATq0l7n6QbEozFwWcnXra2oBuwR2fPohPjqc3CbufOXcdvIyB602SFoA3CMA e=found last=19 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASaV/Rp7bF8MCINwYu9Sm0ojWa98qznylAtB9VDBikUt2MDEKO9+Z8u1D88MbP76BG4HoSN4cj5aA priv=MEcCAQAwBQYDK2VxBDsEOS57zLP9BVY1Kwot5DMD+DE4qgNJcT/nE95YNPFF23xLj4WTD7H2NApxVjsYduHhALbiGLCFYXhsKQ== msg=LnvMs/0FVjUrCi3kMwP4MTiqA0lxP+cT3lg08UXbfEuPhZMPsfY0CnFWOxh24eEAtuIYsIVheGwpIxaDTrq03Q== sig=qyCzze3aURVV6ZpI0Z17QqH+/9KdJafcpsmdhJjbxxBfNSZL3vOy9d6xuLMgPEgfLYd2BJDWaG8A0ExcUY71Wc+eaP2w7bmnfApDFz3NqAeJHfch6sqpZZ5AHxVSIDJBCbxDVQiDO0TXi+Opx1mArBkA e=found last=19 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASVrqqbjqz8YBNgW0q2+CgEieG+2cXzjKycTyWYXHHPEuQe3klLFzwJH8Fiz+r9m7KFi7IeSx+woA priv=MEcCAQAwBQYDK2VxBDsEOXUgH9tM0LnmLbcQzC2kBwlXEqj3yqo4XtqvtYoqrp/EpDE3093rEBe3zjvGG3HaeA3ItUDv4PCUnA== msg=dSAf20zQueYttxDMLaQHCVcSqPfKqjhe2q+1iiqun8SkMTfT3esQF7fOO8Ybcdp4Dci1QO/g8JScFg2NFl7OVg== sig=vDlM9yU8mGQMsOswOqHWLvowO4atcD188AwWY63gGyRZfwhRXMKBa0aDPn+s41SlsWIP4p8ImvyARCfRwtjIDPRUZ6yro4hYBVCK7DMhGLz5IhDtySsf3q2MEdQAEd2S0zcgeXReWrNjcB+ZaoCKzhcA e=found last=18 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIhrmgHn/1smfP4pJuQk+2ohWQSrInIUYFpuszbLgKlF04AsVf0wT6JjmimUupa3LEquXDjXeT2SA priv=MEcCAQAwBQYDK2VxBDsEOQtvMr8kzMRaMbm+1juPdPJ6hqLuu1VF4k6Pn4luAOyzVcU6X9Uh0vPtjEgwCLlVU1kkv6p/UNmYIw== msg=C28yvyTMxFoxub7WO4908nqGou67VUXiTo+fiW4A7LNVxTpf1SHS8+2MSDAIuVVTWSS/qn9Q2Zgj24Qjhinxnw== sig=CDlEXj/32NKSK9m7CsnSZX6FWevhHiYA/9wgobzc4odr+V8j+3CBqJ803iytEXbxZfRxKb5r/cWAalzab+/Ad3PTa1+KLiYw2YPu8KpngH4fIHW/mQZeZtff1/zKI+rMPnDoxp/3fLHRFvXkPTEXIR8A e=found last=19 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoANBOvZGnsLyHTbUHLEhaj7I1CFUnpIFNHBwiOxraxEAzmQaAuCsdVMb2+nbygkw2e0ByiqqbtgEUA priv=MEcCAQAwBQYDK2VxBDsEOfL1FGEFnNlBxZWcvgMqQljZ/grzmAvsp4sHg+Drl1b+zvy11GsAgqhGO8DfNkSYtVI6R/Hl67I/QQ== msg=8vUUYQWc2UHFlZy+AypCWNn+CvOYC+yniweD4OuXVv7O/LXUawCCqEY7wN82RJi1UjpH8eXrsj9BZyA75RDRUA== sig=Up4PblPTXTGlsU81QLMJ53pUuj6PN/QPxoTKdxJzmXceVQqUNJpqRPwkZf2fH5HyFXOerGV5cwYAxinu4SNmUCiv7pjvktW3b2eYk5828P6EqBwzqwmKfjYJ2idWLtJe/zslaiMdwWjoxd8xnHQ1rg8A e=found last=19 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2vOVe1Xzs8T4PHVsz7xxO0Cwa8MJ2eks5tpnOANPkj17uzAAiykvR1I6BO6FNnos++FMk1fD0G0A priv=MEcCAQAwBQYDK2VxBDsEOXZ1PrC4E1aeJ5W0XM0HWnq5Xc6fe/C1DR0IJ/Rj6Irn3lcb/veJGr+kIJ2X2ZyOCvR6Ea4Ux/F1sw== msg=dnU+sLgTVp4nlbRczQdaerldzp978LUNHQgn9GPoiufeVxv+94kav6QgnZfZnI4K9HoRrhTH8XWzsG+hPHfJuQ== sig=etyz6/knKcLc0SgVhDWYPq8hlfSVJ1f4mULbZJGLZ5wZvejHhY4g9onzRT4NygRIbXlFRRzFyuMAJY6yDxmYp4hsH/DEbfE39J/b0x+mrqUOijCDbvjci+7fCOlZpu/ZOCBMAbRQ0AVeN6YP7x3OBhgA e=found last=20 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAgD7fB0hnnCOsFGTV2h5lNgGpy7GteHflb9FIf8uq8YaM3IWvAAuME2OLJ9Llc0TFoVCivhSy4lYA priv=MEcCAQAwBQYDK2VxBDsEOaS4E47OQyt8TBOEHjRqfKU2dtvuBg3gJYGFggiTEIuKaDEDYk0CV+AJ4pdoOElTpsYTBcDXwcj4rA== msg=pLgTjs5DK3xME4QeNGp8pTZ22+4GDeAlgYWCCJMQi4poMQNiTQJX4Anil2g4SVOmxhMFwNfByPisaNQqdeafFw== sig=J5bx65RAk30HBdp/LdCWp3pbVrkb1v3YMS5d1uDOGPgIiR6tNBU7TKmcu4GNumstMK8z+wwjmUgAsUzq8i2LfoYNB4wSB84cKjUBjHV6Mb9anxIVopRU9gBF27o7QszeB85rB3Nm+YdsC+DSS0VViSYA e=found last=22 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoArqE+fQC9byzh5V/cyALAVZx4QFtCdu1Bbfjcj8tt7ocLBtiyLnKOGL60C4WXlwWaKcF1zxiBoFmA priv=MEcCAQAwBQYDK2VxBDsEOZw59cCnM9KMdE6WfroNHAkrdxvlg1ExFxbti8izlkFuV1QsXlYKU1Z8ILzOqNdfVluzZ5vAJYRdJA== msg=nDn1wKcz0ox0TpZ+ug0cCSt3G+WDUTEXFu2LyLOWQW5XVCxeVgpTVnwgvM6o119WW7Nnm8AlhF0kOv2z38+0kw== sig=4YYOiNGCSO9pngvdsFNp+R7qT8sPBK05Rt0e5S44SXU4sUeDoI1VHiK9e0we/L2EKBH235C9O1kAoUKbjuGStkiY4sN66tAjS6wCPrINmW2j7vxBQ4dRAwbUuvaPP7UMB1Ys6yr0kyUa512WkjohZB4A e=found last=19 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5AX08dhPiHHxQRACIFnRY6VZAuhlkEEQTgLwS7imPKN21MyTNbK2/0V/6o5I5IJkGBnKr07rKSkA priv=MEcCAQAwBQYDK2VxBDsEOX9MIDjb+KcF64/wfjIlEx4pIQ5nGJYVxlCm0htFO3IPTzW8+o9/5CVT8PXFqKlti5PzYmhB+vv6oA== msg=f0wgONv4pwXrj/B+MiUTHikhDmcYlhXGUKbSG0U7cg9PNbz6j3/kJVPw9cWoqW2Lk/NiaEH6+/qgevaLQU8X9w== sig=nIop4Ame4YvDx4t0JowJVK80Bdgmg8jldqEb6oEwz9YIJ3BN3h0/1tkS95s7xJLI0+hoBRJtQh6AMEds6Zre8wJ+UlugXkf9d8Bnb+fch4CfCOfT/FwdS5UCi1Mxhr3LocgzlVUTgbztqNTY7D8nlCAA e=found last=18 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAl0wLFPcfMz1hArXei7MpFOuK3Gp4Ib/4ctxQHEo2DLUeB24wJbC99ubzIRMk1Fj09kV5yrErz6+A priv=MEcCAQAwBQYDK2VxBDsEOWAuEHbmSZ/y0vHbYPTkjcv+mPbD3TYBy7sPnr+YrOsO3xohJL//AF2cOXb+kxUvbgxY2vXDMp44AQ== msg=YC4QduZJn/LS8dtg9OSNy/6Y9sPdNgHLuw+ev5is6w7fGiEkv/8AXZw5dv6TFS9uDFja9cMynjgB3opaEXevHw== sig=88JEMeAejFYTEYrAcj3BF03fyaXNbneRwq2lQT4krwdVJNZTwp4Y6NcQJTVzIcJ8nJ/Zb4viLmEA78EsLWvp1t9/KUXeU+6Hbs0WrQJI2KPWHOY1j1Gz3M0h8hZmNVOjHev907xm+wtEP7mBPuLT7jsA e=found last=18 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAzXbjVrYiFrYIh6zFMATwC0KQ0Gf3G4OS6T12aAEPJmhaU2HirY7rExITDDbFZqxVvnKJRYQnKkQA priv=MEcCAQAwBQYDK2VxBDsEOYSLXqIsW3q4av85m6W5xjyAWRb0yCS8MuhciWufs5os7JGa7EPjsVz2L0DGG95teKa4VWucaBiJiQ== msg=hIteoixberhq/zmbpbnGPIBZFvTIJLwy6FyJa5+zmizskZrsQ+OxXPYvQMYb3m14prhVa5xoGImJ6MHHl/ryMg== sig=klkaSymmcTDkTfIl7aRNeFBqQ8vZ6GYRl08VPJKIm+G66Lk+ywzGVDIvnnKe1pAIND8KrjdUWWIAus6Sy7Q/zeYcmSmuNm58MiZpJr1hDMuS4RgzQ0adXakc5+M91+I0JpIiw9z7ENfLjmBPjjSH7wUA e=found last=18 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuLIKGmJI60O1PVQef9C/47P87XgJHritBR2br2RoqQ9jODNDbkEMVtfFlml7uZRpBi3rl3Km3egA priv=MEcCAQAwBQYDK2VxBDsEOenkb4RQUHfq1yyxUGK88B7F4uUTwuPR3FxxJ9rKKluP3zNi6D/HgAWJUlM/928oTAf3N/Gwjrk8ng== msg=6eRvhFBQd+rXLLFQYrzwHsXi5RPC49HcXHEn2soqW4/fM2LoP8eABYlSUz/3byhMB/c38bCOuTye24rrDAeXjw== sig=aZYgMWZvysyOWO1l5hg+tYxpgzxP5yonUDU+N7b6CdWuoFlME3yV+DTPk8jTR8uFxS3ZiX53bcEAKh44gDpWJwGOjOOZFh0y/pJ618ui8SyFIoK+fK7DfAEihQpI7IWiIA3cIOjaY6TFCMT8lcAmgy0A e=found last=18 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAerJwMTSiAfgk09woZTfm4jWI9Me1JcDf+FsTC9Za1LiGsE+SOdJsB5q5BuDX91mfQllBOp25UioA priv=MEcCAQAwBQYDK2VxBDsEOWy2lx8xhDaIPL5F8oktBqzuoX0bSHQ0mixZy3INKt/wsENXheiNeca5S0dZ8NBapmEeTGPaQ+Dm5Q== msg=bLaXHzGENog8vkXyiS0GrO6hfRtIdDSaLFnLcg0q3/CwQ1eF6I15xrlLR1nw0FqmYR5MY9pD4OblYLjYPCQK+w== sig=apY3DYpTb+MUAhYhtyRkTuIh0bYWN9MWL0eN5Gv3Hfs1Z3cFK/pQz5v1gQC1gwRA7Ndk8v+867OANGpSngfSuJnVliKiJxxTAuGWNMemmASpUcH/Fu35g9g1/Z5cMZvgbrhMHfQYfBLPPXMVBxe65REA e=found last=18 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfwbIA4f07JeFMg0luuQR7/JApm2+OFYqZQfa+mfbUdwaIZB2BWB6KqMUXUVK4b+jxKo9rm38HV6A priv=MEcCAQAwBQYDK2VxBDsEOehZwd2zGz8OTqRkRaexpH8W/y5WsNBGZyiSsNC55goZw2+tMs97k1gxF5h31NXm8jFwvcd7OZ72fw== msg=6FnB3bMbPw5OpGRFp7Gkfxb/Llaw0EZnKJKw0LnmChnDb60yz3uTWDEXmHfU1ebyMXC9x3s5nvZ/Vb7CG3JYRg== sig=sLc35X7CSZdV8yC5D9MMZd6Ifg36WBdvImROA48t9i5e6Xqz1RJw6Pwno9MdPsjWRnvnCZ5iQNEAuwsNlVjTlie4SfQw89uRnMpFXoKU5y4PDCAY7KzHKVLKTUOD0iZJ3luBlYoxx/YFT0a5JpAv0ikA e=found last=27 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAk27KLvIY8+6mzeEvEl6vFfzjBfz2CPaIQP7QvheiwMYeMugEVBoc7PSgFac1x4FNicJRZykJ3NyA priv=MEcCAQAwBQYDK2VxBDsEOTSD6tBR1qHvJDW9tO5WRFClgyTD/wE0jX/+qh83VvDIuS9x49dSV+WfLGjVcAoH1mCO51F5bYLu/g== msg=NIPq0FHWoe8kNb207lZEUKWDJMP/ATSNf/6qHzdW8Mi5L3Hj11JX5Z8saNVwCgfWYI7nUXltgu7+9vhPzaOneQ== sig=aJzVygGPAQ4ZV3pVgolwwky2Ulj4RSkmv4VXyETXo3QyrK1pwFW4N67mLaHSlDS8YsWrfu3xmEuAK5IlriZecaVb+dBqIsOL9Si10FQiW94YSS8Zv4iEepwEbrWYgI3QuA75GfjFzcmmMm59OqglXDMA e=found last=22 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhYVojMRffaZJCduKShfjU987AISUGYwsapC1+16FEBrQVheS6hdOurFarPjdg+lYT+rRxEuK5V6A priv=MEcCAQAwBQYDK2VxBDsEOai359+i7pRMtZaC7U7yQ22kYQuGRtq7Lc8D+fFoSxByHA2dsakq57m8gWU00G7J/gtrrvD3e9ENiQ== msg=qLfn36LulEy1loLtTvJDbaRhC4ZG2rstzwP58WhLEHIcDZ2xqSrnubyBZTTQbsn+C2uu8Pd70Q2Jm/NuDxIPTw== sig=bpdiY06WsU59ofeV7bzwzr9MCZ8zkVeGeppNJugnQV6qkmQgUExS1FE3bJX7zi0fIFY1AUfQ7OUAxOSx1ylKgDknC9RAnnXujFAqpskR7rpA5kOv5G/maMTC9Y9qUTzEi3pTLTnt1+hOT6K7MQkD4RcA e=found last=18 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsDdHL/S9FzXPjAZt5GZcQ4PX9yGLx5e4sS2fOmv0Cqnq85ioqRIyvIo6kc7np1q2xqZw4gxqfX0A priv=MEcCAQAwBQYDK2VxBDsEORlJU9d6SbLoeNH7S5R45XkIVxOWmoa2l1oC2QCRTPa0CBpjUovpzVtOYuSqoFPbB5mfo1CtjPB76Q== msg=GUlT13pJsuh40ftLlHjleQhXE5aahraXWgLZAJFM9rQIGmNSi+nNW05i5KqgU9sHmZ+jUK2M8HvpZ4BrLq4abw== sig=i0bdaP4tqSsy/qj/g1L/z/E8pzvrD2VWm1G12cPd1YkA4b+0ZFBMK/PXv8uLaXHPNOp4jZO9DcKAHLIb4Wl+vNH2FBb+qPmfAjXml39yR+DQvUsqYSpWOYTEu3V1z7k+STAu/5KtK4ASJqPyhZLKvisA e=found last=18 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwUdIWJlISc65cPpePcV0/LTp0p98Zc36fpVc9MX6unozWTznLR7Snr1vR29gXFzrrbx9mwKwTuEA priv=MEcCAQAwBQYDK2VxBDsEOUF5giYycQd5Nn/5SH1i+X03rEeQzkKYxGfnT03r8HP4KGSv2SFaxirchCznGxEB2fVRETHqplwmrg== msg=QXmCJjJxB3k2f/lIfWL5fTesR5DOQpjEZ+dPTevwc/goZK/ZIVrGKtyELOcbEQHZ9VERMeqmXCauVuOsNYpxNA== sig=rZblyRUBrukDxDQpLpf8Y0IknvpKUIsrlRUnpHYsanIXXLj99ZDWEcLuQ+5dP2z/TqpIljlPptIANwRSqH2+JO5rIFVZbz1Pi3S7JR3Ga2z+5cGmToQKsahxeCPh1uNvYb08v1nGqQykFGVA4E2X0hgA e=found last=23 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfzcsgdQKIG8VTiMQ/f2FjPK867/sA/kjnYlOvQI6YoJL9AwV1Z94c/0fuQXl0A38AeHbJVdn6mCA priv=MEcCAQAwBQYDK2VxBDsEOU1CfDZX7WWyPLwMYLXQahYQj6bRxhdSBzZwUR2LI05gRuKSwdHlLrs0y+G84JjFyTsuNyFvqvw/mQ== msg=TUJ8NlftZbI8vAxgtdBqFhCPptHGF1IHNnBRHYsjTmBG4pLB0eUuuzTL4bzgmMXJOy43IW+q/D+Z4DemuZ9hYg== sig=Ln+mFrl7XiDzXeaZ8OTbqvJuPv+A0JdV8JNNklphoOWWylKIsQOD8rWQrqS9WlhR5LLsSEr6LcqATUwkRvrMDr6BugSy7xJQWOAMcxMDV8YxF7i1btivxP0Kc3hhY03vstlbpuIXFBQuvfLbqV3XBxIA e=found last=20 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAp/fLQYIQJufdgK1PBJk91N7A23SpzqRw+EAH6YpajJG2ok9X9QWzdtt/aMQn0f0ACv80TRfHW6KA priv=MEcCAQAwBQYDK2VxBDsEOQUnkB0UUbIyFZozyvg2njxsVdXcyGeHaa7cQc8xm1azYxRjuHb1lF9IOzFv745jVcMj5GhzSBk3Aw== msg=BSeQHRRRsjIVmjPK+DaePGxV1dzIZ4dprtxBzzGbVrNjFGO4dvWUX0g7MW/vjmNVwyPkaHNIGTcDlQxsU/XsrA== sig=6XSqnZ7mzDX+t443Xpr51t1PPScp2wiDXCiqXuR68qnrq2Kk5pb5fNzEbd366rRjDKQlQTb6yJeAOHtVNqZDvrS7kpfIo0lwifs08DtZhv82jjXo0R9fTySk8WvhyLYYH8yoa0U0gxCDHIdn5ynW2wIA e=found last=18 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAcNFPbipSp29ZLuliEbbWiShmc8C8eB6V+8OHeKDm00Z3DlDFt07yIMwS9n+OfL7iHXDj4Ud2JFMA priv=MEcCAQAwBQYDK2VxBDsEOTDx67hp1kMLij43vsu7RnXtgV3N2Q+addKU0urP28l2Dy2yll3r6EleNI55bz3u6nAt+5xAKzDtgg== msg=MPHruGnWQwuKPje+y7tGde2BXc3ZD5p10pTS6s/byXYPLbKWXevoSV40jnlvPe7qcC37nEArMO2Cks1NmiU+/Q== sig=0TWSKxj79Y3pMsaYwsrvifhr4DXEI0ZlBiKV8E83/FC3NJFrOvc0b6kh/PVDPK3ZyIJHmNI6Np0AM8rTijNLpqovxVvwiPcF2cRNWsMoMu1fn4Y46bC/R3FvfTrtvnNY6Cmp2qzcWj3pGdhrnnY6oTsA e=found last=26 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAjrsDbtWGCEqPBUxXERQENihD49JUq/Ecuew/lhqNVD+JT1XM72H6WuopcpX2iEVdYYS6O5MISj0A priv=MEcCAQAwBQYDK2VxBDsEOepqJzjfrrAKVRwvAal0sWa2CeuVc3vYUJ45Od+V11FKIKbV0zca6OBwg5PdKrA5wuELe4ttexGx7g== msg=6monON+usApVHC8BqXSxZrYJ65Vze9hQnjk535XXUUogptXTNxro4HCDk90qsDnC4Qt7i217EbHuBi6r+pqsGQ== sig=gmy2wEaXYPeIwcL8IOgn088NA3KrHajZU+3m2PymqZ3L4mqPx5ZISOgILwDjZaLRniZLjSLTzYYAaloRz0AEXqIc8MPA+tnx0UQ38HuGGa2l8NhS/pzl86hYxinxK3ra+JAJme+pHzOfg/HrlmABahsA e=found last=18 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASFaz65nr7hUll0/2cIUJi8jKyGwQPpSYN4up2Yrt3TbrtjH1dDls2vDc8ciBqozuyETwNeq6hI+A priv=MEcCAQAwBQYDK2VxBDsEOcC6ftaMJk6ZzI5VVww+PTVOHUevhm+FtiLEINWBT4xNd1xdfE6Xyptc/1sN6Q+rYWsC7NNi5BXnGQ== msg=wLp+1owmTpnMjlVXDD49NU4dR6+Gb4W2IsQg1YFPjE13XF18TpfKm1z/Ww3pD6thawLs02LkFecZyueFMcyELA== sig=yMHjHYvmVAUL+RTd3Fkkr4JlA4kUMublgsrZ2Uv/Z/5z+lWIc/9R9o0244E1Dp8Y00vVvlUcBTMAgBZaO8fDGksuzU9h5JI7c07mH6VeokxP8JqAvNrSDZfXhY1b0xgiILE0pYWk7iimwwxxKzieaRQA e=found last=18 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAt2WkWjKIh4NkzA0eoofwlqCRHlOYUEgtQ+v6qMQhWAjVG8kF2o4kza+nHLctmDybq/60ZNmNpb+A priv=MEcCAQAwBQYDK2VxBDsEObfxZT1ttf/yWxpBRxqG0bbUm0Dme3oyDtgHFTT2zJjNCvFpkKDHaQH2XILJyBgNsqqsB0u4thEwww== msg=t/FlPW21//JbGkFHGobRttSbQOZ7ejIO2AcVNPbMmM0K8WmQoMdpAfZcgsnIGA2yqqwHS7i2ETDDta4zo6JPIQ== sig=WL97u/UA6KhoTwANDk1v2fAv3f6GOTRIwstKhjjH6poNH13UKCtZCOMPh0mSDb8a367C2XhQnfUAdi3dD/yB6MQBm+sPWtUYboHPwA6fTVLBkGZIbkPhNPsfYOgIlJnIq0ZFQi7XBvmdW1p44GKVPxwA e=found last=18 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5diy9Cpy79SkpFq0poCSxSOS2uwdtFbjNrMNHm0z5AhEJxSj2hudArrFI4ZH/DwOdXo8n28H+3AA priv=MEcCAQAwBQYDK2VxBDsEOf23LwOSOxCFA88jikUHnljMcpXLwP8t3YhDMW2X/kWPEyzKi+914p5+Mq0Vg6mCXdaW+Il0TyM8Kw== msg=/bcvA5I7EIUDzyOKRQeeWMxylcvA/y3diEMxbZf+RY8TLMqL73Xinn4yrRWDqYJd1pb4iXRPIzwr2z7YZA3LOg== sig=vnWimHIKgij/rp+3e3TQUEd/vTtpfXRLPtnnFKMeDeCTRJxXWyE0BHIkDbOFbcltIjWOClXjMN0AjLBBr1ZzqYanmXEm+8d/u1LcV8RCGNGwvYqYt17D39adn+48FNBuRvF947Ph1mZo5toBnbOjZycA e=found last=18 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtmHEXzp/fdj/W8iXJXmMtejS4heUkB6Yae1c8N72oX3IO5CPicG7XBwoABrr8RzK6bLg49Bf2fuA priv=MEcCAQAwBQYDK2VxBDsEOU7mZjH8KdlS6YeZr2yt/HSVWIZ7dpab+OYN8sHEQsseiF+fgNmQe487WTfbIUUiw4MBuDW01iy2Cg== msg=TuZmMfwp2VLph5mvbK38dJVYhnt2lpv45g3ywcRCyx6IX5+A2ZB7jztZN9shRSLDgwG4NbTWLLYKckw7EFR4kA== sig=CktlhAQyk+kJghFsjVmSdPaBaMEg963vFUJIpGhSyA/nKJ+dDYcCtU0RCFtPezpYqn0bcRTZDdyAyEYIRcKtJb9TztOJjJKzpzQwRKpaeIaXW4OFsrKpWzB8U277aRKEqJGAYqH8/0vyZ7pwrE0IgzcA e=found last=19 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9pIVzbcfhxScfDUQy5C/ETrt5a+BN5BhZXxCJNn3ZnTXoWKHJtJqun+dipZTkNbUP3ibomDUvlUA priv=MEcCAQAwBQYDK2VxBDsEOeYj6QZqYntJyQsYG3VBlJzfIU6YAjY9U9nnmfKHKb6h8oq6JYvod5y0QHSI3UNvWWuj34vxEsEfRA== msg=5iPpBmpie0nJCxgbdUGUnN8hTpgCNj1T2eeZ8ocpvqHyiroli+h3nLRAdIjdQ29Za6Pfi/ESwR9EdrFGZoPDuw== sig=guh71jr9uDBlQ7HO2KV5akajCUtsWHhsU84br6LphWr3KPIZIcYr130eiCiDwwgxDWXWtgC5V2+AsX3PnXI1IeBNXKyGFCu+2L51DO7f522+BhgNPLro6imjzF69TZDS4DzH2vi5oJw4tCzn64Y/2wcA e=found last=19 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoArRaPN4ueAA/offO29IfTbuJyrVi/Gr98icxUFqJrHapYARpup4rhNz5HGKEz+2Lm+iYc84W1oqeA priv=MEcCAQAwBQYDK2VxBDsEOR6aFxzjsO7EN1hat3lfVlnsTenAOzG5S9FPcgOZio4ciIMS221f0XhfqH1izsrf5beKALFhwDptng== msg=HpoXHOOw7sQ3WFq3eV9WWexN6cA7MblL0U9yA5mKjhyIgxLbbV/ReF+ofWLOyt/lt4oAsWHAOm2eFHzUIRVb5A== sig=7ba5Gpjlpo8DPCsUS1OnGFiqPJRUyhT7mjN90sCgI+Xm2wy3fzlilyBdRthXoiunGVa6AXfzJXyAwB9cxNIbbrJ8HrsH0ZTrvnByl6aOCbZvXnwGIjRwDIqfy1Rj6pNETLawhEw4xka1y8chZLDelgcA e=found last=18 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAS82x21DwiQ3tYSo06SkGqDTMJ8ujsG2NIdu3Yuyed0SAztQUWvGaoEIpWkK/aJ9qq5cOXPhCD5eA priv=MEcCAQAwBQYDK2VxBDsEOYi0Amr1I6+3Gy9pZ1hwl8xH1IIm3mPxSDSxVhT4VBdW6NElVywLCq9lDFSHTOwjkTFkIrQxUOOURQ== msg=iLQCavUjr7cbL2lnWHCXzEfUgibeY/FINLFWFPhUF1bo0SVXLAsKr2UMVIdM7CORMWQitDFQ45RFqsEXv0xxmg== sig=2EUv4fGPrbtj/ShOG2BGMrYJUnopcs5RrHgx8HE/TqfJjiLqL1iXZaAmW5b7F9VLMjqEEnJXQWIAtYXVENBP1MowMQtae6eoawZP+Ug2zTEoFFJ54grctS7ZFJXW3XS0SHjBx24/j8qklzj0RId/rxkA e=found last=17 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAr7CDHfJsbd0HnKsBjk5fFn6LBTnGmVm4Ky7HERbEHwOm+zBQEqSeK7ZEZ9c48w5lBPmV3a2UAb2A priv=MEcCAQAwBQYDK2VxBDsEOZpCEFZWs2PcYoMDp87VSV8iTZ31Bp1wJ6T3fZ6XqbvSYc+ixg6ogLNv/jamYlT6NMvr857aDW2a1Q== msg=mkIQVlazY9xigwOnztVJXyJNnfUGnXAnpPd9npepu9Jhz6LGDqiAs2/+NqZiVPo0y+vzntoNbZrVn+0R+XoQ5A== sig=ovGdzqhFegiVwcXRQ/aQcMcsvyDVQcngsHhjLq90pwHXiL7FOY2fhGJMeGJdhT2zHbYBFuLTggSA9cbbewFVRwqL+I1qZK8TLkKM5tbwEk4o/B6DQVIkmw/4UQMTjTeXzrKe6tuDSefD02lUjGVS7yIA e=found last=17 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJPZkVsmoBXOlRv1UYrk/XPDiKJyJBhZt+MdXC0j43XG56QZgeIXCSstZP+vKTh109OJTx6L05o0A priv=MEcCAQAwBQYDK2VxBDsEObeH7bg8Vby6aznIYbMikA+so2QJf52c4Vu4rcYgNwbuhmQQr51XLcpR0lOcGqzFO/wqWNhNkAWaJg== msg=t4ftuDxVvLprOchhsyKQD6yjZAl/nZzhW7itxiA3Bu6GZBCvnVctylHSU5warMU7/CpY2E2QBZomqrvBVBhw6A== sig=yt+oAskPvrqtYfyRjPE0QGeKfd+Os5+t+WyiHG/N0leXcpfvbpAhhxIAZ4C+h/+2dbdw5bXBatqA/5ptXf9Zmk7ykfqk7Pu6YyX8Tonq/hwqoxJyqfnTYvkgo+moGQ7sIfaDl3OotR+16drm/IUiOBYA e=found last=23 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGKZxzim/t2khGNyH7H/ycO0aAzvaQmQRiFkQypEZpeSkWIlCn1GPixjATZrfrdVsyugjtAsu9IqA priv=MEcCAQAwBQYDK2VxBDsEOYewUJ/wON8WkTkZVx7SVVgmbT7o0g1te/FKl6GrOb3LiMIC4fE9CSGHG/aSZ6wkDonq++Yd462suw== msg=h7BQn/A43xaRORlXHtJVWCZtPujSDW178UqXoas5vcuIwgLh8T0JIYcb9pJnrCQOier75h3jray7IQgrO5216A== sig=W5iNflLsH/3kQLDjPLi+RHxODnn9UUe4J/JM811E9glOsxOXOD+JdHPknHBeovOsXGMJxy2X1/sAwD+AuQyBrtQGCT4NOty8KzIChPgHuOZRKU/2QWCIWmWhv6Jza2BypZBNu1/+WZeSdWKrvmWwiykA e=found last=18 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbF9Zv5R7jObki+7D7zAke1VSA/7BzPMfk4GdH9/Ogh0YIM3ETc+xtkqVgEcij9BMCpQyFuEpx64A priv=MEcCAQAwBQYDK2VxBDsEOdkFEV1VWl4uBmd2HxAP22HMZ08KKxJZ0vAAotQoMk/JCzouobRnDa/QkoKuv1ur2P+t9tnzpkw68Q== msg=2QURXVVaXi4GZ3YfEA/bYcxnTworElnS8ACi1CgyT8kLOi6htGcNr9CSgq6/W6vY/6322fOmTDrxhVHCd1bggw== sig=ERhjA34fzxCj/VIQj7H95Yg2hHYFWKJo4fg3zFDt2DBrCwJMSGaahPQyScNeOii656nr6REOnZaAOUvz/5w/1f7g4XFRj9kraYkuexJp5HPg4l4aClDYR6dM+mVw3drWID248i/zVUI2bKxrCkbk9gQA e=found last=17 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmqwL5yeV7YlCba1Nr1EcNv0/SzMmOFteBESuAOABztMsG2YFTzXCsINDnJMaDS9pZe0p39lNVB+A priv=MEcCAQAwBQYDK2VxBDsEOVNW4khwrINOHLxmiewqW4Nv4ZwyoqB+tukdDDIjUKHB38CoJkuiuaj9KeTDF33g9GgNG3+yUBnWcA== msg=U1biSHCsg04cvGaJ7Cpbg2/hnDKioH626R0MMiNQocHfwKgmS6K5qP0p5MMXfeD0aA0bf7JQGdZwQJWEU4EnoA== sig=4bapDp6zhep+gq2yepyx9pBfhlIn4psk/c8eS4mo1Yx+oqLomESNpGa5AbGqWqR7j2hcrfuvLZ2AKSiI6A9eHfCRGQnRM/rtM7SVFzbn9ua6b1EESQ7XbzlrVOE5/+dz01z32uO7aDf7FqgAsarRtwUA e=found last=17 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOv6VNwsD1lelGQt4qMOLNMgN0DwI1p0bvq2mexDPJGbL1gLe0UZsBquHuyv8nqqxBOeeTN8WUw0A priv=MEcCAQAwBQYDK2VxBDsEOVXYjbm/5X/4n85uYrUZXecKPvj5Kc5gCiIxfF/UkszqzUZEVuG0KbtP97/dbKlO7JAKPAUbVzfg3g== msg=VdiNub/lf/ifzm5itRld5wo++PkpzmAKIjF8X9SSzOrNRkRW4bQpu0/3v91sqU7skAo8BRtXN+DeSc6t2Bi4+w== sig=HfmwWqJ16tXizerpW6D65udqhYkPD4o1kVKpRZhH0s/A3L/601Fq39wm7saHD1JP5E5dwVLMc70AAaR+yTuE70zS5/7CrcUoJNYxurWFeKHQd7wfxWoi8cwcHQJmqRO8rEKCYDFiueaLg+JSm81awDsA e=found last=17 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAxjzUL7M3OTlfr2DvjS7GtyH9MO4RngfPhlOT+J/rQGtq0Q0+534eXecdjezQTz0EZ7k88FrTfdAA priv=MEcCAQAwBQYDK2VxBDsEOVdmlT3406icNvEKCDGNCkXT/ICJWCLJLUfHQpilWaAWVILM19heUZvO6AUHDDH4ja3eJVAiuI0cGA== msg=V2aVPfjTqJw28QoIMY0KRdP8gIlYIsktR8dCmKVZoBZUgszX2F5Rm87oBQcMMfiNrd4lUCK4jRwY6kHPS0lZYg== sig=5NUQVxkvj7Zf6xY2Xm3xv73Z/3PpZ5B6aJ715oZs11RofAChu25aOIFXVVGiv0UEyWg/wt2/bfYAwx6SWNhpwO+HMfGs6v4nkF3IvIIG/WwO+1NvICP8Oaa0At1sfGu+2eG0HIwYVhf10XzgE69PURgA e=found last=17 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4OM5NR+iCkZXZH4OttcTs+xB0dsVy+KwGkVm003YA7ZjmMA0n3AYS1Lh6UOBG/K+T8P1wD9gJQMA priv=MEcCAQAwBQYDK2VxBDsEOVUBVylr1VYF1Sdjb+xKWe1VgbgBfEY1Ue2GMlUmHKND8d7LDwYAhsGCkaTg/s1cDlPIRoj24nTDcw== msg=VQFXKWvVVgXVJ2Nv7EpZ7VWBuAF8RjVR7YYyVSYco0Px3ssPBgCGwYKRpOD+zVwOU8hGiPbidMNz/6CaungheQ== sig=eelFtJkEQprADQ99nhWLN3hhTPWK+mwUHdBz3YWnNpZMc7EUU9WwGJ9fsp7lVCgwP48iWJCXp9AAAkQyrx8cmsPvAg+XEPgqRWm4AKZemPQBHSjlMWOwMDYrN/Z1RKVP6NLSfzV6J1mNRkkznsT6owgA e=found last=17 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhUF6XxdiMl52Jw8PW6uyr8fc+QZQDCLjWLX7qjLbnC62EXqOH6hXBndMl+P5Nuci8VRnfh0MqI6A priv=MEcCAQAwBQYDK2VxBDsEOdZ7EAjXJoCjRofQv8W+O1NPSf75PEIueP2yniFACLnVs4Ah+7CZm8kPjt9MnRcAiFH14HNN9ALPkw== msg=1nsQCNcmgKNGh9C/xb47U09J/vk8Qi54/bKeIUAIudWzgCH7sJmbyQ+O30ydFwCIUfXgc030As+T4URphS+5rw== sig=VBdNR+ieEh6Oks5h+Apz8HbOzo236aqf2A3x/JF/Xsq81lPG8aGl6CQ7NpRTLgwYlIkgIacl9fgA6Cl2Ld2qe5f59BGjgiAXcBs4I/gRyJmZV4U0PZc+CyGayaofhbJL17eE7W82S3WFcDOVXghF3yEA e=found last=17 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqVGGHybbBPKXDQTML+25BNJpEKWHR7ULPjt//4vYWsv+9fFs+4u2RU7n9Whbq49LaUAqow6gRMoA priv=MEcCAQAwBQYDK2VxBDsEOfOmWn5ByMhEUhmwP0ORYj1ijKBnTF6ArxKm1GqmbYixpmZi4ZxicMiGFh4VKKvoJe/KjYipCTe+Dg== msg=86ZafkHIyERSGbA/Q5FiPWKMoGdMXoCvEqbUaqZtiLGmZmLhnGJwyIYWHhUoq+gl78qNiKkJN74OyqsFuxdfxA== sig=wbGR532StVE0O2hA02cvY9aJaiaKjQymQafa5D3Om81/sQjrqctLRg5B3bU45yCP2bbOhFebQPKAXscVALeVDbznWDJ3fpwm+t8xtPbEmGmgsHlcsabyzohZIgo4FiJgLPRoFA774+kc3C/t7fUoszsA e=found last=17 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAjBF0agDyb/H9SAXc5ioVZMja47ANL0jYgY5r5QHTnY2nMPwQHKT7iQfCEEV3EVNgREnbzIE1eeAA priv=MEcCAQAwBQYDK2VxBDsEOf0FHwoerra9N+kaRpOqCulj8lHbjq2PeIHNesX2CbTPMGxYd/FdQJ3DYMB4KaQ2n0t3T2bQUar+Dg== msg=/QUfCh6utr036RpGk6oK6WPyUduOrY94gc16xfYJtM8wbFh38V1AncNgwHgppDafS3dPZtBRqv4OIMGubkPQiA== sig=XEZn3RvRUrG7x7LLXBHg+b3g5wPMZsVhCJQZ/7BSQWsLF/3197RxHi4XdxM8zGDNmlSOQK+tRWQACMEYuzsdoSh4jTV0YWglgLt5zrNZoTg/isStYhCm7qHlBYmwRHKNe4AEitGRYzasFIMBoAZYfysA e=found last=17 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhzjfsbnVkXNuXEogUYbLinI7AIVVuBCI/BqSFZF8S/m+6PJyR2YeTeyJMKQlNH8wEVyAGG1bXw0A priv=MEcCAQAwBQYDK2VxBDsEOUgTI8lTnb/vPtdsAmLkoYWMpdFLmufCboxFl6HAgKb69A8MIcqUPZfRIwIJjmr+Nlf3kgksiE6lvA== msg=SBMjyVOdv+8+12wCYuShhYyl0Uua58JujEWXocCApvr0DwwhypQ9l9EjAgmOav42V/eSCSyITqW8EhGWpcjqCg== sig=D+71p/SCWSi1P15PJeloW9o/G9ql4sysFfbGO4qCkZTVuZhyWw4rw35i++ne79OlzLxeYUI0sOkAGbR00aJArAwNR/Lh43tzDYzlQR1rlLe2Rkl9f3Jw+bxmSy6jh84qBXUP3uXpZjSU0LWNQ5nsVzwA e=found last=17 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAoc8tZ77cBZnTNlw1AlwoElN+9GsOq2VcryImTBIwu83PaVHXUnVBJX8pa7dHpuXOO3JoLgq3RlyA priv=MEcCAQAwBQYDK2VxBDsEOfrYhtpKWuOtqfmvjrJdEGrDKF7TeqRKiFzzRvJueeMwzagGjcOKoh6sWxufCreW/Wry+vx1xFrT8g== msg=+tiG2kpa462p+a+Osl0QasMoXtN6pEqIXPNG8m554zDNqAaNw4qiHqxbG58Kt5b9avL6/HXEWtPyLcCallezng== sig=zdWyrccASn3+sDmFhJzpi3ZwmeqeYcvvwCobe67Gu467ZqBjuEjwil2SLpxdpQMbL9dKbjIZVeUAa9MTyJSQZNTg6ac0liKL/X6IVhfvdM3eS3DUD+eEu7tCw/feA8dy24Kp1GEsLSMswr3HaYCSazIA e=found last=17 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoACRe6jM9urBXbBugtGJKjDvHnApXczdUN0rb2JhkgmHTRYOyjYxnTJxD+TA4NMC91m9WabaxrliaA priv=MEcCAQAwBQYDK2VxBDsEOdwEA5Biv3k3MXJ9kbR0RgQcSuetMIqdGPnbupVW2jnRJJal7FQ/bi0bTQ4IgC+ikgLfSxzcP1ioNw== msg=3AQDkGK/eTcxcn2RtHRGBBxK560wip0Y+du6lVbaOdEklqXsVD9uLRtNDgiAL6KSAt9LHNw/WKg3N2A2uTypXQ== sig=84VL3b3yr6mtiX0OJ0uX9aMjGoyoyYZsMLsiZVC0mzhEL26KrnYMXV+WmHuovXH5tZWcQrvS7guAsmWz/Oh8bG2fddW29hB9WkgDZUgS5HNO9RnrQtLznkcf77Omv93PLOtLfelHJ+BgnDwWV+aFyA4A e=found last=16 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoACN2HnF6uuu2yjPrkaW4+53z6BRXpLmKLDl6GWidGiolwa3/hGKdiK+NRDhxk78oqPcu2u4rJ90yA priv=MEcCAQAwBQYDK2VxBDsEOfZ1nXTlPzw/2/F2k6FbBrI1brrtNlCOqWYiKpkAIF0b8AMsCmgbEalkYrww7GEAOMN8LM3YtLt5TA== msg=9nWddOU/PD/b8XaToVsGsjVuuu02UI6pZiIqmQAgXRvwAywKaBsRqWRivDDsYQA4w3wszdi0u3lM9zkAzAj5nA== sig=vWtTvIIFQnbYJ7q7qSo0vC422DB/uREqp+B3x8xgfHVenHP8TviaBkrns5ReStFGS87H0x8qJSAAOtbyjeIS8gBBSGASixDosPflU89MdsIzSenss2nbACQ45tWeHye77N6qmVkr3hDXw+wHjp1H3D8A e=found last=17 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfTowz15El8lYZWn7lW5fAYjC1QL2ST9/rc+eI4zZtWEunMF+EH39bxc8VY+yFNLeBaLxiUkznNUA priv=MEcCAQAwBQYDK2VxBDsEOWY/bjK8Go1YS4pLGXatNssdPACRTdyyhbRu4gcC2cUW+K3vGt32Slu+NoDey147le7E22kmv9t1DQ== msg=Zj9uMrwajVhLiksZdq02yx08AJFN3LKFtG7iBwLZxRb4re8a3fZKW742gN7LXjuV7sTbaSa/23UN7opo5Pu3og== sig=oflhl/8xm9FuNOVtA0MIQQS5Rj9PsD70fNnh/8Ze2wbb9Ljv9Vw55QHizsZFyCbYV2AK3EYh6tIA9/+n/O319Au8NbDJyBMQWac5ISkgt81Zv8qcLLKAFkSzmDE+I09+rjzG6FAkNYluGHdJHalTXCIA e=found last=16 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA55UlVEs75o5TCxqGs7CVVFpoIwfb2rw7UfAie087TRehf6OmkeD2V77xxJOSLgRqJe13EzHHfJyA priv=MEcCAQAwBQYDK2VxBDsEOb94/mT5yzyOgZQBjX0wpbckGVzRgLf3tIPBVcn5b3+QT8jXywf4PPR3k2ZpMRf0uXRFtOsdxFSLRA== msg=v3j+ZPnLPI6BlAGNfTCltyQZXNGAt/e0g8FVyflvf5BPyNfLB/g89HeTZmkxF/S5dEW06x3EVItEFGVTapPHYw== sig=E/eqloJ84kyaKNlBs2MJX4zmdzIiX1+P7ugOkX6ytovCVS90RgFJCWGFV+ZmzbnMOhS95b/2DPMA2MEROncRU+IsNzwHptq25X7QlnI4a6Y4bxt+uo6/54Kx68vhON6DfHH0GgP0O3Xg7P6RGiJsORkA e=found last=18 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA62Ykt4knniyhV1yFpLXvrAg4F8VKqo8KDfmrUrdXm4lIbR4/B+i3AoKz4zvxWLnIpol1vgC30VmA priv=MEcCAQAwBQYDK2VxBDsEOTI/mfbN9xfb0ToyMYJ3SS7z7Df4nRTur7w/8ACegpRUhIzfwgKtAVDX8zbgtkdwRL67G6Rp8xeOZA== msg=Mj+Z9s33F9vROjIxgndJLvPsN/idFO6vvD/wAJ6ClFSEjN/CAq0BUNfzNuC2R3BEvrsbpGnzF45kwomG9GgzYg== sig=qweR1hfTlBzbJAVVq34rM1Tq7O6tRETFRoWcHvQrxeP/kT7vuexPwsuxizKbCR7yT3j6IA6SmIQAdbJ5ngpH5k3Ex8oiU8QRnLv/6GI+BCTTZsigPlbh9MhTspPxQPsSNi5sWItCY/qNoH9hSUXOHgsA e=found last=18 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoARvIg4rMmgf8Hmx467gmLO5Z/9tqD1QxjUUAjgCZUNpnVIqd5Re/f3RpzOGl+vrrFD4SxIULuwtYA priv=MEcCAQAwBQYDK2VxBDsEOWGcLbbe0UATA0bPmMI/0MlyLItizvQ3wQREvz6HL1DS6ZUWlFH/FgapJImcojW5IV1kziTxE+medA== msg=YZwttt7RQBMDRs+Ywj/QyXIsi2LO9DfBBES/PocvUNLplRaUUf8WBqkkiZyiNbkhXWTOJPET6Z50de7eKpPnwQ== sig=Z1hwUlnW9U/JV6HCC66fZKWZSVynbOL2kntNroy9PuA/3P07qwW7fhnqLrGjWavzDzNkK/+PH+GAPKBndXcnn9Je8haVT2htZVD0jaZgL50TFxlAHJv9jFsXd5ULR7PknifPOD6Ib84xvAN1ZdaduQ0A e=found last=17 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAcKJCYdas9tYL+bKEg5XmKNsokzE+WBITsP8OplSgx33Ep9FtSjpzSlWQVs6ATQqv3kI4NooZTTqA priv=MEcCAQAwBQYDK2VxBDsEOVJBr/gdvaCmp4Lcrysb26Sg1PJu4eIFI6OCpWPT8bVN9tKGE2UuVzjVq8NDr1Scx4qmYHE6B3MYoA== msg=UkGv+B29oKangtyvKxvbpKDU8m7h4gUjo4KlY9PxtU320oYTZS5XONWrw0OvVJzHiqZgcToHcxig35AQ9PGCng== sig=W9Zv/sUP8jFStbfZvqxecYTnHRBdq75d0zd/zFJii4RFRrOAHKsLUgx6BvLN9aVWe75IzBc7uk2AQ/fPpEP8P6R3slegnn6LklUfSh/Ayh4CMBxVKB2gBf8yuoHyElPGwnWFyeJNsxZT8p9TRX59zjkA e=found last=16 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAn/ezlvbDPCr6P8OQb9Geq/c0XI5sFgIzDQDhF8vSLDNWM62QhfPI8Cp/rS5VIy3xycbIFDrTDt0A priv=MEcCAQAwBQYDK2VxBDsEObug0d8Ig5oP9pO1SwohY9EGJWYLTOYlO4w5Lj/HOpMI3IBKUB9GP7B7gcHc+O8w9ecsPS3BeGpoNA== msg=u6DR3wiDmg/2k7VLCiFj0QYlZgtM5iU7jDkuP8c6kwjcgEpQH0Y/sHuBwdz47zD15yw9LcF4amg0owkTA6IplA== sig=abfp7srC1EaqN3q0c9nQ1HluRBs7iTzZJ8t7ROuMhNTTHcu0XM2WT+gZeeoCi+xfyZ4eI2ypq76AxDicIazoRhKbX6lMNd6SAyJ9rLN0FvjkPcVlghiU/ulnyDcGnFYzM/2QHb6bBJuecSYrFjCFQSgA e=found last=16 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwAB5KonzvAI8kFCXQNh4fZefsPjdGFOHRblgIHhE+TdPP33uJSFBz4xlZGfZkPPK6pWMnuOcx3mA priv=MEcCAQAwBQYDK2VxBDsEOW1H6C7Lh6aGCRxIOBHWS45iJRulo2xsZ0LfUTboe439QPViMJBRzHJmSyMTzZap2RsOhvE2o+eVDQ== msg=bUfoLsuHpoYJHEg4EdZLjmIlG6WjbGxnQt9RNuh7jf1A9WIwkFHMcmZLIxPNlqnZGw6G8Taj55UNvXHLHf/oRQ== sig=RGiwU8pmufdusKm3do9Sva5Pv2CAAGQ4U/R7XaoGveQecYMMBCxFVGGRrY2oGTtpPBfMVBfyyK+A8erHcr4FzfnVaSOP+lLRIcZ88UgpYR4NzCqNnIV+K4DnttvM28d00ZJba8/JPd1jQE1N3XUmJjcA e=found last=17 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA35pJd+3URW+OhtlAnxVp0xOxLJ4L2Ld1jMKtpzDu3Bep1C/zDFD2OfXBRCUPM7sQMjDEhryjPLWA priv=MEcCAQAwBQYDK2VxBDsEOWrJoMdDqB55WIMCZUGD9+mCiqvtJBw/WW3PWeZt7IsOliRlQSQN0jriroTwCAkNiGjNUY7TNBDCbA== msg=asmgx0OoHnlYgwJlQYP36YKKq+0kHD9Zbc9Z5m3siw6WJGVBJA3SOuKuhPAICQ2IaM1RjtM0EMJsfJOYZiXJ7Q== sig=nP4STWXgzdTatEJJoE6ASGlJ4/tz+U4jlWbO/WAmL4+/89DDnK64N2hr+BZwu7MCqQSAUI5ACvkAPYCFiV3mdCbLN/a5w7CLDVw1ce7pvZa43GnVMnun0l40teHJvkrHW6W0TVs58ecO+nSGvKehCiMA e=found last=19 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAywa3rjMlIKdGtCFH/627rlKhPAS8F/cZV4FpHkrwT1p0vbETRxNGlkPlb0s1s5Q8XUOErL5yXvOA priv=MEcCAQAwBQYDK2VxBDsEOTiOU1FlELzztfF6O+2A+HfChzNtJIPF/uy1NImP2HWoOLej4bN8i1Lw386LA2N4bEOp1OwTm+fLxA== msg=OI5TUWUQvPO18Xo77YD4d8KHM20kg8X+7LU0iY/Ydag4t6Phs3yLUvDfzosDY3hsQ6nU7BOb58vEMznOhvwWbw== sig=LjUi/Wm1jogS+T2Mdyk6sjBdIiYs8kYtS0o9xsc4JTx5fs0P28pUHE1kgW0QW4OsBMNNHTaAcHSAS/j0M5aYsxhpEN/RF274GHLxbTMdVhkiqT7i7Za10pYN9owdhqeHnFlVB9EttI0C9aiLjFAkeiwA e=found last=17 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIg3j4Gvjy86AONKVIQfWvQzANL1cXXZZvuKynv0xSWKCxPTm7oeWUqKrYVCoJQqi9iJQ0Mt+JmGA priv=MEcCAQAwBQYDK2VxBDsEOTHLrQQZECIZ4i0i+F/2IbY8SXDfPvoCyto4/yxlptrQGus6bwyfB87ZVNLVUFGrTZP3hyIda0D5YQ== msg=McutBBkQIhniLSL4X/YhtjxJcN8++gLK2jj/LGWm2tAa6zpvDJ8HztlU0tVQUatNk/eHIh1rQPlhgvNtTB++nw== sig=aY54EAqPw9aCWa7ZBgZJAm2WmJpkVSl5ptHr0ZQqNp6OYChp00fLmT7IyS/LL2Rxjyi9UFj0cy+Aa+uOWFqUWqqGUnIEawSTfJtc8S5ONxuQ90PRA8IT6zEFyqduBxE4c++XUT09Yolt6tGofkVw6z8A e=found last=16 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAHaO3KjpZ7rTEojaCfoa5B6GGFvxAIaK9D15eaqmO4xqaxbJg+YPaIKYp9dRVXl8JJSh8vGZZ9RsA priv=MEcCAQAwBQYDK2VxBDsEOQdhFnaelvvKdOnET1wm1LrMpuMVWg4LpThuC1WVsVB4mLOZVyT+Z52kMiJhojue5T6Wj+HjrEM7Uw== msg=B2EWdp6W+8p06cRPXCbUusym4xVaDgulOG4LVZWxUHiYs5lXJP5nnaQyImGiO57lPpaP4eOsQztT3FwDlSmaLQ== sig=DfHgRFMeflBk5gM41K8CUlCgBc1mQZ7884K6SlgsXx6Q2GleJElIlrSgsAyyerMM/ge7kZd8NAmAufuWuCSLQjZnQlfe/5GMb1TetV2e72hHzkwtR0THS/B0iDon8ciDL8ZnTxnrX/fkdGOU2j7Vtw8A e=found last=21 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAT+nOta4/+zd8mUQFVL51UecNeu1FG+u4kmf2gv4/0fYjhTJ1kBoNddMqhC6b1NfNNRvqtyPuaT8A priv=MEcCAQAwBQYDK2VxBDsEOf6JPBhl/KY/FNMEy86cj07jqhYiDWT3OJF0OAEAlahOmuyn5+VErT05SrtX9OcnVl681O7u/hsa1Q== msg=/ok8GGX8pj8U0wTLzpyPTuOqFiINZPc4kXQ4AQCVqE6a7Kfn5UStPTlKu1f05ydWXrzU7u7+GxrVajLWil1KOg== sig=lh1qCSkiNkdJlWdq4P3gTqyoQwZCZ5K4sd1LGkDO7FB7DSVzs9KGiEXbGTFg3vLCefHUJbSXKd4AsUITAkvD0U//MS6gCutBeuySewwsjzoTdjBzWUzGlXW2oUBrjo2mze/Fcpzpw+VWyI34na1XrgYA e=found last=24 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/TYlnlKVLJq/BP9WWIDnQq6kDTwyZIsGMoJAiEe+xCcWLAH8G9XqO11uFNnGM5ZvjHFdlixhTbIA priv=MEcCAQAwBQYDK2VxBDsEOe2yZbfG8ZIQ/uT1FjSj4bNK39alB+NgHFJUsoQUz++aUkuWCevXIWJYk3D7Qxx4OxxXIipZK4pQiQ== msg=7bJlt8bxkhD+5PUWNKPhs0rf1qUH42AcUlSyhBTP75pSS5YJ69chYliTcPtDHHg7HFciKlkrilCJ6113msT7UQ== sig=xJLo0woC/8pb6sWLh2sl66rjc5lCtj/rrv38iTv+wQYVdNOpm5rx/HKhZGb98P6r7I/9V3cqi1KAvMILi3dxIhLwA+ZH36W5LVfbvSfexEXFjv3JejVSkuBUZLOJl3AxSINYuJGjZRlTOb6GzLgd3g4A e=found last=18 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAl+rFPWb3baZo7EByQWYHeGlInDsHbWa9mTyQgX8Xm4xVIyclZg6Y0mlKAiS/ag6wsXASmPX3GS8A priv=MEcCAQAwBQYDK2VxBDsEOYG0f+dp9+tkPO8zft9F7rSZFTEsD8xEKRN0YZy0otUbeAcrwLB2iyjC6lvptBliwQuL9rrHXtNo8g== msg=gbR/52n362Q87zN+30XutJkVMSwPzEQpE3RhnLSi1Rt4ByvAsHaLKMLqW+m0GWLBC4v2usde02jywRcAF0eW4g== sig=TLg9gQ2g4WcbBWYfxhzpFGwwNZytRvE8JW2CVjgakncABF9PwNacrOZxnJpYDT2NZ+LA5zq/5PMAskaJiZLUUHsyON8BfzZTvZsFgAHIAndd5wz8vo60UdHnSqIchjqVF5xC/STDbwOwvOTBK7PZQR4A e=found last=19 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3iHPAie36F8ToCafOg/vh2t0qv4BNfR67f68t7y/pvx7b9zW17XA8j1jV1ycjXn4QYaWaEn7zbSA priv=MEcCAQAwBQYDK2VxBDsEOSVYYKqWGXLZbRtAJekOFvlXKj1wRuk3NSJFQMo22lQg2/0fpojnaBF934noRzNTHfEKQlFI2ReC2A== msg=JVhgqpYZctltG0Al6Q4W+VcqPXBG6Tc1IkVAyjbaVCDb/R+miOdoEX3fiehHM1Md8QpCUUjZF4LYeigrmnk7WA== sig=EZDZCbQ8V/3MkGBL97L/3MIggC/MXTr9GW/HVk6iIcH8n9xofsNEd6kTqz9oxcnfsRndk/gJu9GAxYcbWEqiNG80/rRX3xiGdSENImDAGoFZL7/GTZ5LVxzcdWfHI/+YX7lxth89MG7aM7PXVyB1wzUA e=found last=17 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPu0z08E++ZFZVpsY2MBWvqyRpgSCvKds3DhBey0fsuRkIi4rjMm3EGCJOeSJ6yXFLPpEsJY16fAA priv=MEcCAQAwBQYDK2VxBDsEOcs2Iaq3tQGOQFc2NBSCEcl33oc985PoYBEXdhHb68KPZwe+c8w82ZwKr6ac94SdNc2ES9FmR1kOZw== msg=yzYhqre1AY5AVzY0FIIRyXfehz3zk+hgERd2Edvrwo9nB75zzDzZnAqvppz3hJ01zYRL0WZHWQ5nJ4SSS45erQ== sig=Aibt3tM6tXUHw5UlvQjpJEeS0KPWzZXHTsTQrIlOoY1WySlx1TwrwYbM02C6TzJ+mKBQmQ8QRX6AyTV2MfrWFOnZ1yUX3StKRWGouSTejRokdVtgTskhV2I0YprZeS54dLAvRfqY1r/S5FE4OSxm7g0A e=found last=17 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAG4skHCa8nTqmGo2YvCksX5A1Smgsm5Ja5f6wI0pHEgIQ9b18Du1KJBboNZKeaH501G1RalrtSCOA priv=MEcCAQAwBQYDK2VxBDsEOVINnazr3GARCvyq7/WgNFFuZUYPZ6vN2ljrEc+DcqOVOPhnV78eKRx1h6NYSIEA4XOIK+xylxvzfQ== msg=Ug2drOvcYBEK/Krv9aA0UW5lRg9nq83aWOsRz4Nyo5U4+GdXvx4pHHWHo1hIgQDhc4gr7HKXG/N9A9AmIhqBSw== sig=OIqT0Pc/H/OLIZ2zN11LDo2CNi9GJHoXeqh8f6WN/8Eqo09cb6t/u67cpz8zV0veVa+82UQQV56ALk1XfAp3yLcnJveg1PRdAQn1H3SFJryD78CnNXa5yG9taFrTMR4VhjWtCK7OC2ENgGp45dS4wgQA e=found last=16 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABjhaMkGmgVxWmfL64mgMdzvdMKEDXnqRFqiVPfjSomPtOv8NcWAOgjtGuUWlAg2kVxcyvoMfn/iA priv=MEcCAQAwBQYDK2VxBDsEOaLMtkZxIr5FeNPsXDLk7mEDF18oKK/hP1MPNwdp6TTR7+6BiD+/D8VQLbNAPf9QeezRoTYwpQd3PA== msg=osy2RnEivkV40+xcMuTuYQMXXygor+E/Uw83B2npNNHv7oGIP78PxVAts0A9/1B57NGhNjClB3c8Lhog6gRtNw== sig=DAYJ/BYKa/6mZ1pWNWU+TBkv90Ji7ywhYW1tmu/R5lDSJEkJy/B7A4puOaSEzx65YE1FAF9bE3YAVWf7VvA2BMUjsSYEBI/M0vu03Vqiim/hhli/+tXtQVQElcSIygabgyJHGFKPxQDVCZAZiMHIWBQA e=found last=17 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALzc6/zERjYTotZ4K74mRASGERuIIY9u9JkVJAJASPlNAgbDjVv/nM8rzfhFRghX1j8NgfsWeYr2A priv=MEcCAQAwBQYDK2VxBDsEOSzOkvhMobXk2bGddTGjuqTfwYmJt8SFiD2O9FoOg4YTOQZYSQs64DGbUWbn7R58B+Ucgkqk9b/qKg== msg=LM6S+EyhteTZsZ11MaO6pN/BiYm3xIWIPY70Wg6DhhM5BlhJCzrgMZtRZuftHnwH5RyCSqT1v+oq4VbBuvQX8g== sig=Zdu+8Fte13oxF+1Pov31trUfEbelI7QlIiQeNl1A7hSeXWqJshdMXJegOXiVi3IU/nzWTQmKrasA4UkdnIInCYidU2xBHRGsr7hDdMHv/UmyRrZVuHopi43EQlzdaAFKGnSCqiBt49vaoYM6nvD4TScA e=found last=16 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAzqD58XTYXLz36D2W/QJpWRwxyxAlev16FV7qykvsZvdwWOwa4PwlZmKF0Tz5YIFCmxPgkSDjLK0A priv=MEcCAQAwBQYDK2VxBDsEOXXbpTbdVbFejBseowJ2wF610CnwsJCa9hQLDjYEMgg/M3ittWT7ABAsbyB3JN56Yn5zXYopDtmi1A== msg=ddulNt1VsV6MGx6jAnbAXrXQKfCwkJr2FAsONgQyCD8zeK21ZPsAECxvIHck3npifnNdiikO2aLUiNdK1jSoUQ== sig=eejG9VXWuha8NjIoIIkfXWXn4YfQwn7xMLJ9aWnRH5SUqHdbmLNN4hP9k0HEFgc8YAEJ1WjVqT4AZPLvNWZXufBfO0FGlqwEecnD8W/gBCC5DW74T+Txmo3MO0tJJHCwsuNG+s3EIJZoiEDKLjGAACcA e=found last=16 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABqKCQIfbS0GqfMmaHM186sRuk2KrJPaiYwNnu6RH9rTWCPC03H5b3iXW3ErYN6Ybhzp22LYjtjwA priv=MEcCAQAwBQYDK2VxBDsEOb4VxAw6/o6bzK4JVWssHionJVcfn34VBz/moidbQtjwcxEPNP6K0YJeNHHce5pmdzpIsUi5o8Axaw== msg=vhXEDDr+jpvMrglVayweKiclVx+ffhUHP+aiJ1tC2PBzEQ80/orRgl40cdx7mmZ3OkixSLmjwDFrXYBdB73rBw== sig=7RCLp4Y6s7VbvEJ6RbtyRZrQwSOPVgSaQoF4GfNVxGEbKUw3JxRB9E4upmO6P/a+wduUc9h5MTIAvR5jfQhNX60kfMF1AdZv+2fuJRq1f7Alw/62AdAE5pO1txFdv0z/rCOeCQSfE/A5rMmeJcLOVhUA e=found last=23 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAu8l5Jboq7sWEdbB+bAokEnxF5SVUJCNWlBb0LZoKzJgKe+/EvAV9E0QHSgwB1lHclC8amQpU0MOA priv=MEcCAQAwBQYDK2VxBDsEORjU85Q/qVYUyeLZ/6fZu+7IIkKTnz4uFqQ8EG6bkOgx2RXBNHZyftKyAIxTxf6R7Amd5N1dpizxdg== msg=GNTzlD+pVhTJ4tn/p9m77sgiQpOfPi4WpDwQbpuQ6DHZFcE0dnJ+0rIAjFPF/pHsCZ3k3V2mLPF25qGN6Ye57A== sig=WTZAgZ9Z5cEPrj6y9MIGeGdXD+0lmF48YWaF4nwP1I4QconlCFVEDSph0DlBLjdDrMALVrXEsLkAtdtLbjYEZb/yllZWnhQJtW6T6bCKOTKwcqK5jZv3w1SLJBVHol8zgA8otg4+rypIDbaEmdRdEhkA e=found last=16 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAh882SwgsB5J2ozu2xbEE5WqI3BL+UCmBZmPVdX+BgDz8VRRPqY2QDVPaZhObgMunRL3GJHMm74YA priv=MEcCAQAwBQYDK2VxBDsEOb+B/IM5txcRzp9OcxSDa+uW6inXIMKUqp4ASfHGwdav5csUfZtdCdHxN+mKI9QgmuoXILvMPN9tpw== msg=v4H8gzm3FxHOn05zFINr65bqKdcgwpSqngBJ8cbB1q/lyxR9m10J0fE36Yoj1CCa6hcgu8w8322nKXf1ZAf9zw== sig=zj4bGCOgweT2GvxLgLB+ImEBqE4IFW0psthGM8Sx6TYhC2nOgBniEwKjZdhliCvhlHMScjNoKlAAWAV57/jRsLq/9eZxqwi6qww2qMQeOHNYWm2DNY9qK3mo2wD6W69YWjuGF80BaWi20DMQa1BtdSIA e=found last=16 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAHefNxnRCHdbw0rsdCBdWxylmOehVGF+7kBbGpZ0+qneqx1WalmM9+jbyxbYS7UbvyreyrzlauLMA priv=MEcCAQAwBQYDK2VxBDsEOdK8cTeRwK2d/BQa6nihnaunef2HFX6ObMyWp1+vr1mHnK2Qh9PWTpc6tRMVq6jLT65T9WuS1RNaFg== msg=0rxxN5HArZ38FBrqeKGdq6d5/YcVfo5szJanX6+vWYecrZCH09ZOlzq1ExWrqMtPrlP1a5LVE1oWUiSzErvBzA== sig=l9E77JQSmqRIHtvT+8fmj7BjI44/KElpCf/GJJjrXmPVNYRVU/etatnXM9xqy7FBBcsh9z0iI7oAsZ7RhU8zBj+q9j/6uvjRepsWxrmpKbF+PF9DqdFj1O4+ebx3xTJU7VWp3fERnmqQ+B1Sd41WVRoA e=found last=19 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZ0YKJliq76Poc5JXT3h+VM5guFTnfcvCf4y5l8RMj/Xp+rQWYdAPuLI9Aki8K58ofoLdB5nmjOKA priv=MEcCAQAwBQYDK2VxBDsEOTqH039AGbLDQJmxAW1czkCYw9pYBUApoud8bgvA0fbkv07/SG0FS7M3H7pJTlaE1B/DEVRgp5yhAA== msg=OofTf0AZssNAmbEBbVzOQJjD2lgFQCmi53xuC8DR9uS/Tv9IbQVLszcfuklOVoTUH8MRVGCnnKEAsP9OgV5hPA== sig=vDlK3Ws4L5p2pU4CtimfyOwwFgX1Akd2ru3mYTXykX/9ox2CUbA7ZoddYRC1R6jZnhD8oO+Pik+AyLl+RFtJArBEpbd0fB/5xSBC5/Q7iFYYINNol5TsftqF5VaEdpRarOcSsSJ870vOXRN5ug+2WycA e=found last=15 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsMxm4KhAXX1eJXzWUMONbuROHEYd35O9EZ1sCMx5o/aaKLGDT7aZDGC5cd+/uax03zVHjEkRjFYA priv=MEcCAQAwBQYDK2VxBDsEOaqOy8uQ93dh53wN57dUOC/awp7mvoOM+o8NYk4ccUVcAEVALrzKpXR11cWuk3uey5wnJzSCPia6KA== msg=qo7Ly5D3d2HnfA3nt1Q4L9rCnua+g4z6jw1iThxxRVwARUAuvMqldHXVxa6Te57LnCcnNII+JrooSUlDpbWu7Q== sig=5v10lvaEYxS2xpcjA/I50dCs4tfrX44Aqo5US4ZOG1YutmOzjgGFCy4Ln3J8ve+sxFh/I7ml03eAYVSadp1V53Zwf2Z2GAndNDuQwV+/AhW7Wg+CxEOyibZLeaSLmEgCvQ0jqJyC2Lr5n2i74JFMWSgA e=found last=15 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4LLqt6igN+01TlbcJtkaS9qwDEFWJrDmha9Fgoaqjmj6XDLo7koDqr+48/idHtRbaZmpgx+NxFIA priv=MEcCAQAwBQYDK2VxBDsEOYIG0ZNIj9n0jwvIWQTphzk74Q0OAHregiuyAx57FnLAdrD2GSd5YYDevTX9uPEDCxh5GJAjWxMbhg== msg=ggbRk0iP2fSPC8hZBOmHOTvhDQ4Aet6CK7IDHnsWcsB2sPYZJ3lhgN69Nf248QMLGHkYkCNbExuGBS5lxYOr1w== sig=btz+CRgkqgNVfMvCDtac/wetijz4IdNZDuRJp54nYViGqNLzVTgfsI7LDcK0jmo3kq6E+DsrKK4A7xnwK2GiBmEFJcIYbIVNY2/zJcFRcLweZnncDF6OjNZ8PrgrAzD1I4S1mYn+N1wEpCnCv6EJawQA e=found last=16 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApT2D8aoC6OTidW0uAwo2gTtpt2fWwLblC6pMZfQY5XFClONV44zeRp5PGk+AVO/t1WQEcYRk2giA priv=MEcCAQAwBQYDK2VxBDsEOeuPGnerOPz3FFH2bEdTkIzolStZwejQO0tNmvCMfx1D6vP8wMFcVC5rBrqi/jZPjHHOFTjt8Vie9g== msg=648ad6s4/PcUUfZsR1OQjOiVK1nB6NA7S02a8Ix/HUPq8/zAwVxULmsGuqL+Nk+Mcc4VOO3xWJ72Uuz1tCt2LA== sig=kl6w2mo3N251O8H00lcGGe11b8oykhgvm32Un61QS8YDkKbYdBlk3I5sQe74/aE5PrFbSxfdCJeAaChz4udnc75jel9NnhhByMC0bhwM77twdW4jUWb7j9b3t5yAuSOE/ZhjNp5b3DUfUyXbUVzXgBsA e=found last=24 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAjdjfYO416KBdkNFumswHe7M2r9XeuNKoMvtacvJXgIug2jikqf8H7OwVwQHsMJ6+vuti4x0rW72A priv=MEcCAQAwBQYDK2VxBDsEOUe120f8pX9CNSjrIIrlfH+XuxsijyYIRGHBkqOML+5L+ftHlQqDehvET1HJucyuAQbitSPUQMYBhQ== msg=R7XbR/ylf0I1KOsgiuV8f5e7GyKPJghEYcGSo4wv7kv5+0eVCoN6G8RPUcm5zK4BBuK1I9RAxgGFk3rv35XwCg== sig=WFnNLSJntNl5RoqxTVUytAFACKjrxXqxShn4s40WYYGOHG6d4aYsskIRRO4OLBKTmXM6hp4P+lcA9PVBoyeV/GznmGmxlnWH4mKp9ZYaJ4yyIzVMfKTWupUjF2hvCaro6z61uvEyHLjd6v74ZQEeUSsA e=found last=18 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAQZfxOisrN7s3yD9yqTulokAZ2kEe0c4zyM+PByUx3lbG1c6M5Nv3xVKGOMNsDrsFhTHPgb0ReAIA priv=MEcCAQAwBQYDK2VxBDsEOUjmgK9uarakuO5YCoLGeKpsh4Sfmo1wVtz1Fo2+2AMUdUEkcTv7T0mMdy9vXkrkW4spb6abKvbssA== msg=SOaAr25qtqS47lgKgsZ4qmyHhJ+ajXBW3PUWjb7YAxR1QSRxO/tPSYx3L29eSuRbiylvppsq9uywmqV/aAwIYQ== sig=XzJSbhLBTSz2Umiiqu9YVC8kTm209EKmo0boLgNMrOvrGTMZzEEHS1/zT1CRcc0XUP2CmZugNLAAno+dmx5PAj7dkLQSDF1TBRYAOnqXBOEQe2ARnM+ECs0+h3gd1+mCt/byY+LGY8LPTdcf2p4WNRwA e=found last=16 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAeKq54r3/bZmfl7/LZWZMutwZuLNS9TCPU8o+Bqmn0tC9qQIyMR5RK2uu0RWYd7spsHbqUlZuF9MA priv=MEcCAQAwBQYDK2VxBDsEOcCc0egBNEymurXeg3jRRpnAIFY3XE6xZu4Spzr1P1OnhBHCI+rcEKj/8hMZgNCYuumz1+NULN05Qw== msg=wJzR6AE0TKa6td6DeNFGmcAgVjdcTrFm7hKnOvU/U6eEEcIj6twQqP/yExmA0Ji66bPX41Qs3TlDqS87ghWPYQ== sig=jHwEVnOS6FDF4oxj5n7lSXiy4lJMFIGwcjhnmIXL4Mop5a/ZF9ONCj+0luyM2CxcfS+Q+HOfqiEALKUWT7q+9gApVffImHqD28qeOx9/AFzrx1e73dBgROIQ31jFjdIplM65/vrai+D4IWRUYRRldTcA e=found last=15 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASKo5baXqtB0c12551yM3Z9TzNZIjFYU9Pme4Q9vLwDXvQeJID0A8sRa4179dwpl+Wy7XPAqVLz0A priv=MEcCAQAwBQYDK2VxBDsEORc6EZdjJZ82JmGU+tndI+51CZl467wi9gFUFjScNwAwHL+ROopRMGsxOWiNCM5abWGo0gEe/m8MOA== msg=FzoRl2MlnzYmYZT62d0j7nUJmXjrvCL2AVQWNJw3ADAcv5E6ilEwazE5aI0IzlptYajSAR7+bww431x9klA1Eg== sig=OtHUbhtz8fd8lynDi7J3JJN4b5h8dgz2kzMiANKIxNoFtppd8Ck6mzzLdmgjhvXXf+N9jLN412yAi97Dzf86C/vKkb6uQF4zTHARLAoCBUJBmMDsIt3kOqVmadKnGMT7iICGaq+1nVyY38HjxaYCNRwA e=found last=21 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9+ypLBl9VISjrb1ASliRxXiTJsbXP7qClV6yaHIxRSOzKfW2ScxbMw4h2kmibK5t9hNUTzFodvqA priv=MEcCAQAwBQYDK2VxBDsEOehGpmPVI9pRWBdx9335jOiVxeF9Cktmo7TZPONaYokBjDlwEgrYn0vxhziS5j2Ll8bltz6FMj7Ugg== msg=6EamY9Uj2lFYF3H3ffmM6JXF4X0KS2ajtNk841piiQGMOXASCtifS/GHOJLmPYuXxuW3PoUyPtSCdO2Ayv5SRw== sig=P5ZAO6MSaCkOZvGqHll9Ps/iU6YaJ5UN07xp8JJGJYAx3lyDP+hUW6GDUjeuEzAIAZdt4YLQ11YA/nud85xVOUkRhTrjyIimC0E92DR0pJWfgiRGimtpO3VvE4MEvBYiMmtqhATUV3sZnfnf0adzlBQA e=found last=16 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/hDlzFYBpXZWtnJ4drHUyXVeXK4SQ6JGudZ9lX7QONIyppB5E7Yv07AIbZARhIWtYB1oBJUgZ/eA priv=MEcCAQAwBQYDK2VxBDsEOQyvFoaRD1i0u1O/LTNuH2lDd+j9BYKPsxK1Tf8XjllDQ9MivqnfYf2c+GqQskN+8SgGC0LMeL7tOA== msg=DK8WhpEPWLS7U78tM24faUN36P0Fgo+zErVN/xeOWUND0yK+qd9h/Zz4apCyQ37xKAYLQsx4vu04V9cP76ByKQ== sig=CYY/4GeFsnQGZTLKm6rQxZjKjcq7fP92JMpgVrBDVY4t1c0w4Gugw2Cms/In3x1FMrzl+/+K9LkAgqOHBT2Jjtt36/2wrwKgrgpz+1KTjgMnIOGEGSGRlolpTAsEZAcjRMC5yevdPryMsurub+i1vQUA e=found last=17 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATL+YOf9bmo57NgRm4RVx9C18THE/NqBY3198Bfo9McCIMoRBDWH7LDZSSsuvpZBY2cVmFDsKwkAA priv=MEcCAQAwBQYDK2VxBDsEOZ14n0t4Q6mAfZgc4/SDiKRUmP1p2OLSX5ccpG89DdXwC5XEZqxJ5bbseTf/5Sb8PSWxNLZiNmufxw== msg=nXifS3hDqYB9mBzj9IOIpFSY/WnY4tJflxykbz0N1fALlcRmrEnltux5N//lJvw9JbE0tmI2a5/HDvtFYIreNA== sig=q5Lok0Nvp93ZcMAZasPBkpbsck8WJ5Icdmo8pilKw4CYNhVnM+ubxRvtG74aueyX15pYtrb+bjaAg79SC4sFviRWUUTYgdW4So7o9kIORM36zRTfPFsayjMM5ppE4+sy9SYlvzfN7Ub8aPvz/ZkPly8A e=found last=15 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEEOYqrffZQnw0yoCxUuMW9/UBGL5CMgPv4NLN250DfZKiHDsKYwi+4mDnGY0BYsI3Je6jsT517MA priv=MEcCAQAwBQYDK2VxBDsEORrLxAn83XbJLOWZc0da5fSAe7+moO4+LERGaeDNqpO8PAJeJiIqNvfQFhldiRPUK7g1rXwGhqrFng== msg=GsvECfzddsks5ZlzR1rl9IB7v6ag7j4sREZp4M2qk7w8Al4mIio299AWGV2JE9QruDWtfAaGqsWehdtmd/jJoA== sig=rgoE9+8CGzq+R5PkBF84wHYfTeRkIXitCUKEhJDrPbk2VMOSVIYD1Fy9NUKQrGRWE15OCykwtDsAd+a2z5GorDzmeUhJtGpw1NL+NfASnTJfSWHRwUCxxgT6paxdQ9WeKa9MD6ggwUgfdmM5yUe9KgoA e=found last=15 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAoS8MArB0JzAL4kk8k+F4Lg9GveH1nur8UukK1FB58HsBE4x3j//TyQN5VnI9RZfx4wHdQ1m9D3wA priv=MEcCAQAwBQYDK2VxBDsEOT1N2sUAI6dg4tJPvIH+nhXAK6/u7r/Sm2D+TBQ/oCwz+TjqCm+bf35XEtUiRQGfddI6RC2RP2c/tA== msg=PU3axQAjp2Di0k+8gf6eFcArr+7uv9KbYP5MFD+gLDP5OOoKb5t/flcS1SJFAZ910jpELZE/Zz+0HgWoLZL9Mg== sig=SA5o+g8CiJVzAPEvasWDRbZNefvf68NPkLQkZhjdCgl9LQ2eO6lB6XYKu1qJLI/mnislZJXpmhuArapzDkIWSq2dSAHbAEay3SI7LuCsWMLxR1ph6tjElnFLX/2h6AqIJElTKv4RX40S+CPLg22I8wgA e=found last=15 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbVbvEdRezMsDHjsSEb42AIu41xAxzMgESnS2sXlfOsiZsfnVTjU0W97ZVt0WVByf/RkA2A/355CA priv=MEcCAQAwBQYDK2VxBDsEOfZMC5CAnY5IyS7YjO67yCFvct6vtKEfoI9q/PDZ6TB9zQah4lYHY68JkjotP74VtCIfS8uP8i6F/Q== msg=9kwLkICdjkjJLtiM7rvIIW9y3q+0oR+gj2r88NnpMH3NBqHiVgdjrwmSOi0/vhW0Ih9Ly4/yLoX9m40QWAnLTg== sig=qOJQ4LC+eheb9onT6tl+4Tvc4mOWAlOAxntadyr+pKMJesFj1WjA0Dm0qB+JlfYI5zdqIfs1LZGA3zQcVWbBrjVSC4wYxl0yuStD8W4SnDcpN+0i6/WNlprLBl1/xPxNGhfOWuI9lUr7y9EIQYHoZSAA e=found last=16 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATLPcMUohH74YtFdB//gl2t9gvB+ZM+0fNPztmO5bmmOhPwv5Fhso7EXLKme/hWMywuGHvOVM84AA priv=MEcCAQAwBQYDK2VxBDsEOZW69FICm53AsE2PaB0k5IdY0iYh4NH1ooAw9r3DpH80OA+rbPje77eUORdBk6hZGu1MxmfMY0AeSA== msg=lbr0UgKbncCwTY9oHSTkh1jSJiHg0fWigDD2vcOkfzQ4D6ts+N7vt5Q5F0GTqFka7UzGZ8xjQB5IylIMmlbQdw== sig=3FwgPe7fnW0WnYVt7SquHErpUW8DFCWhYOMHUZucykMUJ7FTFq5CeJadmxgyFmLLAdluA3WJRywAWXCg9KLSZAWgiOcUuvHsUs5oggrqSw4e90t7tzc04NfVqMD9Er1WFEnPABjwy200cMvwiSq1VwoA e=found last=15 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsisnV0aAjPRfnGL+Bbu4BYAaFmDyboBx5zu96kzi70LbaAdzsbAy1TOYUE0BKi0mch5LlpflzvQA priv=MEcCAQAwBQYDK2VxBDsEOUWTSjPvu7xDfsAmxiE0JbfLyOU4ubdw0yPh3Y9ZYA/JPPle+feNgKkMIhoOPShjUR87huc0fu3PZg== msg=RZNKM++7vEN+wCbGITQlt8vI5Ti5t3DTI+Hdj1lgD8k8+V75942AqQwiGg49KGNRHzuG5zR+7c9mJBmTzm3Rfw== sig=7Y1GlrrFx++t4plXKcYPwu11TXZDixQuPbOgqYXQu0e2FOVwmEkboQQzn6L9YoshN6ZHPhSrziwA28uxJbX9/KcSco/syRWqEdCG0k+KralLwsgA68Db28r02oZC7Ui2Gel7nBhFk2+XNsHwHATVvSoA e=found last=16 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAAG2JW3Ks/3UpaaJdtJ00Mcd3z3fRm6kusJSj0GxuQa3SY3tMnTw5OEPDaptoc2P7IN4+C2dG4gSA priv=MEcCAQAwBQYDK2VxBDsEOaB0RX3QarLqEkog04NM7f2XhXD5mIz3q7vIK4Nkci79wkcVA310cHQB2H/OxoXPU+QaPh/cJrOlzg== msg=oHRFfdBqsuoSSiDTg0zt/ZeFcPmYjPeru8grg2RyLv3CRxUDfXRwdAHYf87Ghc9T5Bo+H9wms6XOKNC3qjPOgg== sig=9XDeXuHY1dg/9m8v2BUp/WKhgMup+YaSQpg+03tmK2z4Kj/PNSzQuneQyBzBKDDQx4rooLnzSwGAK3t7lomOIteFXryf9VzNMFOKX3FXDK5eeb3x03RL9osypB/TrKTDdsteqsWlF4YoSq0Jl5+F5SEA e=found last=15 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoANIpyFBPKzUJyZNuBBCF95TLR9lswwTNPKbbknZ6tH9/qaTBDKWDqu/2DYhf6bezA+BfAI1eVMDiA priv=MEcCAQAwBQYDK2VxBDsEOZnY8weTbePD2bYrBvdb7IacXwy62htpMCQA4KkSLq0J8cbDLCCyUT2FuNm3vX6mJfLyWg2dKWW6/g== msg=mdjzB5Nt48PZtisG91vshpxfDLraG2kwJADgqRIurQnxxsMsILJRPYW42be9fqYl8vJaDZ0pZbr+joy52/tC/w== sig=iRh098AqBs7p5LD8HIe/2giKJwyeaG3rg6DAGKyoVxplJa8qAqAFr3Qrp+jopzMUC1uV8PUKzXiAWij2XZuOY1wJFfymu7K1wdSjNuLKyHNsHwrJ4O3Hzk0U9joRbLXx166LXhCW0w7DU+Wd5OEBSh0A e=found last=15 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA619kAJsNGV4NSTAIAGZUKGn9PyIQq2jigu0LnZ0+hwjZozYSOqbayOLiQXAJYdJnDet+6T1h53KA priv=MEcCAQAwBQYDK2VxBDsEOb/xiW7iZQiQYlfgznNDCGOi0l+ZWIkSGCc54eAxpaaKXyhn8gxTtGwq+FvTqpSL5OI7c2lNgvfPuA== msg=v/GJbuJlCJBiV+DOc0MIY6LSX5lYiRIYJznh4DGlpopfKGfyDFO0bCr4W9OqlIvk4jtzaU2C98+4unEPgzEkJg== sig=GsSEeCyObDFP7x1j1X4V2/gz0kYiVwBVStv+6PDWzXxmfsWgJ8Sdhx2Qc/XwxS5ECFqa8n/nViKAtNGagNoz2GZ/+EH58qjAuGTH0v1yv+RL9cVoEqxUnuGUESOCY4S1k8t12cMas+fpE5Y7/dQf3ywA e=found last=14 s=1 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbEFeCRGpxN9afgG86y9sKv6Nz9X8BfExyS4vceYnbAoxCzzjdOSsEY7Z0rY+uvR930pizLqv4i8A priv=MEcCAQAwBQYDK2VxBDsEOWWEtmlLRYg/yoepBYr1bYM9RQboqw4+vQpqaoiBCLUFugR25eDN1P0wswi8VRM71nUuTxnAcx/6og== msg=ZYS2aUtFiD/Kh6kFivVtgz1FBuirDj69CmpqiIEItQW6BHbl4M3U/TCzCLxVEzvWdS5PGcBzH/qic+/H8sQcSA== sig=YWN9pf9Hvw00UDRlOut488MMnvDvlQTlclEUKOB91EkPMxEuwAIxUySd3LjbxnhbATYmKXY8OHOAbRAuYcdiMg4hRG5Z4aY3fKkUv+bpgojmT6uy9+D75bDw2WGBlpguyw2eOq0oir/T99A9IUnsNxoA e=found last=15 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhXwjNtmLP/d0eYeRJfMbh2H7Cfu4GZbpKN4SBnJdzhM3QJAfu1XCerdGwr/QzlOI1pjuPjwPkZ8A priv=MEcCAQAwBQYDK2VxBDsEOfrmVI2W/QFI8x3Ib4fcl38lrtNK+ztLjXMY1Dp2LZR8nu+yyrchNk7T/h4G5tHTst32w1lqPBARgA== msg=+uZUjZb9AUjzHchvh9yXfyWu00r7O0uNcxjUOnYtlHye77LKtyE2TtP+Hgbm0dOy3fbDWWo8EBGA6+5QcCualw== sig=eawwbDZ2wVO6y3k7rNoBcISa8sTOuNYoB0E3cBjrPBN1IK65V8VwhiubNKzDOWQXZxKlSedM+mGAXzVbmneh+OAPFjub+27WOKGRvqP2f91DWNJ4vCGaB5eL8FWtpYRnLtmH87QKvqTrzk8TzmxJNRoA e=found last=16 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABs0enFxLDptic0LW8LT9uI9lfO00zA4KCKgJ9dmACqm3SivtKAwYwuPyQJGy2VeSkydWS9aS2o2A priv=MEcCAQAwBQYDK2VxBDsEOVOAAJWg5Vn0c0qcVUl/oqksq1ZcLcDRh4Oeq2+n7Td/nB8BlyL7k/OTOil0EO8KK5YJwoQKzCn8KA== msg=U4AAlaDlWfRzSpxVSX+iqSyrVlwtwNGHg56rb6ftN3+cHwGXIvuT85M6KXQQ7worlgnChArMKfwo/o5I4Nj7Yw== sig=X5plG8WpqjUuCrCvvWvtKBdLsjp44BghioikL542cPnAmdbvLXJ0fUp70YzYsx9HQGzwElr5nTwA9DlO2rarn2VdMtSn/nGBE6vIvPm2M8wMZpz8aM9kzIzdDzzbFbyaH0U4bo5SustAyP0v2flczD0A e=found last=15 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAyOecTV7zJinzeL6y1dRt5+y6DwYwj99CvsQ6jHJX8CDniHI39b9YfPa1vwdgMuMErSIQGkbnmzYA priv=MEcCAQAwBQYDK2VxBDsEOblJWoncSAdzX+VRAZGSdZBNydadJY3wZnlgoRjW32sqOLFo1iW136vyNxmK65Bw5aOOMT8PkXM01A== msg=uUlaidxIB3Nf5VEBkZJ1kE3J1p0ljfBmeWChGNbfayo4sWjWJbXfq/I3GYrrkHDlo44xPw+RczTUnbdZVAtgPg== sig=ePJGQoIj0SCu3lM8zItk0cmnDGfAIjFLbI0pjAmi3dPxeQB4rKwR8MuSg+Ec24maE0UuKcd9I8uA9UHLx5Brb1LVZtqAWptG+ykZva9T/NdHI448R6uWxK6OgSykR53BcqCTQtGFGTaNhbrBkbb33xQA e=found last=18 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAn61dgdtK7Tq5rv91fG5U8qU80USV3xYFz3AnlLFsrRjNVkjGMT3UMdU2N2SuFn4DjuBe7yGcO2eA priv=MEcCAQAwBQYDK2VxBDsEOWo0TcRijUdbA6XQErem4aVSKSS3QNVlFhLYzkkd1L9cfz/L/VHPirOvFAaG89W9aHijIuYAH4FIaQ== msg=ajRNxGKNR1sDpdASt6bhpVIpJLdA1WUWEtjOSR3Uv1x/P8v9Uc+Ks68UBobz1b1oeKMi5gAfgUhp3zQuH9oX4A== sig=2f4PqmULIMAK+Hycd3GJ8oDhQWl20gnK3xe3Jfvve064zTIGH3x4FtkgQ3Pn6n7ozd2Z4p6Q3ZsAKYAlGyktiCOF0ZloIyb1ENz4EcGpLpUE9SRTqm+9UMvyA21d4yViIPTZfDZ/ItiHWbn52aqjwS8A e=found last=15 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAt9aYhqMu34v08N/QBPPVXV9Rd+a5rrrCdIhQfmW/Z+f7DGseGkXVgvWwvn1AUFh2Ld6e6LWstrWA priv=MEcCAQAwBQYDK2VxBDsEOUmJyQLmXa7snBDEmUmY1Zyp45r2JZIc8ETfB2MBPd4TDwMXhGVDYrtHm4YQUVyWtIXZbe9wiyXZ+g== msg=SYnJAuZdruycEMSZSZjVnKnjmvYlkhzwRN8HYwE93hMPAxeEZUNiu0ebhhBRXJa0hdlt73CLJdn60rGXgE9VWQ== sig=yzicqobQEwEde05plEQuhKhIDnZETuLDnXg42AYezXsjbFheIj+XtCJRJ/U9w+YTd7uFqfJsGCmAAehWQc0h6LB6fKew92EpmQYDti7O16KA1CZgPJbYskClsoWzSwVJQeaSMJwbolEoUqPedzB5dzoA e=found last=24 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAskocm9KyclQXnQLwzokY5LYrhsOcWfTZYW+ZtpmRcHvkptWTPDEIw6kbPL+yiaG+EROPAQB8kyKA priv=MEcCAQAwBQYDK2VxBDsEOQv7XUCIIHnyViZK/MwAXFKtVho5S4mI84vN0AOtUcKZMVA7bLaj23lDKgtSVkbmqj3L+C1n4GnYpg== msg=C/tdQIggefJWJkr8zABcUq1WGjlLiYjzi83QA61RwpkxUDtstqPbeUMqC1JWRuaqPcv4LWfgadimz1EZ885gxA== sig=nWZanlI8lx5vLOo8EC8dG8j9s0HbuesNfQzw8bq22p+WhPNcq2pUSC6da1OvFwGYGLBHu3W2P46AfwXEGP/b1RBqj2Bs2Qq7xEBQ5LAz/L54T4F+17G5KVgnDw8h4xZdxxzoIXVw45FwB11cnZ5kMSkA e=found last=18 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4aybARCp3EWnj2MfEbPjtDnTk24VQtC4YbkY39bCBEXGZTaptdORnRlBCenOKzM42s3j0vTaxbmA priv=MEcCAQAwBQYDK2VxBDsEOZwBMrFiB2SaVyWlUL4EUqq3XJ5p6h9tliN5xKXM7FGFOSn/Jy/mtnG1OUz8D+6+34Ot69IgcvwevA== msg=nAEysWIHZJpXJaVQvgRSqrdcnmnqH22WI3nEpczsUYU5Kf8nL+a2cbU5TPwP7r7fg63r0iBy/B6853/ef9z5ag== sig=Tdvo9TkmU48yV0+78vK+6COSUecHX3MPXiofJNbrA07mF47cm3Gy+4PGIBqoF4veDa/4oPeu+BuASJtlJS1do9DYU8MQUFC8sHOnBdYXtpV0cQCZVY/MJDGRBPWz843BTt62vwUPfqnVaOJ9sonbbiYA e=found last=14 s=1 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAX4YViSbNX/juzXRBCDMMeuIb0RHkzafhcf68jdCrcgHUr2CnPY03INZhIKli8W883OeIewVxp14A priv=MEcCAQAwBQYDK2VxBDsEOQhBOyA9+J7JMjNLA9ENwNCC+OZvi2bLOjZmRO7kD73UM50mQzeNpjC2Rz+BfvmFZZmJUnv6tbz75w== msg=CEE7ID34nskyM0sD0Q3A0IL45m+LZss6NmZE7uQPvdQznSZDN42mMLZHP4F++YVlmYlSe/q1vPvnvN8tk3o0Zw== sig=LPiYZmqvdybIVX0PU5/tbFbO80RtnhQwwVVR+stl6dvd1mxKiqvsHMTQiUcB4NBqgueoq8f/o9oAnR8585uDli27nRMz2nZO7Ri5SC0SXnu92DWObpQB0KlROfih4YpZnBPt5eynukSrCUTybyKd+DYA e=found last=14 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXw33agG4LXoYuDyl2FLdqHtUlYb7/4h6nxGyo8EjT3vni+ZVLcOmo6LPGeJO92HbA3JRp4KDk9AA priv=MEcCAQAwBQYDK2VxBDsEOYLH48QjuvTPi0UfxMPViROf5zLyhL/Lu4AvFV3TDJGvP5n+hu2YjI8p7dEWMRruDQW8BW6ELEZjqA== msg=gsfjxCO69M+LRR/Ew9WJE5/nMvKEv8u7gC8VXdMMka8/mf6G7ZiMjynt0RYxGu4NBbwFboQsRmOoomQChXkLMA== sig=+duSEtYmVKaXZyJdOss8Ju3Vrl5CAfllkIFiOH2Rn+UNeNqnaoa3QgfH9MLeDMgiRuTYfAsVz1wAhN7RjmaM4NOSqiZi4xuGk29IZDLRLkLDfnonEnzeGv1JG+KYltx1LNc3/vgdOAC8h5ceOCGujQgA e=found last=21 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAYolacTbECdEqMXwxB70XzzdWvMwwIE0QIqefdEy0qEoXhXklFSvk14tNI192jVey7+W4SD1NjFUA priv=MEcCAQAwBQYDK2VxBDsEORyx4iZbXIEF69LezFiDggwWvdP6FqA7vofVTnEbbXe0ormrXKABnYlRNmDZVTYu7CRdXjpo3JyzBw== msg=HLHiJltcgQXr0t7MWIOCDBa90/oWoDu+h9VOcRttd7SiuatcoAGdiVE2YNlVNi7sJF1eOmjcnLMHJn3FVLj83w== sig=cRnCXUw16LSUWMox8KSsuJ+vOJunYSAbzO/iPOVPX5kBvbsKDIzAPj4XGV5rb59Z33lqSpIkkMUAVPn+qPVuwnfeGiVZ3LqWAbxzigpB7TOB6tdGUl6Od1KD7Qguvg1xXyot2BSvj7Xv5vZlEVwtYSoA e=found last=15 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABtBjcAFs43ZewZ/vR+C9Bu0bUYqIRq2IOePDAU1V5rYQGRtFcezncpX7sWh7h7JmcmdlvPN74bkA priv=MEcCAQAwBQYDK2VxBDsEOV9Q4OSIjsw4YxtumvtiaG4bN4LY8wD6MGYn110roOdfdfZTyh2EnYbOM995poQzpjO3hS7TEfFjmw== msg=X1Dg5IiOzDhjG26a+2Jobhs3gtjzAPowZifXXSug51919lPKHYSdhs4z33mmhDOmM7eFLtMR8WObvdiHzbNzbA== sig=idyWeXB4gTe0xhdg7DDhtMdV7c6opJPM+zS1ymirKZaZuGRcyYbIEUHBCX5eQrW80mJ+3J1BtriAc0Aozmjwz8EZepkU+Q3O8Ks5d8UmGKzX/+u/UPmftKirsdd+RE27BKGFJp88ARmeN6pMy+LTBRAA e=found last=14 s=3 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAd8x7enbNJwrpHMhO3rD/xCxpYv99IaQDh2rhdxYvZZyKWpkxaV/yZdKPopB+9gZ2R3dOudIz3ZAA priv=MEcCAQAwBQYDK2VxBDsEOXZ+4HKyX9e+UJVsYkHhx8DG3jVtfiMSj5HhRqjtT6fG0+Ticz5t3xxfKujLb7jLoD0GpImM1RdnqQ== msg=dn7gcrJf175QlWxiQeHHwMbeNW1+IxKPkeFGqO1Pp8bT5OJzPm3fHF8q6MtvuMugPQakiYzVF2epxEWClUURGA== sig=GoyF5W7jrjtjJt5LLR4b710iuCLq33XHkA6ULqEbQHXuS8jfSfBpxJC3YV5lAZkMSYq0z1rw7C0A93Zbu3WB7rmJ00oDgH4LOxaTOmv99f4G6QhJZ21zXO8sKc3Doglu5t/icg8DO5XNJX3dlowwAhgA e=found last=14 s=4 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAoJj28UA+WYPmKc+mOmFOj6mN8DzGX7bpK1utEPdazYBRkEmjnKGOT3x4RW6QCWFxqUCN+UxPMl2A priv=MEcCAQAwBQYDK2VxBDsEOZ9Pabf8pfrLMScRugbYGWz58MelNoVmuLvfrg0hOJdO741XuvmqyadDmJsNzGce5RguYfYF0v25Vg== msg=n09pt/yl+ssxJxG6BtgZbPnwx6U2hWa4u9+uDSE4l07vjVe6+arJp0OYmw3MZx7lGC5h9gXS/blW3n7KhGd25w== sig=5v0iCUlgRBBW+XzrHSoBkV6tmV+WWf5Kuk/sLySrwGuhJcHWVKyfgcb8jYeZVCLxTub1lWI1LyyAfLjahDVZyTWyofU094D3xzOvJ4tHnZ1xYzCgryLhVfZs1ZTqpOxjReb/+foUEBqg1GCuFHkYjiQA e=found last=17 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAkHylBfXfVrg/vlFVs0+1tNvbjPQh89e9bqntsv1ySz+9bOIBNE2T5jo1mwhHK8ku4PAzKd7YAbkA priv=MEcCAQAwBQYDK2VxBDsEOZDY5bYuCPvqsnYN5784Thc3ypsbWMPv3sXcNr+4+r8jliwWWYQ8N6il4mGJh1lYJViIMLSOKx6MQg== msg=kNjlti4I++qydg3nvzhOFzfKmxtYw+/exdw2v7j6vyOWLBZZhDw3qKXiYYmHWVglWIgwtI4rHoxCrCkKPi2nrw== sig=vggSJir2gJIAL+XM0zGO+cm7vBYvCMIJix7azSRDmiE8NoMmbDOg/b8A8NrUJFhPx9QpJgSpfLSAHOGadIklxZ/dF81YaPdgrOVIvH/KiI/G41xhfYHM2JAZKPBgdAuOXURN+YwsRJ50S/JbQMsgJAEA e=found last=14 s=2 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmvstzXVHgLeLTod3Yf/I2r/rABYbQ5D66SFw0SH6rohL8/cN2psSOdbnAx25qoFSCspMpGZ6psOA priv=MEcCAQAwBQYDK2VxBDsEOR2IOEJeggc8VdYckPvZGemNQLu65LdZNJZG7geYSbDxw415YnRNFzysP/tVBNiWnHz1BSarm3j55w== msg=HYg4Ql6CBzxV1hyQ+9kZ6Y1Au7rkt1k0lkbuB5hJsPHDjXlidE0XPKw/+1UE2JacfPUFJqubePnnacmGEm4Kfw== sig=nZ4K5Uuy5MgUhG5fVbMirtthd7sjRpFgUlbAeqDkXW4NRuvXxS0OIbEAdA4BUZP8yoxuGiCZIjQAWkTsjY8aKhn2dQpJQLbfUvQQ1lOzSy3GPfyXJ0t4tIbv5vAFW//E1KvM95lQgYdVirKjinvshjoA e=found last=26 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5wgeKP777dZAQONnPSniALrqbBeOlakmUGCNQ77RE86uz6juK34oeIuLC5E1VO4HirJysjT73NcA priv=MEcCAQAwBQYDK2VxBDsEOdMN4EDqmO9xtMG0xI77W97AvheWm9LqY11SkNU0R12wr3s5O3zgRr0xswXgRlc9BWm5aIhGzFdB9w== msg=0w3gQOqY73G0wbTEjvtb3sC+F5ab0upjXVKQ1TRHXbCvezk7fOBGvTGzBeBGVz0FabloiEbMV0H3m4u2UGHiiw== sig=44khzjy3j9L8poMhqtQfYT8HV1a0hnR7jZDyQ7abBNEoWaOBrnhBcPw+rUterw9dUK/TXz0hzQ0AVB6IgYjU413IizaufyaIUa/Srh7QTtiyfj1nSsth2pKpMtN6niUGuPjKPDjbB6oZqkINxLScwiwA e=found last=14 s=3 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZpTBjqVnwGqS7+9ks0hXzcYaCTvA3r7bBrpLB8tn8M/pLpL3Z0NiSRsZ0E9Dr+FeQzU/4dld9nGA priv=MEcCAQAwBQYDK2VxBDsEOU519kYIztPXc9wKF+L8StNe79VEyDCL+22gDYMYPFKweMPjTq1g4O0Dt7dvM5nO68+VoBK2jkG97w== msg=TnX2RgjO09dz3AoX4vxK017v1UTIMIv7baANgxg8UrB4w+NOrWDg7QO3t28zmc7rz5WgEraOQb3vBAEkKUn5OA== sig=Eh6eJGsO3lkOlWGaYasUTsFqR2zH/h853gaJhg5g6yuH0J5qgbHQzd8zT4qkFHo6pDQzX3pA8v6AQ1u5+fi3Zsw/KWDtwKM/Wr20c16whilRbo6c5mOSnqRcO2nA9OR9UsM3BLew2swDq+Ihn/rc1hUA e=found last=14 s=0 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAa0MpXwvcyNnsfAuYT2a2yWctgM+cS7ls83010nXGKk9fp8Dzwsb9EP/Xf9o24jbdE6PWWigyEvmA priv=MEcCAQAwBQYDK2VxBDsEOb8zKC06RgzkwTE1cBnWLMFYw6GcEyd2j8fABBqw3i3w+KC/qJWJeofixPXWY+uyOwBHFfgnFAh78g== msg=vzMoLTpGDOTBMTVwGdYswVjDoZwTJ3aPx8AEGrDeLfD4oL+olYl6h+LE9dZj67I7AEcV+CcUCHvyGZDhvJd0pQ== sig=uKSSajmX0e2eL9HGUjtr1yqlzT23xAEEhZxLJlezcFwm3XLrNa9TIzssdhqByD3Y7GKwez41uWmAq3MN4OCq7Hadp3vmO24T8bIe62sbk+jPrnl4Qel58Rscdz6ER1Shh9Fy5WQRpzWNfPPi+o5DVz4A e=found last=14 s=5 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA0H/4fiqDsOmzDikk9W8UyLONX8b0afWXZ7WutuQb+tMj2lC41D9m7Nm00ej/TCKf4A+/2EcwCJSA priv=MEcCAQAwBQYDK2VxBDsEOXakDTAL9esdPsd4r3bnCrrQ3HIesZupXyWVOqpOfQfikQCsmJ6sTj74lq2nGWZrpgvxADP1Yscw5Q== msg=dqQNMAv16x0+x3ivducKutDcch6xm6lfJZU6qk59B+KRAKyYnqxOPviWracZZmumC/EAM/VixzDlx/VOymM2Xg== sig=G0+AZUA0T7SAuof40bNr1iMLoiS2gyBWpQfRxLJCW6V8Agvi4gzcJ4oXzPmLRcKdEFM5zIMrw6IAL58QYQCfoozGJD/AYCPJJILuXyEDV9eutKYbQlHXZDihgfpBFSvFvcqlAU6IplzwlynO704MdzcA e=found last=16 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAG3B67U3C748SB3yoOWrPCvAujMrd1JmvOk7QYMU1Jt4qfY+4Rxt/moDPcLFDRbt0KtGJklGWESyA priv=MEcCAQAwBQYDK2VxBDsEOY4rchoGxpWEvK9wbUahgIEdxDK5xiVgoftE2p+nwdmaGHSxnB/k3HcKbNweDEoLuinYPgyOaR37gQ== msg=jityGgbGlYS8r3BtRqGAgR3EMrnGJWCh+0Tan6fB2ZoYdLGcH+Tcdwps3B4MSgu6Kdg+DI5pHfuBIIP0INvcng== sig=DNuGLoMmiFN9pZ/nO+EFDCKesL4ck3QuC+RITaUHPPkbMzv4xykX5kxriNqBlL6WvzlFy3p8UaaAy+u/WOuEK4523FbW3bH8ZK8v8Cny+ZSgohKMjva91cso4WW7+XZySAngRcG5rzC0QCS+Z8NxMREA e=found last=14 s=0 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/5+nkLpvoCYfQ60RUIlWtVZIujOza2LQGhM3gaHVOVmDQl00MEqpVlWvPWLhVXolIhiWd1v9Z9oA priv=MEcCAQAwBQYDK2VxBDsEOdVepr43uuEnqyVCug6RVxWjt/lm+76BTu23NoXasiVQLr7Yc4RJuQWTkocUzAgXI1Pvmi9dprjdMA== msg=1V6mvje64SerJUK6DpFXFaO3+Wb7voFO7bc2hdqyJVAuvthzhEm5BZOShxTMCBcjU++aL12muN0wKubwnoVNAQ== sig=xOyYIz3JaY5LhJHcavmGIWrAEk98hGb2ar3joKSqQkt1ZgBXv0kXhiTLoGh5YJAsfp+CbuRd/TuA1Ut5x0eQJFd7BJ8+6OVDfEXhXnkK3+8qlzzZmgoFwv4YJLKQ941LGciCxR5d5rwLdziWJXSgcCwA e=found last=15 s=6 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFM3ZyNNTNDlPDr7d2S94VB+VgXKWVgfVi1uVDA1D6nnnmP7nvg+4fUpD1Yo6M4dphBAlomgBdwuA priv=MEcCAQAwBQYDK2VxBDsEOZfyhkVti1XjNq3V7+XgpNd9R4VhXrYmSREXhP1sHyVdL5Sy8aM9dvsXQnkjyQR1AAy51ezA6G73gg== msg=l/KGRW2LVeM2rdXv5eCk131HhWFetiZJEReE/WwfJV0vlLLxoz12+xdCeSPJBHUADLnV7MDobveCjLSGc1zhPA== sig=oHRA+cxcZS8WeDbPYwzJht65laJwrKeZhg5GWhT8YA16bcHUtSw77wPz7sSeeLSQDDhKdYAg3NAATFNFdRd8tmoU8tDe+KZ9eLpFJG2CTg21ELUqwmJmql+a1g8vuXdKsWakP52+5JpIlBe/v33mIxMA e=found last=14 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJtxKV82llGYWkDx5xF18qYL4Cn3+tdMOh2LPQ2wzhjYy+ufuvm2xiG8GIz+yzbR25e9g6HBZbsGA priv=MEcCAQAwBQYDK2VxBDsEOZlxBtZqfl+dBr9ZjrqDyactOzATiwSc6DcvXy0NHowa3GgHneTSQVTzIB+wAcFaC4UZ6rup/cKxfQ== msg=mXEG1mp+X50Gv1mOuoPJpy07MBOLBJzoNy9fLQ0ejBrcaAed5NJBVPMgH7ABwVoLhRnqu6n9wrF9JeQiH/wxvg== sig=q6EY5UNTJlbz7azyvyGlrhzjHS+meObH+4ZconBRmRd6IELUa2h458g4qBMXcKvyRGU0gMIycakAL58rJ33hjIx2OPuIeDWC0UEAUAySnq/+nzMh7FuK5dLk9cGQ+evySj/TLIYfkLMWFfKOzsGrhDIA e=found last=14 s=2 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6/H8XQNwmS97HxbHr9JOSoEV0ht00XGDuNXDV+2EMVER9ebvik7Xb6MerBmKIQbdS+DCd5n3UAWA priv=MEcCAQAwBQYDK2VxBDsEOZ9E6QYnB/ZYWvkB19evz+3jUgik5Kt4IJa8qxtdABwfaHiWxZP+S5Vcj6l1Nd48JFNjhFv559DWxQ== msg=n0TpBicH9lha+QHX16/P7eNSCKTkq3gglryrG10AHB9oeJbFk/5LlVyPqXU13jwkU2OEW/nn0NbFBZ2Jg9kucg== sig=q0vx38x3IIE64M/1JkcIhyJZ4oPKZAkwZRQgbB/LnffYz4D/ARpyUxgX6UCZ4FD14WgdD3EGsoAAr/y3g6V2ICr8l6ENRSIjOthoCok+4PSnqU2nvRmEmrUlpMzyrn/+a1dEBG3lbk0PWHvi86cFezwA e=found last=20 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJJyOzzeSXg+2GF+N13oWyVEYmJ+EsBVdESA2yicSPGN919xuT3mntFfr28PUfN8gxPcbKVGcxNuA priv=MEcCAQAwBQYDK2VxBDsEOUP6VrFcTO7eReYWfdhpAcCSCvNPVVH/ZuahNKCGgCqIy9Z7ELs6clARjERRPcORpnaEi6BS/LZHpQ== msg=Q/pWsVxM7t5F5hZ92GkBwJIK809VUf9m5qE0oIaAKojL1nsQuzpyUBGMRFE9w5GmdoSLoFL8tkelrJgWrURcRQ== sig=osehLa7BCJcsr5OkZwW3SZ4ENokSMhPL1NXrnOxdZg5NnSQKlOukctJ6VdOiQujCH/VUznwUSv8A1ICvnFr/6Kh57a5aPacCfIK5rPKPARiTbf2PnmdHp0fkM7ERdfrJmomvXrzLbNupKNnSafa1CBIA e=found last=15 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASBH4/HKrpCtdgWDs7+FrHDQ0MaV/5IFGOzQk3YFzPF/CZAqfeft1z+158nXTV4E1mR5k3plRZxKA priv=MEcCAQAwBQYDK2VxBDsEOZ51sHNx7WOeCEC4wKGiPSLAxtwax0XvwbosIZNkRc8tbAOz8TAQFInaLzmNGzSkQqfvTP3n8Wrq7w== msg=nnWwc3HtY54IQLjAoaI9IsDG3BrHRe/Buiwhk2RFzy1sA7PxMBAUidovOY0bNKRCp+9M/efxaurvC3L7CxsKsA== sig=Ja0B8ejroqyaIf9wl1V+6hP7AUYvP/Tgnw+fdODdxie7jflnhEN1JgppidKCtQmrx34Lr4pm1J2AvOM31Oshz8cImPISLI7ywP0UbcUp74zQmaTFWzBzYJ5KU11eNswa3APSaUUv7y/RKFsql6qs2CwA e=found 172 iterations",
+ "pub=MEMwBQYDK2VxAzoA0TOAEYFmmVhwsA6XVbdqU9uxozBluYkTniZprt+kRVIGOwUnrnnRuIRaKY3IAoqfnk+OB1YVF+AA priv=MEcCAQAwBQYDK2VxBDsEOXStaIGzIBwg81QvPWrTCFHWhTYOwdiXq0i1+TJc9P3xG7th/kcQ5kp9pflhx/ERCLSn3kusRTiZqg== msg=dK1ogbMgHCDzVC89atMIUdaFNg7B2JerSLX5Mlz0/fEbu2H+RxDmSn2l+WHH8REItKfeS6xFOJmqewbXL0oNVA== sig=Ifz3wx04icbzyqLlNuZclJHHjgBbSaUtHeW4QrQjdFMy3JS63a6UDSHGIwUUpm1LiVOcJxrvbqSAfEp1ECbbV9wg+KOl4E4YjREx8HRW9qMbNIGjWyC3vyGPPe4XqZElr9kMQ2N4Gjdt6u4yadmBUhsA e=found last=14 s=4 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALqckGZ+oMTp4WDkAvZlhv8XLsjsx+Jb4IQxiH+5gJU7mu9QJaSY+QSNlrnFEXwvfHaAivq+mG7kA priv=MEcCAQAwBQYDK2VxBDsEOcrmNdWBbGK+MoLB4cYQKgrMZMqh+qC8lNVbivsPlqOcBtxMm0Xd72PaYSVg+d9Q2/U1t6klJiuFeg== msg=yuY11YFsYr4ygsHhxhAqCsxkyqH6oLyU1VuK+w+Wo5wG3EybRd3vY9phJWD531Db9TW3qSUmK4V6nbOmN5KLNQ== sig=OvjwknrZBlwLPtuhihsyUyGVvNxsf4FRp8+8bn1dNKUCaseAnnh2St6RDoxi1SVHhVkTFYX5OsaAKp9tDpxC2KwHZdc7JfXTm65yGQluSGNRFIm89DtKOqdJ5ZbFBPJztu3L7RsmVjVt3vgxUCZCui4A e=found last=14 s=5 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7IHoWSidTFeNGuj3HYaLj7vgLYVIMAVuBwhWU7Oacn3xa+bc9t59X/Koui8GALr9oNzNZibaDxWA priv=MEcCAQAwBQYDK2VxBDsEOUA/oI6HQ88QVD+4hYJHoPskH9qrGBt1IyY1FHzW+3OtrvTazzeP3XUyY9oZAhUHcP+xCjH2LW5Etg== msg=QD+gjodDzxBUP7iFgkeg+yQf2qsYG3UjJjUUfNb7c62u9NrPN4/ddTJj2hkCFQdw/7EKMfYtbkS2B134ZQuu/Q== sig=Zt1UfB4tjJWwCDUTI0zxjMviFxPaLFTNQZeyA5/lhGD0EXZeXGoKXNgxR/8YyhFIeNqco/9z5/gArVL7b8JZ+DGb/h8e8bi79DHF9cMshB1657kVuIbwqarbqYO+XzeenOif6ujKovHQSfuSx4IynicA e=found 169 iterations",
+ "pub=MEMwBQYDK2VxAzoA4Jfz0nEelpWX+g3/o4mqa6EJG3dYpqAKz10zQQmFRrOlFfIaKEqDXFq8Ji65Qs5wQT5s1qUsI/QA priv=MEcCAQAwBQYDK2VxBDsEOQBHzY3WT+B5OziTYDFlxlbWcOyAWfsU+AdlugGsCaUHueDtkwkeLrbylEJu2VB8wpdBofiN3orXMw== msg=AEfNjdZP4Hk7OJNgMWXGVtZw7IBZ+xT4B2W6AawJpQe54O2TCR4utvKUQm7ZUHzCl0Gh+I3eitczy0mbH9n5EA== sig=k3MSnCejxfnAGGP/GNkTHHF7Xe+QAMJz30TJdMT3hpjDSMmJUMj1Bnfmjz/sPNkx8NCrdgASSKAA1KcXPm/k00YLOALHAaTjPoYR1TVHuhQSCcr08pjHa/3vt7Ry7PUC3okNswLnuplf8OiFqG8X+ysA e=found last=18 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPipcTWkR/lxuKMJ0GvyXE7ZpH7cl1gR8HEyJnHnewZE1A5okwQqpIWLA8KOJ+xgogEZzdmusxwSA priv=MEcCAQAwBQYDK2VxBDsEOUlKEL42RLE6GK8U3JZABV3HQzGa/S3t9P2GXTkD16w3Taw9PyZTOy03ZCUMpAbiXZL9iu1b/hFKsw== msg=SUoQvjZEsToYrxTclkAFXcdDMZr9Le30/YZdOQPXrDdNrD0/JlM7LTdkJQykBuJdkv2K7Vv+EUqz9t2aBzejaA== sig=OwXl2Wg9H1JH62iY4UZLdVfwLzdoN1KEBzKL8HSmfJfud+Wd/r5RBMWxj1Q41K85z+oJm4Ep6n4Ai+8xWnFZ+CAji2cvy7WgRphunicMGuSS0IraAZ3Gh0Ie4G0hVOHLWiQixvcZjDInNBjqD9Ln5DEA e=found last=16 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATKxl6+BByo9360eGKhjZIZVLVZ4cGgkHU0dMlrfAWyHOD9J6M69YnB7orKP5cjFRS+Mc4eAIf4WA priv=MEcCAQAwBQYDK2VxBDsEOXnQRSAACSRIfKxxwO5cXgfuP3cn3m9flDg812uPU+E0gLTnTJw6bf692mY7Di3/Paja4fGxNc3DFQ== msg=edBFIAAJJEh8rHHA7lxeB+4/dyfeb1+UODzXa49T4TSAtOdMnDpt/r3aZjsOLf89qNrh8bE1zcMVBBuPvNDkXA== sig=56aGOWlw9pUQePQquaNOUrCCMNLhRFURercZ82GoJYjOBeyK2DLFlPKpoY/FLmx5tSSy4MmhknAAWVEX2TBKon1fuowQe+NiZDMXB1qgKoFTrSvTOJWdW1rzn+NJFW4jZuiekOPB1YAVIWCtWxHWMioA e=found last=26 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIaayhcVxzu/8/1/i8HFMEWqCogHcEbmFvXiw/EFpGUL7gXU7o4qEWz6BEWHLJRQd7KkAz2szccaA priv=MEcCAQAwBQYDK2VxBDsEOfhfx0/smiiri5yy5pPxWnI9RW1yYYHj5GZQLVBG+TKxc9cIzrmhl1d3700GD+j/Q8wifP/KT5am8Q== msg=+F/HT+yaKKuLnLLmk/Facj1FbXJhgePkZlAtUEb5MrFz1wjOuaGXV3fvTQYP6P9DzCJ8/8pPlqbxQGhiKY8ePA== sig=omx0xxsGFe9bTsYBLlKnIRKiNcUdGVCvX42uGSqpIz/Pt1XCUsnb+qhA7w0H/8CXMrGuLE08TLcAwKl0o1p1+KcTWp3iVh6AfXTLKAKDtrMD9e187zSRlJUtlZOGtkMead8wOwVPqjx7xEDIqyxWzAkA e=found 162 iterations",
+ "pub=MEMwBQYDK2VxAzoA2FJZga4c+yRTvVPuBoBKHpCT4vrx2CIQjpN27CJsQaHbhi1mNsgc+iXC+EwWtmn1uFhQJNGLzXQA priv=MEcCAQAwBQYDK2VxBDsEOcCm1WxSJSpywwLui7EbmWlfXzDgVD/BLIw7BOjHKTlEz1eMB4i5v1ZiKHP8C4WFOBt6icUDKzSUaA== msg=wKbVbFIlKnLDAu6LsRuZaV9fMOBUP8EsjDsE6McpOUTPV4wHiLm/VmIoc/wLhYU4G3qJxQMrNJRo/4ppv5n74A== sig=Kz/WO12E8ypl/yUlSXgPdMH88fCKlEWTpjFuB3xuL5cejvmYdPe3YxTXZgUKRbq2kZkvFNwWZJkA2C0AszUxzbLpwTum2fg51x3GjnIhWN2PE9hYw+r9hP4FKcdQyUYmvsg9uxq26/f8COgetZPnQj0A e=found 187 iterations",
+ "pub=MEMwBQYDK2VxAzoAoh7PzuShlwdgKKydN2TH6UDIEjcVcz9maVXIEpeKBGmWOhTCqhLwB3YhswVz52KwwZkk6athFTAA priv=MEcCAQAwBQYDK2VxBDsEOR398tHkQCJ9LUx1dlu1lR30abnxNl+A77PZmmfB4/Ygo1seG65F94oUmri92PRkp/B9TgDek45b1A== msg=Hf3y0eRAIn0tTHV2W7WVHfRpufE2X4Dvs9maZ8Hj9iCjWx4brkX3ihSauL3Y9GSn8H1OAN6TjlvUw0PzD1OgkQ== sig=Ov9mkGUpCMr77AJdYSL/FZ95LUxQF8PFgd6BKBEhj+2Zh+JCEu6J83V3l7KBiSi9KJX3NA/FIg2AtpjhueQrjvjr53UVQydMxxIit9dv4UsCLXzg0CXSyFoY05UuXDL07LFUYB/awqhvCNnY63zA8gkA e=found last=16 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFL33Wx/u4WcHQSRq/Wcs7XdZAD2xrsuOGCfJ2hUrQP/DUCSRYnTtMlpJwiUa4mYEtIPiuZDHhyuA priv=MEcCAQAwBQYDK2VxBDsEOfOm875eFH6TtIgTUvF5WaAh2LBj6o235vRZYsGPQJ20fFKpNtW5+5ajCSd2JyzrWLmoO8dsnNKG5g== msg=86bzvl4UfpO0iBNS8XlZoCHYsGPqjbfm9FliwY9AnbR8Uqk21bn7lqMJJ3YnLOtYuag7x2yc0obm5abM8T+etw== sig=MBl4nmj+6dcV4DC8hsHZTb/oJfAdEzxBeItQHL4m8HIVnIurVCkIDvSEZ2ASUZ16GCpwt3mcNjoAhbWGOyZIN/CiGsshgR2Xctm3afSe4NXZSh20oYbnbWJYS91DbgYCGQbQrFOVmRXBY+R8YsgoTBwA e=found 163 iterations",
+ "pub=MEMwBQYDK2VxAzoAiUXW4URqK7UtJdw0RNUlJcYit0LGIggOpFA4x4+altLERia6/nqPdd13TJeeDExYULqBSYXYhw6A priv=MEcCAQAwBQYDK2VxBDsEOVwGuNGoYbNjTcKSkrLmB/gzY46fOcZR82PLW0qAuEXZt4r0xrG7TJDQ5Ya1wBQlXSpQUaDtgkjf4Q== msg=XAa40ahhs2NNwpKSsuYH+DNjjp85xlHzY8tbSoC4Rdm3ivTGsbtMkNDlhrXAFCVdKlBRoO2CSN/hJ7sgT/Vh0Q== sig=q912Qhhh2kJT3pbWaredNaDyz99pmK8nIcThB339ah1gg5xelcrQp5LmFNjTWwzJqgx3MjcwaOOAkJPuTMJQDhT4kByQqAt+VC/RLMOG8zyYg5yUhcq/T5y7b/fWJ63Tm5RS116AVvOhnX9MIlfHlC4A e=found last=20 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAgGt7ajX87GWW+6RwRLIiP8/Q6bJS1wmOLkXMRLHgSQ7XbkLHkSquFvB1eTwE28JdjCJTPHGHf5UA priv=MEcCAQAwBQYDK2VxBDsEOZjDx9VVPFKZ/o3uFcBZWMtO/ADgCzvdUdO9NgiWEcglff3ums4pWQ+9DXmXmB/x8gSUMB0gXfLgMw== msg=mMPH1VU8Upn+je4VwFlYy078AOALO91R0702CJYRyCV9/e6azilZD70NeZeYH/HyBJQwHSBd8uAzxampx2fxXw== sig=oj7O/NcltH2qBZXp77c1KlMhBc9bigaucWLxsDykbqcP6AuhbrJjkNJrM5fLOxxasVTd1FQgUUSAXrLYE3JFmn1/Xmjl/kbuYmse5hFA8RMG1DQEan8DKf6vAgRZwbwD5ITLHAexsY3hm7AEjTFj6ysA e=found last=14 s=7 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJuqtbDEtNEI9o0lUE7tJJIdJ2A0mRS/5emJyL0A6K7xzPryk3X1rD1djKw42BpnPOwizOky5ehoA priv=MEcCAQAwBQYDK2VxBDsEOVneGg3ExxJsszz6iPTChT3JTNgO+sb0mABa/8CUKazY38rKK3/Gr6ByZrZJQpfSMW4w+uRMS2ffvw== msg=Wd4aDcTHEmyzPPqI9MKFPclM2A76xvSYAFr/wJQprNjfysorf8avoHJmtklCl9IxbjD65ExLZ9+/BYma2loiYA== sig=lS5JZ/K9SSX4fRPJja+21mcA53IOa1PZH1vDLJI4QLO3/Ym73wMz0ee91LWzqelDV3jXk95qBFQAKxbOSF4OOKbUamWhQ4wh8quaCJYrYfvbZ0Ics6O/zkp6F24z3Ik7THBrhG8gRXOm9G6uZ6bEkiMA e=found 158 iterations",
+ "pub=MEMwBQYDK2VxAzoA8AArJ85lZL0zyEGVJgGRIPnGLsppvLif+ErVw0w7uGz/ZlQHhgF/xoQhGpEtFGunpr1Hv2jrkDiA priv=MEcCAQAwBQYDK2VxBDsEOUHi4t7RumxohBafcuIzTRrOMAYgbrvv0nWOaugt7VBO2NAAYDHhh5R22a3SpajIn91jtQnbwL6+7w== msg=QeLi3tG6bGiEFp9y4jNNGs4wBiBuu+/SdY5q6C3tUE7Y0ABgMeGHlHbZrdKlqMif3WO1CdvAvr7vMuGfM7Bo2w== sig=d1CV0JoSbkO7426eiw3SDvM1cyZ1dKBPfLXS55TMnRt6GIFj2bBo0yRoV6nDKq21yTZ7q1cCpiKAXbrvXdSnviUxZ9D24k0j7Ru/Trnmw+DJsC9XuOIYQOoAWmKplbvms615rfr84UqqmWpPAV6bAyQA e=found 176 iterations",
+ "pub=MEMwBQYDK2VxAzoA3yo3onLA07aNaN0qtuCKqGkP35bPab3zfbCdSFu03CXi3ad4buKVnDo5o9I+C3GfxF054hX1G+SA priv=MEcCAQAwBQYDK2VxBDsEOc+N9yxhbxijrbYx0D3sqIac96AXXLD0NySA0ZrCWyltY/2knJMEpEKrMfg7aIujGQNCMZmpMUeKAw== msg=z433LGFvGKOttjHQPeyohpz3oBdcsPQ3JIDRmsJbKW1j/aSckwSkQqsx+Dtoi6MZA0IxmakxR4oDHE+vEuDmuQ== sig=LRoI5fAx7xL5L+udpt1WTXivmdpnDALWJoLgt4kAX0y2VxD4IDdkEaCSrPpKBkPyi9QHMX2+L6uA6aviK16VqJatsX+Qry9DjcEhPnre/e0/2PCvjRZ9SzySzzLZfRPlA0FjEvlVShL2OxAfJwk5vzsA e=found last=15 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJi88vLEcpA5RoBxL8EIQhOZaLB3vGCNwjmHIpZ4wYN/SjsCfCVbmAda678Sf93W5LhtpCpEH7YOA priv=MEcCAQAwBQYDK2VxBDsEOS3FgWVCiF18+mPFaGIoZGbwUfygArrQ19DNT6IYW0XefSb6wI5yXkGcx3/ukM+GuA+cpXNBOpo5tw== msg=LcWBZUKIXXz6Y8VoYihkZvBR/KACutDX0M1PohhbRd59JvrAjnJeQZzHf+6Qz4a4D5ylc0E6mjm3cifPDSYXKA== sig=UWD/vwpsZ/wrWxqy1Zh93ObqWheO9lAAszegvM14xatV6t6fcdUxWWcz2UsxJVTYL/yQ/u7NYJsAZ8bOAPMBQwyWEqmk8D/emcQXoU6vSIAv+K6QnIw+vG04udYRUKBS/K325qFDDd6Sa8bEHygsjx8A e=found 178 iterations",
+ "pub=MEMwBQYDK2VxAzoAcV5nIrACuVpPAh5ZqL8dEszTeAkBWMj0R0yaxw9oswagOfZscPEN8TFgyryVyXP++21dTxTgetcA priv=MEcCAQAwBQYDK2VxBDsEOSzTePiwXJPf+wnLojFB7dxxezhRWvsaGSn2HFEhWNqvgNBfZHrxfFVryODmJDAmdQcFkUF0Ux704g== msg=LNN4+LBck9/7CcuiMUHt3HF7OFFa+xoZKfYcUSFY2q+A0F9kevF8VWvI4OYkMCZ1BwWRQXRTHvTiss+wkEiJMA== sig=l6Uf4dlJZexR7yoMvSZkpgXed20LzcfyVDhTRRawPhiSaGJxcEdj18I84ku5iMKtRq6bzIyYeuAA5cIjpiXjq97RzYlHtFG1sIbS+tiEMqqWhurZyl1ZEsAuwIrYZ5toPHxDAEG527GCrjnFsjW+tSUA e=found 157 iterations",
+ "pub=MEMwBQYDK2VxAzoAtbUYKn76MKte6c/0dBwdnN4YXlv/e4MX6yGDXH0rWkxkshzus/ZTkT3YXElMg+xuZRfNYW7z3UyA priv=MEcCAQAwBQYDK2VxBDsEObvYhuKlFEV+3xBwq0yUkAkcFlx16YzwkadgXyogDfLzlTC/w6MBMcC88ti7gPnINtaPaupamFGkpA== msg=u9iG4qUURX7fEHCrTJSQCRwWXHXpjPCRp2BfKiAN8vOVML/DowExwLzy2LuA+cg21o9q6lqYUaSkoo5N7fiB6g== sig=iS4jQy6wyyNxdiPSCGQn7Dg4XBNzlZ7mAO3V3NPYw60LtKWwm91lv0P0e0K5yucIN+1ZhNpy7VGAR6g23T5OdJJDduCWsNTZabt371lJ+xtYCtl4+kAUGqwluq/9eDo/kbARl7X+TKF6xiZojVPT3iQA e=found last=15 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUL93ueBFZqY3BrNcRT0s2feIAHIgKhBc7pRflHlKT9Fy72pXzIi22nlrovRFS+/mx/nJ0214uUcA priv=MEcCAQAwBQYDK2VxBDsEOWoXjmzloV9BwceyTD7RLMN/vQb0i+Wj4n9svhQa1HeZWbVGmZgBJLc3Fq+5NH5bmy4Uhe9C5bQZdA== msg=jmzloV9BwceyTD7RLMN/vQb0i+Wj4n9svhQa1HeZWbVGmZgBJLc3Fq+5NH5bmy4Uhe9C5bQZdPdW9/KkoBLYJQ== sig=ISJavGqDu578bqUFnegNiSsN0PBrp7gXQgDo9GasGraQ9haQ3OSLjRe1MqFS9asySGsH284/dyYAfkAuE6YQekn2xoj4ZRNBQsQ1TmpaJxmVAR1cF4buU/6qKkhInS+2TKYgg9lB9N+qMLpTOLDpFBgA e=found last=23 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/K/fzZMYIimSU8bBl/sg8Rh36hm1ntCVa4Et+5Ovhk5fnlEqku8xANrBsOWNMMy6K1nTOD0jq2gA priv=MEcCAQAwBQYDK2VxBDsEOb+lD1yizcdv5oaV8M3THp4/HXi+pxhM8GU92VVI/gQwi4L6T4W3m0/p7nRzPVS13YIcOSa2Fp0+VQ== msg=v6UPXKLNx2/mhpXwzdMenj8deL6nGEzwZT3ZVUj+BDCLgvpPhbebT+nudHM9VLXdghw5JrYWnT5VlaWsr4lyKg== sig=0oYgvQ+XoIIUL4tyyVWowxtL7T5aIKvoHmiVsbdLO6pBQKzPShO7SgcfaJfZDKJ6nuF+6bquwc4A/BADjxp8+W1nJEgzKoNmUrxIGs+Re14EkIw0wHZEsRAaeMTf1uP2QIliW/c1kOyF1WFHXT5MyTIA e=found 168 iterations",
+ "pub=MEMwBQYDK2VxAzoAbImmNC/bZTL3uh0rXxlPmuK5tMiHdaIey3pihhRSdcQvdkmQV3wH6R5dUOuhXQhiN/QXZIGQ7oqA priv=MEcCAQAwBQYDK2VxBDsEOdjrZH/OXvCs1JXxlSsrqAqawyc0kgpYjdd2j27FfsnVuuO7qrPzpef49gFK9W0cwkgKWhKRcyAA5g== msg=2Otkf85e8KzUlfGVKyuoCprDJzSSCliN13aPbsV+ydW647uqs/Ol5/j2AUr1bRzCSApaEpFzIADmwMbDibfr6w== sig=Wd+I6SiBIEnSLfHxqOVmyz5keUdnViwzPdCESWdv88UC9JhCJuEgbEgQsrak3FbZAUqFSDCuYZ+A2L91vXg4SfOTE9oN9MPkVKmfUHzbaMEGNYgOUJ0xZbqe8ArDiaLjkZLn/Ne8WDY+rZxE8YZbSSkA e=found 171 iterations",
+ "pub=MEMwBQYDK2VxAzoAbYKrwWFOmPKdp2EQu91fY6uNP5fCrH01+YFStSDLAcE30SgX72FAvE9HBnmWL5irEHUV1/8OW8CA priv=MEcCAQAwBQYDK2VxBDsEOa1ycLa1MZLQB33lChNg4xR9BF6yHwuyrLEnZmyAz2bHzBbjhTpFAQNnzttLIuHrxk0wAguwA/setA== msg=rXJwtrUxktAHfeUKE2DjFH0EXrIfC7KssSdmbIDPZsfMFuOFOkUBA2fO20si4evGTTACC7AD+x60kcor9wKmGQ== sig=2IdtJjl0LboPhAVreHyJYHmfnlrGG87K0m8b0bfRKD32dkkmUj5ot4GYDAdKnVxbuVZ6AM5GXIUAJi2i89D8EIuIKNcUrHn9hJdToyRgOCZh5ioy6UTPY6YGSPX9AGs3qyZDxw2r9sFn4olfrQ0r7xcA e=found 161 iterations",
+ "pub=MEMwBQYDK2VxAzoA57+V45XmUtpjx9mXtQ77BVJU7L2aaZv+euDL2+RczhangISVvZffxueEHj/lE/kAQiqVeYjyz/+A priv=MEcCAQAwBQYDK2VxBDsEOZzVydXJ8ychAiMZb9+yYwmnLEKRrtMBsz5X/j605li300IDg+A2zBeQHmVU6RhrxQ1p0QF1rqvcPQ== msg=1cnVyfMnIQIjGW/fsmMJpyxCka7TAbM+V/4+tOZYt9NCA4PgNswXkB5lVOkYa8UNadEBda6r3D2xmFTyUnh22A== sig=nZOO2bhrb0UoL3cZRGAawxQL8EzFhm3fQDf/FVZOaOUKE6zN4Nq//W2ZzbC1MgH8hoDpZkL1rfeAi0NvtHwoOulL1JrtUgubdNWAm3FUgthTuKMk4T8QvOoP1MevBK4Ib8nHB+6Nr+6CpWf4PTbuBDMA e=found last=14 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoANMM/DydAdBEVjaoXb+fI4unDfGI+JkTfibCtrApkShiXoAAT+twxqr4gXTA51XJEZswuX0hT9LUA priv=MEcCAQAwBQYDK2VxBDsEOfxDhn8lqgdjz+f7svYBA5lZAK3rCIhbAFK0mnplCKDTgoe1GlJ/Edq8iRs90pflXWleDo51MBEL0w== msg=/EOGfyWqB2PP5/uy9gEDmVkAresIiFsAUrSaemUIoNOCh7UaUn8R2ryJGz3Sl+VdaV4OjnUwEQvTwfSFvDSWgA== sig=dRgUaYbJAdu/buPJjsaocjllo+KLjKw6YhBsgxX9CT09APrM5M4o8rcp7Eogwma47d3D0s/ZP6eA3B6R3q1JeP8sqRRcgHlEvcHy+ytRL9LwfqYR1A6nk/WAVBFYrNeuuu98snmCwEwVEaGWT0XXlD0A e=found last=23 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALhtQxj9sXJTlDYbNKnY5rbb+u8pgwF6aqp6bJyRc5BFRPgNyvCUfmF8vdAjN84LhELVsMS4QAeaA priv=MEcCAQAwBQYDK2VxBDsEOfF9SlNyxr7crhkIjdNk/2v9cwXV3g7oU++OyWWfOfd9K1TNcE6x4tsH5aqEDnkOrtsprNUD6sIXDQ== msg=8X1KU3LGvtyuGQiN02T/a/1zBdXeDuhT747JZZ85930rVM1wTrHi2wflqoQOeQ6u2yms1QPqwhcNGyfSzHsiHQ== sig=PNvDdMONCGEW/YVrauQkw4k0DsrL4nhMD2UUe/JS2sDjPH4cVLnU8eUtPkC9KYGWnoPPRttQWF8Apfh12UEf7VL9Xq/+2AhKgL1oSyEMjVz2q94L+OzAfq2RJtrQgOtidrchBiyhi2Gpx02XJv5lngMA e=found 170 iterations",
+ "pub=MEMwBQYDK2VxAzoALTMeav4sZNGAnaVsqxNC9NF43Xu2NuuZfdhJTgrhcqidZHU5RJ4ef23WohyeTRyl7qNu1ny056kA priv=MEcCAQAwBQYDK2VxBDsEObZsc1xH/MOlBYoDsIbMD8NpwJrJ41slyCdr8XhNcBrNWJRA5DgUpFyjZfO9VpOB5Q7F+Ny+eOuJoA== msg=tmxzXEf8w6UFigOwhswPw2nAmsnjWyXIJ2vxeE1wGs1YlEDkOBSkXKNl871Wk4HlDsX43L5464mgC/0bGPEAhQ== sig=7ML/FAoevUnBUgWEeE+ew1Pg7Z/9O9N/xLviXtE8toRY9AKozlv6C2aKA5UV5EkwRk7K2qYA2M0AJh8szPqFmvFNig138QwrZORcaS465/zZG/hxyaajZo/O3r6JZKbir7VhVeQ6p2yPjOkdBdhhohsA e=found 182 iterations",
+ "pub=MEMwBQYDK2VxAzoAfWQYBYuvElUgGCGNo1RjcBvsZoQw1NFtQOpNosZpSikkY7qQOfHuQkqgOl9+lmL7o7oFukxk+AkA priv=MEcCAQAwBQYDK2VxBDsEOdpsfpzD8WpyN1S3tfIyNuZ/8KpLYXa2cKgXlY9JEi8yVamEhxrUIVp70me82e5LymKiIvWbUWGE7g== msg=2mx+nMPxanI3VLe18jI25n/wqkthdrZwqBeVj0kSLzJVqYSHGtQhWnvSZ7zZ7kvKYqIi9ZtRYYTu/Roa5gLrMg== sig=HU3xFocCL+kKYqgIxP7037JS5+7gq7wHAxUHxxBzXy76nMSXZ/Mgp8kG9QpNv9E9QW9KNbJu8beA2DPyhFo+ATbBCN4bkEL7XHJwBzCpmHYkPzGCj4ZkFz8bzp5FdO9wp9kHG9NTCySJoK0E6W4ovQUA e=found last=19 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA+twCMHeEb6prLc4YcAgfoniUjMz58Z7Zg3gWcRvrOgq5fVUH5KzEVBQw82yjZDR2mAeU4HkZJXcA priv=MEcCAQAwBQYDK2VxBDsEOXElpfi/fvhLPFgxQanxx5i4ssipBqdcI8Z6yIAoW1ELB/pISWMKVhZ8dwNxPAieGBPTwoJ2kOMj9w== msg=JaX4v374SzxYMUGp8ceYuLLIqQanXCPGesiAKFtRCwf6SEljClYWfHcDcTwInhgT08KCdpDjI/co2AtkE72k9w== sig=tXIQDeIlMA945ThTruKvXnU3jhkxq3Uu318riqISuFjOWpujtVanrJHxS4YrHS5ArnA47zUn6QMAE8SYv8lYxA7LCepamXezSRRmzZj4hGb2YePgZ7R8X2fkMZMCAnB64pym4pC0nOrvC7xbCUsvPyMA e=found 156 iterations",
+ "pub=MEMwBQYDK2VxAzoAv/a6gc2YBK6J2+DrNLR3PuQmRD2IgejtFyCeJVCUc8EYRVUU/YAnPafJKQrjPM0KcFIbCl+RxRAA priv=MEcCAQAwBQYDK2VxBDsEOQ4hwgcGewKJ1/r6aunUxwArP5dYtrBcscF5bfOOLj4NMZPb73JClcTZGX22Voc8Irm8gLd2J2E6tg== msg=DiHCBwZ7AonX+vpq6dTHACs/l1i2sFyxwXlt844uPg0xk9vvckKVxNkZfbZWhzwiubyAt3YnYTq2agEPLz2Muw== sig=wh1WqiIHFl1I5tI5ZpU4O99kSbRpIvWGU6l5jIAOhHuhBsBjf5DX2bGpgW3lNrqUYn6MRQmI0CiAq6XQQDYJWOaj5l02fqb13o9tY/ngxvCYb7Y3l+0Bh2aoFVJ0OO0VKmP7wyyLdkRDbn29WK6fnToA e=found 167 iterations",
+ "pub=MEMwBQYDK2VxAzoAkNmJ5M6WFYUSOqNEp1Tu9LFy7F9/izmZC/JtFSisIOB2PNtliW9AO2ENFwMXYJpnNQPF5HOhiUaA priv=MEcCAQAwBQYDK2VxBDsEOeUsA5TgtBVde6Tpg/3CKo9dfyWrINHVF93NLC4GMpKU9eqXhYqtSa6ZZ3++mXBimAZbm7Yvhl9c4w== msg=A5TgtBVde6Tpg/3CKo9dfyWrINHVF93NLC4GMpKU9eqXhYqtSa6ZZ3++mXBimAZbm7Yvhl9c494IS0TYnIG7aA== sig=PXVchhnfBLc4JojnKN6fo5yH2Pyg0ngDJzV8GdVknwDvur0Z6C62EIAjeoNQ6Dutly+0wozDALaAU2iZezgHjj0g0BOzzTN4nlbA2WSzM4c7OBSnYFMNVy5xyL49vy4rUMaOUWy0X/cg+J0kRL6cWjEA e=found last=25 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAej+qXGswXOf5QrnFp4/kI3mlqjhaS2Zlqxi3wfv2cpjxYdSQGDJHbs0tecQW1yi/5IFIdtshjH+A priv=MEcCAQAwBQYDK2VxBDsEOSxQ1SgHUPTcEmYCucNF7LaGXJx8l+DDuQG5w0lQ1jYTzJXpDpKK07M12yy0Wo1G+FvvQkWNiNbGcg== msg=LFDVKAdQ9NwSZgK5w0XstoZcnHyX4MO5AbnDSVDWNhPMlekOkorTszXbLLRajUb4W+9CRY2I1sZyUaGM+Dn5TQ== sig=tQrzbgYYLCUTCrIn8X9tRGxnRYbropV3pLrtUTRaLvY+LopekFk3StcTVwwEGKdP7iw4GxvdRz2AYpFUyvUG29fADKFBMWXcuy/LFdqqIkY5iEOJxeSQC+exixOuDHP1YYZ2TnToStCIsuhk4rVY9RwA e=found last=14 s=6 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuUrcvicwlmfbSuJDohoIoAAoCvPx1h3++T1FJ5bPkUVFZIks0q8Zz85UxSSgYvmw2sFNtJ1p7TsA priv=MEcCAQAwBQYDK2VxBDsEOYAHW9VVVD6INyREQq6BM1PZZBD5eWXKeeoETFZOsYpvuDY99Mu5+6AQvxsxKMBOYz4LsZkxDgjAaw== msg=gAdb1VVUPog3JERCroEzU9lkEPl5Zcp56gRMVk6xim+4Nj30y7n7oBC/GzEowE5jPguxmTEOCMBrG+BpXKxK1A== sig=uTHtoDPcUL66t/pMfYUvLQQYeJLBxz6r7YDCrIrMueZe1pf8rfXgBWKaRZ5Piwpvqnm5B7QbfKwAY1Aw/cUSfSGd7adxKjb1bFQQvWMDgeLtQZ8R/jge5QNVqhq/4WSMtWhlzimqrDLaqLTURy5cewkA e=found 175 iterations",
+ "pub=MEMwBQYDK2VxAzoAE3SDj8n/9eGpGhsG63JefwYgkmWIjDCsuFsTMNJLu7moe7XJ/i66Yoy9jCbzwM1gOD+x2tMzctWA priv=MEcCAQAwBQYDK2VxBDsEOdFnWx6UEr8QB5k/APzq++W38An3q8UDomPZcliwfdpbEHtl1FTPoiDiYV5ASuM5rCx3jDa1oODBwQ== msg=Z1selBK/EAeZPwD86vvlt/AJ96vFA6Jj2XJYsH3aWxB7ZdRUz6Ig4mFeQErjOawsd4w2taDgwcEdOPKHwXVjgw== sig=LIboKrfk5E2Ui7/8fhNIDLOO5O9STomnfCOq42rVNCN3vpLyLxtW2N3Lya785x2nM0dfltm1shoAh80UsOvysObv+pysXJNASk1NwUzuP8JNMxGIJWNWwjl8tWNvptnt3YkrSsLAGiBgD0e1augYyQcA e=found 160 iterations",
+ "pub=MEMwBQYDK2VxAzoAwCuFt2SjXXv6hncmv2Fn1tIXuzOugR1oNhIziWxy5MHJdKVIFvC1MUJjyOrnFtMuN53gTt/UsM6A priv=MEcCAQAwBQYDK2VxBDsEORN1sYdTXL+gKeftujU6lvFHMMlKHoCsvNe6JXVtcz9v6kATyIdiSCoiN4KBHb+zd5sSClMvV+u3rQ== msg=E3Wxh1Ncv6Ap5+26NTqW8UcwyUoegKy817oldW1zP2/qQBPIh2JIKiI3goEdv7N3mxIKUy9X67etD3o37CpXbQ== sig=4KlqshSblzPV626tERkeTe63d7rb2RONr6fvrqc1kfr3i/0wANAkSfiJBTmEGLShaLyxirk1D1EAAFW+CIuXwpeIQ4wtlageyMI2k3Q+ixn/H8fUdaQ+40Ar+LLBm4weCKVTSjeYt6MiXBxt1t+ohy8A e=found 166 iterations",
+ "pub=MEMwBQYDK2VxAzoAmCshBafbTwiLJWBGZt+tNkHOqEDNorGFlbsV3KfJGOa3dZ5kQFqxBl+cwRhpP32Vk7Mt4CjaQawA priv=MEcCAQAwBQYDK2VxBDsEOeteJ/muFZ5CqyjavAWM3P9F6amYPD/icN8ER1T6c9QkwgjeBqAd0U+oU728gMeAeCIRt2oB691Mvw== msg=Xif5rhWeQqso2rwFjNz/RempmDw/4nDfBEdU+nPUJMII3gagHdFPqFO9vIDHgHgiEbdqAevdTL/7AWv2ePo8lw== sig=bSaAeFnN4kXgEItepIn8oAucoM0+6M4ZVsVGo1YQhI9zZ/M/ROYDWxFG1goPdmUzGd63NV4k/loA5nwE+TBxdSem7iEx5uWtUdyUS21fjHArKrCoawdOgtqobK+vAENHfyXbn4kPuyzWN3OTZJ3t/RkA e=found last=14 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAnxl6WGboVKPC1iKJGZYrlapl44qzEe/d3NFmv9MpLFcoHkWFPfaJQB2LQE6J7ucjv4xtL+gmVQaA priv=MEcCAQAwBQYDK2VxBDsEOTf6x9+30J49aVZYrUe3J6FjEn+p0PPlps31bys1EHdvgqxlNApDJ/VpCHMXhHCg1lEWe2BoH3zLew== msg=N/rH37fQnj1pVlitR7cnoWMSf6nQ8+WmzfVvKzUQd2+CrGU0CkMn9WkIcxeEcKDWURZ7YGgffMt7G7c8CKGHBQ== sig=6o5kzQrENynD0JkvNzP50P5Ttb0WH/YCkZWTWAJ+CYBcrHFiEhuob0z5QAi62yiaikGJw80JHakAKowEIpulvR7N5VCe9acZlzmnxcLXRYypmQYzYZprguXQYc5h/Yq/Qyaa707tWv1fQo1vFb7e3wwA e=found last=15 s=7 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfQr01pZtFLvyIJsh9LRFkJMOf6IOIEXxgoPWbyV0IN5N6R8TXvfbI/4wABbfYQzG2wgnJH7yp5YA priv=MEcCAQAwBQYDK2VxBDsEOSttnRhpeKXmU0aj16xGZD0UrE7MclYiHHisEbqsk4OT2hY2ALUelBeNF1+CUHf6GG1Gnln98211lA== msg=nRhpeKXmU0aj16xGZD0UrE7MclYiHHisEbqsk4OT2hY2ALUelBeNF1+CUHf6GG1Gnln98211lAM0D7oO9wH1iw== sig=6iau96XTQT8GMUqwmSFwqSBqOYSzcMvXuWpRi+IxwwFeczJ8U22Pt2CKy+650lpEppNwlVQtt8YAdtQAHE39ggULdhIfDCGpENGL1MhXgZtVUhYB1OSBPR/afEoIyMi16obFOWabrDPxD2Dp+dvc7iAA e=found last=26 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGrOoi0uqAyLqHphNJMQ0CWb6/ZCF1dsh6o9qUtqSxNKWqDMfi+7PIxm6Lu/Hep9kmLB6RRzZdXsA priv=MEcCAQAwBQYDK2VxBDsEORakEHxqOsEx5iI5shEfizo4x7WwbrJpDFZyYiTTTNtNrM36E2zsatsE3qmOnY0qQ73ANKURU2CUIQ== msg=ajrBMeYiObIRH4s6OMe1sG6yaQxWcmIk00zbTazN+hNs7GrbBN6pjp2NKkO9wDSlEVNglCH+ZYVzt3JpHjdnPQ== sig=Z7EdInC8kcuFNs1/h27Ek9etepiIw8I/aGqtkOSOIppshHm6q24zRQ9Rl5YR8p9zbPqkPzQPYEUAUhV7JP64idGNFMl01yJLHFgCSv/fAvJa1crGFZ+OswR1sHsj7kf/B7HRndf38Pzn7DEaeeNaPQkA e=found 180 iterations",
+ "pub=MEMwBQYDK2VxAzoAv3lNC5EvzK3ehOz3a9p4jmBkQDLR9apAV43mzDe1jMnA5UDMd+Jd2Y9BLaCa1PsGE5iglSrkEESA priv=MEcCAQAwBQYDK2VxBDsEOWx02ciQzwB2XlyaJDHdJbAHjpcreLwP2uuR4R4uqKt5dcxXarSK5U/+5USggfR/Eb0hzGJgXyYirw== msg=dNnIkM8Adl5cmiQx3SWwB46XK3i8D9rrkeEeLqireXXMV2q0iuVP/uVEoIH0fxG9IcxiYF8mIq+RMU31JRV1Dw== sig=z0DH58c4xFUcnYJBco0BE82Q+aF6GXUZtjzaM1AAlkHXjhUdjiwQeeCM8Tth08fTkdp6Nhzi06gAreChn5KCQ27/w7wQ2QrgjzBhFlwO8HzBfmX9lbzTDkfGsnulR2Id1OpJYetENCZaiU5GhUFS9BMA e=found 155 iterations",
+ "pub=MEMwBQYDK2VxAzoAtwm2OwcySbeg2QWv76dSn/lrfUxFvvl081NE00LgJBv6ICnQ9ZvuycI6kyMoN4gNcoTO9MORv7KA priv=MEcCAQAwBQYDK2VxBDsEObLQj9hzyxiWYE1U4Oorw69J5Iboqdv4XyibHCFbvZVusfYIoxGaYhsNiDfevv6VOkjViBnJXNmmUw== msg=stCP2HPLGJZgTVTg6ivDr0nkhuip2/hfKJscIVu9lW6x9gijEZpiGw2IN96+/pU6SNWIGclc2aZT+UMsQOXmOQ== sig=Qn749bT6QPlZXXGgw2Wway8m9+rtH95tqEGbFh9ihSAXkoeDvbjJMm7/ENdNZ7bcgHVfxAN37GYAaFRqt7RRlBFGIO8i4bjzQ+l0GrQTxbW1Rfe0VoZEVhICBSvLOWd7h1IK9Gwv/z6Ac92WfLCPhDcA e=found last=27 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALzfeU2Or1KH6U/BlJJFiSK8HdDjQ/JN5Yf3iZRF1gl+K+jTi+kJKdajnJ4KAHmiWVTSbxtE9CHMA priv=MEcCAQAwBQYDK2VxBDsEOSyN4ZYwhKDTlXcsXhnxFCMatSeRxC//Wf9HZniEYujEVm/kpqp0g0OhUHESlqLfgZhUecUWY6/QfQ== msg=jeGWMISg05V3LF4Z8RQjGrUnkcQv/1n/R2Z4hGLoxFZv5KaqdINDoVBxEpai34GYVHnFFmOv0H2aXFkuETCEhA== sig=dTr7EYnVl/jXYzNx/15R8r22I0QVkh9xy8fVKorfdHbr3lY1AoN0qU1hJHQD1IzwDgQAqmEvwqIAKPxB7GB+zv+N/grEPdjk3FsTD6mcppz71E7UvcUebtHMWPlnMvPIr5zgu25KDR5Gi/IqwCFTUD0A e=found 174 iterations",
+ "pub=MEMwBQYDK2VxAzoA7iT7mv1jX9t1mkYRa8t+6AeHIkSw/fisjtWWNRhwCf4MnivrqqNCi901QLQ0af0o4oCdpRKxTrQA priv=MEcCAQAwBQYDK2VxBDsEOfvLgQP927GG2h9OdT4QcgZr/TXAXhwvbD80yBUtOn5RMmO318rI67XICLBxFgLiTIoBuC0PJUjx4g== msg=+8uBA/3bsYbaH051PhByBmv9NcBeHC9sPzTIFS06flEyY7fXysjrtcgIsHEWAuJMigG4LQ8lSPHidUhuicdc7A== sig=5ZIZ7k1GQzpvIkIvzZJQjEOwb14pynekn+OgvF7TrLL2hbItoitQqryj5fl1qUkVPY0BzPRqv++AG2p+YgEGQX6i88u3X5wDatpKaqBsKmBEnElx1+s9Zyhwo9jbH02U7ayQK5RQrw2lyI+gG8qcyzMA e=found 179 iterations",
+ "pub=MEMwBQYDK2VxAzoAEXV2fLCP2slwN4Qu3WHwXqZrezhtDDU72XZ42mGnpvjeZRDtNZ6g1j0yPDpv4SM5VospHbmekCMA priv=MEcCAQAwBQYDK2VxBDsEOZTcNMUnSBVxyYEGinJX61i5boQHk0wo/JSyNVMF5Rwv26nPLGvLPqnCtdOBj9OIvnGHQuvtxuwHtQ== msg=NMUnSBVxyYEGinJX61i5boQHk0wo/JSyNVMF5Rwv26nPLGvLPqnCtdOBj9OIvnGHQuvtxuwHtWn6nziwQZVEUA== sig=4aL5bfUZsC97ga3f+7PCdC0Yz6a8Pe88yMZLydQzRz7XD/PLCQz/eI3Xt9nNcpIhn/jPqyi3fzoASrOqGm6ut2Wv9Ao9oBN1awseUjGv6LMLKbUpnYQyGsnLgY3RgVm6eIPRsa6iytLbFmNW0h50vRIA e=found 164 iterations",
+ "pub=MEMwBQYDK2VxAzoAsyfywVG/NslFPSLEZ/yCJzysWId/8j2HG4WC39Z6bcWsursSoeGbr4ZJIuIXEGCRGOg3a1dJ1uuA priv=MEcCAQAwBQYDK2VxBDsEOUXU1ejjdyJtjmlvNnF7Bb5HEC24FmTihiVoldLCClsoX8hLOGhRnrtJ5XBt0Jk9hFmLkk312MGgAA== msg=RdTV6ON3Im2OaW82cXsFvkcQLbgWZOKGJWiV0sIKWyhfyEs4aFGeu0nlcG3QmT2EWYuSTfXYwaAApFgtv1DR+w== sig=8KETHKUWau/X6akJZUTAtk7zkBnmpNyKyJsDSYEsYMIlSamL4wTx2rRLqR7Yqac1zGlwuxGY1gWAZVFLMy4nU6R7KhoZ4V2xmnIE6cLA/bwHKMBALiV/iBaRWS3B64fTjGUJ1iWgJHfRGB1jr3RL0gUA e=found 151 iterations",
+ "pub=MEMwBQYDK2VxAzoAyWd3gttciIDxHu658WkAcF4Ey7rpfg8D9YDRjvklehUiYYc9P4poQTdQDhnZEiqlTKMsQYuk+0GA priv=MEcCAQAwBQYDK2VxBDsEOfoSTHe8gSNi1Y4InbLjQKZiycNyYVKk5S6r/QeJolo/tdx8Jt6gaI4MtzoiwIufE0v9J8RwjwwJEg== msg=+hJMd7yBI2LVjgidsuNApmLJw3JhUqTlLqv9B4miWj+13Hwm3qBojgy3OiLAi58TS/0nxHCPDAkSFosawhklpg== sig=4aRoUJOkYws91WsTIixKGOsOb2HkYMMNqhNwagQcWrghia03quNymx04X/RyxcdrcbkYO9qwVEQADheQgnU/0B1zg9UO2NvIb/HdiyUkO5piJ0dugFfmWTN8+/PHRvFRieOlF5rHve3j368K6MYmFzgA e=found 189 iterations",
+ "pub=MEMwBQYDK2VxAzoAEcpmnZORdNdYJ6DHFDKQMnpgEZROZLRyvKogavyBL5nDKFZ9Jn2Zln2YFgNJmE+KO79rnHeVlc8A priv=MEcCAQAwBQYDK2VxBDsEOcdJ9IIvqRm7qZxl1IXwMwnHmP/ZIFRfL/LoXGmLSRzQsrVl5wZ+WST3z9XM2GgcFZvXqzahLxQWuA== msg=9IIvqRm7qZxl1IXwMwnHmP/ZIFRfL/LoXGmLSRzQsrVl5wZ+WST3z9XM2GgcFZvXqzahLxQWuEEOBAFTLhLIPw== sig=wye2wdE4UthH3Dj/0dwK8H+Ztn6bobQLXap96P8VrdhgXISmpuTKumBRFLOaQ4HXYiZfmBgfH7OAzXUg5/Hx+i7Re2Lyp59CN5YSP/Dz3pSjB3ISn7GCqdn40FmuFDMLuhMh3lt5FWZfwvhm+TB3XQAA e=found 188 iterations",
+ "pub=MEMwBQYDK2VxAzoAYYpGQL4r9BRcHvKXVuU7kcL/KqNY0qRTYFg+2c7eHLJQMg1xWvK1Y6VEegIEQ1ifha1VxrJv3fgA priv=MEcCAQAwBQYDK2VxBDsEOf7qsgBOuAnksngqr3sl60ktIfWz+4zNTQGDatoX5c/kn11Z/hwAnXCW/Dl32uFAIN9BK1KADm/Qmw== msg=6rIATrgJ5LJ4Kq97JetJLSH1s/uMzU0Bg2raF+XP5J9dWf4cAJ1wlvw5d9rhQCDfQStSgA5v0JtfVxYktZVeiA== sig=A5CwwU1pxAtM4zRYrOHUMRtYJRFEJZHu1iYbN21cEiQtKcNkZ2QLdA+2F4PbJn69ts3VjOxzJoCAvXt+Da7N6hGC+WzUJwQg4EtaPkoVRm8WLwxSkUYvS8tSse8GTdJ+dxIdmjTJTle2ggzNaINlYA4A e=found last=16 s=8 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAxOP/xq6ECuUxQLWv1IWz5mzZmhwqwEc0IRUoy83bE3P4CHixW1jKx0IzaeDn6J5j4EcYtLfRvwMA priv=MEcCAQAwBQYDK2VxBDsEOSmfCfjq5h57eJPIOagJlrKpC1d3SKnmQ/iwBJjR8hBE4d2j6FgmadfNlbHKHmobe1fRUwbPlb1lxA== msg=KZ8J+OrmHnt4k8g5qAmWsqkLV3dIqeZD+LAEmNHyEETh3aPoWCZp182Vscoeaht7V9FTBs+VvWXEoaPCnGjOPw== sig=PqCGae2YyUCexlvFU8eAKTsuTNEkzObbm4G6XyGOJqEd3p0i13HR8Brn3wtB7pqmDDqfgizlSg2ArUMgPxLOE+FjnTK+PA06E1rvdE0cEPkkhYIhYAK/aTgNsNBhGDVagfG7v7n5TnUThPfBwzwOxAYA e=found last=23 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1CUfENN4Pvj1YEQWw1rb7E1bDZfNtbjHj/LnOr4M4Ge5qG2ggipgsOCSyRUOnpV2/H+jk+OuQi0A priv=MEcCAQAwBQYDK2VxBDsEOX4BNQVSSY/lsCSxzGCbHntpbu+m33fD+mXX2vpI/kZgNDe1XnF9dnQXILdkzQkZ3uUcRtraLmrE+g== msg=fgE1BVJJj+WwJLHMYJsee2lu76bfd8P6Zdfa+kj+RmA0N7VecX12dBcgt2TNCRne5RxG2touasT6n4LkmAvfig== sig=RrPymQJl7BsFYSWNYqDBAj3wcoe6UPjf8hdaFcIWPtX3nnvLor4knd7uGospurcUX+9pTY7DIQsAsg7S5Wkbp+srYNZZqtJOR7Mkw5ph+s/W1ziVTGI/fUxFoA0fi8z22tryhQ8kujrpQZsoBhBqQAIA e=found 173 iterations",
+ "pub=MEMwBQYDK2VxAzoApAjGMqYmylIijKT9aV1W7ef4SiY96Xja0ng9V+fPslD3xVu68AyJOCnLxhRkGXOMrTG5IxNCTF8A priv=MEcCAQAwBQYDK2VxBDsEOcCzOJ9T+hJbcS0/W1WkcMO2KtuJhJsSfvQSrmvS8AnjFKYA9oGTf+h1c+XQrpyRbTp6HztAVGtTUg== msg=OJ9T+hJbcS0/W1WkcMO2KtuJhJsSfvQSrmvS8AnjFKYA9oGTf+h1c+XQrpyRbTp6HztAVGtTUje0krjZJ5Bl4Q== sig=038Bc6djRenY04WttiLj01HZNLO+/0529jR3t9iDOi8GrYEIQiKHIFRA3hK/surGOerjqq+W3+qAl9DdD3yLroftzkcyy6TPvTSZatBe2HZOqy3S0QqcqytvwGRVtLb0g5/ZJp2VHZFNoB/8L69zZhgA e=found last=26 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAh5eRkRFrmpatlv79IyRo2Ew0deQZDTH8CDNNpmXA3BdjRQJsiZIVYdi6cqf7APDXq82gKY5Eiy4A priv=MEcCAQAwBQYDK2VxBDsEORSGE66s/36FRHQkHmERrc1OoRXnhmM+Gryf9gJXeBO+FL6RmYEb1PQktyF4lOqxJpLY0iGQasRDRw== msg=rqz/foVEdCQeYRGtzU6hFeeGYz4avJ/2Ald4E74UvpGZgRvU9CS3IXiU6rEmktjSIZBqxENHtTtmlMsnsnWyGQ== sig=ztnU34iuhMdqRXJX9oaNwTwt39R6lgfRvHDNzxmmODdQtIR0Vwx6DcYjMQOpJBC2j+wzLUS1KBSARU3B6QICB64Fjz2uejTMWRw10uHG9LJ3czFWKS7AlEIdTDNN+5lISfW0J2xomALDjiAqrYsp7zMA e=found 177 iterations",
+ "pub=MEMwBQYDK2VxAzoAx4Qudcx0VUHOjIuLCn/Q0HCVrcxk2l/jI+d+KDgVwZE+vETW/9UzlcfpueClC/u7UmZ8db4F7+IA priv=MEcCAQAwBQYDK2VxBDsEOceDjWxNHMbgWsOUj06dENIibBZLnQ+ntELVLOplOjgKMTEJKf1548pqa0Na2YZd9ln5rVP2tgPGXQ== msg=bE0cxuBaw5SPTp0Q0iJsFkudD6e0QtUs6mU6OAoxMQkp/XnjymprQ1rZhl32WfmtU/a2A8Zdtj2hnK5rOStfrA== sig=8yAzFKopFewB9gWiXQ6Rnbw5+bvQ5N/R8Z14FMXEKos9Rf9D4R3xKmeHCOWEusB1JS3wamEhOHkAgN7Gn1+ZnVUEuDtym6OvsXe3m2Vw/zjsoWUL9eGTiYiP5ZydISK4idEBoV0HiLkEMihwA/P+gQwA e=found last=24 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAYP5mZnwYMPy+odZB7N25vj+ds9Pd/IS/9D2/9nDGpEfBEst3eeipdZlxqybGT+MDJPykV0kkzG4A priv=MEcCAQAwBQYDK2VxBDsEOeYctGz0U1ecBkAUzdg+kveN1esd1/tFowefeMKW3G06JjrU5EtjsYCQqXITVk8djIH543tNWj/WLQ== msg=tGz0U1ecBkAUzdg+kveN1esd1/tFowefeMKW3G06JjrU5EtjsYCQqXITVk8djIH543tNWj/WLbuG/ON5Eob7pw== sig=bLzTrLvYl8Sa3I1GBcLGkLMJkMET3ik+/yDRjeKKTOJEVT1UzsCV/HoBrUH9Wq+abz/yJZjHHNcAxrpAuVOYUe9S3FsAZSPdYVtSNVKS+7rjMZmQHoa4GersnALFAgCLY+w+QQXiTRyiT4zNoSIrnBEA e=found last=25 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAaWpfREeaKpRR3n+0Y1wSt1vMt3RKZkZJ+U+FnY8RBV3laaMQHsxjWr+zjX10TeRkPKyW8rpCsG0A priv=MEcCAQAwBQYDK2VxBDsEObeQop5JXx7SoeZYym6XE2wYNaeE97BwAVqmZhy9JdZeRzjpEL7s21SiLcL7cPimibt0tOhpSKxmGQ== msg=nklfHtKh5ljKbpcTbBg1p4T3sHABWqZmHL0l1l5HOOkQvuzbVKItwvtw+KaJu3S06GlIrGYZbHgruZveyUBJpg== sig=4QjGKh4zu82ZcxRX7vy+MssFWi2yHsl9LzYG/IktsG2QcMbuf7xa7LPmrFNgRMkk/yaHfldcHagAlTd0Zcw5bkbcO2JblMXi4lH7V0Pt2Kz9ERS89ZDkqNPFK0iwzqH/OyAaooOOQMhgUgq+vhWibSUA e=found last=17 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwJTARBZ0b/VlyTEWCrsyV0MUZmi+GoSQNsqk+EAzKoIMtpA+YwjKVzDGr1q2KpyV48woK55284mA priv=MEcCAQAwBQYDK2VxBDsEOZemHiSVUpL+ZCNk3UQ25XvnbNYtQ4QH1TFLXT4KtBrtnlVS9ya3wke5onNpQSJwkUJNPKmvaEnaRQ== msg=UpL+ZCNk3UQ25XvnbNYtQ4QH1TFLXT4KtBrtnlVS9ya3wke5onNpQSJwkUJNPKmvaEnaRS4PapCNifpTeRjxjQ== sig=KF/+U0FrFWt4vjb2lAF77K5gPw3NmRo0smvuXOLwhjZoVv8UASkehenJQWo+a7qHuXhR9UJau2cAHAJ/w7p5c7uCuQUwTn6sl1pNaugguByR9ABYSDBysHKg+jlirRBiLmNShRdG4J05DoPLEmdDiicA e=found last=21 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2ty/XzjT5A+FNvNyQ2qV5XHWlcSFun1b2Ni77nVqnuIq5Q+k/GzghpHI8IKE/dscjbteGqNRPPkA priv=MEcCAQAwBQYDK2VxBDsEOXl68kJptsg/JfbOs0YeyNRi28jcDi0NLHec/aKVGvzte7Iy6kJmVoGzjAZcWlaCXWBfiZcpTWhK4w== msg=8kJptsg/JfbOs0YeyNRi28jcDi0NLHec/aKVGvzte7Iy6kJmVoGzjAZcWlaCXWBfiZcpTWhK44qTyWjugfms6w== sig=Txo+dlz0GVnhpkOAInxfuP1OzCvhK6927XgoO/FkF/CHFt4f61KUt4xZnn7P65uv0ZxOHlta76MAU2ohkqejz1ktSYKgdfarSDMcYG6V1EMmLnsfB5hyXRq8wkrEzEiJgBpXd8CPzqdWz8gYqPPZhQMA e=found 184 iterations",
+ "pub=MEMwBQYDK2VxAzoAPUDP9fmkCzMyRcdVeUQykqJXiDi7zfwEuKaEjcOT0rVbEAbkaX+JsN/iEcnWwnIJdlaD6K0bH9KA priv=MEcCAQAwBQYDK2VxBDsEOc5kwkz4wAtppHMBxrJioWTNGzpKmdHdPZ0Zj3hu2RcnHC8Q7a4LihkzpaeHbXUGZjz2zPOm4uRAaw== msg=TPjAC2mkcwHGsmKhZM0bOkqZ0d09nRmPeG7ZFyccLxDtrguKGTOlp4dtdQZmPPbM86bi5EBrnX/L0HMuS/zqPQ== sig=GSZMHbgu2TKdZHzVt6XMgHSCAJF7qoIwdh1MC3kDgD3dOoDHt7tn9RPb7YxW3eJK3tY4MEz1/miAXtT0sWIhyXzKk96iYnJ2h0hjoMMTPO8h09eriNar652Z/bXcW6B1CQL9U8DuLDQzeRRDyDdQaCEA e=found 181 iterations",
+ "pub=MEMwBQYDK2VxAzoAPRst9mM/FBrBLHKr7Ht79yIIIpdoC+cRgKD895/hmJC8C2OaswUs53XCPERZnPxVa8T1uGbNOkQA priv=MEcCAQAwBQYDK2VxBDsEOYUJSoF5ueDbgeDe8DoNBFuc071CMd4KDgxQobuwXBNVcm6Pg0ZdGHhWgRl724A1IpKbVotjEt3fCQ== msg=gXm54NuB4N7wOg0EW5zTvUIx3goODFChu7BcE1Vybo+DRl0YeFaBGXvbgDUikptWi2MS3d8JWfpwyfqnn1/tUQ== sig=JMS1Xz5NdfoxJzfdrRJ1v9QURib9OX4jMneTWAwBmAQbsP3b6h9F/r3noXD6Bdu3CxcujoZ0LR6AWVrT4Rc1ew7sFfGp8xEcJi6UOAF21ZmyeHtX9OKInDdeZXMRFX+ZhlgY6QnoBQXG8Q+P8cTgKxsA e=found 183 iterations",
+ "pub=MEMwBQYDK2VxAzoA6ef6NpgXV1wdsxje5eEnLqhBMxot8kRjUO6tvyabx0JVmB1pC3Yk/8ydvfBwllY82hzzsyPyDFoA priv=MEcCAQAwBQYDK2VxBDsEOUhWTQ3r4ElKxYrserD5+HAo4G5rybqcTOti930SZEkRko+oDcxUy+3xJSDMy76mwU+8J9DZ4sejlg== msg=DevgSUrFiux6sPn4cCjgbmvJupxM62L3fRJkSRGSj6gNzFTL7fElIMzLvqbBT7wn0Nnix6OWzLORHmxUF/ADJw== sig=GjNALmmhG1mY+kCKlrICC0Sc02/3KjWPECVXt9ir3TtleGRNzhvSq8DnEOmvbbKwCLmb+w7r2fyAz3YiKnWWUgh3mZFsmlE7X3je9aN9JgI+Dsq057KRL0bS6ompXA6rvXmA2ph3eIcdWwpI7KA6ixgA e=found last=20 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdjLaxgh/RUD532V5oajhmS3mAb4MHW3CJgVut6FMwlUR5uVaVUE/WDL31a4t+me9LzHYuu6a5ZMA priv=MEcCAQAwBQYDK2VxBDsEOfto9QweOzTn3WqMjn5d96hEt0Bx3cIkvjwWCHrapBwD6cZNMHZohwVLc4AEhjJ+BCad6aH2Z5LYjQ== msg=NOfdaoyOfl33qES3QHHdwiS+PBYIetqkHAPpxk0wdmiHBUtzgASGMn4EJp3pofZnktiNK/pGNID83tgF+4M69g== sig=KCAXzLyX05RuxVaoYV2Tafey4SgOwDFc1h0zmdEZIwwl64sq/cgTjDs6/6jiQvh96VPWTWWrUzyAX2Ho6XEbvFsP4vBihIuVJVyvsgCP+OWamDXgwLLuGtkIZGNCVB22wFKz4+V1O7uWnWBVP+fjtjIA e=found last=22 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmaYySPdRp9Flj5IlbFLN2gvgZg6cQFolfmU7Xs/5ljnFy2ARkNeYKOmZfQxv57MP9Ui0pZWPgv6A priv=MEcCAQAwBQYDK2VxBDsEOdsV2pshtvTgewyyp7QdYys07Vp0pO7Oei3U0YGSDCJ6s+rIcbEmur3CndVBBdLsIL15L79kgssQPA== msg=DLKntB1jKzTtWnSk7s56LdTRgZIMInqz6shxsSa6vcKd1UEF0uwgvXkvv2SCyxA8nUY8h4xqntRnE7l6Kt98CA== sig=jOmfIi4CjQkHqN35bRUBGXK+7uRNgqkbcWmjZ3upiqb2qLMWwT6TSEDDJxKeeI6sDvR1V6D9TPqARe7OG5jOO8NSu+Dbsjgm0EGq90In2EAY4UfWQEOj0jr4xwNZtEo7ceBnszBi8o5pEra0nY8rWxwA e=found last=14 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAU2014hYGcLd08hltcD/F6nfKKeAS9CUy+XqIcsoAj0lY7WQimmWI+94LMc8f/1ZGi1ccrwyzp7iA priv=MEcCAQAwBQYDK2VxBDsEOXrw/G0pHL/n5uYcWeen7amjSFVM5p+UKZLPiL7a0USJyjLcVuAR+NSEhe3WR1fvy6IGURW7wQbr8A== msg=5uYcWeen7amjSFVM5p+UKZLPiL7a0USJyjLcVuAR+NSEhe3WR1fvy6IGURW7wQbr8MzYn/AgsaTorWc8hMjZ1Q== sig=F2F9wNfmfNk/w1Kv/Eq7BH0qfxKbGpTOzrF/Iq/GYS2IGyLzXeiQC4BnNZ12Jl4PwWSngH22e84AGrzgMXbWTL7dY8IbV/leACXYU1a0huJHI8m4Yo+kVfLCMkIjioigDQ3TNGpXwMtk+A9Dq8roEgIA e=found last=24 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAiYj6jMUS3DWq0PIxeRMLPAt3OM0qKepsW58VdK/nsjuOLPH01RXfpaq6AtsdbZJU2Ox7uULXLegA priv=MEcCAQAwBQYDK2VxBDsEOUMZMesPdsoAi78kOWFTFXsv9iw7N9J0LI/wvMtQUjuAiU0bY6gRhMhW2jAnNDNjj4PUfA0t5Xyv9w== msg=OWFTFXsv9iw7N9J0LI/wvMtQUjuAiU0bY6gRhMhW2jAnNDNjj4PUfA0t5Xyv9wi6/E7jkq2UFgpHg2Uz8Qyd8g== sig=J8J5N2UQ6AV3iyXXN/n2tSi/PcLc0p7qXsXimaR6usQkBA+wZuVIQ0vgeFgZz0DZ8qIozLb1/70AFczaayiqxHg+o29pA5n9mWGqJoWr02RFoOEZtfwJdbgWtJagkFHrf6ARGNB9QBF3p6e7hEUTcQ0A e=found 186 iterations",
+ "pub=MEMwBQYDK2VxAzoACLmVzOIfifPw41Ni584yp5iiH2IU7O48234t6BVXoRKIOBGAIGrEZqk2qPE7d4OBn5ZtPtMVE64A priv=MEcCAQAwBQYDK2VxBDsEORme+x8Qk8Fgvht4apol429Ua2nMZnSjvogxRc1pQOuHRHC40l07xA+KcMWWyoPMPTbNY1EtMoRRIg== msg=GZ77HxCTwWC+G3hqmiXjb1RracxmdKO+iDFFzWlA64dEcLjSXTvED4pwxZbKg8w9Ns1jUS0yhFEiY2QcMlKpNA== sig=3wDj9glQGTM7YbTGh2uHPVEvCT+b1H/5C0ikybp3vJFoNyFuVEgPLWTD22T9o0FhBc/J4De4+dsAnuwCDf4FfsjqYZLmmBhcDfJUp4B/KGr9dg8GTdM3bhgmPTMP3ghtOQ9woQ5UiTVI//EldQDbJxAA e=found last=26 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAcj2qpMWNA5AuvuPahpq7Coe2ChPv1Xa7Xli0zUbbtF2+BwN5JVLrBmRMiQACziXdng0sZjbEHhqA priv=MEcCAQAwBQYDK2VxBDsEOYwXk8AMuVH1vpnLL3MsZarWHVWLIMDVfR+YSgbqBvr0CHA3fjj94n3Y865/OEgaXp8M4BX5Vyd7YQ== msg=F5PADLlR9b6Zyy9zLGWq1h1ViyDA1X0fmEoG6gb69AhwN344/eJ92POufzhIGl6fDOAV+Vcne2EH2kZqkpZXVQ== sig=mZzyajoZIFXnhnbJNCchPgJaSndvC9JQamc+bxfuxOiGzdXFp+cplO1hP4ZYsxn7qRakVICvNUiAkyNkZj/1jNkJ+TYimmTfd6A+3NqKsWg9XWeAmK9vtOejRHq29QlLZ9tg0pI/0bcrQzt+li06ujwA e=found 159 iterations",
+ "pub=MEMwBQYDK2VxAzoAjVdvNvceT65JMwfJtDD+EZOYDZ3mVY+vJFTqwQ8dnKXtPw+kolDayaTmcnKZCbkudVdWAgJVX2iA priv=MEcCAQAwBQYDK2VxBDsEORrv5FnPB6bYdee/NSjFOj/pHTRkDQW/jsEC5fQp+2R0k2XNxg7VIgo/5uOfjB2Y0nVdzOXdZ87U5g== msg=5FnPB6bYdee/NSjFOj/pHTRkDQW/jsEC5fQp+2R0k2XNxg7VIgo/5uOfjB2Y0nVdzOXdZ87U5sxpuvC0wc+Mnw== sig=NaSpZfcm/ggpAYsBaDCnSREo6RTjQFg8AN9Sf4l5/VZu3sdXR3184Gg3LnKcvfTw+p5KgWZhdvGAzD4nVo0nHDSql29CfV1bDrLkCe062a6RsqOjw5uRqVQo/a+ethfY9dQaeXd44Zh+KTc/OPr1fgcA e=found last=22 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATBNgIOzv8LXD4kUIbrU/kOwQhsdijx42md/8omayeC3JHz/cwzznqRPZUQs+uKNX6n74hUa5pT+A priv=MEcCAQAwBQYDK2VxBDsEOZ+Fa1tHktdsr6H44bN2Dvna34JFVkP7b7ToXec0Kj54+mWEwRd/dNlEIFCaNlizwmxeAw/a2p2paA== msg=a1tHktdsr6H44bN2Dvna34JFVkP7b7ToXec0Kj54+mWEwRd/dNlEIFCaNlizwmxeAw/a2p2paEVWGrsXeGzaog== sig=chHBKUDd+PZJKvqaiNLy8kDsHX0kCPPcBf+Y6rG1Be0WcPcgndPq83hKmPl14sh8rn8e1QG8/IeAc67I8pduv9ht2hvmAceANusKhD2wA4M53EljlZsSzYWsNdQDwfHoXtP31Sm2Z1cOKpDV6zhAPzMA e=found last=14 s=8 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbvDt4MTpNI8t15jFrTN6Q5nsLi60k1e5WQ6Rfd22Eob2QFXAT40cAxgsGIVrxhk/WBSlgC30rzSA priv=MEcCAQAwBQYDK2VxBDsEOeujlHOi1ISgQFMAqh1VsF69fGQ2lKnFLohn0t1rpUv8rSvG3Rc5wJqaTRwmVpOIVdbcl+nJKKmyGQ== msg=c6LUhKBAUwCqHVWwXr18ZDaUqcUuiGfS3WulS/ytK8bdFznAmppNHCZWk4hV1tyX6ckoqbIZvSsWIbxVjGsOAg== sig=atgLezVmwDnyg04fpSRK/L4Nt6OTTIvdZR7Na0ZRxisaVab5GwL6C0ToJyLSXpLWAee4ZHc6KYqAXIzIu9uz7GCgt1HhABneVEiqhyghJMqzVIH5L5pn4c51OqqgYNht8b15C+JjOKZklNdYcDDF9jcA e=found last=22 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqyQRPnhFsIykNK9XEf5oImW8H3fj2kezda096is4PksFRJEYp1/ZYowGSAPARB0q7z0w4aQgSPaA priv=MEcCAQAwBQYDK2VxBDsEOWRdTGhoz0UqvQJrintrnjvQOBGF2JjLM1M5qBhpc3lBQ3nR6L4dZQpZ6/s9fr0aWB6CsRvqxJuJaQ== msg=XUxoaM9FKr0Ca4p7a5470DgRhdiYyzNTOagYaXN5QUN50ei+HWUKWev7PX69GlgegrEb6sSbiWkqW6LOJSyI8Q== sig=x2VRQx1Rko6Ps5D/E2pzRp0E3cLpBynJm0TO4ya0kR8hSQ5aBozArQSwWWwmj2fG3e5nISHJeLYA43HO+3u2I9pd/CsC60hSpGEJWfilALEwgWtGZNd5HuAzS9+2cbHUSxX+74VioUs8DPb0ajDwuigA e=found last=21 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAT0AihSNd+5IzNrnbCHvBXhTUKrEnhalgV6oMX3m0m7fNngBhqR3pla2tikBck3/In2AMcMRbYrwA priv=MEcCAQAwBQYDK2VxBDsEOV4LGYbKNFNGMxaXyv+bTUEZ1EzffLEiA1tgbmPw9m22WpqljZOqRfxTHttgl6zZP7bNBWA2S2U7Wg== msg=XgsZhso0U0YzFpfK/5tNQRnUTN98sSIDW2BuY/D2bbZamqWNk6pF/FMe22CXrNk/ts0FYDZLZTtahua9cv+4tA== sig=I3re6SeLTg8sWQEjRlLWvs4P6tm2KwhJ1yiJ+wPwxgwdHuXPEfgntbdGF6tLt6pWMZ7Onto6G4SAFcnWbyODgU0SsR16ISQQ5jgJ+WTqJDz0lvOBBvWxHsztv3xtPRAUguJAKRLOXeAikUrdo4BSxjgA e=found last=19 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJVg8rlkB0hT+3pAINsJOWaivZevo1qJzZq4Rdfhu2xMAORiXZUGLbCkS/kwdg/k4bvEHh6BK41+A priv=MEcCAQAwBQYDK2VxBDsEOegdQHaPQp5NpZ/3AyJeoo5h5l7aZlKmKvB5Im2PZotRCpE0ES0o4qhIR/b1Flct+ksHw8nz3WDYNA== msg=QHaPQp5NpZ/3AyJeoo5h5l7aZlKmKvB5Im2PZotRCpE0ES0o4qhIR/b1Flct+ksHw8nz3WDYNGnz/lSKMVwlpA== sig=CidbsYTYG5wp3FbbOKyWJ7sOq1U4ZjCp6TENJC/3uCT22Rfl0UiNXiTVH3nlS6TZ7UPRnK50i28A4b0iiEY8pyqZpef56ohqLPkKaFPYSDveSRiBJ7MS252ibpmAvsQcOiB5q/36sbq59stsbBku5hoA e=found 185 iterations",
+ "pub=MEMwBQYDK2VxAzoAX+/Wik1TzNKlg7KRBRTAqF9wuxiZU28b59gp/2YBNU+D5lSBz4jFzb89Z53BSjHZwQIuX/+3zbiA priv=MEcCAQAwBQYDK2VxBDsEOS+M6iG1/5KRXgY6qAqmR2L9r8HByMZe6kOxh31TQRi/WTWLuAuK85HaVSRrP4heP0Aps+BNPkm7LA== msg=L4zqIbX/kpFeBjqoCqZHYv2vwcHIxl7qQ7GHfVNBGL9ZNYu4C4rzkdpVJGs/iF4/QCmz4E0+SbssvYMJ8wohTw== sig=pzbM8lEh8KAgL55awvgPgM4x1eJ7NfAyR6B7IiLdAqqsyKzUyhsvFu9dmKd0+W1hpjtxrpkBR7UAT3cVgltaEGDh4hguLrRIrhng5fJc3hRh+Z64Nt+qioK/DImfXT1LQ77wgHh40CTZ9I3+lynykzUA e=found last=23 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVRrSYmr6xF6+JFFcvAahCNjg++BDiG+7C16Qnm/sf0VTh+f5FuoX2EScOEYFIHb0WXXbHoeMuVOA priv=MEcCAQAwBQYDK2VxBDsEOZ/IOCppiPGG1L5nVPgLGuZuLqxC/2CYIgXiRVk5xncTHmE8GavbD6PSaYKReqIi4etpPEjExl1bhA== msg=OCppiPGG1L5nVPgLGuZuLqxC/2CYIgXiRVk5xncTHmE8GavbD6PSaYKReqIi4etpPEjExl1bhMyrG+a9c3xebg== sig=XW50eLfH80aEcfpTTlkWZ3ntG3T+xYthACKJgS4VkmKpor2RqqorUihcbcucYbHS6ixEIp7Ty7mA0hbVySDo2rbCKbB8tQljQ2Oay47fPz8/g8gR7l5RZpUHn1DPFB0WGm2Tpk1RwqecN68hMvTGmwEA e=found last=16 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVkxb//gSa8vSsjO/KmfI7lqDfE7h+EZZc02f34r4daa7kSVXYzlZyKb63SAHFYjusu+56f3xV3QA priv=MEcCAQAwBQYDK2VxBDsEOT31TsljTmD9ceIqlh2pf9yOM1jrH89EtPSMOr8ZkXqHVz0RAqmerwsVVOHipIZ+RpVwQsEHWhIcag== msg=TsljTmD9ceIqlh2pf9yOM1jrH89EtPSMOr8ZkXqHVz0RAqmerwsVVOHipIZ+RpVwQsEHWhIcajZEar9fcft1fQ== sig=VBskaJ1vXzOWiRaEI74vmcHpKN1z5CpK6rR6S4TgSCPUiT1kdsKhMTLVqtnW6iVyaJ/D6KjkP6sAQJNLEcNBHiEW5OL1uGdRn5ZRrZho4xh2qgR0jekeKV9QsacKMMgCZbx2nMonEP/jQAaRNB37RQ0A e=found 165 iterations",
+ "pub=MEMwBQYDK2VxAzoA0knIkjggTJ31NLCVM2+mHxAQEGeRN7Svc534o/tLlI0/o4zjq4tZIewEoLkrM/dqI3HAARJpXI+A priv=MEcCAQAwBQYDK2VxBDsEOTF3TZ+kBd+nmc+2vYGomm2B6qNuwkRzAB36605pXF8dTF0lIGaiz/rT4Z3QBXp5/OQzFlZ3OlRdzA== msg=Bd+nmc+2vYGomm2B6qNuwkRzAB36605pXF8dTF0lIGaiz/rT4Z3QBXp5/OQzFlZ3OlRdzLhOv0Np9VHt4/22sQ== sig=8xytufaZaEHegC2p2eOTRBb15cbYtWaCgxrAloiy1YeEoSyO6OI8GHK5pPiR+wyiq5QNKaQYhqCAIR0R42CPZ1sH6FP+5Tm87zbd+dlxkYfNPmdSunPOr2/sNEwTS/kU9VKxpHA3dpDuhk1C6jcBiSUA e=found last=16 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3oukEljMoBGtfdfmUToCpn3RaPsyfYHucoCHUADc0ZnjQz7CNj1ZcIPFS2xIrTCHFZdnRX9c54wA priv=MEcCAQAwBQYDK2VxBDsEOSlZkvq/kH8yN1ct5kyJkJhtA1mDAH8sWHzfjegabVn+sW6dZQoQZh+LuoDVoeIm9By0ADRNkro7WQ== msg=WZL6v5B/MjdXLeZMiZCYbQNZgwB/LFh8343oGm1Z/rFunWUKEGYfi7qA1aHiJvQctAA0TZK6O1nQPwzMAyswEw== sig=h85ylqFYFHGQw2uB+JO4yiDIgpUHhbDtAWKtivMhBDiuM+AJBMoOZkBJpY5yQApVQhv/VaiOIPgAEd0rTdCPJwynqaRj4w3AJ4e7FkqZUXfJXCfNi4+/HABEFhi97FHRlFdkQ6Ri54w43WAX/IURPSQA e=found last=20 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7N+7hXh6gwAts93fm66zZ1sNdpbfKWA+BO8o+FMkUC8rKhDhP4IbtXZh7VSSJvKOMLUjJl+/9yMA priv=MEcCAQAwBQYDK2VxBDsEOX6wt83i6WVFuyHvMWK3LiCHE0uZqDis5Ti3ozACD096u2gJLi2EsZIMW6cvVHdDtqjAKpz6xPLBRA== msg=frC3zeLpZUW7Ie8xYrcuIIcTS5moOKzlOLejMAIPT3q7aAkuLYSxkgxbpy9Ud0O2qMAqnPrE8sFE9TNS2x9VCw== sig=BQvQzGeL3uujnEicegduM1YnUoGP5Ba3gfPuI9ksyaYS0kP12VeViEE4EPc8467DlXpBVLZNsd+Ak2+sjh8kDRQcSSFIOBeV6SDzxHTwQx7ZOoANAR+gHEKyiMMKyO7TwyGmt8/VIea62di4l++76x4A e=found last=15 s=9 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtvpja62OGHaBotz9PWUIfLBXPO3Wga5TDrOib3qM3sXkvIzi3ncTePKp+x9Wx8P+DwcjWGb66yqA priv=MEcCAQAwBQYDK2VxBDsEOdN0+tpUJqLm8eM+4tE+mf6scF6Ylo340ZoAvCwm3nWsi7yy+jIZ0VfWVNpgCiHrpZRR8H1TLf+KVw== msg=2lQmoubx4z7i0T6Z/qxwXpiWjfjRmgC8LCbedayLvLL6MhnRV9ZU2mAKIeullFHwfVMt/4pXuUP/D/EU9/Zmpg== sig=Qnx8gBBmIU/tG6ZeBNQXkNTirVgHv8RPaXWxhJqEhTWlK5DheBLl8ZUm8lLByfXA9mFymJDwfHAAasigguAwAC5M9JshisCo/JkQclKpZNRuZSUcaQLghIBz/j4sHRmJzwUXgjkExiPwEldVT3xowjoA e=found last=19 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMa9tuXtyKhO11CFPwN4qIXkOp2if++QbDaMuGBg/iybpKdohOQsm6R1aflpD4OSQmAJs07s2LbmA priv=MEcCAQAwBQYDK2VxBDsEOe/Czi3R12zbuYJk+hwhnZvAooCqR+HMQIaqPzX+stwjalffLCCoOr9FoyJPnkwM527y368D3Z1nSw== msg=0dds27mCZPocIZ2bwKKAqkfhzECGqj81/rLcI2pX3ywgqDq/RaMiT55MDOdu8t+vA92dZ0v6LP7sx9DlqxWLUw== sig=zvLDvJ9FfC8hTIDqj/xiQJk80ABJrmJwMwfG/a/6QlT8cxQMJG+94J/1rK4qd2rrwZYKDIlC6NmANLe9nzmgw5RfnB870bbOmkU63DaxWRBluBkjAis5YIDDWPglwXgZ/FZHWCvm7gagIAfbsSqmUDQA e=found last=22 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAV3CuNH7089j3Goc+SUqgReVJCi6cLeoTZvEzIcCOUT/kA82y2EZYhIIQjpdBNjqR676AfeY5qXgA priv=MEcCAQAwBQYDK2VxBDsEOQXP2YtHT7KLcPXKbmAxgkQWnlnQ49vb/MOM4w4HTYraow1ve+Wo5YabiO84QyMVAYC92n3IRh4NzA== msg=cPXKbmAxgkQWnlnQ49vb/MOM4w4HTYraow1ve+Wo5YabiO84QyMVAYC92n3IRh4NzKv9QHjMPgzPnImn5EG6WQ== sig=zC/fMPIRBviLLFK4MEJjjjQCOgJbUwyAsHc09/sypO+f7X5FkuIcElVc4OguBSxWv/dJygxZRjQAaG9A8UDTQziXQr0X2GtWh18mysrtzeADH4skB7A0DyoDlDTA4X+vXKkEs4/1P0/JR5l0paRmGBwA e=found last=18 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPwq7kxygFEDM1mjrKvswu9Nl1wZEQ99A/FQnlWw+O1mDGo4zNuD9qlYrsamTh2sttKF4vSYhMgsA priv=MEcCAQAwBQYDK2VxBDsEOfRdfGWStclAQxcqIn3Ujrg2qB+o0okYSB15yQ1UbD+675rFKUfyMpdZa/nvjH/DMUs45mB7GbsSOw== msg=KiJ91I64NqgfqNKJGEgdeckNVGw/uu+axSlH8jKXWWv574x/wzFLOOZgexm7Ejvll1AniXSXo2JpNvGj4RafXg== sig=SPtVtF90Zg3zgJ5vEi0VwrCEbeOMOqe2zj6gkGWX3PVrp3D/mhSSNx+Yto/a2HF0a2U7MfFZkrKAmvxaBsvkXyvK+9mejfq3UicybyKwKwVgbNKK39UD7tCPuvHwib3JSws2ZniWqTfK0hGRrBQqpDAA e=found last=16 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADo+wkOqHpBQpsREimpJxFXqR/lGpqTZoiYxS/6GwkAg17+SDJssOodpv32+oX1/qkwZLGQr3oHaA priv=MEcCAQAwBQYDK2VxBDsEOYJPrLPDGAmsRqTllHkGhA+Mb5SM0Dp1CYL+czvHl07npTh+MnXwLh/QKcn0osbmyamIjmvYRbUa2g== msg=wxgJrEak5ZR5BoQPjG+UjNA6dQmC/nM7x5dO56U4fjJ18C4f0CnJ9KLG5smpiI5r2EW1Gtqf1BARICLkteEsxA== sig=V/Cc7HJFp08oBkQreZwVc2WuYPZWZ0J1DIRvxaOXPvfA5Ir6eCZV8lgPfAmdFairzveHdvsz2DCAeDXrnPnYaKEMhGEloFlitSKWyFnKbpREeEjdmZFp/QcF+gUOt/jkXbh71Bj9CkRYBSl6QfWfJzwA e=found last=21 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJz4esbb3/1izABKafbOk0Qfqyy+J/cFqvJoX+czNDekHIO+z83hf4izS0F0TAeeuf4MGZq/4OJiA priv=MEcCAQAwBQYDK2VxBDsEOQhnk1J9KF2Wyo5PIGwnZFExC8cj/qYJmCmVYxecWttCwhq6BV5bcYZhG6Rnuj6rL3tfKihccmurJQ== msg=yo5PIGwnZFExC8cj/qYJmCmVYxecWttCwhq6BV5bcYZhG6Rnuj6rL3tfKihccmurJd+rRSHHABsV8WHHukNv3Q== sig=/+QoCBHiLXWIxY7Ztwb5zAK7CzXNvDlA2eLaAMcdShbUmg6mXT8GJpMVZtOAywqMPxWyVrR5m1+ABNs/NR1fJfrYh6ManTkVpAyrfNmrKiENSYRyh4rkEEtcdQZRWC87viuNcNGIzC7DtN7WRSf2DAQA e=found last=17 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5Kg6g/HhR853pcvJpItIeXuseWGuhCrl0eZgTqidNDws495jz8WlCLsyDQdRMpSSMfgDHT3cTWSA priv=MEcCAQAwBQYDK2VxBDsEOavG23YBpQFTH53gz+CbFVpo5KiGcillXDVYYq0RwZmc37vSl/KRZM3lNEekYu2EmF2AnFm2QiE0AA== msg=Ux+d4M/gmxVaaOSohnIpZVw1WGKtEcGZnN+70pfykWTN5TRHpGLthJhdgJxZtkIhNAAHC/ASdFZIGH4HsogUrA== sig=HTPCtM00oPp2TRc1v4h6nx09ViBTM45zkid+obu3gOmaXQG/3XxRkqPDBbLJvmLHSYMoaMCyi5mAg3RP36FvVvEpXIYQkL5ygHVDEagM3b2xkJVpTgXNpYvWS+OlUQ/vUVFoVHHsLl4pclToDnvMcQ0A e=found last=17 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAAlGxO4BhYrKzPLm9HQpmOMJm8l6U9tFTyTKpJ7MD5a6j436lczgLzQFZRbchiJDzFTMM0/W6iNSA priv=MEcCAQAwBQYDK2VxBDsEOS9u0i2iTHs9F8t5MObuiS1L/wBh1oe4RrvrCwtYNMbOjhcpqxjyf4lJGpky1+0I735qIWscWWxKiw== msg=ez0Xy3kw5u6JLUv/AGHWh7hGu+sLC1g0xs6OFymrGPJ/iUkamTLX7QjvfmohaxxZbEqLVBYTvfJGdtKaUBE38g== sig=/g/la3VTh7BnmKWagIOavu9LvO1Ihv2oZnadJZlA8fX/wXaOOd0FdzzJquznvCX6jgq3qv/34EeANOlyd/f5ZaW0SZ/vjxBv9QyQ/AWc+r27i0ftLSXCxJ/zkk9JDVR0HJbxLDFXBq0W5F4LUuWaQjIA e=found last=15 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAErEqXX2n1wtNOezE/CYwRbTiXr/MSHGEWKpBCqh1onkNeBtprILd5BKMXuL5OwLvN3ARbf3iSECA priv=MEcCAQAwBQYDK2VxBDsEOYZmm+n61g/oMXU05zZ2xibZagYSM2FjpmwhQ1OKDlOi9y3lWzFjurqemYkLQDUcUFx4WhLLb9bM2A== msg=NnbGJtlqBhIzYWOmbCFDU4oOU6L3LeVbMWO6up6ZiQtANRxQXHhaEstv1szYQjAuirQQmGl0w8U9pM7lr2NjKQ== sig=cAhO+tWJzm0XB8JE3yJf1B4c7lP6KCt/Jdk8mRwg9HZY1zvuOwO8hy+8Ut7rjv5PJNjUoak7SK2AxSrWyzzgemGpWZHA0TlbOjI88Dl2X1FdL0s/K4NG+zIIwU27rFvkDBv8S4A+Z8A5iRGhpzQwIQIA e=found last=19 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEEtj0SN3LcpXhgQqeboiU4ck/xbYS8JRjmQ9F8tH5qRpHdUx9DsZDZZliuVyrqvnpOyh443VTqqA priv=MEcCAQAwBQYDK2VxBDsEOfDwCaCZdSSbXWq5GPMKwDxwLzMjdAZeq3IJv2mQXJ8NKwhKKR9WUwSUM3yNCzhpXbe0OQ/3yZn6jw== msg=dAZeq3IJv2mQXJ8NKwhKKR9WUwSUM3yNCzhpXbe0OQ/3yZn6jyyIo5qEOXufjALf0yN1Lkzgio1U4llgrrh8Ow== sig=VP1J5qLV7+Sa0rZwGgZuNJERN/nn2Y5uoni2EE1g7/WOE8z1P4YxCapweIlzm1B1jveyQA13UR+AWomrU1mCiCfBX9UNyHxSxcRf56HcxsNnCD+PY1TVXa6ac2HrQy5vWsK/3VKkZDGBpUonKvCEIAwA e=found last=20 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJ5ljqxcHCsx0+8nEpEZ6RHQZAct/eBg1rc7SIqUavZgLpoWmpRmU9lQat3vgJtI7Jvnh44GkBe+A priv=MEcCAQAwBQYDK2VxBDsEOSAwjEz1cbi0XTVcS3jOkJ4lw6Xh2CRgenSKZZhkXKPTAiRXTxhNFbdFh+RMZb+J9mA5yjKtheKkug== msg=dIplmGRco9MCJFdPGE0Vt0WH5Exlv4n2YDnKMq2F4qS6cW0XqBB4mww+GiLm/2D4bH9sUJJrQMmGbXGpLtWMbg== sig=jqnX+3rXNHfN2AawPwF6L132ubSu5hLU/SO1jJecGeaJPx9r4wn/6NTRn+kXuiQAecGSO7K7BHsA6nJDOjvfa3cptCV0k6210AOjXhj7Dis6JNGVVteZjyIKr2tk7D9QQqYxoVuIBl0NSmVW9adJIQIA e=found 195 iterations",
+ "pub=MEMwBQYDK2VxAzoAGKvaNG7NfPvtul6SsNhRXoWG7swAddXrf4p6b/EvQRNxFXgtyu4KN/kk7ev9kkDQQRP4PlKd4V2A priv=MEcCAQAwBQYDK2VxBDsEOWmOP0MOtuyKcU3F6M2P4Az42xNrDa2yd/ku8v8DEHWS/Iam3KkuK3ehGCMdowqxODYExS6HRiwCYw== msg=jj9DDrbsinFNxejNj+AM+NsTaw2tsnf5LvL/AxB1kvyGptypLit3oRgjHaMKsTg2BMUuh0YsAmOF9Hs+y8bPxw== sig=kf104gpFs7MfEvF8YAelAIWYbn3yDsISHvamUMp2RMUY9iLfnNATKWMFyBmoLui3Te746au8gvuAJ1s/DFRR0NzOdS1e7l8zvJFVIShfzptzVoiqRdtn+E7CWpds5rMkZfIpMcmqY9ywZgvMZ4dYnwwA e=found last=15 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMMelfLAlcHVNzThwXy7Y+V+GPlj9xYlFYfxDP2TUzONuspZdFAU/B2jsBUJnE+B++Q9nE6SdIKAA priv=MEcCAQAwBQYDK2VxBDsEOWjyQHTyhPiKPApw/kspHThV4lHVGT7q5HV1miDUq8d6KIsEdDU8KzbL7qahsFeAa++xZ/cfxYOgfg== msg=8kB08oT4ijwKcP5LKR04VeJR1Rk+6uR1dZog1KvHeiiLBHQ1PCs2y+6mobBXgGvvsWf3H8WDoH6O6Xa797ozRg== sig=NxF/b7curRnNjpo2EMToseX6PlpdsH/SIu4MTDVU9JxpBvXIgsKdBXxksW/fY5oEJP0tXJy9sFWAmtI9USh1Gld1Ku1siqBmjnF9Tc1PgU2OeE90cACcWCvfWcQVWFIHjTI2KeWQMp+YekkDQUONixEA e=found last=21 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAAfeKRBcyJyuvI0+hmZjcCmSpkW1xQkmPREWDQf8RAxCxHfyOzGHmNC0Jg9x/4MR66RDCzY5S4seA priv=MEcCAQAwBQYDK2VxBDsEOT6cjh5WqCBv7kkhCYuLmkA2f4xqOFp93uMd7Ub/PmLrgopkVeqE6YOo/wHsuCRnXR+m+eMJkiTa0g== msg=PpyOHlaoIG/uSSEJi4uaQDZ/jGo4Wn3e4x3tRv8+YuuCimRV6oTpg6j/Aey4JGddH6b54wmSJNrSymsQeSGOYQ== sig=FyukK7as8qyjriCOhI+PAhYAukMDumwOgMXXW6J4hFzdrQa0bSezx7WpjY9Z0setlAAgnUAEiG0AmT8okUYiF1FMRJgHHf8587oH9L+/XqKWlUxHzxlDyQMy8sfy0dyOZGtZ757c9f/C08CpVhvD1BwA e=found last=25 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALaITkHyucAnHKelBLCRu6lMbAFkozELMSmi0JBnu9v4LXIckeoLKSJE5qEg7EJnHZru06Rw1sN2A priv=MEcCAQAwBQYDK2VxBDsEOSB5/fNV6t7u37Fhdibo90k0/OKxh/Cbq6b6uF4UeNPe7fdimM998t7pvkMSIOLiJLpelxmv5jSmGg== msg=ef3zVere7t+xYXYm6PdJNPzisYfwm6um+rheFHjT3u33YpjPffLe6b5DEiDi4iS6XpcZr+Y0phqGm2+jUrNkfQ== sig=aFVvLWweTFn7z/ZWYkldFUDuDW6AEFTx3z5BcnDRE1bjDRnYaO1yokbIgCENYVSsev3nLQ8Sd0MAPlgopFduWBKvcqVl8/m9eHBk+sPwL4g2HExbtMM/E+heZHof/m3l9dNBrj+mzCviREtM+Now0DIA e=found last=16 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMhWTtjBQzA/dOrd0unbfbJ6A/4HIx0kokS9USRjRnSSNK7ptKVJrX0VtufUmTGTQrdwzRLlqbwOA priv=MEcCAQAwBQYDK2VxBDsEOZgS+PWX5c/ZRdmxoM5pvBIGMs5mKMDLNvr7MulTt8r5qi4xm1tTP5XPAWt1VYiQ0IsZ5g/qUVAf/w== msg=9Zflz9lF2bGgzmm8EgYyzmYowMs2+vsy6VO3yvmqLjGbW1M/lc8Ba3VViJDQixnmD+pRUB//c7C03EWzoZrVMg== sig=HWEf9eGQruaJNbuKMwcPZDFw8DGNvO+AkbXsObOqO2JV2KC7b4KOHwzBZkW/MfbKIEGDD6s1opYAfqZ7ej1cjT8CGApiVjoym1pbqs9TFt1CRbPH4C4YOfilZa0vXuq6+pYIp+OqzMRRRiyRdAjsNigA e=found last=20 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAzNGX1L54UhPb0lyjfDdEMLAxWjwaIGbzW6hU3MmGe4LzAUhDJg0WNIwboZHjIUGb7Dt6V4CI7jYA priv=MEcCAQAwBQYDK2VxBDsEOVhjWYxy9qcKfLWQaBBrekinamnQ5knBjX6K2ZyENp6YVTag/HGEVqX8RrA2Vm93EhIm6PIABRrbvQ== msg=WYxy9qcKfLWQaBBrekinamnQ5knBjX6K2ZyENp6YVTag/HGEVqX8RrA2Vm93EhIm6PIABRrbvbwHhbpTIWhVpQ== sig=Avh3VYEjDWB9lamkAYha8FZccTlVyTUUXZ1UKkyKxo6QEFmlHkIrntsmKlnQLNjdA6iNeyOBVgoAS0iamlSl670EH9yqS4N+mePDkAnQKP5sTTvb/zNXg3CGk/GscN3IGHsyvg2rI6fJEFc+NLrdvzQA e=found last=23 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAV9dMahwCM0fTy4NTTU3FvIh+2YjgS3ZmII1hM87HBYgufYLXR76RPWxHKa/6Jq4EI+50Rw1DJfWA priv=MEcCAQAwBQYDK2VxBDsEOej/cWQDUB5CjOLI11sRA0SDqZjro8K+5+w4pjlmFwo8MzGjchOvSaiDhXQTu/uTD4QaVJ0Edkzg2Q== msg=6P9xZANQHkKM4sjXWxEDRIOpmOujwr7n7DimOWYXCjwzMaNyE69JqIOFdBO7+5MPhBpUnQR2TODZXS4T1d7BZg== sig=E1faXEr1jeYBo7Jq7vpjWspe0+pki9OZaZpYJ1K+mkX7m8JBsETh6CB4VQ9sovx0CB5XQZdAR+EA2CAy11RQA42/JmDmPaGqo7E9lcm4aAvocgcDSxqguP+sVPWSW6dbuc6m9iM6Ig4okyASCVC1HSoA e=found last=18 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAlvP4ofDiQ/ryRWaADuwAXG908Tor7df74dgLK1Q4uLocOIqDZDjcQ6zVIbLjX83Fmhtc4Yll1pgA priv=MEcCAQAwBQYDK2VxBDsEOfJSPuP/E/evtu9mrp+izsWEcUSFpVT0mU35NiArsal2YgtvM8uznXgp/ryI1rPuUtMDC9ISqsLRRA== msg=r7bvZq6fos7FhHFEhaVU9JlN+TYgK7GpdmILbzPLs514Kf68iNaz7lLTAwvSEqrC0USvChzuOC+LieWw+wO35w== sig=A63IFVJeyZCV0A5PLrIRnzvo1e5waBLqqTIKFA4T5NfUegIFEaopAcxA7JXR2Lk1vTc+uzeuzOSAopysJart1tVMp926W01XQW1KyAMkw/3nZzI3Q2VwzzBBUkEE+Uwb+ApECV6lZt5wTB5qKI2W4xYA e=found last=14 s=10 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAiVGm69qkXi564UaRUvAQhhAN9pI62iS012nmN9hXxL8ffrprE9mOuWk5MogcCf2cH0KdwhMdO4aA priv=MEcCAQAwBQYDK2VxBDsEORQGe453aOe2u+8pHglWnM88XzxBpCSn+9mW1hDplEJQQlGwlHmaTQAqaMayCsWJuq45FvQfS+7cBA== msg=e453aOe2u+8pHglWnM88XzxBpCSn+9mW1hDplEJQQlGwlHmaTQAqaMayCsWJuq45FvQfS+7cBKjFcHx1G3lleg== sig=mB3QYIL0/Ynmz5juQK9++ofWhXl/x3vW6F00UH0kKNZNtFkGIs8oXiPLbAh4abSSRw4IKQmnbFKAt/mwcpe2UmQ+Avxjen83QhMHxgYuB5mSoSqqrfcRFvtth2KbsUz+GG81Nu2s86dUJ3nVbPKPJjoA e=found 150 iterations",
+ "pub=MEMwBQYDK2VxAzoAnoWRSFVGmLwLC9pXkVp/uCn/B5+xO7+qCdUeaUTB5fGxesZqMstYWJY2YTeKlZ+u0jbkhRiVFCIA priv=MEcCAQAwBQYDK2VxBDsEOflb5VtGIs8SjHrc3YF7lDKtkpxKGYMgSpppcOnXmDWjQM53I5MKqPqQuIcFalk0OgPA0s/lpIZUsA== msg=W0YizxKMetzdgXuUMq2SnEoZgyBKmmlw6deYNaNAzncjkwqo+pC4hwVqWTQ6A8DSz+WkhlSwJX3TSV5OMcTrVQ== sig=KeQhsm9TwSJ7nSc7ge9e7pM9n0wfigRo6mw9Oc4jNgn+vj20kePZvmcs8uNISn2YVNNo2oJiafCAXPZtDD4RKjbYWUYqTqLe/Y2dy3j5b22+UJBaZQClRNm0+kTo1cPfPJxs+dpG1zPJHyJG1yDruRgA e=found last=15 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/2NzNMf1OVMnxj8/VrOgO+TwF1LM9izAtZH4x2NRxyZu3NaiRG3ngUFrUchqQA3y5YHkLqXNKIAA priv=MEcCAQAwBQYDK2VxBDsEOZlmeO1NDoUFIqGOZOsZdvVD0MupwODZQt4/T3WtCNc9c28EO25PC8iP3gSUstLVYuBUObImPEYBnA== msg=7U0OhQUioY5k6xl29UPQy6nA4NlC3j9Pda0I1z1zbwQ7bk8LyI/eBJSy0tVi4FQ5siY8RgGcD7K5ky5Usb01cg== sig=3sNRAsvdL3QLYbNjjiHKiymT4g8NmyOJni6IvRf5Kox4AcO5gvMB1kxGJF+A5AJQmP1PH3de1foAw198jod0xh4kQQx0kGtTqSnnqVSTp9ohOwLH3+yp4+CE9gQ24zAde3Rb5gjtQzNEl3FUzfbdNgwA e=found last=23 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1twsyUlc3Sao/UX7yKpYP2G/BL2j3FIHaz93BtLBLPEFkDZ8K/u2pecXSIsIi8mT7qPUs8gBTXkA priv=MEcCAQAwBQYDK2VxBDsEOcjIHM/yO856ks6eRDsck7ZeVJBTiSSpp0Pa8djL/iNLIwlhAqbXfCmMMln5DEJERQWD9J36g+/HNg== msg=yBzP8jvOepLOnkQ7HJO2XlSQU4kkqadD2vHYy/4jSyMJYQKm13wpjDJZ+QxCREUFg/Sd+oPvxzYc5i1azK55KA== sig=fqC1o7q4l4ZudwUrLPERvgNLzxZhaDqUUgi3jz9aFkwGk/PBt4A1tWnf4CKdpWXK9pyH0ZyKnmYAMRlp+HEGcUDxJt3rGa0cy0KQ/9NvLt16LoHHML3d/hum3IP+3sceaxN/aqaJOYPwNPbaWNl27hEA e=found last=23 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2CCWInRItby/MpnXtSfIw8YO7p45IbTO7HalwqpQYV/aYMFeX2CYdOdzgKr5//bnTvr3HM0WYt0A priv=MEcCAQAwBQYDK2VxBDsEOforHWMemQMcfFnmvlv3Qv40Xciy8Sbn0fmVyL2LqqRUfuIKoc2PWc5R71riCVHrF9KUIP2Jl7oO/Q== msg=HWMemQMcfFnmvlv3Qv40Xciy8Sbn0fmVyL2LqqRUfuIKoc2PWc5R71riCVHrF9KUIP2Jl7oO/WhFerDn8aROyA== sig=yf1vSBkAdSZr0SGozJ2bSPBFU2hYiY8s0p/eh7NDi0HW5JnifZf0N/94imZrKGnnA1Dugqe0qC8AdnrPp+bdUXU4uZ8KuZh43BkYbEynJsOviVdXY3O7a1ijqKzs5/SqJmrR+e/Bl8zIvI83yb9lZRQA e=found 153 iterations",
+ "pub=MEMwBQYDK2VxAzoA9fylZZHiY7cLLUlBgbMqLUknxrSko+dARpxr4XnBBcEMMh7R8DhqXRKspo+pHnz1fRVHFnm25PWA priv=MEcCAQAwBQYDK2VxBDsEOcAN+ERRFswYsYez/CKZSeuDygkW7Bv+bVA9Vi6gGRq44FbA4L7q6ETapKy/O5eE/3Q3QatWZq2sTQ== msg=zBixh7P8IplJ64PKCRbsG/5tUD1WLqAZGrjgVsDgvuroRNqkrL87l4T/dDdBq1ZmraxN1FZvcpcaFYVMqZq8Bg== sig=/1Wlj3q7ITCtfBb/PbwE3cGC7d9qaRRXX8ujQwMIp0mdJmOSsqjkyHDyJv8AtH8dPfXHhsJZtR4AF6m9Fi4/qZp30aTWTxC09rkJkOKIysyaZm4N5q7uM6zqVlJ2r7MvHtE0UO9YRSwNnVhnSEnfrCoA e=found last=20 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbUJmsQyN1LB2wdcDGMUijF+yJFs4+UxKT/bSdZAh46f9xnmssEk/SxMVDTOTuUYZzisbkTYmvvcA priv=MEcCAQAwBQYDK2VxBDsEOTWLX86rJidaNBG9j27Ll5X56FPnFRmE4EFUvbmOuBm8inJCeM5HNgny8dPEnfkJ6sz7CtozQAQC5g== msg=J1o0Eb2PbsuXlfnoU+cVGYTgQVS9uY64GbyKckJ4zkc2CfLx08Sd+QnqzPsK2jNABALmO8C8uz6ZoEBVwesCIA== sig=ENhSMwmEID6xB3l/DfM19sng246v0M6Hua8YFWRxm8W1f5tMhl72nqClbI9dFhUSGJQsbZ3sCZeAHLQDhfX5nMGupvblVn6BrvwrgGUVqdcM3exHawy0l8YMl7+QZunzjt2SCy4J5GBrAVaS/eT18T0A e=found 154 iterations",
+ "pub=MEMwBQYDK2VxAzoADcQmw0arXiw2o9m52eFH2me+LH7LH+Cu8NOnwkG5H8eLTzWL494PtkoroqGuY16XghE3cV6EcbwA priv=MEcCAQAwBQYDK2VxBDsEOZ0zLy0P9NTBYYH8q+fG3P3YhLMfZiKaNXLbSx5uNrs5HulMB5ZzsIaq3nlhZS2IJsyTQIoCtgEhIA== msg=D/TUwWGB/Kvnxtz92ISzH2YimjVy20sebja7OR7pTAeWc7CGqt55YWUtiCbMk0CKArYBISAjZFxsEagpQGfqFg== sig=Pbpq+1gl0k3CnpGEZrckCnAMf5Jxa8xa969Wi0jQ9gb8bkZHawush+ggXYPpkXAZ+OELX1a36GgABd9PlFrLvFsxwkI3nFXinDHAic+GAae6lAQy3W/4Z9wV3eBjNr6gnejBnyrfiQRemLoXCJI49D4A e=found last=22 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASisPWJOzmpaLon0y65sDkBKt29/r9C0PZqV0K/SqO/7n3305r/7VYoIQLj0uVBhtBvjAQ0V/OgaA priv=MEcCAQAwBQYDK2VxBDsEOSZXKafaa9ttU0M5pV3BKs9uzR0qT6YxnohPBnL87eCy5hmwBUN4SAP3YxIOTmkp6j7sPpV5wBM4XQ== msg=XcEqz27NHSpPpjGeiE8Gcvzt4LLmGbAFQ3hIA/djEg5OaSnqPuw+lXnAEzhdHuOq5oI26a5HuVCGov342XsArw== sig=YjtJkDlR7aI9UBFP5gJOIFc2sqkDwQyHT4l5JxCnUGk8l26MAp569toJd4U0ArQmDVhNreKflIcAXU5FAn25tq5Qkmc1roxz1/8btrCl+dO+86bIQg1YFFrTKsM67gqkT4N0UESOgGv9MgTFQpqOfQgA e=found 142 iterations",
+ "pub=MEMwBQYDK2VxAzoASl75PWj+kClSYZYujNhcfy0fvXzpFuN4DLt3Hr59OCUWStiNim7PSEFefv+OVWTbPEAbuYRdwlQA priv=MEcCAQAwBQYDK2VxBDsEORWX8gAxodYFlx9r0ctuJC9UNhoIJrlsJL6MCytTMcLxTKK8e9psiTmv6GhHD9C1Q8JhtW8+QcZ9rg== msg=a9HLbiQvVDYaCCa5bCS+jAsrUzHC8UyivHvabIk5r+hoRw/QtUPCYbVvPkHGfa6pZM2eDU2cQb6a5r4caxX0oQ== sig=Rxmpl3HfGO2alKs25LWmzJo2rwnGYl142W3JsRLHNI3vJpw7296ZAwRuk3gJtZMJQwyvClJJUz4A+o2ddRXXG6W/YKN+eGO7GjGg9oHszf+vFYOmOcvjI+jNBg8T2ueR4Oi7/fInc9TixPHxT42PUwAA e=found 145 iterations",
+ "pub=MEMwBQYDK2VxAzoAPnEiHrUAdWxMmvM4RfGdj78oACDJnAiKf/iVtaP/bwBt5eLHARRIlnH8tPKcDwR6Zsc4ubhyoTCA priv=MEcCAQAwBQYDK2VxBDsEOclrSZhUXBSktiQe4QRvUxZuJVhT61+5k7arzF2SguBZBKFnQeytJ8swoq0vGPrl+tOPCvJPpN253g== msg=tiQe4QRvUxZuJVhT61+5k7arzF2SguBZBKFnQeytJ8swoq0vGPrl+tOPCvJPpN253oW4C7nPKDEbrDqPSSEecg== sig=NcJIAmSowCHotySIHwKeCCNYkPJEClKVoeID6vI38F5agCI58qEFyTfICMwNyQ5edavt2t0RC8iAYGzSTc1kJo2ciBAQM3K1hkdbGPh40BD3F4mkI0S08V5ItqyzxreXEJUFBsODvhS45xCJxJKGxS0A e=found last=26 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1r1M6ksDZqGgWiPC8GRW9M+vSZm+e3Bopqhj809c6EgzzvdvJ9T3XhHQ/RGrhLoN8JlPgkkr5qUA priv=MEcCAQAwBQYDK2VxBDsEOVqi24vCjWRyX2MIvZIBvUrBZ3hNB8469MqU6EoG3piPvMyzfnq92puELpcrO7LReZXYB92JWmU+lA== msg=SsFneE0Hzjr0ypToSgbemI+8zLN+er3am4Qulys7stF5ldgH3YlaZT6Uw89UsvINSnlV7W9lgZ01ONIwAUh+yQ== sig=d2JL3Aluqr/zx5PlvYL6baOq/HEwoSJT01WfkD7C6R1AzZ3cqiqNTyi7xtGEx+DJq+ZzJBdQDyaAwLnVHRbLILVE4KUMxcFs7vW2gmd0v916+9LphHrugMAY5qAhIz3XSyheEQuro4vVWBhfD/mTdAEA e=found last=15 s=9 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApvoiw0bcyv4+QcYzN4MLnajjTmvOL/9PtFbxJzgsMIHQNFK+K1nDcISsthPM2BpVf/UXdgjoNzYA priv=MEcCAQAwBQYDK2VxBDsEObJ7Pp3qXM9hVAGOtu7GDta//eAMZlnowd7x+jcsy8WK1HO9xDKaSY2BlqqwoUK07PqkR00EXCcnKA== msg=xg7Wv/3gDGZZ6MHe8fo3LMvFitRzvcQymkmNgZaqsKFCtOz6pEdNBFwnJyh5WD5qrlM+cmiidROHRu3/LWotqQ== sig=XmCrvVmNFy3K8HhOC3a97j4oIuLCVMRxBSX5+LC9y9w0hdHs+vBPOHI/tW3WI5ZQdAeePSj1Y0YAKvs2nfOn+3jOgrhZL13sMUuqidcrMNJfUX+5BXgcV6M1TeFB3SR/mhRi27bt0O35Aq/fPniTFA0A e=found last=15 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqr0tKNx0fQ3OCycnFm7F60+D2pp11N4uk4viRGfzrbJBUNHLozM6yRO9gIGUa+aa0Y1f/bwX+iGA priv=MEcCAQAwBQYDK2VxBDsEOepOpB7pTynWoWXtIlFp+y+tPHDck2LgUZ3tmRfkiCocrNoKi+2WBC9eb3hs6xNrJF2gUb+wcw4Blg== msg=L608cNyTYuBRne2ZF+SIKhys2gqL7ZYEL15veGzrE2skXaBRv7BzDgGW9xN8BQ57GCXk0MhyPbSAo0mE2u74Rw== sig=qNcqsXDVHPFoJa6DgGveMgLqPFht8XdnZIaQaEfKE86UHwhwXJpxiMHv7FUD+UpbGreWynZ9bNwAwZVgv7gSGDT7im6Zyp38b49lBFQyAKl6bKwGC+IkbQIzMY5LBUCoZXYEEsGjqiKyjXGchjlXYhkA e=found last=23 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/vT/qeDysT5F9zgDtpyWKV+hbysrPHLQt/pWS0TXIrpc9rzcWrb3qJZVaGjO7ezCbNRIOcfA46YA priv=MEcCAQAwBQYDK2VxBDsEOfASzHQHh4d6FF+7hga5ZrjCDq3cJ7NR9grk2gSeMoWWoefo75z+nzuxCHpF11izPQ8aKqfXdehhew== msg=X7uGBrlmuMIOrdwns1H2CuTaBJ4yhZah5+jvnP6fO7EIekXXWLM9Dxoqp9d16GF7t7v3eAQyQBLVIO5N6D3fFA== sig=vB40Q4EHD861eW1Pc1boZPT+dqhPEbeFhfuu4D9z9UdkzqkI9vZzQ+Y/0tbSWIDzuXo1WQYpr+OAHdGB521cHIgPgTkHuT3SyEhAgf1H0EDBhM9dbjzUNU7I/qJTM4GHj7jzZ8Fwnmb1GJ9hZhgH4RoA e=found 191 iterations",
+ "pub=MEMwBQYDK2VxAzoASyOtDczpmbkaaBDC3pvB09poUWmz5DpDkX/o1jBN/RFaRvHzEEKIJ8AxuEmgoMdaGaewsdpP94uA priv=MEcCAQAwBQYDK2VxBDsEOceoPAxTk4yA9Eaw3Zr5zEAQQhPgPuYOcVfSOySQQiSD76XcME6pMqD3eODccKXs7oASCIet1RTfGQ== msg=+cxAEEIT4D7mDnFX0jskkEIkg++l3DBOqTKg93jg3HCl7O6AEgiHrdUU3xmOYmdqUhY8og8tmdZflTGl0L3Wxw== sig=nxacjHNuea/II7xbUgwURmGdiZybALFXrZDw52yh58qxgFRAqgnU0fO7WjJuugD0xy6jdGOop8WAhzhwz+YfJMhwjUIFCQU0gMxONokD32qAY3xLiCYESl8iGrHmnoI8fN7jDpt59XOjhVYHGtygpDYA e=found 193 iterations",
+ "pub=MEMwBQYDK2VxAzoA8BMeSayVweKNw7CRE+Py2cedjEoikRhtqNvDBt35Fa8+2J9ha7sP9olPHOIosCCAR5Taa3vA/9aA priv=MEcCAQAwBQYDK2VxBDsEObg/KRocVEWne5+r6jprc14YkTCOSCyJhjjLc57m2IvbMWFnZ0R3nfdZJejGyxi+EHecm3+HcTtDEg== msg=MI5ILImGOMtznubYi9sxYWdnRHed91kl6MbLGL4Qd5ybf4dxO0MSiiu3+kIyMozQw/4baNISF+OiIR+qg1Y7Aw== sig=9NudJJgNYlDFqnuC0s2C0AVA0dNg9DSrp5BH6J4X1GvYP3YryHRdtmVt+ddYU26VxjiZVESNNfMA9dNgoc9ZVDemv8cWTfTyXq2BdoDNQHGUUmSrSaVQVHwy8bgrBeWy+QlGW+UjjWtmqE4XfyeCmBEA e=found 192 iterations",
+ "pub=MEMwBQYDK2VxAzoAnqm3LH9RyxtiTZ8xh0c2VNSg9RL0yuIX/B2PJ3oCEiL5L5YU++JvEHCuojhaNSdCZnnhaFSCi2wA priv=MEcCAQAwBQYDK2VxBDsEOTi6ZcD6B0cxMxPuGWJaLTWrv2qzSnVn8e3BB2yOHkh1HfQDA7u+0fOvD1+geyhDq6Pgg9wt0A8Bow== msg=OLplwPoHRzEzE+4ZYlotNau/arNKdWfx7cEHbI4eSHUd9AMDu77R868PX6B7KEOro+CD3C3QDwGjNU/T6xFELw== sig=0e3EbTzqR1jTRN6dPSQdLIwhBfLd9pJNjS1HZRLxUkhenB53AOys5QGuGVayqNmsGf0Gvf/SBy2AM2ug6v1k9JYNP6wVJjCuoKPpcrqlKBxKujNWGioIXjGMbUehltGQ7zFkcF0rq8hAJEfwxpxp3SQA e=found last=19 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWhIghNbDZQ3UHeAaV8VvnuyTQp+o505/MF/aKeAkpdihVNDEsy3SYPi/La403UtOEO1ceuQwn0SA priv=MEcCAQAwBQYDK2VxBDsEOThoiB0f81i7rz4ig5ikaeLSICxZ/QVBNHzwN+O+AcFjC7staz1DFEk5RbImujrCOmeH2t69X65l5g== msg=IoOYpGni0iAsWf0FQTR88DfjvgHBYwu7LWs9QxRJOUWyJro6wjpnh9revV+uZeZSXBh17ddPaMTKXsi+4woMfw== sig=KjsUQ2vdm4V4/fWRnLOZSArS/fhu3aUNOe4pwgjPhfcmY8peHYyogy7KhvPf1meLP0dDnpo0UpoA4G2GvHkLEYOHFYfywX2MUaJbYlxtcI1T5/SRk893Wz4BKYhQ9hfTnEYfFQb3LwbaaEzCpfFQEzEA e=found last=16 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZKJNO6IyoYaXEpkb4Q2LUPC1qlJG/MV4GSsfE2SNgy3A4ax5Aii+dvl5JVgvt0iGTjnGzR1g76eA priv=MEcCAQAwBQYDK2VxBDsEOZi0Fgxeda931N9fqW/18N+QQIfYfKAxNFBqDDqZdjiyMd3OWPVUuW3TTl7lX1tsL+r1qu+arKj/xw== msg=XnWvd9TfX6lv9fDfkECH2HygMTRQagw6mXY4sjHdzlj1VLlt005e5V9bbC/q9arvmqyo/8egL5wwOGNk0TdPJQ== sig=KeCWFqQyysAZqRmNBXQHmOiq4Qjq27N0cVoqtm/fMMqSwXs5DvtMjMW/4sut9nTfaQ9R0aQN8q8AuklnHnTpRqUEFFIXbK3WgGzacjkUoNLb0ougyxe9tvFe9+Q0O/nlHYABLovmXLfM4lW9Qd4SvygA e=found last=20 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXj5XlVeUHFwqw920A9cp5tzxrdRdDQXMSmn5x9+n7kwSBlU7vYduGUSl7StIEqhrt9czSbEi64KA priv=MEcCAQAwBQYDK2VxBDsEOaq6wfoYXTAEgkdq3xvebMqssEmgILSUvWx26vEIOYhrb4n551IKPWp1r8Uu3Aa8DItNZ5r0qmgXDw== msg=gkdq3xvebMqssEmgILSUvWx26vEIOYhrb4n551IKPWp1r8Uu3Aa8DItNZ5r0qmgXDzmjwShAP34UYh0A5ahlGA== sig=1JlzbvbwsqDV9jN4kfRoWFhW06mazziQI0LUcv9fyKhsyYkDYuLCLZVGepTAqbDm0up3bYw2RFWAzEQBxuDEAXM/ptYU1In+obJi7k3icLhzhhvet/BKuRdSfxzTKL9VG9lyuoSBvv/f9wUThs/s/DUA e=found last=27 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/clIv7loBaBEEoGmND4SK+XQzhkryl5/+lnAZyVdsUzTeliv/ZryvDGpZzBPVIV1GbBEzosqCg2A priv=MEcCAQAwBQYDK2VxBDsEORElqfHpe7hUoyyLfcCZCHr+ibC8TGWEVNXzig2r2w6OZQodGqGgN616ObF0lmDIRJhKsCmxIidESw== msg=oyyLfcCZCHr+ibC8TGWEVNXzig2r2w6OZQodGqGgN616ObF0lmDIRJhKsCmxIidES1U33SM2TolCJ+txQZB9IQ== sig=a4f4LJ0SmjcOIkAn2SNz9qWrgmbLaaGOBB2E1mxEXC6KTSnXOAlsjy1vI0iMXWEYwKwR8hPJzxMApCXn5JClLKaBziCiuFeptK1ufTWmpY6Stm4xOin9oQcSc1DGd+xu0TIb3KkqMKTdEIatZpXx/CsA e=found last=19 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAK73F3oJLy5FB+eGNLYO+k+FvLVd3dJClSMzy+2oXfnrr51J53YZoO665trkQCDW0OcsNohgYd7kA priv=MEcCAQAwBQYDK2VxBDsEOad210DAb1gAVY/+P7v9q515x034sutKApOyOFdNmLPTBvGHeIafWegfCDLVl19S1j0vRePUXLZDCQ== msg=WABVj/4/u/2rnXnHTfiy60oCk7I4V02Ys9MG8Yd4hp9Z6B8IMtWXX1LWPS9F49RctkMJUf3pFinI0NtdrOAHDA== sig=nXXNNHDBNe8Ghd558KsSyL+WqJHzV8jA7dFxXbXYVZ0VOPYIxvf9aKqJRcw4S0/lCCPUy/WvUquArhp0HMBpf67iH6EHgLS3p/OKSeeZUWg1oF+uMlPpS7p9pDGSNcldhnZ+vILhisUeYwoeR6qZBgAA e=found last=27 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAaguBmw+9L6TUTOaB+UfkWO9HtesUGKPLPsZz7yhC0e3VqnpJ+0tpe+593GA1jbnS0jcFaMIqMqqA priv=MEcCAQAwBQYDK2VxBDsEOf5GpHwq7KniJgwvdxVORbZUuCQYvVAO8emkDzvkty52ul637AN4MNWITaHf0lHeuORiqTW0anCA5Q== msg=JgwvdxVORbZUuCQYvVAO8emkDzvkty52ul637AN4MNWITaHf0lHeuORiqTW0anCA5eH/kR/wux8XO6SZr057/Q== sig=sakMQ0mj1UQVhMpk6K+0vxS2E02ymuV808Mm0AiXrUlADScpOw3lWZb469c9h5r+QzJSaeHmkQeAlOgqjbNAviKpEkzHu4dgD0JbRfH68hEYRNrJ0asJi+r9AO/1q0GANs4rgSG2ADsRwoi8dCKpFD4A e=found last=16 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAcmXAChz6/6hufHNoZlRE2xN2D+3JKpDI3I2q9wDX4AP9BnprkLUZSMfFpaiO+TJWRIcllyavOsMA priv=MEcCAQAwBQYDK2VxBDsEOcEvxH8HnSp0le7+uW2UMh6qVHX7M8PFsdBvwSy6L9mA+yp/Ygn5fpNMeplc8hK0coJajPA9kMCdWw== msg=dJXu/rltlDIeqlR1+zPDxbHQb8Esui/ZgPsqf2IJ+X6TTHqZXPIStHKCWozwPZDAnVvAdnyKrfKFSZUHn1+fPg== sig=fv51KHg5N1U5Nq8NnIkla5tyWCz+sJLucrp+prfebfXjaUYb5VFWuZrTaV4gvjf33R4ZURpSXQGALp+VP5EdSlFWyB0PhC1Y1YBsGa9I9ysOfcF+/QyViMzwvWsO1dsfrq0GuSu5XUANU64VDhFv3SgA e=found last=22 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA68IAKIWqsqHDGmlyH3xjEpASsOZAHfa3CpKL3Wz5T/4GKf350XOHZqUfOqWPcXWR/NvsEcVCcBUA priv=MEcCAQAwBQYDK2VxBDsEOW2vC/DYkwc16LLGpTtWjYUzobE+0fzj63BFqvIEJ696fFyn9Dipkb29bz/3cR8NVrdb3Hbx/zThJA== msg=C/DYkwc16LLGpTtWjYUzobE+0fzj63BFqvIEJ696fFyn9Dipkb29bz/3cR8NVrdb3Hbx/zThJC3IsMSIaueEIg== sig=uNnNeXf7DzM5opIOkET1CeEGq41BgSbtXk5+gw+BEReOzUClM1ENVkPsaOSR698lfV3Guk0c4cQACBZTusWZJAfjwleuaclFYjxuM4gvRMUfzBe3Mx7DVi8+EWKOOXO9N+6i/xpiUUacBgNR27JNRAkA e=found last=18 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAY365+XQH1Dfaskx9by31wveWQIKVQdVROHXAwW4IST8xgMNOa6hv3OxSLU7//svJ0HQi+MEc+dmA priv=MEcCAQAwBQYDK2VxBDsEOflgodls4LNAe0zfm0An13JPRtLwoMOIJ8U0NC4TENls68lh8zLMbZrP0v9rQWDynDNxkdTEUv5ijA== msg=TN+bQCfXck9G0vCgw4gnxTQ0LhMQ2WzryWHzMsxtms/S/2tBYPKcM3GR1MRS/mKMWjCTcXomDX8hg0bD5Ce0Jw== sig=RHhaQ6MsnhczVGuz5YnNVAID/U3nCAE0GSyh3X+TIDmRiyMbmujquamUGYPRxeSvbax4TnzRMloAz52Y5xsLL7m9nlq5XxD/QDSQ1y8j8IKLl8Uw0dQfzZorxPuOn1vHijdgNrhW9R3GYHbpbYvIPhAA e=found last=15 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmpnn+vvZCSTyawmRbZxxJqkpSmfd4fwtbcSK5Rf23K+FnNUW9mIf8eYPAfb771BjNTer6QR5QdkA priv=MEcCAQAwBQYDK2VxBDsEObmWoNn+/9bUbvM9qWXI3L6UnIRxo3uzSD+pk1G2gzQmpg3kb6HZfGJim+h8E5VZojytAf/dAOyCsA== msg=oNn+/9bUbvM9qWXI3L6UnIRxo3uzSD+pk1G2gzQmpg3kb6HZfGJim+h8E5VZojytAf/dAOyCsG1T/TUSC39TXg== sig=JPPZYJW3aGfF6jMTDu40HE15zsKVzh1b9oBxB23weaCeNFGzaGR+DPG2t+IUAmzd6e2rk2e6jGyAEjghk13hxA2SKt9tq77HU/sTulQBe5oNtQn7QCvzZGPJX5B3LtjuGb7iCWcoAh8PZrzsT98pQRoA e=found last=18 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAlzpVkORvpHCYpRG+0b8R9a118mK25Bj0/teLlFvoKLTwR4ikFeuGRb0xoZSqagmTgoqhs3soyDSA priv=MEcCAQAwBQYDK2VxBDsEObVJAHEdHRtbjnCPlqdHWQrqumHKj0ioMPP71pkOmNWobVOFsWGS1Mh0jaK8Lm5ZVslsX+fmmd3LTg== msg=W45wj5anR1kK6rphyo9IqDDz+9aZDpjVqG1ThbFhktTIdI2ivC5uWVbJbF/n5pndy04IZKAaqCbxqPCaYtIhIA== sig=HfH6TAn9/Wcu8DZPkV5VKSQj0XtJV8aR3g34bYpfFGf7lmhbusiNrsFUPDEqCww6PYbLREbSbeSA9O9Vlb5oGxfy8ArE4uCH3gpidJgoZLyLvivehflht3akpQnXQD8q7qmtBSPpjPONn/jQWPBMly8A e=found 194 iterations",
+ "pub=MEMwBQYDK2VxAzoAYoey95EkiazeZi7Sb7MJIVAKgnxEudjDBoaWj4hEEfMVVNUqi2tXdSJWJw4TO7rZqiOBBTRGqDoA priv=MEcCAQAwBQYDK2VxBDsEOT6XWQNMB896ReDcCp7XzSq8+nATSvydq+kogeEdpwB9JMoNJnCQ/r3xuSdu3mFmmeEo99sE6chaaQ== msg=WQNMB896ReDcCp7XzSq8+nATSvydq+kogeEdpwB9JMoNJnCQ/r3xuSdu3mFmmeEo99sE6chaaYlGZ2m/FIreWg== sig=bIx9sYL17sxg4LnrHSE4urSYpVF/IvbpLILuKc1kN7zeZDHCteWDg+4fVxFsKS51Dkx94DQoqKAAseHmqZjKrznIwgiS4yTpB5k1rK6pqj519RAW5+7JdHX0AkhkSl0gGJTCfquTZgoEeFx0MDJD7y4A e=found last=24 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAiMdW7QMt81LZdjEJfUyG3hsW6ABs44PaWYsEK9+rsAaOqKIFEdwsJr9t+a1kaUY6LTR0JFDtc04A priv=MEcCAQAwBQYDK2VxBDsEOWLfNhAMBrCYoAeBdHEujeOMMtEhQ7DBxmwgmnt1jyngmqRJkt6yS14Df0nbh2rH7gblZn3523mZeg== msg=NhAMBrCYoAeBdHEujeOMMtEhQ7DBxmwgmnt1jyngmqRJkt6yS14Df0nbh2rH7gblZn3523mZesir7JEDaygryg== sig=5tWz6Bb3XoYLTGSn1DRLj+MTbxMDxu40haPwMhx1LmsaWlNOoE+wM8ipRKzqjGQ8K/EuE1twy/mAuV6r/pxPHScAi+EV9EN9np40LP4uYgFUasFjUzUrPDSbjB+faeNA+xvciKzQSK4SYwhachG9OBkA e=found last=17 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfMzpvoY+MHmW5Ku/dCQKIKMZZLFndBEQgE9jJswHYSD07jGOguwOJWsdcCSUyDOU7Z6Ozpdo7YqA priv=MEcCAQAwBQYDK2VxBDsEOWoWWSZCXCCh/z7e02Ffw/FhN6g8Vcg2jgnfM/gnYjAEq6XZ6u14xxEwzNk/YzBeLP/p5wHsFHSA6Q== msg=PFXINo4J3zP4J2IwBKul2erteMcRMMzZP2MwXiz/6ecB7BR0gOlz/utiUSYv8Iv4fRfE1E7iNXsm8T9aQPjJLg== sig=valf4bDx3/FcATwQCoDOanMzTPqp20ifBNGBHMoKCSbHRr6lE4A+gfe9mYz0RR7/b0PVWjCv4uiApho7MzpNB1kpO7H45uJhryGXK7ZA4f3/DSogtnyP9B5bWDMIr3FpRvGULcN+R+/NTpB6tC3UkjkA e=found last=14 s=10 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVxqmTkE2cj8RFfnviAk5vR9ZiREsUrBhTZeel78N2ffRnRgWYpeDC4RYQGc/XRprAfT6muyHhIuA priv=MEcCAQAwBQYDK2VxBDsEOQVeU9Uxb0gyuriT5U58rA68Zj1dFod84qh2oohdD6P+5cQ7u/qnRnT3bdzDeyweo+SCkKZUwGByeQ== msg=Zj1dFod84qh2oohdD6P+5cQ7u/qnRnT3bdzDeyweo+SCkKZUwGByeQRBLSIdVrphc4JhNmfRS2R+091nWvDJaQ== sig=c6PkLpytnth8l437JSABb18JsSPd7+6KRuIY6Vsj8ECEdU3bIs6Bmi12JvlhvJigftGR3ADD0ssAN/+ymQ62KWc6DfFnCecAF/XKqAcMSZi9vC/kjoIitDplRgZhH2//U/2IoEOKPKfJtoDnjDUM5DwA e=found 152 iterations",
+ "pub=MEMwBQYDK2VxAzoAvTBNJr69v+/yWj/c00nNt4sjFYCqOXmLUdmWPPa9advYzUZ4cf+Z4VQig1aAIzi22rtuDmceT38A priv=MEcCAQAwBQYDK2VxBDsEOdomtQzFqYtkspMLpEKcByI6PSYFJsnmPaeGLDvU0enDQbDt+FAZZip5/+XoVDm3CShBNUJ8UFlvKw== msg=pEKcByI6PSYFJsnmPaeGLDvU0enDQbDt+FAZZip5/+XoVDm3CShBNUJ8UFlvK/Gk1abp5MPRLk0OGsdlMCLPyQ== sig=T9wLDw9pQNn2Hm8fLolqp1r1H2tCQB1FLLD0ZBQt4zF12lOn4v2CAyogSkk5CJys8Ia1uORgmQUAC7AgSejPn5XK1UaoCEZ7kS4UNEC3X0TPOAyqQuAsGKvgg+E1J6loPSz0lP2uHu5mBHe8UAKPLAIA e=found last=24 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbp/EylnmLNaFSCuFbmcnlXs6/iZuh9taGULtvT756NefYTAJUehidzr6HLzDbMvqBi9cZUqpdmsA priv=MEcCAQAwBQYDK2VxBDsEOQrU7VpRi55m1Xb6a0aWHg3tkK1Q3/orePdX1wqZAznIGgGAC8ZW2tatMqsowcnPF6Y27IIUXh9LBQ== msg=Hg3tkK1Q3/orePdX1wqZAznIGgGAC8ZW2tatMqsowcnPF6Y27IIUXh9LBY6KhP+cftO/8VA6oefb9GmX6oH/Xg== sig=IyQFTj9P8LSle25ocWSHUGBatLXeQPwKMXFI9OzAoKjR32aK1Y8PAUry8ilRL3BqEElCPPIDJcqA7uP7R3iqIvYsLu/XUHPyeYqp7HsFCxsptD7yR/V2mlwAwHbME81o9TcpAwqoLI/lUAhdIdvNPA8A e=found last=14 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUzR/yk+IxMjgrn5tbkFG4UQnp3XA30PfiB0DIuqfg05e38E55/C1QflQMxqHMgj/H8uo6jc9oD0A priv=MEcCAQAwBQYDK2VxBDsEOeIkJKv+FgVLMjQtFcdlaH/f6HT2eoaT6bpzOnxLrbifHRBFJye/zgPRfU1jeZ0h7SL44aChqtzYwA== msg=FcdlaH/f6HT2eoaT6bpzOnxLrbifHRBFJye/zgPRfU1jeZ0h7SL44aChqtzYwANOf9r1bfgBAD2opcft9l5lzw== sig=3swO1+tbrPYW/9AznxjGEzO+9FqIpbTh0jnm4sUETM4oyn2/X0r2RsvDWUNYAvxuf4+QeTMn/50AuK9TUvurhw0ONk1IauuUUTGfm8xqVTlQjnlgC2DVEJUJjY5eRFe82Vh2EU1rECCzO/Zi2llsLwEA e=found last=21 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAil7kbW2PIXwbG+gUeZf3/4NZ4e/rDUvnby+2S/ILt42SayRC5/VQ4hSKDu3znkQDy3t99zDK4JsA priv=MEcCAQAwBQYDK2VxBDsEOXrfWw9qNGukG7GUsYHNB/VxifwsrEl0lSz5Fe1BY18ns/77Qfi0nAxjOTX9ph0DM7iGa2gBhxFmnA== msg=QWNfJ7P++0H4tJwMYzk1/aYdAzO4hmtoAYcRZpxrYFj002fm0Dg7SkH7bzArVKJIA99PxwbSz/CflvPqBA2OcQ== sig=DsdqkBwzATQ/AifcF/sJcMyLR07Cyg0jH9EZZPubny7jxkIJe8wa8Kjvwm8WTkAoxewm7QNFE86AVMsmOWwYoi1VjUGXJewjIeJwQhQZPNJ0UNY0CHrGKGkN5/By4mZxdWDdTY9Z4E7A6ezA0YnRVBwA e=found last=17 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATKz03mL+U9jWJDiO/lVaAjUtHFOKYiVS5Ea9ybyERfadUC3Y9apWjPKzjt6cr2q2t46xEFRIvrkA priv=MEcCAQAwBQYDK2VxBDsEOZfUc3Z6WsE5b1VnZ/udj6BaQFHUh5Sr2LfbFjGwBr+vvuWwlFrXSzMg03EUgUO8NnYa1tLdbpgBWQ== msg=2LfbFjGwBr+vvuWwlFrXSzMg03EUgUO8NnYa1tLdbpgBWS4BclkGA5lwP2GohFcP+ALWFjJdgmezQJ9evMGhQA== sig=uvQ/b1nVXJhFWqmERz7lVAs7bwIzBf3fHmTk5CxzRJPCc+hPRWRDDtlOHjLW7eAwtIwBDWW/ktKAaoa0hNDl9cVRrj4ozQkuLTtkDK7BfIWq/hqjPrvm+DMb1LOWYcqp4sPBo1p9J5xIaVa0a78vRCAA e=found last=18 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAYYTZuxQYjoJWfZnI4AQc0BlhucKHJns0mh0m8kLs0sx1LnxcD7896w5rebLuBXdq2FZvJw2E4LUA priv=MEcCAQAwBQYDK2VxBDsEOS2Agqb8Vfc5hy1T/vka6q5Qx5jMeOThCW4COA/mIzxzvCixsiWF0LnwfEq/dzC0VTPHedKyBTYAhQ== msg=D+YjPHO8KLGyJYXQufB8Sr93MLRVM8d50rIFNgCFBU2jLLucwwiVZsffc0W1/ue/UxlFax1XFlT7r3tKMW90hQ== sig=OkFpTX7YtTO97UbXd8ht95SWb+nZ9yT4xJ54df+rhCCjFlPZa59TMlQWf0q1glR0hhZ1eBFwn0gAvX45OPmmQXI/0G7uxDEB7WN74wtTpC8NC01fsrcQ4bP4xjorBW/b/olKXtKIVZSYLplWLoRCRQsA e=found last=21 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALy5IrJEj8KDg77MwRhvbw0qcAth/DLb40ocHOd7kdvFsHvd+PlH43ctqATSLeisFLq3FFvhR130A priv=MEcCAQAwBQYDK2VxBDsEObg8DzwtARgDEbOi+OH6nrR8v/Ab0BUUCVBizxmHFaONYet1UnKgZxPwiGiQxYird6iKNIpiurgxyw== msg=63VScqBnE/CIaJDFiKt3qIo0imK6uDHLCPjw8C4JpdDH6UvtaUTkKcWHrtgF+Y2WuS+ymHJGb/rcx8pPXo6KOA== sig=BTy+upKdLnuSoHpOCZFe+XCV/EoAiphQBdT59brIWAhjNLSEaf1hM5FOyq/nJYhxYasr7t3djqsACKSB4qJuVkUY4ZT/zw+JnTJfu2BqPZ87G/eq1JZXrldDlSdl5VGTES8VpjxPskosgluMdDvz6yEA e=found 149 iterations",
+ "pub=MEMwBQYDK2VxAzoAKpBv80sguvuwGQ7hE5lYs3w9CYqwUVPznTnpCMx6iFL20RGSGRuBnUkI/2Wv5jZDV1GE3Qq5BZQA priv=MEcCAQAwBQYDK2VxBDsEOTOlVbP1MEv4azMVNHBsLB/BSwgo5jL3/t3RkAWcClQQwt/X3rqMKt4N+QipYX3mRzKuT6Hq+eBeFw== msg=CKlhfeZHMq5Poer54F4XTOkD45VRRMg5PkjBiE1MOsWT1XXXNkyq5kp6y1BvVaoiWPsgKQWZ4aRMNwGHXqxnww== sig=FZ1naDk9YzpLD55fjdhTQ7f55jEyUE8A9UjyMkphohqdBJny4PuomO0W2cgGtHl9aVY1IN+RoGYAFKQ6EBg0gfmdtoqU3O6lDOJ/kfr4c1Ed2JsfZmJcrvKzBPhH/8RZYQRlJdqRryCZmbCm5zfuTyoA e=found last=18 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbJm8oxabMmNN7qorFHsEvAU4GJN5r4r+MzJIvHpYYFLhDMYRLcM5V9SA3abpcV18H7x/JEQVg4gA priv=MEcCAQAwBQYDK2VxBDsEOe1/aMf5aCZTNC3cHF1FT5AHdihTHM5eABHPUE8FcglGONROSDR+prHk7OmenI+/FNs7/B/6qu2grQ== msg=GB3pMx/LVaNQlD+S85vcF35uDORCqRqVPH+vmBtQlgAErQnQjPq4f2dKpeD7gYesk2YPoFZO7DdF+Zbc0WaNRQ== sig=ENsno1pFZqIXH6ayZ2JjzJBVeGP3TkZ8Cc8U0++EkA8lGMu0Hh/0i896H1VmIJ2E0xT/oLTLm8UAbTSw+q2zFSVKpCy1FhxmcZAbpaw/fyJZbRyYOtjMn2Gq5uoMTlemEN6LeS8qc1txr8VRjzr50BYA e=found last=19 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA19kIXQ9cb+HGi2tk8DgEBUgIeuv8ZLa8tD+R/zjewmvA9orG+nWVr6eJETyY40uVh/QtvATkpU6A priv=MEcCAQAwBQYDK2VxBDsEOUFxb6K0gJGk6TKepYx4t2zxElOyLoQfSkwbs6lhevVxMEiv84NHQ30LkFbOAyz09OhN6zw47xDNKA== msg=QXFvorSAkaTpMp6ljHi3bPESU7IuhB9KTBuzqWF69XEwSK/zg0dDfQuQVs4DLPT06E3rPDjvEM0oZn5DxYk+kw== sig=LexRpk4una71scmMNfwYeFUrp7VgrB7lSr5wEaFU+3ZpBJ/zUNpThelwxbCDyiiODZpcMzFGXuAAIIxok0Yc6efo5ehSeYPth8FUCi2tM1dw5y9H2VVLsSVS+YOWkxSgmuks/7mFhIhGWOXlKS4WqCkA e=found 148 iterations",
+ "pub=MEMwBQYDK2VxAzoA/tEBr6f52ufH0clkw1/eLs06X87UhmrTJr5nYuLNLMLvLhouIxBl7l0QgROytQBf2kNurJhg20kA priv=MEcCAQAwBQYDK2VxBDsEOeW6YN+3rZGjWpFr/ELJ/UXclAQk0iCMfPEt4I7Eb8CIQaVI+TvF8szXGZO1fX+VX5LCoQtzmI+Qig== msg=37etkaNakWv8Qsn9RdyUBCTSIIx88S3gjsRvwIhBpUj5O8XyzNcZk7V9f5VfksKhC3OYj5CKorpOqE2Lxne6oA== sig=EgZtdxm5Nk09YaIeS89kpb9E9e2R17C5AyPzd/mVaxXXRnCrvLAuqaPNJazt+C3L7JHjyrxKti8AMUySE+z5mTZnkPB1qKGJtgYDuDMSriBBIm/3uWJ2LqntrvLVnXqQXx7YuQoF18G4q5E8D1KCbTcA e=found last=20 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7ii1p0jqfd8sNu77JodViAs67rJjuVgHsB9kbA0jcF+f0X4RdIot7En42+mYWDpRT/PieUPN8M6A priv=MEcCAQAwBQYDK2VxBDsEOf9ywK47sCB2hBF2eqcI3iVJKGTR3XuhjYmDWRqyRilqIJNOQ8bOqSV70JlvZStOKqwxxGtwanPtkw== msg=wK47sCB2hBF2eqcI3iVJKGTR3XuhjYmDWRqyRilqIJNOQ8bOqSV70JlvZStOKqwxxGtwanPtk2GE25o7+G3SCQ== sig=Lrbp3nEJfflv3/Y7XIl6/EotUIepzK6aAh9jgbE1TPCd9lHwyrUW/RQgdt3QRX5UJzNQKrCBJ3qA5mOzDgOh01ijfpqPSDV/ib0hBFeZj+38s3eFZ5pvpmc/0Difl9aUcvXF/8mSVnD9jM1e/3GUhiYA e=found last=16 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAryyZN9brQaCKmQrLw8vN+ddwxok4d6BuYVjg5xqQBmxiEJQdT+OT5kOb0zaIWcoXkbOLAGQ6pCQA priv=MEcCAQAwBQYDK2VxBDsEOYLHpSx1z585KRb9yJ5VnHDyC4RIEZcHdNYUdqji15aMBWqypjGcxC1La390SBfFd0vYtJs84bK5Fw== msg=x6Usdc+fOSkW/cieVZxw8guESBGXB3TWFHao4teWjAVqsqYxnMQtS2t/dEgXxXdL2LSbPOGyuRcXu3OasEoXSw== sig=WCN5J05lO9t/cmQk8GqMv6KrSONDay2t7GA4JGCNF3BVofpY17qWZyXYNPzz7LYsJpTbMIuwzbGAUAnofYE91Rn1/9TI0dyRcuYZby/r35ZMDUxDw03wui1005/p4gnvfWhJiYAl3hqon6eTnvmk3CkA e=found last=23 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOPfjW16Q9FYu7w61lAOG3yxC8r2v7cR/eGBKE8PTjdwei/jfNSoUnVGuQpXF4rgT1jbAzWOg5ZsA priv=MEcCAQAwBQYDK2VxBDsEOazqhb0RxbX3lpvqTn+RnzStySui538lyHjLCI5baFUlkjP0CxiaK+FhdkxhaeD7vtn5yFyXSB/NFw== msg=rOqFvRHFtfeWm+pOf5GfNK3JK6LnfyXIeMsIjltoVSWSM/QLGJor4WF2TGFp4Pu+2fnIXJdIH80XXxGdYjM17w== sig=ssJQbBxPgSA6KofTXPlgWM65IOXbozcPnDcwn+LzxAMO3Ek6yGpZqxenQ0YVeY3a2LqIbfiTfbOAufzPgplpokwAUBefJaUCQJA6JVF5667h+pIBqtxo8ohYdEO4VzosCsvnVlo3fcljTdTHPHn3JRIA e=found last=14 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAD1gqnK3v3hoQJYQ+/RchsExadncRM57pZTsdWyZqUNVPXzJPvodjaiiUjfcXL9MqwVMED/zc5kEA priv=MEcCAQAwBQYDK2VxBDsEOUKs0f7IEa2TTS7CeVDcRm6ybOkUlcWyv7Lug5ukvPci+yeuis2qciLl+xCT3BiDuktR62niWrlHRg== msg=yBGtk00uwnlQ3EZusmzpFJXFsr+y7oObpLz3IvsnrorNqnIi5fsQk9wYg7pLUetp4lq5R0Y2NeGIX28/ES9/Fg== sig=HHG4uKqjwXl+Asxf4ziBJPwMtadBtI5+pkKSzAslqGuOiM1AR1cWZeZr/ZKOvl4CgoVSnQe3SEiAMjwSiuGJ4tO0SKvi54F1Dezz/d9dqcMuX7hOOAtqANisauQsHAmLftApruOs8WYZbM+z6Koajy8A e=found last=20 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAn+NIdnflj456kNyURxQxJdqtrWmIR2nH2PnI4A9zIJz6NwMtXcAwblPcUtwZhMwVOfHk2znkPAWA priv=MEcCAQAwBQYDK2VxBDsEOeHlsK6ShnUbmIwKHOYmOcGAw3MZWECmPlDRppvXCPLjADiBAR1C4/E2uzoETRDWbBUf29WSf4y6Rg== msg=sK6ShnUbmIwKHOYmOcGAw3MZWECmPlDRppvXCPLjADiBAR1C4/E2uzoETRDWbBUf29WSf4y6RkjG3cxnQO9Nsg== sig=Or7Exmi27HzKQx9AylGwVUejUQDZBS7evOQmq7HTFaSxinpRipv7JzPh9ueZUgUqjExM61k13agAb+yvXr+tQkNpNouszrWwJXZg2Sh/U5b95hS6ph6uQkqROb+Dg16K1NJzJI7BZt1SBs8j9tdz6zYA e=found last=22 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAjD8M7JgYAL8sz3RhAx3VAgEIZiLn52B7VtqL7Bda90H0WuFqKc/dUj1F5hjlUyeDI3kjPrxgriAA priv=MEcCAQAwBQYDK2VxBDsEOVUNchneCLuwHLNqTQdyfbbdX5ia7Z93+N7+3StBQeX0wzvBOd7uPtKT63h87YjAY/jEEzMIDtx5lw== msg=DXIZ3gi7sByzak0Hcn223V+Ymu2fd/je/t0rQUHl9MM7wTne7j7Sk+t4fO2IwGP4xBMzCA7ceZdiNUmYLicqYA== sig=bRjxZhqOWTCFGmx3ofhbqh8mW4Y2WeiOQa3gXnBTuCXB3omM9RmT+zcK4YmcUeVzJ3PZbGhnxYmA3Usvaam1850ZjOOnnbk0DjgTItZY9bErlLR2jex7iK1CtPlDhG9cWjpP2faQBvZfLd6ydqCr1yMA e=found last=24 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAORjHC3UtzXqnINCXdTGnu3UlS0emSe4YuoLm8GRmmKkQCpx9zGZG5BQrVl7dOq0VMTrcxYGzuEEA priv=MEcCAQAwBQYDK2VxBDsEOchgmbvJzlkT87xcedi7sjGOFFrslb1V/AfTyYENv5kSPr40aIn8T/7REm3WCCWrNM/Cba6sRYl0NQ== msg=XHnYu7IxjhRa7JW9VfwH08mBDb+ZEj6+NGiJ/E/+0RJt1gglqzTPwm2urEWJdDXrk9GUqW0xU74zq/YeklczAA== sig=/WH+yyGp8IM6cQTbFWlIhbeM8yOBoAzOeZrI1NBKgMEEEpo9lRfIQ/bCqsXR/zZaEI0iZ4egvmoAgK3th994s2ZDJlLK3qR8Xh+FbYuICn1akg9BXnFzSywqFwik/6wIMPYb+hpedYFZHQkWWKiWxy4A e=found last=15 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAyn/R3o7bry1UTHxN/bZZMPyVWcUGDFllWKuN4Uec9aCLQQB+m7srJqAH3M3+8gMnm6okosuwRGqA priv=MEcCAQAwBQYDK2VxBDsEOapba+UkI9GVJgZB7Dga4MaD9iqCgCFUcGCnaRp5vYooV8CdNjGx1zWHedpTiFiDKiw/inabkVflcw== msg=Qew4GuDGg/YqgoAhVHBgp2kaeb2KKFfAnTYxsdc1h3naU4hYgyosP4p2m5FX5XOUk6m3d9R2DMFLwD/XLZDJwQ== sig=Oe8vaTqXZZsbojQ6QZYZOaaeq2qzNEbXB1BhRpWKc5t4GavnXMWYpHM9BGYW9F5n7p2s56blDzGAxGlZVpYDMll3u+oc7IpjmDrd7fKAlmpA7YxrRY6POuoL1LZmrncr0ob5S3ydzaUTGKh6YfojcSIA e=found last=22 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAcUnB+XIhRmQK8MTIpHvd8G5PWSaMdFVgWXMbUwGryUAiTVBP4NciRanBm0N+Pw05PJqQglPOhM8A priv=MEcCAQAwBQYDK2VxBDsEOf/f3/ibAVUmRzqOOCO1A9gRgh4yRYWCnmkUn4f1/Ie9zD8Vss/8Vy9cNe45QmzYwlay7FSZlk2zUg== msg=AVUmRzqOOCO1A9gRgh4yRYWCnmkUn4f1/Ie9zD8Vss/8Vy9cNe45QmzYwlay7FSZlk2zUnVV/ddhbdaBF+OqNQ== sig=tTvBMDRbo3PHD6yJmQdOr6yu+oiqLvtZIETf5AI18tiGgWya3N+WpaQ9MUrFc6LXBmf8tMY7H1aAPeNnqre5pA1ozJReXDPbetX+ZbyEiwLzXxwIueCeN7cRB3ddOM3uInWFoWjHE8I+p1m3W8vJJTMA e=found 146 iterations",
+ "pub=MEMwBQYDK2VxAzoA8r7r5/9I92jwEjQ3YfUTCzl7rWgdO+olCZZhHw/9zxEVhSnYHUTox5pV1wtdFQzSDWeuMCO5+5UA priv=MEcCAQAwBQYDK2VxBDsEOeOepWhRwt8V49h9hp6esd1UYLlrEx6ekN0fsknID5eV9iwvziesRlJfscwxE2QkDgQC7PX3heX9pA== msg=YLlrEx6ekN0fsknID5eV9iwvziesRlJfscwxE2QkDgQC7PX3heX9pBUT5IE8cjdvfqu2sUTAh/cGFKMRrIXamg== sig=XI2vJmdrtXNFpkw/Emt7AegnWIFB2PyKpLQhWYpakAdhGawLzyTDu8L69/RYIPTCWPw3QaMagtkAuOoCU0D2gYXW05+f8iUdp4kmNAeweyUZkijPy4OfFTM+cntUgUDLcvQF+3D+yr/Aelfo1EYBPi8A e=found last=18 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAQRSSVoNjHWqmakUGKG7LZnw9qMf7EJ1DlAcwY1XFNkU+UnUcVff7RDpo5J+JL6HMZbMs2v5fr6uA priv=MEcCAQAwBQYDK2VxBDsEOc5ocmQ7yp2Yc8Ua6s0mGPElTaVsu7c6i6Kr5tuLrgECOaqI76yjvErSylvsXe/bsh5O4bVd2cIEgA== msg=zSYY8SVNpWy7tzqLoqvm24uuAQI5qojvrKO8StLKW+xd79uyHk7htV3ZwgSAmIvv3qP1JCd3m76LSPo6/lPInA== sig=/oRmNTpCoNjVydiB4YNpF3ejvgvzBScB8MB2cVYV5kNlk5IYs1XVK5a/yUO4DgXZJOB+n38Mr4yA4XTWpShk3LOOkxU2q5irrZDQlx/fZPbf8Hz6a9x88s48XEGyOZwfI+x3/57Z0PI1e4i/qIIrjTcA e=found last=26 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmVxS26lHLjZa5P1u4lwJiPL5ebgWIwaREXB4w9ZiNvsa6e4K3jEz7KrWBAVOTk4060/3FGbmL8yA priv=MEcCAQAwBQYDK2VxBDsEOVQL4/oDlXef53AomQx9aY7o/XbxGkx7PMoBAw/n5JxPa+O6q06WoEEG4pG8YojnIHMteyG8kAaGSQ== msg=fWmO6P128RpMezzKAQMP5+ScT2vjuqtOlqBBBuKRvGKI5yBzLXshvJAGhkkGY5PkNcs2WiCr16PE9uffBOqYKg== sig=Y61d+d5kYnNG0T3b/7/Kh7e0431y85GPSKvyS8baP0zXB7Ky6EUihC1KDzGaQdhWN3t9hyd4M7sA7aOk1wZsbrEX7o/5V2ziZxPLXzXwgj9RZtZrSXL40G6d6qMLeP/xU6d96DIJhWBRTyfSsRM+gggA e=found last=17 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAplpCiZfdieSafHqSFgYzLqkD9c+Z3AqElRumzWjjggbXaWwWR9nAFHUKlfpYyiZTEgSwzPHjE28A priv=MEcCAQAwBQYDK2VxBDsEOcVPNk5zlR43xA2wkpWfU+IAmh4jx0bxwesnqQohO4H4uZd9ISBhJtJdoWjC4a1z36GsFRw9vVHb2w== msg=CiE7gfi5l30hIGEm0l2haMLhrXPfoawVHD29UdvbHa8uGPPJ51GLqrLgUJuVvFSReU/UtBaAoeKalxQxLd0QnQ== sig=aiT9IjVMm/Ji6/lSMpvoZ3+oLUEcIlkWIu/8Wh9jiq1NFWED9wloJFw4GAB8li6yl0RDZ3YY0rsAC+R7uu66adQO2uslB2ogtIR4OTrvyAPIop/P/eq69pk6ygIlBP/KxArzpbl7JYuO6dsVanlIzi8A e=found last=27 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2PprHtVaWSQO+sorQURmL2eWqj6lAav0JgeFIGXev98tDLsgeRem9VY7Y16MeVqIN0AGm1X2rNOA priv=MEcCAQAwBQYDK2VxBDsEOVjEaKkkfv7nzMqlrYM/LiPF2ORPPnu2dSBwKLyMMXKZx0YiX5yZojJcR5ynJX6TrAaIaWLv3OPkIw== msg=cpnHRiJfnJmiMlxHnKclfpOsBohpYu/c4+QjDIJg37QxOZj6x/qIkF6whzpPp9m1+6xMV2tKCyD6O1m34UhVvg== sig=e7XApPxgRYEviTtD7RrkdRGEAk0dzP6gAlA/v3orPk5SbqLDxpoLXQxJ+7M9Nq1tDiI3a5q8SLSAmkHirQuSqYFTSGepaHekmIi31gtErMu5jGYiPLFq3I4YtddcobyfxSo3i5I5jXolQuM/Zm0YGj8A e=found last=27 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA0BwdJ3k/myOmTJbBBl18xHkysrsmLoAF+FN+MtMoxlPtVS9gfuxrkL0yHkUXRYlz/F/ciZVZMDuA priv=MEcCAQAwBQYDK2VxBDsEOZkP5BuHFnwpcANp7XheXVAFPR5TcGyU+RrhktCwuo5vI8yFj4x+A9ToHmPcYeHpPeFw6bACid59sw== msg=ktCwuo5vI8yFj4x+A9ToHmPcYeHpPeFw6bACid59s5DmxHpyR5tMTGTRvgGLKLYTQiH4UBBcO/pExd4uuFBJjg== sig=9iu064ZaXTk5cmtz93K1ybGpoqvRXzQFL7o+Mdg88JoSe6YT6dhoThurYxqyzz3OdLlzAPfbYeQAw6NJDgGvsXVfYNtFvO7HCYIZOSSDpzSI7s5VXetyAvSXA8R+MnmP6JO4tVg4x6Ym5fLa2GemYBUA e=found last=25 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASXyf5d6EQhZJqYhkyeBCfAAalfwD6wwuYtzH57Jv5+mWmtv5rFwFgiBbZFuaUwD25vkAzgcuE0EA priv=MEcCAQAwBQYDK2VxBDsEOaVUyrDevXQGL0lADFpUvVgEkAH3tfhaVCECUD/iLBs1jnrSoejAAM3EBCpn1ay0HWv6N+mjb8UJ8A== msg=jnrSoejAAM3EBCpn1ay0HWv6N+mjb8UJ8EevJMb1dLH8hXObRuqpkUX7kZgEVLFXaUfkE2+dvVy2S5GXP3i2cg== sig=WMqJSivoFgZopKCAbxOo3pxX/y9Oiu4GE4ERxYe7QLZLz4/bmvzRIg1X2BgdZsszHlScVw3vlG2Aco6xrCPoEdO99Fr9t4MNw1fzA1oT3bQaKrRQmVX2SOukqKl03swiRKcIb/ZNjdouNUqIhT53qDQA e=found last=20 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAAovbgTMKVc+pbuKCR50BuOGoOBnxjYq6H2NrbdLmb7xv/t4jQG/1nsBNP12Y3hPZMItP01BttgmA priv=MEcCAQAwBQYDK2VxBDsEOVTM15iAWsG0UJnQ/NXbqnBskJ2mnKbBEC1gI+RyUwZ7hYJgMJc7gL/LXkZ8M9tL1J8LPcgqB7eIzQ== msg=v8teRnwz20vUnws9yCoHt4jNZhps5Gsi3EsSskPidGiITPzxYmhaGXbbxvf5/W+gVzZ4+tgyq2H8AHBHwjv6jQ== sig=ck1w9rZwjihFGaO6Kf76OZKRKPXB8fK94jkgGbbfoeu144zMQKyt7sQI1sUOrH9sWBBrWZMCv42AFA7alax+2Hs5guyikosOdHCWdxLKH9QjUdS9iPeHnaJN69Mimz0A3Z0q1AtNkok7AtDfGNM69gEA e=found last=16 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVxqD3kXCO5RUi4rMki/ymciUxXfrMW0+T84DVFzaq85LwGcirFWrLaHCoeoSgSI+Y6zU1P5QByQA priv=MEcCAQAwBQYDK2VxBDsEOZ19RBrN48rVyXUWkk1r4W7EfImXNwSAdtFnpkLnt4K1ky2qnvmfjtlBUAk67XU25tkW8Go06A08Ow== msg=5tkW8Go06A08O1gJfCMw9IvzEjvZY9jeTT6XvmZ8vLT+aUxBVZ/VSscI4Vi+nnpD/91F2c8cwswuD9klIEemRQ== sig=WjfpziayvcvovNFfVDV5HgO7lLJQ53RklsgcpQKWKtX3Ovutpkz5oBrrmIo7Eyo1ZA0Agp5Hc0IAtzDK9dA2Rxf0Yo9sM3S7J3MWjeJFabtnpvacVUTOofGlD51d6c7WctuG4rCjYNlrjSm6MIydGCkA e=found last=27 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5unE3beTQjBV6uJoAqYss7nr2HhjVSce2AUJ4xVW9pI+cbC4U51Z8qWmBXaV9DBZCDWY0ZKIORGA priv=MEcCAQAwBQYDK2VxBDsEOYiwvyyf3rS5VS51xUpPaom3A0OOgy+DliLALscrDspJ+aShXkuW/7eFM5B7Xsljr4vtmVE31r2RrQ== msg=oV5Llv+3hTOQe17JY6+L7ZlRN9a9ka22h8yc8xyFI88r4FfiQMra3XULyavV5SZahm9pljmKQTZ19w8DOJmMyQ== sig=j+S4smCPYAAHudAmzt3yI/a+W2C9jUUUqpcce1y2F6IMEJcyj7nWdU6j4wq7ftC1vH1bQedQvCoAb9uNZjw+wmqVJcXo7wKNix/FGmQbg8bpq0cUJEH5SUXVuUZCQab9qKqvfw1WQ4aQc0umAWdO/zcA e=found last=15 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoACWGK1oCFhLgaRCtam9w5+L+dBW77T/Gjit+kPkCPoOjxYnjKAzoIBdxnvQ46jHfNFna3QqpOdvOA priv=MEcCAQAwBQYDK2VxBDsEOQBpUhCoC81JJd+pSgPl43lvSUiydYDE/q7S9UdgKBNajvZnzm1jpGP52yBDbrG4LU0WQoD1wRcz+Q== msg=+dsgQ26xuC1NFkKA9cEXM/lEgJEQgc1dzZE8y5Y76oeoizQK62775qBCfMRN2tJFTUqO70+rn4L6s49tuLye0Q== sig=hn1g2Ja2sVIEQUQhzgeWEDsCIJ6O8QfWmL8EFjqoVzvWs9QLOQv3avW4ezms8jvIhUKzGdWSUlOAPNXydDs9ThYWjjEI52wH4pO5r1NA6asruxAs66BINS/cPtbzEm/SXUPlqNbPDQnRAD+yoLvvOikA e=found last=14 s=12 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOlUrk9XKEO79snFQTy9Yg/REoUB6DY1Oe6Bd9PjWeFPq8U/0so/2BLPWxuCbZ29JamtlHoVVljuA priv=MEcCAQAwBQYDK2VxBDsEOWJ5kLJbhRoOC27VDsI3+tC+fChzhYy6HUZk/DBgIAc47HsA6lMEkcYJTbdSr7N4s0uon4IUEN+NTg== msg=BJHGCU23Uq+zeLNLqJ+CFBDfjU4R8BWwRYMQZFm2/k1glKt3wiV6D7HfdU8wvxddItVb5+sAuYYGJruxoi2QSQ== sig=h1Io4Lc9UTQnjIQ7zlf8tJfowwH9TelHH3GfhkWxMA2DA402nn7aireccRgQEDPnw7W0FIxptvkASNdbDW6GzgQy2Dmzmx7uKBtrEdV6v/lHoZO/MD0PbS4DL7IzAUV0GVHLb0GYMw/ERFCkwSRvDScA e=found last=27 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAP5B+RqtAFLqQ4oD4vC+JiFYY2Qd28gtlUEl9tA2yOl0olsAHGdhOWMtBWsgLoMuwZf5hkY1HpiMA priv=MEcCAQAwBQYDK2VxBDsEOSs6IZgRjx4jzFWc7KeVDBh5wd3yDWFX6jCFxl3zWt9bCfkfDuDX+qAQTi7/BtJxoiqXa0z1CTWOSg== msg=jkpzeMafitU4XJy8lLmGEhqvdmRVy9xo1hvJ9TBzVj5fop1DOtQRqpBe1ksscYnRE7yAqLEyaucTSR+C2vgyCg== sig=U/2hcGSpNckkMGj+pVeKytYi7u/30FIaEiXLR5MecXMpAGNRGZB8gM5tV/ycOtjRcnNdEmXkBB+ANQ09fbNSE1fNgMwnxUed1P32J0ISP5K0tf4Jky084Tu5kt89Y8tkxylwY+ocAm9SeEBY3foe/BsA e=found last=15 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApGhjnE/vmbugPDFuLkG2zqRnnWM9WxM27t9hyIbJSeL5Ju/oAn4zkV5JVpxmOE56HziPEnSWH3qA priv=MEcCAQAwBQYDK2VxBDsEObsII7T0X9YYv84SuFSpDH18AYGMoJotNdkb6SHwxMGzWX8qPI4MS9IKEHVlE6tuFChuwo3U9jxpwg== msg=8GsOi4MUURy+xFlnZtOOiughz/KjOwmMux1Ye1mBTIWZNiCB7kiLRT4aXaqt7o3BsRQEs4GGve66m2cvXdne1A== sig=Y4ZQh0sPIimEVgZaWj2Nyf872BoL2M1pObOzsAs9Iq2J8XwfmYTOytYwqTIDCQggbw1+2f5aIASAsP5sxcokCrgJgzJDJr89lm9OalNS4Vh/UTaBvswdBWqmFAevfL+O/M7O+1jg1uPgiGwtMOspqioA e=found last=19 s=11 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAvZ1j85PfP+1qSlWOksvll7L2ANnv5WQIMRKsEIVY3Pevch4uMsv8MEh3JMiL8uFMaSCwFEzKX5iA priv=MEcCAQAwBQYDK2VxBDsEOWjeXuA45SZTwje9fZ3nbD1RxXBNVeBKhD77rWBDdA9Ihjfhn5kE8YnuM3X2v9ZSTEqlqsmJsvzN5A== msg=OOUmU8I3vX2d52w9UcVwTVXgSoQ++61gQ3QPSIY34Z+ZBPGJ7jN19r/WUkxKparJibL8zeTgIu4ausJQIXJSew== sig=VPRSALrWqs/vqBRI/F0b1tGIqAqu+qhu1lbMcKGkhIAG4tgPA5fBpep7xce9ZRWiYpapJzHgdgQAiFqBooNkV9H68fb/StlvHeWODzSOqvn4sQTBaP/EVNlaxlvkPqFkK3NfhLL/9QekoGIkiNqQMSQA e=found last=17 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUbrP8uxKtk+P848pb/Vrl80Kxo1ZeWe+taAI0nKIzFr0/CGiOwNoZeuZ7l9DDdbbKegkCqftJvGA priv=MEcCAQAwBQYDK2VxBDsEOS1K1HR2Z7Fpv9Q89Uop/LTd4Lo05oTEbD7TO37p2OkwxENWNYto679rgA5JDb0n/Kfmb8P6uaKbEA== msg=ab/UPPVKKfy03eC6NOaExGw+0zt+6djpMMRDVjWLaOu/a4AOSQ29J/yn5m/D+rmimxAcx5E3cU8hVXZG+Z0JtQ== sig=GeRB8zqvpeaoA84Mr1N54SY/cRHvJ6+WavwP95SLjGCt1TVcpxbO5CRxfdkMUynxpnlXsqrJlzOAB6daG0HJS59sp64gZApV1DH7ux4mcgSdt1yQhJqHDkExb0i3iV7D/l52MdLjR3KSbAJINLfYxggA e=found last=25 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAltMbD994aljRldJVdCbTV/v/HuaM9XMNThYFRsrSqG0UqWLKU/ZqJu0gxO26pWsgr8XlQGH0dU0A priv=MEcCAQAwBQYDK2VxBDsEOd0yDi0yvG6UdgmBgfngqGuvhlr77UBzhNU0/6PwCH3kuOeLjEc9766OuXYJWM9jEAvoag4OAtMK8w== msg=MrxulHYJgYH54Khrr4Za++1Ac4TVNP+j8Ah95Ljni4xHPe+ujrl2CVjPYxAL6GoODgLTCvMmq8d7RIBnEK11LQ== sig=PvCahuyoqE/tndrylXdQPferAiBPxVjomMQLyHzEcrwpbRcBrfMZtXEoC72dkA8D04ZeiZ+oFiMAW4mIohdQDulEV+tuO22x2BTfPg9QXWOIAJL4deudZSh1+41CQYDFkl5DbObaTaKC+YtE0N0EBBkA e=found 190 iterations",
+ "pub=MEMwBQYDK2VxAzoAL/Bt/k9zzDaIXtMBHgL9Oqg82mmOt9YtLiWTZRzUK6rKKidB1kthojztEKMWlPveI1XtrFTOaGMA priv=MEcCAQAwBQYDK2VxBDsEObTayo28NPgU9wtu4EF/DqcguBp8HlXQ2QEaSNF90cMsSCj3i+iXTVeagkdZOxSYyCTxzostBE36aQ== msg=+BT3C27gQX8OpyC4GnweVdDZARpI0X3RwyxIKPeL6JdNV5qCR1k7FJjIJPHOiy0ETfpp+7+wcWVhvR3nUT+Z1g== sig=6QspGe+XBBU/0+UZgfZpdktmDothWzU8XsR0TRoj/4BGAFZ/KI3fkTxo7iuFj4LZd7MMfipp+AsAqR4OLQ3AjuIDtwfsznJU4bOqLUywQfAVRWvph4QN/pzwpiCNTsWQztE603E+VgwdUwN6uEBGhzoA e=found last=20 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWzivRKOhmskORuI2CMReJ+3efA2fGCsL49z0wtJmQnM5H5T7UzObah93V4PHll4Axnpc44hFIRqA priv=MEcCAQAwBQYDK2VxBDsEOba89eEQHTRaAHctfCwIMexxlg6t6EPmxDeJyWdsBhCNHJQERwwLRaYrBk5VNyE5foHDPQB+kBm5Yw== msg=HTRaAHctfCwIMexxlg6t6EPmxDeJyWdsBhCNHJQERwwLRaYrBk5VNyE5foHDPQB+kBm5Y49luEhUcCoLf6xzxQ== sig=qRf5Ihij6vSGkFRfvJ5ZJD7ClsEahciUpL0nZuHItokhGQL73YXinTPX+HRxpA21k9J0gpxL+uiAY13yDEkTTuQuMDHmPD54VEGCbFjG5ZeIFkR1P/qnj74fo5ZYwu3AVzuRrOD6knt2RhShAHTW9RoA e=found last=19 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAl2mwVKuhB2bfEh/jjmtxsgxTnxTMz1RwSjD9yq/Rff8ZvQNB/lsh3O9VY0eeUkTSid8GUS588lOA priv=MEcCAQAwBQYDK2VxBDsEOSWiR3hryXn15+86u52aPVEmFBhKYWuO93vvGr6QVmWGb+2zZ0So8U8JXlSxJ48+yEul5Zm8pZcdXg== msg=7zq7nZo9USYUGEpha473e+8avpBWZYZv7bNnRKjxTwleVLEnjz7IS6Xlmbyllx1em+/pQeOMSgHm8tRA56pNYg== sig=fK4PTzCPl/6pxIV+k5NuROIMSMg42n6+bg10mAVKuV6Q8fy3Uo15XrgLBluWuWLlCpbXbd+mitsA53LbCNix3OA2sttye6wS2PMYS+QrBQ6o0AZVdkIqWBh8A7mySKAI6JcNysuISLCP3kgvLnAVOTEA e=found last=20 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWK3SdKW2vPN1+8HHnDVL186dHgG8Gzetd8+7K2AI8otScAK318JKta+bqOToTe84APYA5wdI7AwA priv=MEcCAQAwBQYDK2VxBDsEOccSrCn3Bd/kZ5eM/5NsguxTePUQiiYqQ9W0IVj1IRRRwu7TBbVUyiiBVL0IVV+lfO2vpAtmjTLAPw== msg=jP+TbILsU3j1EIomKkPVtCFY9SEUUcLu0wW1VMoogVS9CFVfpXztr6QLZo0ywD+/086oLQhd1etdgAqO/LM9hQ== sig=2Tea3eycAcALlq7vELUMXOt5bhjaWvAfOIqi0Kwih04svRO9+gcEY6/6QE6oXyNDZ9CrtuzQ398Ajmw+K+ePb8BMEmXIQsdGo6KQUJT6zNBtzX3xBSPLnOIRcVV7IZAUhYM98YKvglxLKnrmN9Kn/zoA e=found 143 iterations",
+ "pub=MEMwBQYDK2VxAzoAJGNle4K9PyMzatWV828nP1NBB2FoRGsoVGo6OU36l0Z3DK8mQUx4eNql6qRZc3IJzF8nUqPnLNmA priv=MEcCAQAwBQYDK2VxBDsEOalNISSnH4vI7+jOVAZU1bq5LvdLQePk4vlZr89HXVV42oaZh7Lv83RkBS84buD908aQUhB2R4MWLQ== msg=VAZU1bq5LvdLQePk4vlZr89HXVV42oaZh7Lv83RkBS84buD908aQUhB2R4MWLSrjYOr5v3NTEGAv9ix3XhVRCA== sig=aqXeBQhkCaR7tMYV2+s9kw063secFyGXHAlbuPppjufAO3Zdatlj3yOlHATdApARcashSu9UEZ0AElRNh5iuaj4PUeBQNeNgAatJ0ppXig2PWAKSjrTfguQAf6L7rAcMwzyCkl0lnff0fkzoh4/9HC0A e=found 147 iterations",
+ "pub=MEMwBQYDK2VxAzoAtMh1+yw0MNTPwd5zqz1xh5jfUdM1zpgUQK7tHCiqtgmEp5wfighANglnqTZHvVPWal+z7RjlD9WA priv=MEcCAQAwBQYDK2VxBDsEOcGJnwNys6NDwcsydhrX36Hok1j1LXRy+XmoS8Ldm8IWy2l75/uOGMuvO2msFPKpGrn2SpInYExfcA== msg=dhrX36Hok1j1LXRy+XmoS8Ldm8IWy2l75/uOGMuvO2msFPKpGrn2SpInYExfcPZjcUlBA4T9CltH2XgTOdrJ0w== sig=VSFL1RZYeUErc0GpG39jaMMryxg6mJM86X0/4hFn/K16AMtfcTultl3dCSicT2ATjPu+u/M75QuAhOV5uC531gGWc+U2jwI8B+rAvmvoLt4ONjB+ujMo6tHu9rMYWkBqvA1v9Q2VWYv2MZV9girZJwQA e=found last=14 s=11 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIhGJLcDJ5yrAPsO8NvZ5W+3roHztuAJV0kcRuFSnraJuhcO/Iuj1CAnldki3uRWFzTS8U8qVcAWA priv=MEcCAQAwBQYDK2VxBDsEOSs2MZFT4C/pDTkrlxQSprqpZ4NdPy+oxWx4EL/Vtd1fSG0EHjLNo34neB0VXnFK9Pp8AOATJa35Aw== msg=OSuXFBKmuqlng10/L6jFbHgQv9W13V9IbQQeMs2jfid4HRVecUr0+nwA4BMlrfkDpi+oHHTYjECXLPGINU6g9Q== sig=37wKNtGJ3SL0qqUVTXTVFZ1I0va1Mh7eswrXzalV6Jc+bb0JKTGL4djJnBQBzf/7pD0aLkMrb1WA3YSyLv6bEQ2r1/DszGBW1SZ2i2H+8GB3eVpduj5/4PhQMwRbgChnGVTEvgT/WfBVApwwQyy82CIA e=found last=15 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsfrwuNmbMnAKvo6tqxOLhPjBEL3IUUFtVecuKaHruG6mvl7CBQ0utYovC5BPW1+dl6303lSJmigA priv=MEcCAQAwBQYDK2VxBDsEOW2wRQJkmqWG5Ogi3AYm4EXnf+dSeZYJqIQu3hAPcVRM2vhEF/dQydEf/KvkoF2MUzdAyx6747FKiw== msg=lgmohC7eEA9xVEza+EQX91DJ0R/8q+SgXYxTN0DLHrvjsUqLYggv1gGtqVWW67ae4S2SLQiuHBZEkiETFv8Qlg== sig=OhPQ4LwMp3KAdxfP19v709E0P78aNdCD/g7S4bfWykcyHNhODpStYTYKVbw9sL5YD5tKe3ir31WAcKy8LCW6ubBXdE46ElDBpAcOWEF4MX9kVQfDxmRkMb6q8xUDnZhSNx6fFXPF6zXVX+ZGOZEt9RUA e=found last=20 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqp6n8shW2EsIAnxno3x9ZL8x/jvcW3us/kkTPfGsxkwvc1lbwdaCwDTvVVMkdS9DtyKoox6q1EeA priv=MEcCAQAwBQYDK2VxBDsEOfJ/tg00Y7aKhoayxeEfmX6Vc3C1DWRB2PNHU0d7nrw8HJroB+1l+jPTJAp68VsWUdYaGJN209QNqQ== msg=7WX6M9MkCnrxWxZR1hoYk3bT1A2phHiYzx6MHqflyIGQboxCuwilTRLEH431ldRc3x0e/qRyylCYIKF7EarPHw== sig=BoN38PKhE7iqdtw85xY0ZO5j8MGk85nJayrGnucpupXrqr1kkeKkwhwlrnIZDrJm+f6BDEs2QtsA6qBg+c3nC5C9GB/QtkrzsZ6Yce37p/JV20C8M0JjrmnWcnkROjiLbnuJQ+RTc+JMlo2wvl66FgUA e=found last=16 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWViUYAxxo2+Gd1urBjppN81Rme4Gg4VIlPTE+A1cT/P81PWcAJ8SIjF6PCqgymc393uXTa0FNSiA priv=MEcCAQAwBQYDK2VxBDsEOXz4zLVt/azDIzkHXrhbTY/iL9L0NFdHY84fyWy3Yn4dP2M9LdqcNJ7uncohs++BN6RkaDNSKn0Eyg== msg=Yz0t2pw0nu6dyiGz74E3pGRoM1IqfQTKuRkI6aR4lje8gL7ofk1Tv+Hq1480DOJkxLOg0eTfQwbwksgulbpX4Q== sig=MkYnIprxCfsvHIEozjl2PqA3SROL6eLGUHzWnaDvDzFZ8zXttCnNe7XFCFwfB8a2D/Ks4L/d+eyAPazCwsH80Kt8925FlxJS3byhleeM+rV+cSmdKLsb1JmZAtWyj+/WQ1l5bX2XjE+45N+3K18rTxoA e=found last=20 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAKkqzxSEED4rjJafQBhy4ihd84L0RNhaH9HZbMs6fQgerap4wkYRYiFu+PFTrKHB/FaNfwdDhY4kA priv=MEcCAQAwBQYDK2VxBDsEOeUpQg43gS5RWKCNy7djfWMCQrkTkNIqSLy6HafOMREtV9aXblLCI0iQYlWe+KYVqYXPnyqy3ZLEYg== msg=1pduUsIjSJBiVZ74phWphc+fKrLdksRijy1+tn2LlzRMa3BDeWRd7Lp7Z3zKWR8M/QmxjnhqX1wtaMivo8pTZg== sig=NBM3MTJd0L9Ad6/CmGLaX9VaSzjZW8L6+ni57m6mYcVxmon89AEi+gR9QWTQ9CRcS8LMLAm14aSAtBhxfMB69OS7vAsOJ1l5fx8bn0UJoR1Nd8b3EpgjyUs4MkGnsucCDe7xisSmyMIKoLzJKQav6xsA e=found last=22 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA0cv+RjraAC38s7g+4mDSGsYjLFmg3usf5XO/heZECu4sne6DEUeoHW+S8Givep1uHor6x95W9msA priv=MEcCAQAwBQYDK2VxBDsEOXaUttHvNqieJ07h3prptgZVmp1islJIMNrwn4G5/ABj4+ObIi3iSM48bKnG/axDRNxgRZwHnZb3vw== msg=rENE3GBFnAedlve/iTzY7R3q7tNplIfTd6M3KTkwYfT0rTIndnZ0vDhrwiNWdU7pmWHPwaqzwp4egGi/QNJxDQ== sig=ldIzVUW4vM2x7uZ0CLzdvAFn3JWLZoDJpjuYAXFV6S1PNMFvcNxUO1jpeqLYMwtF9kzRujowg8eAVo4SxwT7o+GeGQRFUAfVnb70o/tEgarnGfZy0KPA8icxJLo8i4MWZeEig0VEdnJzTasprkaHJwIA e=found last=27 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAiNscEfUroiwTwf6UlcSzZxYxGExSkK3S9boi3IM+rNe8+xO0jiIoloGbVNbEzzOdOwT3J7UMMJSA priv=MEcCAQAwBQYDK2VxBDsEOQT798b9C5tmoH5+vVbbE8fkHghTo18R1E46BHGYKdIHo9JeCPtO7cc8lpS7DCYAPUz2oVSWJft51Q== msg=lpS7DCYAPUz2oVSWJft51aZ+q9HnOa+ROTtnwhbCL0bmguKJmlizOGvw2JoYei1mEDLaG/ojrFtWPlc1kUxDpw== sig=cSRddpE7jNjecPDug4EwXiafQlGwRYIS+DJINRZrXMc8Pq5Z9+5M+iIhoX4K0x7PuYOdunbZDr4AFOI18B9T8GRgWg7C/1t4joaVe3fQk0qXyld2t4M80ksKCl+8qt5oD9W3NGzFE5MEn0dOdGZLriwA e=found last=20 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoANTdU0bOCQkfEIeFuQndim1Hf/CeJIFhXjJGOXwOxjhbXQ5mCoHREm2I9fZnkQR9KqyB1y1TwUwiA priv=MEcCAQAwBQYDK2VxBDsEOYXxbtKf+GsLm7zvRxbcrSpfJ48VowAEXe6dmInIfJwZRaI/YUr3Y6sB4qBM3kirzb77ftsunxPI0g== msg=2y6fE8jSSn4Fh2xhBcXasIZVxtV2/EXO5apcSQ6Ak088J/MBo7qZC6PrP6J66HbRpaxuBuAGjk/EGHLgi1+K/Q== sig=u6Cu7M7Mv2fkFuCxWKOSr1zheC76OtfB4w0cygor8LVc5vku0W5skkxlgSRe/Lb4NCNR+IF5k9eAYtJMBcoNQpmObnVYXQLVRAOb/vqoV9C8CazvbV0eWlxdooNjSuKhQ5YAF+tQy4KL2KQjF1ATZRYA e=found last=22 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAE2xMoLT5BDuiBVUfp94/Ehv2roCXoqcow1SkreWZTD3zG2U2Bv0GnkXIrYJYXQOF+yUCF0wq2H6A priv=MEcCAQAwBQYDK2VxBDsEOUVpIRIgg2OyLwZHRWxDnyR/ZYRHHehdcPwVOIX255icMfClYQR8cRy7Fx7z5ZsQDZNV+B3ZSd8HjQ== msg=hfbnmJwx8KVhBHxxHLsXHvPlmxANk1X4HdlJ3weNs7LQbgpowFH2NV5m2cXkkIdv5/1JPQfZMI+rd/PuuACDEA== sig=W1vfErTcXUPiB3/ulgnbtY7Jb55kC7PVIO3HiNyu32ZdMy3PXpsb0BKj3IhryuLtDv5kSTTSMloARlEIKWEHOfPAXZlM2pvL36SDYUi2Xdf1IyZSeUW3vdr3tgFxHCpz8vjXfPWQfv7vUZzvl2q6lCYA e=found last=14 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAacSlr6ROaVrCichSJezleZuKSsRmQ/+TY+xsyS926I2XDBZL9cQ5ZHnkm/3VlfOARwg+n1daAuuA priv=MEcCAQAwBQYDK2VxBDsEOeVbTaLT9Yx0YevzC7r2zI6n35LrH9qpAhofTupz59lWzPoXlR2mPaKwCOmOTpKkggDZ5Fmha+3Q5A== msg=KJfx4ElSMvArnl0uufnJDhiCnBLzW29lpPy6MVPPa2E44m1D6pG4HsyBMgO9bS5pYi+y5gDZnc5KMtJvTaFWKA== sig=nPafoVPeQYBfbGT8k+gdCWuUsEyupgNKR+l1yxiTNZeiNpR4ngpd9hchktqHCElbaqZUTciOFpkADLBoM6wiRJa/yhUyxaNwqxOw2HcfGj5fNTniq83ubDRb1giHvUFIUr4WtEmEWReRxR7qUkqE9DIA e=found last=14 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPttu60QAj4OPqmZfVrxULZB7Z8g5iMswAktyvkv4JJWKQoVWiM7wJ6LxVYi+7nXcz/ppnlqx1GCA priv=MEcCAQAwBQYDK2VxBDsEOTM4u4O0/KkW4ZmDXtmDu5z3ppyRtWYpGkkvl32nOH6OR7mvnKHZvoDLhKZWnwTGXiLFVLvsB3bb4w== msg=WgGHRoGVAzLJyk7VJtzybh4Kce6+X7YU+BDAKT1RXI+3EM9Lx2KjxJIByfxtbwKu8H8uRVaflu+FV6Os9b/qWg== sig=R6wHTseVhpdP8VGJTdgM+RjpppFzeaxHfa27Bs8XEAPxdN/pvaWqkdGdPwVZex3sCkVMyEuy65eAL8z2N0wj3soxw96dYJhnS3c2M0pGbgpy0cW9+gXBcOabTDJqbltjdfw1PexrjnQuTWjgVujIhw4A e=found last=18 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbjJcvWoXG/IPQTAB4qLXaz8Anpr3y+w/DcM7UnwgTO4AsbFqsQIrzYBtknOr7eiVBiZXwWb1PtwA priv=MEcCAQAwBQYDK2VxBDsEOYBSlZ3REE1Clob8jzeE7TSPfhea+OP7uN08r1fTAQv31zUhGIoZKTO9gihdKjhzHbQxIwhotjodcA== msg=+FMd7tr4DsfE7WcbldzPHx2ZSY0T628qFnJjlLRixIE8K/skhlvLqFDIl5iNu0x6YQyNuoCb6Uad4pbAPCajJw== sig=oQCb1+GrUkLIEMJkDoLc8GB+K4xqq57CWqDTsd4JXgQJD7tU9nP6o7mNaqy2byaGTX6riwk6HecA+/SJvZp9m0Ll1MKscTkKclWli8Aa9AFIF/cSrArJGdV2aHfpDuyZ54SZgZOpeJetF+/bVvOU4DsA e=found last=17 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAr1V12asHLXScuKmHdnhrgCtylCHdMl4KBvBF2L0JCjxdxjGmIfhBegvoCtkZSL7MGYxQq4DjdaEA priv=MEcCAQAwBQYDK2VxBDsEOWgFKtJ+Yb+XMcm9KIr5GFCNVDUOJExlK9TbppzN9aGVOuhm6eImMgUtu7rC6B5CmprvGKk5sIRaDw== msg=3MtP5kEfFT6lIGPuPAmXcqZUYIyta+6ezVVQz7i/YEWEtV8WHI9FLlM2ykUIhgRh1VWxrHqF3c6jOqvOvlyEnA== sig=dAeXaAOmFpUO5ZTLWbgt5CplxlTDrlwTSzFOYqsYmPXBvKLz4WLpRlSSDqfGjpyBzZUsuBylsfYAbOLi/sRmin2MLEZbc941jQ/cchfS7xerRmpoVxc3pZyndFo3sYWaKYtsulRDaHSmokkCKGmETBoA e=found 144 iterations",
+ "pub=MEMwBQYDK2VxAzoAYvmO4NqFawVFT1NKkB8XavLjMdQUhBdf08CTftyA9U4/M7oHct6SbWzbu77XbQKOzEAHpeJ9m1yA priv=MEcCAQAwBQYDK2VxBDsEOTX3sD0eZEHTvyIjGeyQB7FpPlkNHTuhIyz6Gg9R1s8LDqtOeP2NhH6AJaFB0FSyVYwVp0/sfP3eBw== msg=dyi3l2/z+tT46ssByViEjh6AqSjCBN8ZMhSJqjY56+5uNOqJglwJmblQttlUcpKg0zpFsx9f7mXFIPYg2R5/dw== sig=NYF6DlMvJFiDNUF2hQpYCX2UTQtDlIBTNujpyBjQ1dbbe+PhciMLKqYX4ltuaA9S5WPXdK+zi4yAqbW56TsbkxuZGYglh+ZzlC/ywtefcxQ12n9wAJNr2omo1xLk+CsK/REOOUI+j8K/C1KodCfoLzQA e=found last=24 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVmteZu26YWbEpPrGYKZvCxRZH1QQLPo9VK9ot2XT37XT5vT7BPjEgxAW7pvIO3c+wPy3YTp2AZ0A priv=MEcCAQAwBQYDK2VxBDsEOWK93U0WEWcF2Rr1CumIK9hbKHY31Idi0JHFj0gsGd+Mn9IrQOF67bh7hnk6sBGcszjpQf5I/CNOAA== msg=I4pg1bZYmPkjitg68cN1kB7HSXOjp1uUxAvVPlH3CcCouSOICUDowz8dY4FHXl4VrXlQ5GhKceuS64HZLFRYKg== sig=4zntSHSmp/L9jfoqzdwDQeWrJdcm7zdvZWKQlKkTj05+BaW1q9XWDIDlEWP8KLxb7Ro3YKesO6YAcrx4eJsMOtBSZj0yyroB+iVvEwH6LBJ1LMBQZwoQV85hJluG0Y1sqJiwtNUgAF6xCYno0kaSbh8A e=found last=19 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXDz6uEzFMg54Z//vGx5EOnvxuiAVBUI68i9C5Au3H03eRfLu1wfqfwWhoHH46Ww1MSZcVcmSXHqA priv=MEcCAQAwBQYDK2VxBDsEOZUkPaYtrxnGjPwUs69/nOiOP+lKmoodaqzf0yN8gtpFyPcp2RvwJ2jv92CLm7xThh44CzCfokuBHw== msg=g8VUf6Vk2ZHD4OqylQDveowf/uBMR9MYJAvKmVp88VXQdGBvY5XuDqFX00jhtjqLWUZxWIxQrMjP6JXddzX2QA== sig=/DsCLUxUztWWZa3FUSSfPdcGPMa7g4DMll6dMxzWHtPtJNjWlJ2CBpKnYGL4322fH9RhFBb+82aA/hWxmQLO44oOoY9QB0XEZQkz2bLlXNYH7rKBYCeMub4x2T8hqy0RHZw66Yzf/pm2x3Jg5PQcfQ8A e=found 199 iterations",
+ "pub=MEMwBQYDK2VxAzoA1DmXRxSmQebZ6yl/BTm9NcHa5whcUhQowISyxXoiLx9PzEsUMyhXp+cT+cHWD67dB7gsCNan8ZGA priv=MEcCAQAwBQYDK2VxBDsEOXFmhg9hacV8bODgZcsXYnnddOUpa0qkAbs1cZPTlbYDnjIfv3JbChwbA9lArO0KrVJEAQaHJViuJw== msg=xXxs4OBlyxdied105SlrSqQBuzVxk9OVtgOeMh+/clsKHBsD2UCs7QqtUkQBBoclWK4nDoMU5YX6Fdx2PvHLhA== sig=8a85b6l00bYG5nc5POPLE1XxtnhwelXm06V3iusfE2SW4k+fsRH7r+YmUbgXhx7pPJKpc1xqDZeAgyrqxQjl/Sp5p62oRfzSp6A4+GP38RMvo/LBeHrD6kdPmrtYI+vzmctuj6OVcswlPh+do2dq6xsA e=found last=15 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3r53weQEmDVDZr3o+7dYiBEtVj5N5ulJ6GMIy9XHHxLsDKIZbCdhOVRmoz/J+9wZI2fvSZVK0o6A priv=MEcCAQAwBQYDK2VxBDsEOYLhq536UW4wuKnxK42MvK2joPw9GOF5iiOfGLBv4vrkvZaGRmcQfrlIPxNXjQgWk6rvHxMzYM+22A== msg=GOF5iiOfGLBv4vrkvZaGRmcQfrlIPxNXjQgWk6rvHxMzYM+22IQpeKepY9mJvsNC/cC0YNKG+ewES8D5C7ijQw== sig=MGYPJzzypPO/gQet3KZnmNQYpPw0BKeEbM8PvtIzAmYnD2DlVyL3dHdgc0N4oX4QEEAbk/y34wkAiaOOVH4YvwlJEUpJagyJV8w3IuMXXEwUnl+fGLVqD2IF+UEAQOjeksEhFUA5kmTBI+y5XZivLCYA e=found last=26 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmeoBlYw4qt5+EUmUmp21lDXZ3A1/671yVYy2F62kZc23n8uM+gHTVgEU5I07cMWA6abuo2nYfLQA priv=MEcCAQAwBQYDK2VxBDsEOV+gtoPVNJ2cUp+PSO58bVfpEsnogSwcl1p7jX0LKOnbzfdWt6Ru0AElmxkDde6IqKks7mLKU2i6Zw== msg=l1p7jX0LKOnbzfdWt6Ru0AElmxkDde6IqKks7mLKU2i6Zz8E/OLaKkLeokKS2h/r3Kdlf9sfHsNoS6PWFSZbxg== sig=gzzINSh+Qy4PgRd34FWSoGCN+tfU9Ofqb0z/DnRuB2/y4kNM6gLUIaabp1UWiukUwedzdlzTQXCAXA6xchuDOXxf+tYIEDyiaSy25WOD/YA4Y7QdFFB9/FeTYnbAEZEwpLO3KJPRQGIm6HBejakfcDAA e=found last=21 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5hjDWQNOPtYgrgfzQM7MB0KwTnCuMI2wPZgGAsnn0c86pr85VqEGjrU6kiRx9qWaf0A4LDbExAOA priv=MEcCAQAwBQYDK2VxBDsEOaGPicMzDMrxF7xRa7cGswWxw4IOF8MyA2cJSZw7v+iuDD9kUeJWWj2rpS0bnm+H2g0jp9xosHItvw== msg=wzIDZwlJnDu/6K4MP2RR4lZaPaulLRueb4faDSOn3Giwci2/ygHc0ts52+Wn4Z+sszlRC0g0fj2E2/44AT47+Q== sig=rb3DKugjRRsGoR/Z4OwknmV34n8ihMRAoONm2vR20eB3iAkT+9HQhCSQ3e5t864PoewZ0tJ8GRqAxueus0LIZdVKE1Ws1l7yd+d/6wDZ2Mvdq2l4V4jc43wy//FGFrtKkO0LA8H/120BYSpe6Er8ii8A e=found last=15 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtByCkKhbh+sDoFv97jkadCrZ7pTLb+Ohh2r19ZljENU4z86OzG175GdFiE/jHb8kmpDcqTthgEIA priv=MEcCAQAwBQYDK2VxBDsEOeHvJLwwYnkmfthiZmPuswRZXzdz3ToaCCZEI42kXqo6B+1jRenwdZbdDIcmVdvCU/xG5kIKmqAvkg== msg=N3PdOhoIJkQjjaReqjoH7WNF6fB1lt0MhyZV28JT/EbmQgqaoC+SyyXCSWbApeESPpcAPoI6vtRRUYpPftqIKg== sig=S47e8ULMMcPKp561IyquSHAOoFjd83LMWTiooczWAfw/Ki+iB+gxK4HUWo7rDPQE2iijAKC6w/aAMDg4lcFP4JAn9zsJ6IL5WKjJ9ev5kmhsoVY/CH4D4WjFwLivFfv0jZittleAo8PZsJSltAYLAhsA e=found last=23 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAusSlabtN4LActPsaTKKNCU0ee2iJbFNE68toFG1/H1E2Z6rAKKy0Gedx8gAPTeEMGZB5xVxa/WGA priv=MEcCAQAwBQYDK2VxBDsEOY2fRD02nuqALZC+lzL2IgtPT1+5qN4IgpID+ZPWvU9XQs9pfqW0HWhF1aytbTuboLcrdMKrFul8Gg== msg=Np7qgC2Qvpcy9iILT09fuajeCIKSA/mT1r1PV0LPaX6ltB1oRdWsrW07m6C3K3TCqxbpfBo37qOqxh2ou07b5A== sig=muB5O0Fyj7975IlKfBz49NtUdTgf/QT00BzB92slyoHi0+PWxYx7aGUe/31A3jSPD5HeL91pO6WAiGeycrYIKqh6cNPKnkcKZiFm8rzCF3TGXAPZRfNx5srlSSPwqUH/FrIYY7Ug9qoevFZ29grlDhcA e=found last=19 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmv6MR96qPco6yzJBLLsqvDVBbfJAo7Ou/LpMeJg2WjrZSiQpHlU9LdNCHkYj62NgM/UUSYStcu0A priv=MEcCAQAwBQYDK2VxBDsEOUgzjGKZJvh70WhpOEFyLO59hudIYV7J/VvBb1Plg6lf8wp4QRC1Glr+N1IPG74BfyKzu3/d9qEsZw== msg=M4ximSb4e9FoaThBcizufYbnSGFeyf1bwW9T5YOpX/MKeEEQtRpa/jdSDxu+AX8is7t/3fahLGfDrYkE2+c7xA== sig=+eGy59SyfA+cCGGts3HncYObXw8TKRWAwtoJMJihvuuD4IsfCvk+A0MglpNOovkFs5Nwx9vd9ZGAgAPFw295rDZEe88J0rdBX56B4Ij0M8rLvPbMzckxTAj1T5bjlX7IVcrRVSfTowrPYJnFrVFzyyIA e=found last=17 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALU4ac9qvd3gCuqEqUWWAtPxgHPNwaccjFfYQWsPBoTxYrE5IO7fxnjWppLzhkprZKR/7JxYerjMA priv=MEcCAQAwBQYDK2VxBDsEOX/RdjO0bA6PThA5jh/v4tLWQEOzQwJt5LnIj/gzeIjNK2ECGfpagpeDuKOGVIwhYMMqOPu4IYmXDQ== msg=WoKXg7ijhlSMIWDDKjj7uCGJlw1Zs12CtlUrXzyRFEGXbhL6IwAB0WbvmZGV69mg98aGgeMRqw7c0Hsc0JsNYA== sig=kDkdymXzLObaifMvoRibHgvV+Jp3CMltTFGIWPYrL7e4VXkjlcZF7HO5Whw0dRTtZF/XiKrIh9wAlb3Bk3uNKqqW9ry8RCA/d9rNuxcaxDt7o176mHVvvRQSZEVaEfCGPhp/M49c1xuckQ/Ul6HSnBUA e=found last=22 s=12 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABdQpNaBFy+v3sR2HpBVRyY4pFsdskBBMcSU/j5iw2+/9ha4xQ1dZUpQhglK+X9dFC6vOzb+SzWCA priv=MEcCAQAwBQYDK2VxBDsEOa3KNeHqlbyHsAPkwIT6j4tMLGZbxy/NPvDabTK/c05V3SUtlmG4HSaYYU4NQdTvhi7Z3jHqjb0tVw== msg=5MCE+o+LTCxmW8cvzT7w2m0yv3NOVd0lLZZhuB0mmGFODUHU74Yu2d4x6o29LVcUYwGml9clDjUgzrd5ctwe0Q== sig=f8AP85ii6Ay1GOB8v4pGCTObJOuwiusHqbc2aJKL6Lsy/c3RbVZfV8nE9ibFIUMhAgWSEGGFfmcAfDhY4rU0yilSDnJaURg1W/DZGN5hhZXVwY4Pmnf6SbDEJdCiKESyM63JPvyQVwAdtybwA2/m/SIA e=found last=24 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAU5g2qVY7uZBcneSxXwedI6xb/h3B38AyA1MwauqS1vHaDETsZlrWrEzgFehPL+lqMH9BvpNTQ3YA priv=MEcCAQAwBQYDK2VxBDsEObLxE3aPPtGC6lt85HWIWwKVUMjnmLoCplvrEMcBu6poNeXWABzbGIQG9F2HsP10u9w3Hcp9dK7s7Q== msg=AqZb6xDHAbuqaDXl1gAc2xiEBvRdh7D9dLvcNx3KfXSu7O2kMxgNyCHmb4Y9nOn9CJYFYZ77wfXet+YZPvKwRA== sig=+crglZL5KEpkLWGXCPhlpkNJXgDATDec/nZenZ5S5e7IgQiF3HovCO6I86GMypqA9xC/dETdQ52ADavyU3hGqo0/4rG92OqCa2798y6wgfcc5j96vWgSWKqy6QQKWf/tAEHoB3RgtfLY10qF/tv9bTEA e=found last=23 s=13 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADUxtj1TRyoKHXGnYkDAwR/tfnt17yaqVfhZ61VEgvHBS5JI53FCmvTTmtymIMawAl5euckJrXRAA priv=MEcCAQAwBQYDK2VxBDsEOcr5ICWImvgL96pNXBoj6U8fO5M7pIoaadV7zd9furXslpOSrHgfbSsjyMoWA5x9h2D07Ry+DULC+w== msg=KyPIyhYDnH2HYPTtHL4NQsL7VlNwg4Py+JSPfJN/cDVtUvug06VCNEOUepSZJ2TkV+V87dlYhk92S+Px3tJ3eA== sig=/hqpnxhi2qvoNT+FMzfuoSt+H/6hjQfDcwFy90E19iWkT4gTA2L8Lh54CaQZFK0gqYROioK7w5aAK656Z4KIfLj+5liBluzkfjCJzVj3VLRPdHRuxhQddhNdqvLhVgYxuQrpe7TTkNPh51hMtbgn9CgA e=found last=26 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1dqnPlIm94g/qG5LCUehYpxlSC7OCmNfXMLTxBfxUzPjpxf2fgreaqssSSQP3+x9SGCqHwyqQVUA priv=MEcCAQAwBQYDK2VxBDsEOc5NrVT5IkR0gTg8hDQRmVSvXE2pT1qPyMEvGGI8EoXldXtzsrDbu7FyVvwWTq6n0Dg6Rzsb7Fyi9w== msg=c7Kw27uxclb8Fk6up9A4Okc7G+xcovdhrAdELX5sfU4eVmyJlbWOGYNfd9bYVBruNdHAQFll8C1pMJn64Hc27w== sig=1qqi9wiX49R0U69FP07i1WilMWPPxt/fuRSaysJUYebwV4auluFDRVB+qq9TaY9n1DIsbcA9O3cAXmSRgGxxPpo9M8XmtDvjZJBUzpQ8q6pI+YDrB/Zdu3iZttVLxk0yP1jTv+bWMryu9y7VBwHZkCcA e=found last=14 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsSdNKBjAhaMYJb5GTJxFvu9RNZuVdognxP/3QqXaOjyEFDJkkDvJ2FBRA+RspsGbh/UhkkRAdFIA priv=MEcCAQAwBQYDK2VxBDsEOfwofgl9vsCAf2xsTHYhX6p5lTlOfi2wUDJVMkMCB8vGgqi50szqnUyZwAwGFqIKvbIunteaddA97A== msg=xoKoudLM6p1MmcAMBhaiCr2yLp7XmnXQPezxaMWtoBRv6hws5q/bc+eKBkl4CiWCyVnb0hcQ39r1ks0E47tdcw== sig=jH2Uy3cneYaOGabmlISkHWA3VReB3oxSeFZuIHscxyXG83mVnP2xlIwesWzMxX1ubznI1GAhQYcAkG5zC2IRrFUxmiv7snwxe4kzbCKROYWI5nFmO40m9J0SYo3je+CDUb3+6FEHjyDabJuZ7N/h3SgA e=found last=26 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoANwPAQ7w4MaWd8bBki8O/S9QMl28sIALYDYvHHVtMVSWFLomCEwE5S6fKcJl5rxN/pmCP/oai18aA priv=MEcCAQAwBQYDK2VxBDsEOaHiUi7U32ngUf6najNMtEfR0lhFFVgkBNZjA2AtaWulzNKow65s4w2j8ehzDysuS/xTNwUkL9uSYA== msg=NwUkL9uSYFiD6CelD988TXmoatiFTVhBQTcP37LBQviy7/3cLpCq6pn+34kTveKJjQ2q2Xz5Ost9sH1WIxpxiA== sig=CM51cPO08TbjNoQVjW+iSC7iM7qMpkpJFdaMs787OyjEEECCoyLiMVmr367pzMHBn9L+pHu4MmcA2zpwe5vZfYk6Acp8EtjEtarF7v0rXILdq9L9PXggZ7oug1f0lKHuaSf5F0Rla1xaylfjBokzZhkA e=found 196 iterations",
+ "pub=MEMwBQYDK2VxAzoAvbTQokJNBGQQZsPH4PzwbCoNLsiwSEiisRkbHP+we5S4De+e0eHvgXhoeo4ZaRt8nNJ+AZ5B47AA priv=MEcCAQAwBQYDK2VxBDsEOUb4F7Kcl8c4kEA+L0DHld50wXWh5VWD4Buu9qp0iD6q4G6dEMNKwXCNKTJCSPzMc5RWHv3RFnCd8g== msg=9qp0iD6q4G6dEMNKwXCNKTJCSPzMc5RWHv3RFnCd8qjOQz5YHbsJ0COkMxMwi8RqwX53/qUkbWgWtB1kImj5vA== sig=o/QLHI3jOmRwHBp0K6Jp5UDbZoxu1/MVNHTIOOWLiUgPqb4PZ2WfkGx+NQfkEO6O38s+KYG8Vs4AVp9tomdHKnUnZMNwyP5znS2a6ptHiYhnEnJ0Sab5LWhseowjp+uOmv+3srhL+QpmqKO8I/fyGD4A e=found last=15 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAR0a7HqLhkn2ZUrUQ1WfS7zKBSliTrFDBUDrKzpS1X1S9b90el4ex+oIr7ihQmfS3OqRDnhIaWVKA priv=MEcCAQAwBQYDK2VxBDsEObsyuU5q0MBx5idLg9rLyAh+7e0+3f1aC7YVYVlxrY6auqJbazviL3PwMdQWJP7RyWnTbrDJ1oHwPw== msg=4i9z8DHUFiT+0clp026wydaB8D/Kbjncdz1GYH6a6G0g44OMJxnKi11FsmtKo0ULxf9baGT41/8zDoU/KyAIkw== sig=HqwWsgtcN/T8PSXz1HR7wzKYQmsKNpZ62UrDy5qGgbH8eQO9yY9d8oukTWs7yTk1x2G48vD/G5mAFF9ZA3rtWumGsAsIF4weOx6hRkBh/Bi1PsQY1rt5gSKXaVZ6Fd3SSMOm/2iN/9VcznuhHsUEKAQA e=found last=24 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAy+6MGha+Apl4ORjRqp4X2Bb9hz6g5f7HB9cp0pAT6JsigOUh+0gzt5WjDy4/V8ROz53flloE7aAA priv=MEcCAQAwBQYDK2VxBDsEOdaBhXxt3zN5djjIRMziwZ9a6ofQCpGlK54bKjyj1oSNjTFBe3BWQt0Y8smiEwR8og3ve/+zfKJRFQ== msg=NP8gaL96IHkcJ+EjngmEBy3o1Z/hEZIkWQ0wirsuUNAf2m8KtTjjd7QDGZWU5PSj8ojdHsVs3cWJgy2s1ElPww== sig=bnFwTO8RRAWLIIVf/7/3I1VrrgJ3StqW3z/rsVMg/+1TWRAALHoFB8iaUBlb5mG5jTapsB6A1lsA7Cp4jOMH8/tgUiPIewkNMZjL07ypJ/tgd+D0cvXP+EPV4W2gXFthQX/JB60UMvz0a2E5JoFkTgsA e=found last=18 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAl/RRvUci5pxb2LDTHOwH0M0p0LscXzLXZal9bk9lFABj+MyhCex+vqgqD0oKVnkpEVWNfk7i3DuA priv=MEcCAQAwBQYDK2VxBDsEOdjn5sfyiWZ+L/zTHvcD9Ki/aSjvQzIlpO8G9lgUv+/pVUQxPmbuqCiI5YFHlLXRq7VfvxIdhOKnuw== msg=/qUJzqmlYzMdf6ptBa5Gu8i9lvAp4zI7wz2JOk9rd8dLg/pCiKwMIGn02AJa99GTJlxp8lFE4RcR7YG3l2/6ig== sig=DcTUL5pDKqqXw3xnwtBGiiMPb1N1IXc2VaRp6dOv8odkF/Lmbnnvu3KghdcaN5qoFGYi4W1A9RyAqteIAsgJ2yuyCbv0wGGJplsmQG069lvzjKtlLoVjR43FcgNrShRTHnKGk1KwoatkZVrik/rbKDgA e=found last=20 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAddTMB4MF3nqzmvPDZiJGNbDcb/DxlG0o7Hg77MA5lhkAOmcH+/T3FV25/VeREW3tBR0ZkntTAAqA priv=MEcCAQAwBQYDK2VxBDsEOaq8F10a3hxHM1bJ8mTV1q+ESSv2gdBQRKts7Lk0k46TPb9FJcHEJY7wWnUoqkgN4aKDg5JOU4/1Mg== msg=NecLGSmvzpgXJwMp6H8yDeKAeUrOvUIGphirTEZSp9/wKaKhjt/k8pFyIuBAnX++p4EXASSAuf+Vjwm1SpIoAA== sig=W7pzo/Z4L+t2tYISGon4IP4+HbesgbBc5IjHlU4vEX74srrV02YcvJZxr5HAccnPW/aQTmXHFnwAVtBULk1KKCOH29irfQJzD3RiwGRUyvqqWOjjqbK3XCkTaQX/3vsYIlz5Em3PP695Tac2DELwlQQA e=found last=21 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAebsxPDZtSm+PFTlOZNwZtRbTCZz7rN4l8kKLxTUGPjZyEH7f9yM0VB/NKJVxAj+hsNzfuGnt9dkA priv=MEcCAQAwBQYDK2VxBDsEOURYmIOujoeIZ/sSNMcjv/IpMjtQJoU075BMaE7Z0kqTlgNkVQNZ/adpCLqDQgu9qRNT/+pOc/5pKw== msg=vvlKPizzq/2ru9wbuz5+jyD4YO18BZ6lhtkKsvV9Y5xaWHvHHtbgmpiQcXGd2gi6ASkFaJb9/wIcilP0dsYrjg== sig=o4tT1niYl5XffEH0c8HzQVJR6SWL/hGSI7bWjhKmX4FD++LAX0A3ADgjT+tJQieiDmYNdNrFEcYAQXxDqtSPGKv+SvBLkyg5JxOe8l6kvmINPwE02NDkgsX0JqFC5QvzmScvkeXcfRZ+JtudXW/QszEA e=found last=15 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtOGRoq0dt4m6y22Qc6RicurrC8zd0JvmS2uZ6StqVvvdI5vF4udr4LsZ8GDwPEATeDhU6Gmvt44A priv=MEcCAQAwBQYDK2VxBDsEOdeTju+p6TDvKldURlDYBWN7HVv7um6f6mjNFdpN2Aer7f2hx8sh2bSpHrFCmA1tG3n/We/9WIw3LQ== msg=mpwPVw3L2LUhgDvzqNFZKQAZE7iKlXUF+rnO8ZINLHkdhaeFbxRMdae83gqwNXSuwtExHOl94Hinuei+uUNFww== sig=230cPITLCzLNp+1oEtDS5F3g8JJ2UIBW9A1Rf3/HzMS99nIazPJhyEpsAzoPVL3ijRjTVmlgb6wAVD6zeHtj0HPghBZko6VLSmglhxz3iXiyoORg/czcrcyw9cRmfdiWQdJ2LgfcytQf5+jW3ygbRiYA e=found last=22 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfNVu3UGhG8bBA0OTNryXjTWbRsUW3L1LGSrqfccGPF7EtTHAE+d0o0eS25uilH5ooXqpbvdTai0A priv=MEcCAQAwBQYDK2VxBDsEOZ0bpKIfjrrLdibz1eBSvK5g90DZYzG9518DuyCUtWCKS1rRs3HBXO5UDIJcMLs5zjvLY+PFO2tgoQ== msg=S2YLzrh/Kn6yQu2hRuwQZAcM2yT7MocZwHcdAQ9x3tIadLugOjbICwIdVofyR9b6vHF6zhh21lyeDitFW8uDng== sig=uDnAu28xUB2HgFkMy8ZZy40UwDPe/ceLUWG+TBLeA36hLA82bx/Kp7o/a2gxHxeIYruEjGTQrUGA7Qiu/MR3zdHocvpTtLJi3u5Zphlx55/JfFxj8P6V00fngk7XmMTaZZqdOeQIFSkzDHFWA32uNh4A e=found last=21 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAP5jh1iPR4YurvXLq5gR92JhiH2EiwTPLq/u8V61Cvb6VcmZGbHA/2lMQv41RspeiD9WDikIyyCgA priv=MEcCAQAwBQYDK2VxBDsEOVSWfjwT6XWZVg6Rz434Vq1vmMol6hzuw5LPtSCIWJAR5Jd86geTQq86VrYklcaTCaYIl88+n7pa5g== msg=hfnPHmJzp8o145krrM3CXQ0N5Bfo2bBH0KXNrbxBB+DBbXEQDLhy9F4/grucnD3+ehdwEOQqBOedBFkf/SNLfw== sig=7U5YkuPb/9cxW9o2ZozyNylGVSX+a/CTuS6Wh8QuLdYNQ4kghfuwWG/bn8PXvIFp+3Yp/wvMLHCAcJZSlAWy4fbwrLBGkGgWlmH+vi/y5u6uFwNZyiKVM4g2FqVQGYHXZ4u8ws1VPiqcYHDuIuWorT8A e=found last=18 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXQvyIAYaCL7b9E0HqZn5q69gwpTeo+S/sK7rLihFL8tkCzRpNkNB9X8l0p4zbDaK95tnxPigDYkA priv=MEcCAQAwBQYDK2VxBDsEOV98DRgR/VkirfE0GsPNPmHj0s+oGSsUvwGmQrf5ZiGZmOJeot84ypakaGluqyLJ1keUl3nO+6EHnA== msg=lTbzNlkUsinLYbwdwPXCe7PkPsiQngsBkOfu7qRIBzU0cN5BIn6Wo2lV9/qA9tOgFPs4IUXiUn+eEP+oAl++rQ== sig=1xpTi70FiFh38/iXZtRj8X7MhyWGWhrMo8TmCgfKcaJ99/KuBYYuPSanYJwXchg9hkYF7zTePrSAy2kZrX9ea7IL28PJ58qW5suc0si3+11lKACwvEra6LBZ9qArKuRUf6EkA5ng6N6QvgKsuTChlxIA e=found 139 iterations",
+ "pub=MEMwBQYDK2VxAzoAd6qK9efQOvhRRZXjcMpfybY+ibn29lkqeqPZjmVfV1guEiCTAaCQslwtVUOeUdJNAe83PXCeclgA priv=MEcCAQAwBQYDK2VxBDsEOWctY/WSohQPIxQ8Am3m2mFd/fCk2Fb8w0WUDicoKxMbWmS0xCfYBZR5aa9yYJpV6HxAKI3qv3/pHw== msg=PAJt5tphXf3wpNhW/MNFlA4nKCsTG1pktMQn2AWUeWmvcmCaVeh8QCiN6r9/6R/7FN8sHihQ8kuysqTlvMJNoA== sig=eZRHXKAWHxobQ9n9kyOgDdsYLKeds8P6Y8GdApu9xhGQpXqMJqLRrtpR12g5OLIjk22AqPF+xtiAjhU59pNZYrP1R/4FIGkmdG6GeKn6Qzd44Ii9v9ILd24eQ387YBCy6YesgMj7tipjuRFoL2XUpQAA e=found last=27 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2/Mo6vDnScLhXUBJ8Jep8X5OztHvnR7+rMRnzBginUamCNN1n5U+2ckVuvWFWb4l6kQTcFoZPUCA priv=MEcCAQAwBQYDK2VxBDsEOX68CfSvUGEnxppU9BDPB8AHGljPWVxlUGjHf/OjIm0g7xswLJx7XOQiM6cEQsPRgzhaoMe3IKoqOg== msg=EM8HwAcaWM9ZXGVQaMd/86MibSDvGzAsnHtc5CIzpwRCw9GDOFqgx7cgqio6PVBL9o3r1pG3fimcOpAZC3rJhw== sig=t96YsjStpS+n9RYtFNwmrP4O4G1Z9qbkzZ5oUcbM6jfjSxArZdQKTw+9FordNs3/zVqjFvDbD5sAYsKcLsurjQYjgm2xttc75cnycWhdUSiRCps1h2g67VQd9D2/3NrBAggIl7kRHM2qGVzp9S/s2hMA e=found last=18 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIixossF2B/qalhJYae8uVQfQE+qZtWt/S1kYiWVJ+kUjhFGTENmSAjrltq3+mfif4BFALUlwLiyA priv=MEcCAQAwBQYDK2VxBDsEOcAT6cVxO9VzKLwIA27rpCg+eKx2hXZWfm9keelZilvqYTosH0D1nBE11s+Pn8oGgdtR+/2eku0rnw== msg=rHaFdlZ+b2R56VmKW+phOiwfQPWcETXWz4+fygaB21H7/Z6S7Suf2+eQxAYGdrVJMbBtFAmaoY/j69JH/nj8Kg== sig=CyLgCcbGmztfRpB9NshB5h03OAYBlHcBQFr8DfgNV0Qzy08oN/MZ2+tvGD076jZauRbRbQH84gQAeDG8lWsVjEkg05WK3lrc/4yjbO/2pXQGxPbR7RBBsZRO4I+UEPVhpS8YkuPzK9rZzKDDReivITwA e=found last=25 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmzrTJTzRJEM5fJj6EWyvjAkiUWc/cF3HkHsKvoiQp1JHiex2SD8sttjPO6om1HaXzY4LsHM9W4OA priv=MEcCAQAwBQYDK2VxBDsEObujMWPGXFRpv/MxNK3OiUBtG4BwZWp8R/iirhBRkFL+3SmukMaxpeHUZA06p9EvczJEZMm042WwfQ== msg=6wCeXrLj+HEA85VO1eJRrnRlk7PBBssAn5MZ751Q5J0vmEUx4NwAVSCDEeaXlpONRTpSTZH9cuJuuqUUPS8+tQ== sig=bNHAEF7EaXhct1ULE1a8oQjKO4w59dxH5R8Aopsl84kEcmRFmNiV+Sy7y9F56d7JyjrHzOsNYNKAKvB/agT8BdFLRcB+L9tANBknZO1waUl4BaQehBbTQUyZykT53Q0nI5wyiyOc+LbY46VnBWKlyRYA e=found last=21 s=13 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuXYHzSTBYkoMNXBiRax4KKMt/dgHoXUJLVOFBsz82Cnqlbw7UjYrT2Bai3GteELFXJqyR+uCUisA priv=MEcCAQAwBQYDK2VxBDsEOYavSoAdv6/NYwtDRfMS8E7BgEyICVw4bvh8DFy7gqGfGiRS44sZNtSpk4DDKLUrcE1U/JvkivIBag== msg=bvh8DFy7gqGfGiRS44sZNtSpk4DDKLUrcE1U/JvkivIBasPOlx6CnVb88L76H7lteQh7mTrclkxTOF8dt7CA3g== sig=POCrv98Z3INCB6Fs6wEkvk3QSZ2Ux1qvFkJhlG1lw9j7GnxkVlersPW1P3KcdyLHkFPUoixMSWiACgyRI4GfPP4C0c/w6es4m7mdDmbadeYRynrLje1j8N/oNOgv03Y1qF4FiljwGjmbByuVUDwYyxEA e=found last=20 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwiySk6/6i/6R7WhKj/jEduU4dQBoqJ9gVsjeBQYZcn52xyhZtMPCNOO2YQz+JMkzHrv9B/dytYWA priv=MEcCAQAwBQYDK2VxBDsEOR4E9tDjtQT7hv0UPw7Xu2agYip8talC8yDkWmOnLbEFPagtDGatGcPFTxca+osWqUsLgyOURcj2XQ== msg=SwuDI5RFyPZd3HLC4cFVhVAmBAGLob8wD9zYB3tHamOmHm5cdbdLgd4WNOxKQfPM5LjEhUft1N9GGn0QvIYe9A== sig=4FOaKaG/ABgUNxLFIPKGfCiafQLvKL9ed4pRmDgBUMuKKTDj0iIahNQZTn2psxvlqS7NOJiVjLUAe1f3UFZU9grALDksqRBTc0QjTHyfABusBaU6o0weO/qwm3rv6C1qY0tmDLekUIghoWBioY4S0zsA e=found last=15 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADBlDPlSAPJ6NVUvVcNeyL/ccYOjEPWD486ffljDRiXcFUKVxI/c1PP+JWtRWFkRvzdnepCDI/0AA priv=MEcCAQAwBQYDK2VxBDsEOdKRltXJ9FnO6KEujmUonK5eZn2NTiVFMp6rMU6M9Bf9jbKVweQCb5oGsiPeGbtZqa3D8l0HLgjIXw== msg=gfiwzfFahcMjv2q/88ndw20XCB35FicYMkfmAUK0AxLmHXp314MtssuJ2kSN9vU5tKTUWu3U+16Tx/fIOCNNzA== sig=m10YjVuegsKY5rBVxukK/yuQoRN+ZmjNNcwwreVKhY2kzy010nZIevjNl93ebVAuzq37uuG+qKaAHGNsWDUWBjJbMFTz1acQ8aKUoQoVrtw9ryJujlPOaGLPcXx01fuPM54poJ4WtT8D4s8ThAId4wYA e=found last=23 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFiWxT9vwRe0dsSKEpcm2qZJ5tKutcer4ckVgNbNf31Kxi3Ao2mYXQmUurZ7r5efDQHJEEsSuhfcA priv=MEcCAQAwBQYDK2VxBDsEOU4BdCdv9jx0Y20mxyfsU8/3BGbhOBKQXsVWz1+bbJtRt6vpvSxSDIoLkto9qevNHY+Ki+dhdRRTAw== msg=dKM2heQzEuNPPzKpw0hOvdthaqJOVqRxG3LK4tJ5iUNZvW3F+dmFdl0phsxDWsOjn1TZx2ybBCcza2pgE024Fw== sig=G/7BbTHE80ItOkGbkHHdbZFVGYtMG7+Pl8r6hvZVvV+h50R8ZMtNYCsLP22ltZayMel+CPWkMq+A6yO02HFCnHXNITwOcbWCMiWy7k5ub18kvsqCBMx1aJU5N3vQe/StcrR8rzb8R/XXiSPslbdfrysA e=found last=21 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA0Tj+oJvlTKbVakc6D1qNCOHrW5sO5nh2HFv+ZUEzLIkbeybzR3rve5d+8/qwIca6W+PHO+Mz+4aA priv=MEcCAQAwBQYDK2VxBDsEOY67ckFfdjENnrU9izV7XQNhlJIBGR1GEJjlxh3bReHiRpwdPRDL3YkytzkxsUiO6dir0l6OREc0Ew== msg=CBCNYMWKB04K86Ml5999yusb/NE1wmRwjItUJ7peJ+VST4D00EJGQgxP/0Xjfk43xM8FHJuaxVsfIvzTaRQN1A== sig=0HaCr3Vdv89HG23VESZmfY2kEtOI65NjaBdCEdolXvvPZ+2Kom+TEpaHoDOQ1//8WpLsta+81OUAXxIAIWWH2hrXeaP2FnC/zr4eAhKfMhSUc8BceFqojOkMJW11er5ekE8BK9n8cOHbG/CpCDUsySYA e=found last=19 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAA0hVqR/FtKm1e6XKeqe6F6y3DL2tjyoZRCMFgUg4/7jsqmtiko5a3bmZM421sFumGib3b/NBwQ8A priv=MEcCAQAwBQYDK2VxBDsEOUD5SnJdpgOxTJQokBmLcA91UrkWHn0ImG6kGKz5YADUGfMK094MRo5ZNUmtnq5dqRlFd0dalIsaaA== msg=1FLjBDMOCH4Vd1BjYnokY0BM+e0froAz9AJn6EkSxV5x7u02GWS7Yyjvm+8zNruNERHXDKg831azeJWLaOdXdQ== sig=FBWJ5G8zR6TavwuOCN5Md/43LQ/z2PuCj40K078S+VkuhCwh0mZHCizeEPJaHPKGy6NHHZFf9NKAg74KM/GuaZB72/KSVYGzbxrz+IeKhJQjbt8MxU6eGlp3IJeedfV3lkjpx0quhB3gwSyvywS+zw8A e=found last=26 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAy17BsJSEoU5e9UbucUelU/I3iag/kvaOeXje7nG3WjP6frWJuDldlzphqWm8LX5H+jCGBIDuPNOA priv=MEcCAQAwBQYDK2VxBDsEOcuG8TW0ALH/G8DDkvCdN3CMr2ZFzbD+LirGqq20ZcEKVBBP0lJQVpOkIfzKznvCfAxXbus2P7dBHw== msg=OL5kFIgT4ZpNjHtzNw2m1erA06AZJ4WUhBviLjhPWmBMWky1Fe7lTjEAk5oGNPHFqZ/eDxA/+RgTemFuoVtIpQ== sig=iqk8H44pw1MztBZfUfB8jAzJL8rBKqsJ9FAx61kPYZrQr1RB3lYB5KZRQOfCQLRuX2cO1go+MbkA+8qDWwbdMicJ9fO6UGerS052cTpCzMZJdPgMia4o9pCVte+l8plcjUZ9MurzQFvHGIlO1c7IzxgA e=found 197 iterations",
+ "pub=MEMwBQYDK2VxAzoArkeOHPx4f8g70cI1Dfg4kRNbeJ4aODbtT+BxE2j/hbwI5B4OMKKmbLxdFh1ZXS10dOif50iQldoA priv=MEcCAQAwBQYDK2VxBDsEOY2dxhr9wmAYiQNKSKSO9dDt5G2q7slYUTUftvIB0sQO++CNnbKMGF2JnHbKa+Sjd7kwaiI5kg7Qhw== msg=tu1xa9JEMrUm1EQ/elykeXmawbrESI3qo9PdOpxoRPtCZffbUIMwHkEvWgJTbKJu19ADsYuEYqlrjEHNAKKfeg== sig=DkTVGmkR6eiU1eh5ZwG4N9K7ApjjAktneoi8zNTX+Sm4sR5ewZgiPUcyDEZnziA7Z3d3bHeVmOqAfHoh+ytgS7b4jqB7C21eOiMZNWnrBvI6wXkoutZRZ8UWww2HrWVktWEQSArvecb4wt1tQVo3gjIA e=found last=19 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7C8t8qFjmKXd/CDmLChpSn8zVbOEFZOUCl5faTRu8dGioW7Lu9CQuUQymsgDXJd94tIbyMEemOqA priv=MEcCAQAwBQYDK2VxBDsEOevAU9r2IZfS55cshmACn/BiB902jHoQAfA5b1B8li3qSTneTuOFOIGGQJt0yQifTACBrrEA5RZtcA== msg=NpDCnhYnuhdu6lItU4ob1/IEw2NAkF3uzIC4SAf797Y4aaNnQg02scBJ5A0W4kRWPuuT0trxou3Ymg7w/WShDQ== sig=z1u0+P/gYiBZxmkwyzndF9AYFOgHJIQjdC36vhPiRt+re4VVQCk9Glyi4xErTPulnwvPuMSU0C+AxNjf6Qig3vd1RIGbeQhksfsBiYm5s/XlAF1QNGRKu1JCFO50LUDK21tZ+96HrhVQmzwW037vHCMA e=found last=24 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA13wi+s8vDqdSaM6FB2QeTjz2Btc6iRZ/T1NMAecbLPHdS50xPGRGKmKqP+lAh3gTLL7pkt700vQA priv=MEcCAQAwBQYDK2VxBDsEOZnc7DNyB4uyEx6FveC6AYxdxZ+fn4jiyfg7VmNYlGsQmI5fJjYISj2O7ni6tGS8CO4h15ga4hvn+w== msg=3qU5+vHHcTCcNYbEdHBNehlsPWuvfH60oZQbf/mQZw2mBFNjqooPtVjh7m1dLQltUU4Z1SoygFTk2zp1Teka3w== sig=U8i5PNc1lhCZ/LiLZmf5ZFHtvrFtcuZi8gs7eecJMd9LmDMHNtf5NgEAPAjy9taB8/B5T5KI8T4AF0LEGaIJz3VRM9bojrKvbTieeNTAq/9rFAW5hKxuDHAsB9nRCreM9Flx14U4+pKQNlYAC5c1MzkA e=found last=16 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAeHGbL/6XryRIQK0V5tq0Nq7la8Ob4zXaE78FJGbx/HiPdO+fGLxNgGXHDCDmFpai2vVOsZGtbUmA priv=MEcCAQAwBQYDK2VxBDsEOYKECUi69XkqPjU+jAORmKsLVccbOx6lT3SPxCXrNJTOV22JCHB8Pjtwom3HJZdnJ7h0srGLwXAYlw== msg=e1awEhONPnXybUkqEUu29ia163IWta0icUu0YF1eGrQecVJagsSjXlxLRlynaDnYmTfMOPy8acQ7I8jlm4Sc1g== sig=hGmryIw+PLlqVB9RvTzGSpCQe9O2M27VzhOmXqxItAcLEVVj14qaoCcqr1TGPd63lgm1MG6E3+IAQD0gMjRvYr1e5foIywDA3X9X9xGmciPQp1TljY3u4K/rogYSp+GvT1KThvEvzk0KLc6VPJCZaz0A e=found last=16 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASUyzE0ly4onebmAa+7pcV5/GKNVeH9DHJ/UXg0OBCfpqjKpb7+CijMF27XxPgeqhRASJ4UHtoUWA priv=MEcCAQAwBQYDK2VxBDsEORQyeHcY/FV8EEll13fBREFHCUn5up7ByxUHPBtq4YKh4lygXXtluG5IX+bVHNhg4fcq7ne/n69QqQ== msg=HuXSIdfPX5FWe6nEwxlCCO2ZRLSg+37fJiOs1J+Xvsls3v+hEwTZ+W69+TlUQW17XeQ33G6Aryq/GC+x/Sg7Jw== sig=7qkxE9GOqr2xnYhFDHBefT2nDmSQ05FselP8IrzH2VrZ5xv+upzCP00Y/5nTXO9kq5lzq8f0hRkA0H1by+SKaQ585QWcOS0iiU2msKK0Y02fpE9mfQMPzAuL03830Ju3NmcgVSNCdTLKLJeq723TRD4A e=found last=24 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABDxrqI1b9BNHk5OM6TPSU0mI7qlxYXGsHOEggTSvirnvpTb+2O+FaXjVt1kQvbKFrMizki3aAPUA priv=MEcCAQAwBQYDK2VxBDsEOXmOR3wyRpqlp72kTqdIlm0YGRXY+GBUZzH6w0VRMKTB6xTbHhAF+Qugi0EMoiWZQ7kiCE4c+3DDrg== msg=U9tD8lPndycQ2Jy0FQN7vyEgx++qASpCk2VaVgOMVLWT858WHX4v4TpGdG7rf3LMA68B+GFP1DBxOreokHzMUQ== sig=WauD77qAkwnYzsSf/yy4uRIPl990uuQqUP7gd3yIN4UldDuyhSs2azNWoh8FJyNOjkSLnjtDjE4AUzAs8LM6oFEOgqmtz7j4ta27/5Q4jAxAS0LWUIY2oRUnii7ynFL7jCN5/qXbiV9qos3ju72e2TwA e=found last=23 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6i7ID1VaR9MFT8oNHCajn37A6JwXIwnLe+QMrmcWQk/vX5fxUXrIsi1f0kwfB3ij59LdnBDFQrEA priv=MEcCAQAwBQYDK2VxBDsEObkzcScEpzYWxRZP744a+R/xjIKzd5/qiW3RhExuLct2TTzJV3XnpcsCFNGxEeL5J6DEtRvnSbaG4w== msg=uAY5nh2yDthpJ2MhRPjXTIu2ZJeH6J3nPKKvhPmQUwYFr9GPmCn6ZgtF5HBeFXShLzg7PRKucTXATAhgfBMqCQ== sig=J6NjwOM4l1QuYnTLCDTyewAb2PczV7Nx4N4l9XE7Rtk/JZDAz6vGKV5vUvjJJSp9eQ/EMzGaD3aA3am7dhyFdtRfuNikc7k052DJiKAkFnrZUDNB227QfEEjLhLz7pdEeAP8JZN1yjdK+/t0/Gfx2TEA e=found last=17 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPITU3r7adV1SbBddZBvT+LMSJB40hmwGMfdzR3Ul/+gTJRza1hOD+Wikx6Ql5QXPvLaOhMImCEkA priv=MEcCAQAwBQYDK2VxBDsEOf4NuIvbEqkTybGqJYPxHQh40aIeiVU0ibJIesUS/A73TV4ttjOSfnPvbUzMpIlfnhv/nQD0qGTfew== msg=i9sSqRPJsaolg/EdCHjRoh6JVTSJskh6xRL8DvdNXi22M5J+c+9tTMykiV+eG/+dAPSoZN972MMyIffBizG7DA== sig=12sJLr2HcqHKj/qreOSMqjyq6J47IddcoZv2DKjYCeYCQv5EUJQhPbZS7dVoWXiZhZ7lHt3OwaGAsn18454FvNXixHOHCzEsSV0qRP2DAfSQ/Zm/b6jE0I74YDF2X04LIeWKqqkllwoIiYkX6JqL2jUA e=found last=17 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqhjFKsWeZneFKaSU6NpiYZOPuEqwTu2FkTzjfunbSDrXhOOFI//I5WpqYnvdXcwJjtA5YI/CmJcA priv=MEcCAQAwBQYDK2VxBDsEOV3r9F6INgk1RCHiV++u/l9/KcLUdZViIooe3H1XG+6B3KLDPeUXdJS1SGrn+0gbvXCxxUmhTCLCyQ== msg=Xev0Xog2CTVEIeJX767+X38pwtR1lWIiih7cfVcb7oHcosM95Rd0lLVIauf7SBu9cLHFSaFMIsLJn6TDDQPB8A== sig=bdRtZd49KMNh8Jwm6DcCT1d4Nww89eyl+daMjEuxvfZpTe2ZTNLMQYZq1glkdJQcqueXK/bwUSmAtyMtqDCTSY8lRYXQnSD8laSd59RDfcvXSTWzp+y9MOBPSnd2MfZ7KXEldt2FXUwtnn51lFzVLC8A e=found last=20 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdUh2Jqi5QX3FmRBXJlx7AvY+wVX0KPnmzk+GqbdivS4nBbNIyCEag5tsA8JTmqXqlC1HKteJaSAA priv=MEcCAQAwBQYDK2VxBDsEOV9yQNIus0KFzwlWMHnn05tQSmNpQoRv1/s7NSV0iYVZi+r068KjRtae93PVtQ+GYSMLb1JegvAZaA== msg=ubNgj1dhMPeE2+nWtnrvhf7+onM7HlzaVJwmr+6gB2bHF3JJrQx8R2ScV9SjJaZeRPSa9iRpD4N96rvw8m011Q== sig=ryE/MKoEXt6xSf5AbMlLKumXNlez9eUU1dPHlRPOo5g3riHuKC3F+2lCL1tRUsipYZvPXDaNs98AY23+lrLTRG2yhRi5mDe6LX1bV7NeaYnFUA7N2IMxqg6JB62tiNz/3mTLYONwuu8f06s/5GfJ0z8A e=found last=23 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmtwJ66XmHnBnHdZhn41VE1gnOG5smosQ0qgODkB+x9gJNAiAtm3EKvMEO9ILlkJFYyCxV/REFRSA priv=MEcCAQAwBQYDK2VxBDsEOYxkRqcG+1yqiK/uZEVgHqClOuT4O9lrUv+ixdRLmDrScBy65TU7llhQrvUWaotuf4npXjYO4LHEVQ== msg=2WtS/6LF1EuYOtJwHLrlNTuWWFCu9RZqi25/ieleNg7gscRV9HIbNSRZxEwnOAEt+T+u0yjSxlEjYcs6Rl4QIQ== sig=wvoZgmqwaeH/cynIoTafPdtnogdfCf1IZwm9iF2aC/FfadFi6trHLUct2j/sbCXrrEjewSIMg/uAhffGHdqLPY5+6GxGVMWKSFb7BfBZuPi1+gykCh8S4LVWy9hZ/TY+YcjDXBJN7AxVa0F+qlPT5jsA e=found last=22 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4DX3nkDB4clZTvLWp00jiLRNeDXC7pY9Dqs9yw3Zuu+ABUoR6ZmhJPUSkVG/+bEMCrLjiILCFhqA priv=MEcCAQAwBQYDK2VxBDsEOWZoilnd+ilFhiRof5Z4PFtTSi33vmAYjbW9JcRdWhFI7Utrdob9sDxXfRV/oEuVus++IPLzor/wVw== msg=0aFm3FbAXggjGhiz8hs3t7iySZgfwCI4sKoLhK7bIQcpj/Cu6UBFbHXDHQPRZTcOovyq0YzBDo4BSJP3eCIgtw== sig=Kvyx3MqjBBAIcym0Vfg92BMciY0SQPeRCk3L0QHUGYF4qO9UnQoKjBCPsMMxkdCYDqqGFjXCIj2APx1FiBqKwcxddRvl9yUSOoZPIQ3C2NRg5KSIw6hDP6r5hsUI+4xcA3xcX6wbGnMHwlNWRGOeXBEA e=found last=25 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAKbm0p25KiqzogVuNWjCyfyeJhHr4Dd9P4O7U80o3AozmpfHIq7LX0PyM6NoBAjS5TZofH8RXHHKA priv=MEcCAQAwBQYDK2VxBDsEOZYfUjkQAYvVmk7Rx3iouewZB6kJcvhFkqFPCop4XkQveVY5Q9WAUCpOV/x1ZqS035I6z1SOxFSSxA== msg=vIijMflAyGJrOhgtCfcMzTr+VP4Xj1JmcnyClD72HiVT4D77rWZFzjc5xc0aPJIr3Ga3XW84EuD5BfKaGM6vDw== sig=r+GOG32Z4YloqoUdINeOWEPFxgfJhWg9/6sOXsPuFgT68tN034y6P2rYhPoXSedSV12M2hO4BY4AfqmVZfe7Y92iLlVGKjvKJPiv4g5XAQw0lDYBfOz47R0FAIw/UI6DwOL6awuM4cYn0aV9o5a0bSgA e=found last=23 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwLkOFEWZ6b90SzCLm+Yq2TvXsK4ZsRRHduRUeMnqxBsoiKrNSk1cjpqvnEkrV6jyKyjSpHarz0gA priv=MEcCAQAwBQYDK2VxBDsEOW5ExwKB5MOSKK3scqhnY9CZsmvDk9ebQTrOXWg1q6+ALv5LqHXOcLuP5fjlmzoUZ9t6UWGZ2akXSA== msg=EFUKIv0bYtJPbtYcLsNLFjGjCwmYppoIP1m3qwRXPtbZ30QxcVlokMjZLh3tI5syqSY5Kj3HsV/g1EOEPkVqUw== sig=aLJYStJj6HemGZhKXO+8P+mKcu19o6AqMP0uK+UQOj2A6cF5Yi/A90a5uewD3+T68Vpa8Few3M0ATz7DZO2YizhN9iEVTcIime29MaVcjWIGb5shTXC/l6SpNNQweduS01o2YLtnmCZc5JvYDY6hzDYA e=found last=17 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAt4hC6xIRne2Z4Oo3wl5FLfsAPi5nIGIQXtfmWQDP1XgAVrezJBXOZOisBgvNMx3IebW6RF0UYcoA priv=MEcCAQAwBQYDK2VxBDsEOQWgsY65l1EoT7JHRWFIQwe8WbYFFdIaShXqeNC5mDULQ7ROcm7IZHFLDVpNDGlkV5lTDCqvsTD6PQ== msg=oLGOuZdRKE+yR0VhSEMHvFm2BRXSGkoV6njQuZg1C0O0TnJuyGRxSw1aTQxpZFeZUwwqr7Ew+j1JLxokpnA9gw== sig=hVpDFmSRZeurISKBfs5amkKUApQW9E2LQG0nPjetWIxfRba72L1D/tLdU8joqcP4b2cahseNmuSAeR0mY4H4Uzt62uETOe4RX43GfUliz533tSZSvXEBc1HPe+qz9XRO8z+mXuqMs0IqDkG+ycA3axYA e=found last=15 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2ulu4yGBgXZCv0daOB9+delqCVkuKVw+j7NGoGP1MoQ1xEFCk7nRdwY3v3HDUA3CEbRlbYbV9ysA priv=MEcCAQAwBQYDK2VxBDsEOdhZqCd/P8EexFzhOnzHIfA06kNMwNXhT2CxGjgYNHgCkSO5WcBXHyp2+nDiwpMdrPcYqLWukKKVkg== msg=lZJzT/j8HgSZlr6ihX+Gv5Kk2F73Rb+WeSR7zJ2sh2pBzRWvyZe6eOBkAyabBH4RkMwg9aSzrzoF6mwzCv7oSg== sig=mfb/E9IBzc4C/5F6LFVwjSTkp0PmvLRmPrkdp1mJb58kbSdhuc/Xa1O73/dObJS/5qn07DVGG38Ar8f45o+DkJ9xTezOgcjJ2FZjUgHLM4jhtvy+MqBskNDqhTumcHZpCHP7b6dhCTsQQ8Dm4mO6SyAA e=found last=19 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAX+6fCYCJi78BIg1ajt+wICqO3TOugAfBrdL2BsIvyHEl/qvmEGsyFyvy6mr4hu//jYbsivvBQ7wA priv=MEcCAQAwBQYDK2VxBDsEOYTd3bYhyPRSdv+93LRptr67KIcdQPH7dHiQ9IHYR4OkGyHgFxNP0p2nNa5wmOqJUpaPn3wxcoAjlw== msg=Hp90mt0B+yHKQiNFq0cHPaWGqg2fz0OJBZzvsbAYDJeIkEEEp4CT+WfrVaxfXBCgQlvDB2631YhQyGzzr/P72g== sig=xYlhHUXRxenfGL3kdQ7N4xeQpTafxtYg+nAWhChDoVQA6evYiP+ijJGDRwY3nkr13MhNTR+rpRKAcC+rk9130qI+oAn9LLtV/GMItVde0LubnpoOqNwRf3xsAy//LSEci+dNn7e6VyEUGB0JJCcZ2x8A e=found last=23 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATYgEH5gt9MVjbcwpPhXs+7lovgvwwVWZUz826wH+Gk3HKLdyNlECHs216Yxx1ZFTo75PuT5Pf92A priv=MEcCAQAwBQYDK2VxBDsEOePRdQRdgj9HSBNUc0ZYQ5oL7Y0nESwqdi87Y/gI5u4ttznjx1d/1b8k9kdeTRtnyjiSUl64iIxN3A== msg=RHcsTE5o+75CIH0qXKeuxf/9iVyojmEsf0yfZhcsDw6tIgvfSRhGmmWjjQ1XSL+ZwTDz6gNz5lp2lAd75F2v3w== sig=1NnYeM0E7KAds+ishyjf6BU4zdfyc2nekOhpjKDxZD6Mz7hXpE27dT8zCscQZr6H3vBmHKBO/scAfZgWkP3rJe1iMAMoAf9w7UmkldKgIpTfsrLp+YUHWnxXJNPxSEnQa8K3iSk+caB9tacoVU2WqTcA e=found last=18 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAxatQ0QyKzBjZZ1DGrRBAefkK0/V1+Vc4cXkgwGyhmihT1dOL6gs6m5Ze2SwwWqBHxJHee6qG81QA priv=MEcCAQAwBQYDK2VxBDsEOYdyo00k4K9aiIcyf49G/uGUOAt4L58dqAcJmyhxqXtO0h+eA163nFslTS/Att8EkNLPpR18SWhRFQ== msg=GwxuS3ovxbUQGK3TybTLt/CU8guTyuSpUKCXopa6zZW8YJsaSSj2ZygAKKP5I+iWA+g8zGhvY8DXxAVCg4/uBw== sig=/mnpuApfV7chcSuO/9+nIWBTXnXlbiM3Yp4pXhEZ7CnQgmeakQxYBgqAxvMksbHKi7d6raB2/zMAYFDnFeYp0CRxApAiFY9OKzrMrx2iAqRWCmHqqn5ZBNEXYn9bIkF5U3cHeD80/RMAcadv9vE4DToA e=found last=20 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA+uoR/QF+zdPwCbUOoUHsXnFnsrLZ74S8jKZVV5crpWJsku+LMOo1fuNRaErJPHdCNmxjE6P94lOA priv=MEcCAQAwBQYDK2VxBDsEOTAVIx6A99mNm4M7idUzC2JDZvGAdusXmQ3HW/s5SOkSchdTMPWZEkTM+Rwi24+rq+Tyd4Uyg5B47Q== msg=vWQcd+hWku+lEpo/tgAbUaQL4D1pchL8bmRXpaJ2pijqRluWiDOuc1W5z42I2dJAArUD14dsjZ/AOap8KDwiGg== sig=DyY+JHiXcSETy0dV5OWfE+vRo5EU+FC48B8UzgQp7sm5D6jhLS5jeXcAreeinkU96YpbaPu43AUA1tedLdAXvsszQmYWWas1h8snUJQki3vzwnLok85i7UxSMMSdQ4FqKohjYJ8LXXS5/GVDdEkkVS0A e=found last=26 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4RGy+g6xdmzJPq5GPxw6+Ex7KwOX/vJtf7DdVy5XaXN51YHNkLqtnxOrkvSfsbKfRcAsynAYzCCA priv=MEcCAQAwBQYDK2VxBDsEOYWrgZmoGvYAQ3Q+imjMfBv1ClIl+Nb2S1B1tPUAxOyZMxtnslTE8ohpP0XzLJPrJmA8Bv1QPkeCig== msg=b6W95dzW+cYTZ/PgEbFNEK3p3YO7juZgKz5tuBDIZG/hZS7h2OijADWnX6go5Vwa/SDZT8gTsaPywsNRaun2Yw== sig=9GaDwHaNr2AnDiReINCpscY8sjkModKzOHkErPkCZGeMciQlPOiBoVFuHk6upJ6RlXE18+tnwYkAtuCEZxkE9TgYHPV6BnmD6AtpOtM/xoDF30nHbTJmaexRAsiyux2YfIh2uCtvVsBHhXh16dTc2jQA e=found last=16 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZ1u4LZYOnoFFLb5L8dlBx9fCU5tBjCdyvbcMvkh/FUU5zcZ3DpTO/z7NtZQM/OEk7SsNIn9qYa2A priv=MEcCAQAwBQYDK2VxBDsEOVvvwSoI2hLliZ1OH9g+/8pKA8bG4mcdL7I+6NvwJNLeKUgetc0akwmvmVK9lGrf63feYjGb03Oqcg== msg=x+ZSg4pnYAwfaiosNycKlg6zyOidD9IxbbB5n4u/08QbY6WOJDi8HhMn/fUGJfz0DaEGg3OkVXS5L5xaaIspAg== sig=OmJLI4aNUdmeyop7H67otNH5Y4cJkhzyo3LT0BnBxljlnKM+f0M5NRxpyPZSNsgjzQLPKOF4PBWAy1OAI1wwsO+HX0j8/75zuga4SD07K9yFJScQZF7k0KCy8KRcjOKHBE1lVHA3ReEIQBvJA5yIzAoA e=found last=18 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA8DOyPHj3jHAkKVIMBvGvS3TMnOErLg4NJgnKRD8amQdB7wyUezPdp+EF1YMOA19UX/WJ9IubENkA priv=MEcCAQAwBQYDK2VxBDsEOdo85gQoay2rpL+C4TGB6RNYNthV4AraTWwwgHAmnwXob9KfE1mCj/8f/htHUUkT7K9Cj951S+6D/Q== msg=j9NJ4I1Cw+aWFeG07AILG7rtdG1Z6+05receKd7djn84X2m4TGUmJjrLcQ0DGz+EOZHWdjJZs2nYRnXjx1brAg== sig=E96zbmnskynKViPPdrm+xuup2kWRVCj/Na0T0NYqCN4TmauesE1nPe4efdssnCE024ASMxhqvneAKz623x+uTiaAGCiCBMXGqYxCERK4si2MtTU1hSTxd7q2EnOD3D+QtR4YkYFMBzw63xzr34J3vBcA e=found last=24 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAKJUennqR2Y1ZwfjzPhDepUjgyQ/dFB0J1DT3gqsD6VC+M/h3i73tSwwBJ/yyp6nuzYNYi0ydjZcA priv=MEcCAQAwBQYDK2VxBDsEOURVPXQptkHmNkVG+G3lX3vhygEo0M7Y5k8b1WWhdsdaMQxLPtDORh0C3xXky/8H+NPcAFhBcvub6Q== msg=RUb4beVfe+HKASjQztjmTxvVZaF2x1oxDEs+0M5GHQLfFeTL/wf409wAWEFy+5vpkOzWfJNd0HORzweYnY1jtg== sig=OyHe7in112rOc/J3+g+jfy1B8bqXUkVWt2kLMmLrzBZzP0yeLVTQ2proRdyEvqKbOZoTlugfM4QAIuaLRT+wyDEOJiuBkiVZEONJ3X3bYAGUefuScI7ZyWthuiG+ZbVSxE3nR8hqr8gwYV2tMc2EYw8A e=found 140 iterations",
+ "pub=MEMwBQYDK2VxAzoAENEFLX8K/aLuw7KCArn0wJoPRjwsROaw1Q5qpqwrdZvNvZZj1DK5Nzj8jbjhe2YNmILMTqr0aKoA priv=MEcCAQAwBQYDK2VxBDsEOa8kRS1pVAwC8AjXOIftd27e+mr2wnJtlkfkR0C8nd3Q/wiAbqW6oAx4lZq+bJfv16VSIwn1ZGvR6Q== msg=eJdGqBe864+4BUYajSWw9kH6PeaJU4efrw5ZJQBOrgwyjjdY1vK6tqd8kXN0MQViO5SgMGNLrIfpmsJM8SbwfA== sig=HTq6yr0Td43O3zvmCDluzgChbaGfW3HjShb3q+iHWgaueXjwMhLPQrtWj4f5eK+xS71Ls8tRtDEA91eft6wUCaQPJXb13Y88lT6/0vuv3xwEgCxccYuTKkcu3vDV33C/BlsmEE1UbDwzei35tiidGCAA e=found 201 iterations",
+ "pub=MEMwBQYDK2VxAzoAETfWlZ2kV8J5DMJ/UcecDZjsnvwlGfNjcu2EqhDsduHnQEFz2UXL4++LO29qzIbvE2iupZdwYKoA priv=MEcCAQAwBQYDK2VxBDsEOQF2qwvhc8tbhd+7rmNFcKwn+gidEmHkqXEBIXZZS0yivfnV6Y5ZK7NyyV73Jfzq75Vw9uBgNV2PXg== msg=5P67+/OIEwBjX6IlPv7LFh4NDFOI2FIUzakDmeTh07iOmCkCA8YGtZ7qNb8CSBTBOAA0BUqFePHH0rqO/S+hdw== sig=BA5T+DmI5PfLQFjBEwxKgrSVef5w9Npd8NSCrAl2q3K2cU5Q+IoRKS75DI92jLU2mceqPdffMn+ABNizUAv28dTbJbMjbyCOeVLUNKfrKfa4TFdkAGDPI5IIAcS/uOMl88r8RpKpLOO1WzxK/ZZF8AEA e=found last=22 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2H0EzZ9vP16zovD9z/1kdF1tT6EhswY5A3mgqxWrbTGPUSB+a2n3uQ5P8tTzrBaHB+lZIaF+YP8A priv=MEcCAQAwBQYDK2VxBDsEOQSvpV6NIGj0ngDh6zTSl5SZAGh09uUUx1K6Gxca7b/YMFwv3OM52M/bODqVBJvcoPI6pD51/ysBcA== msg=KeSnUGml26s5EagwP0a4yvu2x7rHTSxUsuiL0B6KVdutdNm08TFp1kMgIEqjQlWZhZZ8TQQU2sD5+CB0ZEdNLg== sig=2ZeKPwhm2Qp56R4RW36VDfI8D1v+s59P68A+M7mKV0wwBugM5fZ9zE0baJxDuEGv72xqoQT8RyAAuHq5gJk0NSXosnCdKeBZU7o1Yyu1TrZiNO9jtL9NBDOCfNR+OoyH1MrxlXzt5zeqbMZePdmOIg0A e=found 200 iterations",
+ "pub=MEMwBQYDK2VxAzoAIxNZPuQ4qlj33QGK/vUFufnHd2oJoapbtUchM4eE/2BToymRhxMLF/Ulcv6Q/YaWF6lIN3k1z9+A priv=MEcCAQAwBQYDK2VxBDsEOXiQTGcxikT+YfbGn93QdiTN0aZuesMh+7YjaMXyhldFq/kw7gvzZtQi6IVoAfGLj0kj6YZRpnJkPA== msg=EmcQ5x29+A2iY5qUneP/j/Hu/e9cPyrMsSmKBRPQiLgCqQPbJFcGhzJ9DEYvmpGNl/lW4ELTfl3VgiahlqDzVg== sig=FUduo3wakIp+MmRbBtLbTvInu8ra4EwyL8eDxVoSOHg8LwqFe/TCOEHoSk2NRtMVpexMkhQ/reoAgBGl1MRC5Dvuip9VFT8WUaDVOCowC9pc7vDqH8Nra7LS+v4MGDcgAnIxC6tpJwc0jK5BoSM79gAA e=found 141 iterations",
+ "pub=MEMwBQYDK2VxAzoATHxNBd3QSi4ei1stPbXpdpzsBIoo7K4A5KKqq9Ofa4wCJsnXpCwAEGL1VMLi1LzROLOYkyAYIb+A priv=MEcCAQAwBQYDK2VxBDsEOSX60nVzai7U+SDwDplxI5jXgEoGGvV97+Jf9f8kvYP8tRkhj3yTwxwzXkBoaW5U8FnUdX8Tx77jlQ== msg=XUNTAKBEta6IUBG9HpVydP7q0mJe2gsIfwGZb8LKFCMZPx9h60KURJ9VUoxI5sU36Cmj69I2SRgYLLI/my9tuQ== sig=Vfd1c4LCKZ+kx7l0FGAC0xdeXVkNCsTzJQ6P+Cq6YIF7RJuqCLhaCoRBtf5hqE26WAIrfulVfbgA55IXOZu3xRuEJ+FYdEedsDfpYipYIXXeCT+cg3NBwNNew9PTkcS7W2uD0mcrUGGjNv6u58jhqRAA e=found last=18 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJYcaC/UTfo/WXKtaOD5yU+sHTpg+FZsjBrzuuFdpI7DMdJF3eaiRFm3RfvZAg4gaYm9e6P/tzokA priv=MEcCAQAwBQYDK2VxBDsEOd53n6jpZbq1zNNsaFNwSQf55bk+mgE+JGSkL+4lLIOnpe7V1sFN9IrRQjVv/sEHvgsSIeLh8u4tCA== msg=s6pLpniTIS71mmG36nUZjXoaREWHziWFkokH3ep3T/gVAx2iYQJjWfTGSqc5QQrJKx1S2z4a89r+n13FXDgHTQ== sig=xekCfxviO2IlhzAkfDJhWVYpfE7IgfsmmxEVhkfzW1sI0LsgPi55r45AwyiswkDaVDr1GEtVYDaASMpUjj30ZPSU2KaQoBtIhULX/lSHFmEGoHCEl/PW9uRnmrhzBOsMAp0dENqG+pTvxZz6ffONkSYA e=found 137 iterations",
+ "pub=MEMwBQYDK2VxAzoAnujONpWhYo+N1v5ByGlQRr63je4JmZSCyxDQVfel10dzNuobpBhsKvuXe4K2b5X4+Rzap5GTH9sA priv=MEcCAQAwBQYDK2VxBDsEOd2VHQlSnP4ukdE7ZcA4d+ERKbmfllPECmSM2a9AQtK4FaPR2r9xyPuKA/+RkCxgfyWiB8zEx9DVqg== msg=54J2ZV5PQq1lVKwJnM25Xxpn7Q6JuSWfdG8E08AEcMSiY4s0FoQKV1n/Gw1Tj4ty77ytgVoD9iufB3n1icpAMw== sig=UhvBe1OllXrHU+OFhssCnhDRH44SydYfVMUxz90DCugB7rC/1jNIBLvGrIQ1HEPArI6xOPYKTy6AhsrDhblKCsBqAc/c/OvO3h3Fm1wTWG1lGjxUXQa+5Pwq/w8DcQa0cJ3t2OLeOZ7dpwXe1fohEQoA e=found last=23 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABllkhStDUTBpbjrw9ouJxB55p+nQ7tZ19i5X0amFd0wQaLKzJW3mFWmBht+xVDoNBEdDeMaQwwUA priv=MEcCAQAwBQYDK2VxBDsEOcKhwyfjG9xkmIB2Zca6L2oSdaFXkdsfIr+pSL/ci82ICWOHDGxRM4LXBWwPb07i3mmTYRU+DhJ4yg== msg=yxdBDNaEKU5U2yo01NYVt5eAQdjItRYJHDM3X5tqCVJrjhJtZeVZgCaflY9Etw7Lx5AbJyBJrKvsU7ovsTpXmw== sig=A3zGxZ7wjElDJsqjJedTBe3keLFllH4JTb38Y713+zMLsvZasxDOgbnVb21gAApRybR2VJoI4OwAxEWWH2HXvnwVbaIa6Aklvvjwya6euw039dfk+6f+kFF0tsCtijFzu5znsLDkqopl5ANlSJikLDcA e=found last=22 s=14 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6w0K7bhuLT0ZBKWhiJT9NPboDTz5Wm9CtDPYqFl9yeyxSe903FqZkCW9+O3GA8BdlwsVJWqpKsYA priv=MEcCAQAwBQYDK2VxBDsEORTAFmtu/f5ZdvL33SW6Uu1ZTV6uvr3AansQDiKgTVwRRnDtW00wOwOo9nR+UeEDxdp50IceqEuGnw== msg=hp/aOqZY/lyhEf8WXoLOq4rSGEtU14vmnLiogxZkJl0jITv3QPtSY4jVw6QAVe4A4NMudbt/D5JxT6frNNYamg== sig=t4yc8KuO67NVq7Z0GNutEGNJJvtzU4k2TzlU7ikUEvSsIRYsXxmP3aVGRJDkCUGK2UvPuUJRa7cAiT7T7VSfeE5j4XNWBT4MMgEk4ISxWgeixkxFEF32LBOlNineB0/ngPEvLW1UbIO61XzTkS1b1RgA e=found last=25 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbBOtrkEzUSVxroEag6ooX3XUTq8seEBjR85sYHQUXb9mcYg4bV7MJMZ3MaOpACzMJUrppJKh1boA priv=MEcCAQAwBQYDK2VxBDsEOTH7i6balCDjUJs0RYQPKUMY1huodYf6GGOfN9jFYkVF2NDf8p4KFfZei/tSlYP3/TiullhEDoigXg== msg=F4UmT77lypNsguhnsyFg3tOOHA+gAP5dn94lEYQE6c+ezJacYIwiMAhePW/rWgcbduY2pVsJufewfWE1R9eqmg== sig=+1R1M7beyMSCzU9RpDtbJWgTCWHWO9l56IPnk/IAtu35gQnb63ntZ7IYvzUDb/rhFWdWKcOWyAcA5kDTr0F3oEoxAS6GENwRe3PnDEhxPA813HTghWNUNtTnl7M5MuA+AifWFjBnAJLUDm1wySlAjDwA e=found last=18 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2gpTSq28FQwInEfryggTqyb87pO+TFoU0wfNXxVNXxi7H3dicw2x68vM7hQXtenbvVStXWNyxy+A priv=MEcCAQAwBQYDK2VxBDsEOTH/AZSStUJtPutLVOsvtHeogycuyUha2Iix3ZvccSX6XEqISH6x006rFsgudse4H33HkkmEYaRKxw== msg=/sjGDWHM6ZG4kkfPyirpqAZd+SDU+0brKCGWypmp+biFLAefa87tyMjp+UnmwwXEWVFGh7KglKSUgwt5z1+How== sig=bPtCvC2SkI323e2hM6/F1K+9lTkZxXEj+LTLKawMnOxZiQGaGYw5RwFYo4nl3sn4+t16AGI9HseAWRSmyrG6MFUr6OSZCVFfQXPj0JZjeLl0iwN0YD+aCTU0Qk9OM1K1M3+5JH2DP7tcT7ZN6caSSRwA e=found 138 iterations",
+ "pub=MEMwBQYDK2VxAzoAOTRrtUoN9KSdxXnntxSjU9F5o8acKgHhV4+8h5ID8kQmuLQ+y06QCjXHCLdl1pIgtd50DjN8g4sA priv=MEcCAQAwBQYDK2VxBDsEObSv7NdUuLC4wJWgMqhlPfjH2xa+5zE1tSEACth2Ky97frpN4YQNmvaWCOHsrZHVpMkJkCXLRm66YA== msg=ldNEqiGzPVZGjURrTWlRUOslBdBt6O16Zx2vxCx0/eqaSjwFpXwUJX2L42cjuqNm9vsnUL7WIJRgkuY35QUd/w== sig=FsPDducFCAjmoqwez9QYwjeTsFuqgv2Ag70aaMgRldsq+weR0taw+E5hl914EE4lknwVozhgf58Ajhi8LQij69ZaaDO1B98Ps8J1GrjQ4ATzRh8ifwhSsnnpcMnBCC2EtsrXXI+uLRWTuUltDjMLZDEA e=found last=22 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAs3H3zIx+TDPAI6Ud2IR6FACMa0WAD9rnz3eknGg9H27gYmWIrlgYrmQMgYPIJi2Uyi6vcGOHvdUA priv=MEcCAQAwBQYDK2VxBDsEOcbfP0ULapoVJrmAE2VIy/iXN0MhySm+BSPTpr0CNXLXbbn6OROrYvadVJTuILcSiVt4X3SIbnAxlw== msg=wJfMm6VjuUeGaLUZHVXkqwBI3Sh2t9lWZQM4I0SYX9/sb8Frjr1f6rY5rls+7tZzfMImlkhrhD7jjbVPJsBZow== sig=1fbHRV9Z92Xa9wJGwKDaSh84ko56a4aRzqe74Bd0KGpbvnwqfjoe22BCROk9lNwJOnc2eZn5TN4ABN7cAkbAQRRb5IH3IwQlrVTuH1CP1nFWzrQ/IAAhg8jztuS6WI2z9Ai6Pq8+BCQwCAiJih5QvS4A e=found last=16 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAt0w9KqOqh8Dom3ZR0fDNiF3zwRcONzyhN2XAtProgIf2ryzN9B4Z6nTClpvPvf027fHAF3UQFKMA priv=MEcCAQAwBQYDK2VxBDsEORo3c+9qhL+5A125+miuSeo37ZKVBM54sIfhlTbhX5hmBYBFFrzrKlQzWx42WlrdPy35EoWgomnIeQ== msg=2QnpjxEGc+dlsTCBUHCzuyrjdAL3x2RIW3u0X6X4GNcl5LlPc3bj+l1qfACn5KK41935mwjF15xR4CZsCkO81g== sig=KO38jmNK50Yz4WHAT1/wSWj2d/QZDzTvrV2j1/8lY8K/KXXv2PddmkfOq+yh/XGpiAUqyQuhbEqA8K7v5G5bXyU2IEXkds+ivPAk36hkB7z7QSzobJ0EQdPVKnhqPgXWaBJLWunZLdbbpsmLIGSxHxUA e=found last=16 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbwXNkhp3D+1/v9p1stNBi2d5nC+/1ByaTrEPoVt+ttFKh+St23dJ7zxAwrGHZQbgNJmvzcWHyPuA priv=MEcCAQAwBQYDK2VxBDsEOSBcvzd3Ji4RWiBtKgOX8+2dRlZ2Wvn6enihTehIWXRYPPpMNC4rMt0hNcW53NHxa7kVkud4GEIa7A== msg=VnZa+fp6eKFN6EhZdFg8+kw0Lisy3SE1xbnc0fFruRWS53gYQhrs6/g/QRdn5p66JOXqbNKDtxJDYUfNhA4Pdw== sig=Adw2bK8aFSNjXTzWdSoQs4w7jHwSzP5JlxmV/fkCNZhGtpovPahDMzFLpvIedmDDtOwKLIAzKncARZKJQ3ooz+J1VnmEFCm45HfT3VGTz0AmvnDm8HVWdHxkPsZriXIO/oGUuo3rH+jXVEECDoN1dg4A e=found last=21 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGPW8jidYy9GJEsj6yyCvpdbsC0GtzgFY4yOZmRGnPM7uO7Yj+2zKof16ccyManbhrrmzjvRFN+QA priv=MEcCAQAwBQYDK2VxBDsEOWjSEgu8RTjdqqVLycZJFSohNoPiSSl8MKnwrae6YKKtr0i6TL2St65oAw5pikeks/Ajvei7k2ZwJQ== msg=OK2LQQpbOgkudJSF+8PWr0LDK8HDeg0aJD5A6qnNG2dg+qvU3oqfapT2y7RPrYhfTehX1fIo243DgXAi1+R0aQ== sig=bw4f42l6tGBkzbnYLnM5k1hO62V58Vk0HBxsmvLIyUvpam6S9UG2TAKJckWZKEqjQHzKGfrFP84A+cDPmD8isnT1Dh2ivzzZgdQ+iJWfJwHK/y9UUDkKtFsHpRfSxeuQa79t/AV0i0imCSr7s/yxVREA e=found last=16 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAG9MYjl8f6QBkutQj4u1WI+oaM8zOSLzmNPYckkDl6Yeb8V6OElXe992+ldy/GGVFPdA515g6mccA priv=MEcCAQAwBQYDK2VxBDsEOU9wl6VZctt2KogSjr9cOCerPiYVQGAujynPOFDFMBKDLcVkKe3zr3K8eeBtNqzRx44UPawzF65rSg== msg=v1w4J6s+JhVAYC6PKc84UMUwEoMtxWQp7fOvcrx54G02rNHHjhQ9rDMXrmtKLcvR4qwgwXGHfWwXh87bEMni5w== sig=SMH123TZcjPor6iDCdOT+ua0g31Fls50u41nUEApkxcTyzVnVv58mLR3ZcKPnznLvPCHKHU/K5AA0wUtKEvqDvw0C9Opul6DCsx9HKVgVHHY9gch0QbTLKo5tHhhT6uaQN5ZJrfDxY5cvpkvLTPz4B4A e=found last=15 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWw7Y7KvPT8FHe8mpTvkq1ISbrwZyuQ41dKP+tqhCofM/3wJixrOLXI6ZJ1uN6OhHPGFh8ex9eKcA priv=MEcCAQAwBQYDK2VxBDsEOeb53BLy/ffTFtWH+JYwA+qS7KfrZo1uFYQ48IJb5tJixnrCV22N+ZKQYw16Smhq2syqflg/nUTltQ== msg=mFIIp/pFLA7Sc/Jj6DMkjMCS1ZIiAKlEO8QOK/49fi2UariP4N26YiNqGMzhtpgzZx+nvct7JHZHngnhWOR8qg== sig=7zguOfsWMN2HyAv3XP45u28Agh7YowE8hYo69gAyYqUM1YxqpyJyT67imwBvkqa2HRiyQZIJ/FmAK/ufntzAUJZtt+eKYETojPDKR2Iz/oxxnXMraQwX4ZLukeUJB4isadZTBa2H0c7zRtufa+uw4y4A e=found last=22 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoARhPppxgEfT46EHtgMFsDDeqeHc6Q90Tet4GPrviBLgRUl6B27fiHSf/umSk/2JKqMjDRfMkJv8+A priv=MEcCAQAwBQYDK2VxBDsEOQh2Zd5TDrSW5raFkMqA7My3DqKmzSAtr6bq/4TwppuTNws1oyp9AGcBEpGOXSXjqpVtkkEJgyg3Dg== msg=+m+WSLPy74+/wpnimlqQ/py/CUqCqYFkk0FHM8i20fz1w19AnLWz3e9/9/D34O+FJQbcfg2ta8ucHHGZxepNfQ== sig=R6F1k7Iu18Wm5dnq3EbMuaUQuSntNH1cWEklJ2uTOiidxV+OfyagrDTsXt1kRjMtis5YrX+RB/+A4pEkWwG9ZxjUp3FXWgDvIRhWiStESdWCkCRpDHN4wD6g3iQokKW0jA0cSzvkg4dLODRRNuiRRCwA e=found 134 iterations",
+ "pub=MEMwBQYDK2VxAzoAtUMIoXZTMK3ZTloqHG+41he7nBhE34XFI8KpjyvLbow6mnTWJOXxawWQ6h2GXvWH0wGIsi4DKqAA priv=MEcCAQAwBQYDK2VxBDsEOUCuWg7Jp4kMd/jMzc1RjfcZg/M7wKT3MH3iS6b5UPYkwtFW/RM4okpTX0uBsCyy11S9GRpSWCS55A== msg=+if/1ipw+ot8S4wfRrogDPmsTW0b6ZD9xZeFKKpCtckdemRI0Jinl4ZbdUuZjBz2iWa42XYC0ewdKHivcjV0mw== sig=Kamqh3tfiQUg1GgqZ2bcwNGzU6XN2DWRxpV8XHkguJ1/jA9sBfICXclwkjq8WNdpeOxd4uUV5guAeBVfzi4YqdQoIMW/3ia7ZdwNT48lmEYDCWDk1H8EhDJekKV7PEsEny1/sKga4yVxvMMv4EUd6iUA e=found last=27 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoARmbu150W6xIwybdQQNBZ3Kv/QMBNt0cy4cFsl3ZMbEgqErJJaUKDFb2ndX5az/RLq0So+12/QemA priv=MEcCAQAwBQYDK2VxBDsEOYoF3c1YTmQ+7y3izEzXkZBjObSUnXvZJ0GYMcRFwS+ZFUTnwamMKNHhcQ5F0Vio+J4Pubgm0rbEmA== msg=wAGotJdkIKSjlfUOaZM7h9ANc2gV4CGXvITZCsJ2KRVVrN6MINuiMDq877nZQeZOCQhx8ndxnwo5SGm8KUGipA== sig=uIvlJi3vXYG33u5gjyj6gNH1wKbsbhBku/sUWNhOsI1Q3W2GyQSmcKbXrLkPcRQmMa58sPC/8TEAFXN40/UfpLA85VUHFQPFSWXrfK0bKzaLOzp5X+L8geC6CLPxLGkW3OS2kDWueLVXzIXr2PGecysA e=found last=24 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOW7fSAkbEgpCWoJBk+e/ZMOKtNcfcDfgfkDKzhhdiD/uh93/Lf5ZEMLuUGcWbx2S3vG7gukDixiA priv=MEcCAQAwBQYDK2VxBDsEOUK35+LCh9yMEh+d+Op3UPxVgm8k8xaLPdH3GC/ZiI/482MJ4KuY72giocJ2+HOYxZADRRH2u62Jcg== msg=0gBnbE4HKqcNFNb9GlXcGTePTEVdLdbXYxYIsX3RNlxG/2EtTQq7RFO8DnnzEiQr6jiu08GVj/yyndkAmtm3Zg== sig=ZWnSYqi39DU1I3Dq9p+lDPT5LOa//O96p9Nk7pTimaZuCPB9B8ahDQBEWeKyH6AnIwrvHpjT/BwARVVKJafMUgpPQjgrHj0WAaPXwUlGOiFKh1GAuLrn5EXrWL+6L4ondv4/DamqmAC4zrLpbwwW8xQA e=found last=23 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3kyyVFsSZWt+hLV8BU0qV52ILT9UPUg9Sbw1ULiPtUTLDzLcrNE1p0EK9JeX7FsgO9HNBSPJlEiA priv=MEcCAQAwBQYDK2VxBDsEOWvdYJWomqlkhVMrcaceOKzykVfdwDmvBAyFzvYf8/MVzkND6IN5+wR9Q2XHzdNHyaZEOhQ2i2prMg== msg=/sJYpVTD7DsBbTYdKUnBANLQpGqjHlqVv9hRCAr6K73l+15SbPRvqupLvNBhV0AyNrKqqtKFigay/tgiw21QJg== sig=hS7tWQ6hT5+gSoy4O0djDCCqrPUig46VjIfxI5bEikRWihbWJTA436nFx9+mFgJ8CxxjExWoCRoAYoUFv7vziYPmZzkQgn2cLWvt9SM0vR/Q/4mWny5j6iUqDx7nHHi4fgJzR2GESEA4dRknntXxOT0A e=found last=25 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/fAjMOyCMyi1eHVhB4xnIcG6HpGOdOpUAzhT3gz1/L2B9CV2Eo85zzCXUXpNeJsAvFyU3XhNlacA priv=MEcCAQAwBQYDK2VxBDsEOUhHvGJDg0L+DVjs5HBBvKrk69NE5YLT0nS/Xh7Imd8SQ7SUnrbKJYNrmmOQNdU9+iopygKaZiTREg== msg=plHKdxeV6Pn+uhauG4Z4sCUf9mDfnLb0mrY4DQ/FTC3NMHH/1OLa0FVOM561ar3A54JfhjG6EC7qxHNZKVPQUA== sig=YUJwChns4eFjvAW77+8rlO/b6/xLqfYgKwYcyVxmh380tFSzkRsTo4t43qdVUYcjBUHio87UUimAxp9vAWdeeTApa0bwQxLMcmmtD3i6yrrZSRQWPCxmxQnvep1SkbMSTobZB0Jb7V9ppmoVxU4pmAMA e=found last=25 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAzWVc6Z8+k/TVdYqe93wbMnk/lLb3lX4Cq+nXUMe71GhtrSgZmsBPD6xmisRSX/5taoFodQ3JvZgA priv=MEcCAQAwBQYDK2VxBDsEOXFMFygsursVbcsfnTmoL1Gt5iBP0LtzXNtanjtXZjU7tdtTLJS1MMGGEG54tRsd34ynxDZq/2oEcA== msg=PL4fSiNKJbh+E/QAqElGt8hHt/hExdzlOMDbs3z3+/rel+hMTbH4qu7RYtl2WuQ1sHts2ayFrPkgc8YZgOzKJA== sig=Ea/ymDM8ClMpT1St+x5bZEqPwmDZGL7g58ZrfqpGWJjynX4HMk8zycPjMLniwTqVTIgo37bvJlUAkOdwdKul8mdmdH886F7eysqLzU9M2uPEXZLB6IFGE47qgA3eb7bpyEwLmI26giyf0lqazdauFi8A e=found 198 iterations",
+ "pub=MEMwBQYDK2VxAzoAauYRXlPPtlfCM1f+ZdrXdDjyKuHvezr7UYP4r+KLrJdeQbHVOiYztxbUzhC71WQ/83aAHyoBn+yA priv=MEcCAQAwBQYDK2VxBDsEOVdcvfeSjzxjsYvgwEhR5FMGKhon3aVfnE7gUEIqF2m1xyjftJM72CWc3nb/Te9V6lGqp+fNxOExZg== msg=dKb44MLdgEtys27qNhM7VXDQCU9ijGLlhwsGL6vEcRMTthIbrOQE02+XWZBqaaFxn0jS/60Jt0SUNl6DcYvSbQ== sig=AfmXHFkKhfwvTBna3lOF/aophx5jf9+ok7H791y2CvLfaYuwVdHL9bVMQVCE1r8NYFYPbfDrXDMA/r3iOXA/vYbggkw2xGqDhRYA7u314hqs8G5yABGLPPA7IEryp/eJrB90iyQcrnIVMPGJIECGARoA e=found last=21 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdD25OVp68hSZxMh0FmqngEeZkFPzzdkOMXUp99GV6/UNjojhdpEPrKCc4FS4CjqtvuLp3m2SBoYA priv=MEcCAQAwBQYDK2VxBDsEOczwB32oWTyKCQHuUckiZcN8dO7Xf66WeaOmm3frrPfP7CYfXx3SlPk2hPAlO5gceDVtoePpWLG6bA== msg=06uImONwIrAMPmrq6MZOzS5mL5HBZ35dwEEKWLNoMmaQ6JrfH9bsy4s85lDw+GAc6ewUFBicKdSJ6EEUqPXAYg== sig=1VFiqiCoXQWQIp+twIrOdAC8ZUC4EMBUfEp8mKOdM4Q6heqf/jjIriNeuhj5zzz1Fs8UENhaiZ6A46aqTNPuM7jTxuheEs74ete4xmLvjKhY2nAbh70JuPRGdTiwBn4V7uIozJ047/MVm9n5Lba9aj8A e=found last=21 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/a7CkMZtv7RgMYnzoi1JRIYrob9VXQCKzrxtEd2+74Mb5lXdua8pN7TD0A1HJQnEVNB4A3ijCSUA priv=MEcCAQAwBQYDK2VxBDsEOeBJ6i+16r5dyWTmktk4WIClJTjUWit/Iyd/uk/mQpMnMmODOQfH9QF6H4k2mePTlMlZ+j7jBCej0A== msg=oZyaKnS3Qn/2pSkmJ0u4YdTNaGSgwejh5KHJA5ZoHmacK2WfMpLpg6DHu/pgIbS4JBcVXmwr9KvUy6y93upErA== sig=oUyaKUmW+LCJw8Ra+lc6fb9YeOl6OyY0uG4yRbBlAafFxI6Roam+Cfkns8UQlUN2X6pID2ncd+mA6YeAIjsclIsevZifGIxJC0FuQsR7udzThG9KVnPyX2dRk24UpKtRSzKwfY1LWHKgf33brMTKnCEA e=found last=19 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAb64uK4Jmt0OxZqeZePXH4f+ymBn+V2qPE8APreK590gkvPMT6xG0o57WT2gCti9QKQSoWab3H32A priv=MEcCAQAwBQYDK2VxBDsEOREkLAeZTDJymyA+RCtX6Alb00q1vakHS1ssc16FaMwwNVBEVxuVJjpbwbebKfynXoM1pRuN/IfYTw== msg=b3eoE/TQbcPBYq2FRZJjfd7v7eKXsf51OqIJcda/3faQojfgBeq2547d7+V38NJZWy8x62Aknb47PPsMl6zcQA== sig=YH1b4yCd+e9YG9d2IO7ozyIyJj/cau3PzcDEvzOau8s1dySS0UvlJftx3jRsNqNoCeHHysV9hMOAhCA89aClHNmW0Z0VtvC0LS7JUjCZmFYmJgpuqDSyMO605+6yiGdw7X1KoaYc1tuHrx8seILcViUA e=found last=25 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABE3BDATL677cHKiRRfuV6VTNr32AeELeBDqJ5ZBg8F5n1xPL4sbzqZ5KReVuAowTxnIyXwACISkA priv=MEcCAQAwBQYDK2VxBDsEOXYe+khF2WhVk1NHOqemNiKdUjteyoRmRJMjDKWxvCLPb+Im7nW3D0hIjjdO9e5LEYd3Rr08kelqRA== msg=Ylav20Dda5YFITRdJ8U25h7FG9UjSaaofC8Yhe90aQB1T/r5Q7JjalIg55O+/wy8o9x+xUPGwk7vqC7pNjqBew== sig=b7uWgAHpjFvgJ0XNEONGy4Gi1HwnU5FFws2FgEu2Nal6fJI0QK8a2W80+inuBipjSc/nhpao4/qAh0iN7aBEbelsBCyTAvTL2aDNL0Nan8x53JuD0rHttG+91Bda7iuGfI3P51gP1ISUFYSHRlMY5hoA e=found last=19 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuknDKnM+W/ZQ+0g/Rb5VvRmUX8nXLS1KvI7rHJMrQ8ITs7BTbcDPujFwJegK6Lnvyrd+GUunoHYA priv=MEcCAQAwBQYDK2VxBDsEObH0PlmjqHrt6lewJ9SmcTdtsaifxGQs5KMPVuuXYQXZFfRhrEjl1au3ZaHXffRHhr+mZ9YCwm9zMA== msg=0tXUjwmRomSCdJyyZindqLRgj8rST0n+udClCBJghCbfNp3Ro43WkMxTw0SFM/AzDZrbBNQfGIKfES3Apqf6YQ== sig=0ZdHEd/sqT/ZiNJNzdAvkvrsoNrJbZaYPijqqNRMfs2lTP9mJNvc3l+nWQmeSnukwclSyZ/KA+oAuLGY7DsO7/oh533glJbMbBdzMhqe9/oh9ocKqo6S9sRiaimMKIqRHijlmTg/4e5+18sTTR6bzgoA e=found last=23 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6mYO/sIStO+FiD2Lb0/gqdbQ0YeNkhmTWe+Dn8wXsSuaCmmuAfZqmdkMBrz4+dPGCHtw4Ti+ts8A priv=MEcCAQAwBQYDK2VxBDsEOcYk9HtW67Qmos8A95o74wP0XSwmwghSOevpvJ/INq+tDy3n3gB2jabqtpBFSucnmE+dxjT0Nlpb9w== msg=SCv5cHvs3QsC+ZfoHXAp2geWXmJTZIHTOAQ4PN+fM1Y85gTQQJb2qEjV2D17Fk2t/exatCN/t7mc01lEm/L2Pg== sig=REmvLkevIbcYCDb3ZFIBFNc/ymo15VqfmZayglxEBRqrJCe9TjhiVlV0e8w7wBR24LiBtC0IHUsAg3Ydr55+a3ao95yPjOWjXP6URc6EyNU2hEdoPJf7DrjD30aLVxmEQ4YabGv9PIn4vkI291PaWzYA e=found last=20 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAygyO1URCPsy6F0kmGFfK1C0lbTlzvDoClXTwdV4G2RaAVecpKopzpns5DzV334cwUOr7z9F7+qAA priv=MEcCAQAwBQYDK2VxBDsEObpLamEE6JNHRoSQCwzq3CzICKSBFOpKfRxBglYJK++SpvZF328pyykY4TfMTvWnuQiXCwuxjT/hCQ== msg=Ih3XGZirLgH3+AFH1s2pRuNXaAfU7y4Vrw8C9Nv1P7MF2bDtCngS80nBiPXgjJiTGlhdqDJQVJq1UL1Gr9UoVQ== sig=V7R0yzDClRsjjTW+9tRLQ3XRTShHvBPP/Dg4mbeDCplSIkNCgITVGE9DhL6DDxqOdPPHRc1V9x2AsbKcggd6D22Kjw1mdeTYSrNeh9pP27zucRRd5Yqjj5WO52br90XR/13JGBgLNs++WnuT3rrDziEA e=found last=17 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAk0fQGGa2Zv1eXhhg7iywGGeLMb80IgUUIjPPOpJ/5SAIvBLpY3/bKPKmsda8qHRdygAHJvULQUAA priv=MEcCAQAwBQYDK2VxBDsEOanfrjfw9p/phsu2KrYdwkdMb6NacpiHM5Y1Aoc09+cJXsLxvM7jZytzbVYxEIqjDPZ44oDvqVA3/Q== msg=XRswFJ9sPEvhBjVvzz+YIdhYF+mOy882wPQAEm+Shq847ytVJ1ipmVrNZiBOL2tI1b7fUhCZlVy/MbzqjkgKhw== sig=chWfjGsbOtYVcuP1WIMH7OijZcmB6ZJwG9ZRVqDPpzg1kJXtncSZBY0anf9GDhRiJ5cEDuhmbLmAUyEA896DwjbP4m+GmIEkYMygpi7QTSdktbDPaXK4MGTz4EyOWIVoBE1uF8IGikHN7qlOWPtJFj0A e=found last=21 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEHY2eVabIA5E5fYmrEBbsXC7TZAMnf1LSzfzx7x7/U/UHbY+AxZBld44dRx2jYJS91Ko0/4u6ZqA priv=MEcCAQAwBQYDK2VxBDsEOVuexfM6XvaSN6AhbdUs7nIcx3GrMzscrDF4Ukh2VUJG1BLld53KWG3xXe/1OIAHd4dH4nuYJZeMAg== msg=IQlEqSFTnOMtEeKgwWaZys+3wliCLFGO6hZZm+WbY9zbC2LCa1ScfLc2nT5xsvWoWA0RXM822RmHQSZrRWhsGw== sig=RN8ubWzJAUoZZOvwldqvCkhPgB7r9Y+wRHANGYyvlUVHc/SkEtl8K8Ff9a7xbIfIZUiUPX72mX2AZbKc7LTzD8G8HH4K7UniiKXb1IaYaS0gKToSSb6jx+4ldN/GS3qN6qMo7qR5JJdkBN/Q57OB/Q4A e=found last=17 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXZCqJMCScAhrGhnzR9/kfWG28pCBppHAWsBaCKAeWTv02guDZNld/TPdseHnO4rRMUNzJ1OkQaCA priv=MEcCAQAwBQYDK2VxBDsEORIjcXeipU0eiUGYH+Pn3BrHLxgp9wF6K1h0/b81CE9wtvyt1cSkqD9TV+AxHxuDRtjKWQCuv/VMXQ== msg=+AR9GwSGQiYCYOUTD+O2zCE8JX+b5TBL8KmGGv+p3pcoQOZpsHYguFds1lmG9VsLncmOuey1m5xnDKquYJxGEg== sig=L03WOklWpudKNwB1Vlp3rP19WGgBqn2yxJRioVmPJUHGiOTK7+ho92GbMVGxItXYBFDqKFcHPJ+AqxhzPW1XGel7K3/o7BKwAlmWheCsyHw+iDd2a5CsttyCsCTvBa4vdfO3gia5M1i46fA8ZwsNDjIA e=found last=16 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA+cTzPmIf6RJ316MMVLN316CpDGLhkYUzalzy2/kUuiqViNHZ5JKO8d2PFknIOyU3qYe62tKT3/0A priv=MEcCAQAwBQYDK2VxBDsEOQnc2auE/YOgZYRb8CWcSHG9i5IL+x3hzAJ+luc5Du5HBI2vJGOWGvXd80MQlfZHZe6cAwpkxzJidQ== msg=8Zsf03LskaMN6ikMjNniG9/KOxDw7uc4eOKxXZAU/Wn7ByHm0D//XPWWVzPsXEWguvtJi/ffTv66k0jDFP7SsA== sig=qrpIMWyMbvb6mK1Qg+p26MIR+6wfgs3oVivSK97H54huc2o4mmet6pAWOD0FvLnINImYx/X0CAQAeaqJLALwTxH9oS0Ozf6T3pAz28ugxtwb0u9h9PMcC0ZzUV+F5QRZRY2DVhct+WxxzOdDWxsXizsA e=found last=16 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAupYFtFjsbkJCSntbM/xb4E1cJ7k4VJAiwsRCyASuZOU+UvolH3a69m3wIHm2qPj79ycxjBY5yH6A priv=MEcCAQAwBQYDK2VxBDsEOS9mC5CN6wXNreRkQrTS1TSdyTuwTVpHILHHatwHd8YQeAs+NdrQJVNxILzjJWydlEnoKw5OQOR3Cg== msg=+iCgbNMQmtAbOy5B7cdZQgR+I/llDIowhi5If0zPmBuSKmvx8D2xDyNiiYr8TjfeLMmWqnP+83w6kq1OwURHSA== sig=C5BZ9N+YvvQT2tGSWnuFmSK2VhXpZvFeDWJg0iSbu1roEJSqpMbEVWVox/5vUsx3s0llA8W/nRMAzDr7fSC3NHn/edlUOSVWoKYJ0OpIEzqo1bDbPk2M3jsgQhYhubwY+4r5s7IMq35VYoSXaifTFxMA e=found last=21 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAswU+CqRceyz3axsy6qDvDEgbH940bj2v99VUpzvDxxzwFYxTACxMaidgC5r/S02Ii4VNTUXd8kQA priv=MEcCAQAwBQYDK2VxBDsEOa/KzrJhYNVsSYGNCo+M/vl64KeuxA3KArl7e7DREJxXp8rhLHWsd5E3uKT5zcoKyWXJwuiNx/hNBw== msg=ecSk+oMs/pA31EajvsdGWgwhS4Gl0b24dSjP9AkMNzLQTQhI2iBTdzPttGVX+z6jwFeOgiLiDZShFVM5XymMVA== sig=lofIlawhytf/Fq/uXzslBq9KCTiPxra92Yv3/F5Va2jArefqn/Y+tWgrEypapw+PKGRpanIxiUSAP+CBI31ABYdcOe6OKtHZ2HjygBZZPCk6iYdtszlhZ2u47hJnNqgUq1qyOAC+UTpHeFKqEU7pDhwA e=found last=26 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4s1B0b3eI2tpHpHG6KRW2zxgrbzff1Z0jQFNg/qL+5mJOD2y/bzx4PvZMbn/t0nRt/hNrMihah8A priv=MEcCAQAwBQYDK2VxBDsEOXS/XJUNZa/7yglpo5jPz9A/AxeICmwGuZHtG5xOmeO5LakOUipklKw5QJeHmeG3RLUuYg/8JBQW/Q== msg=rDlAl4eZ4bdEtS5iD/wkFBb9Ja1tQOrFZwUwqPUt2jwGBNfWpz7JG5PxiO7CImFTuaXY792Ui7InGIdcHfn2jA== sig=qVtNPPafL3U/xGYOwRBXJPlrd3nX5lkXH99g+RJFhm1RCjFqKueEcjWwpH4Zgah9cvdlm5/psv4AsyfWzK2Ta7AgGXWcj5CUHcxIwTjd36o9UnEODGFCgemmnj/lAbrdZ9MjPUhvdunLOoi0WEHtfBwA e=found last=14 s=14 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAN0OCf00epf/YB+084WTdDkPlyK09pN6/my8S/WUcS+sVz41ww2Zt/9GUO9NuQlyBPxJTBvUacUyA priv=MEcCAQAwBQYDK2VxBDsEOY1mKG0s00YboL85xhO2V8GeBifuUtosYHhCs0UQ5JLrP5QVeyHaRZrtUMkexFGSFZLq7iRAKlwmJA== msg=cCoKS5bKzz4xlq2CESrTHMkRyanbO0FCO6pt9bulaI95NInVZ7aGoDQyX7rNuR/oAbFYxWSUFCqlifXkut+DFg== sig=jAHQgQ9Rw7EwRsYL46Q3sQpyYVlWhAipWaYQsy3gU4VZJAvMRjIGH/TAVDKA21ulL2jaHZz9JHkAB3iqr5C3g/u1QIldja23X/OcF9fh0NT5plqfIpMFidwUEJDP2a3Mlq/R1fDZ2AqWhedfXPxXZTMA e=found last=19 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA//r+bdAqL6LBDhSomuUeNtdysQln8RUdnBJ5L2nnSZ2wZiWcDUPNpX1TndZpbZX5YSM4Ktm667kA priv=MEcCAQAwBQYDK2VxBDsEOY4cyyO6vCzQZnbfrgq8bQMuR2qXNFlPt8jnOdexDZeKj9hpu66FGJbaShk9uh27pVx9X5tUN1tN0A== msg=O/Zbv6rNNz7z21rxCTSDU6L2u6cNGSWuPUS/6AAq4okUN3xQ/IiCkwPlQSbTdotCWoula/ewy+BRA1bFE5Eh9A== sig=cfY/T1xhGAkD9pMUeacPTdpqj7/ugU5BfBHYjb8PSAzjiq03kZLs0PYZAzj4uC52BnnbXMaUut0AZB1nPRDzdNNq1MEowKvIMaIqoYGp64LltRvDsRJNvAXN09le+8l+IHfHRbUd6N2y7RCgRpKc3jYA e=found last=17 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOlSEMTeYZ2Mp1Hm7PDkkrsMrNGMk0MlY6dLT9pzLae0C9XYNTqxgEPYU2l6q4nzvDzHZ2zrkcQyA priv=MEcCAQAwBQYDK2VxBDsEOZWvUJFhISNv1t5xVkGrN4YFzHor5LtSpcNzn9nJchmziLGmoqy0BE+fSOUdyiTd4IWyi8PoFZC45w== msg=A/DeZSalQmz1jsUCBNds4mlLlRxFHr8pFfuHQWyevXA8zN1UZO3RfecOWbK98VaNczxAsW3ijsLFC9ucPdoLcw== sig=QNmIMpDk5a4DaXX7fC61gt6bKCcSXXA7Za71p/S5yAXfY4WxBixmnt+tT1WnsB3ZxkmNDM6XqrUA/X3L3k94jc4uZyGYVJw55zkWNWgygu7hhD7eKAtIh9VbSoveMVikWi+sGEnDm/8F3+37WCzwsyUA e=found last=27 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqBDATZSAS5v4PsyoC6okWFzI/Mew9aL2bF7Wxo9X3C7vyMfeZj2L0GodqNmkWqTtFUA8WVlPFUeA priv=MEcCAQAwBQYDK2VxBDsEOa8ZFHPRxvAqO8ej/SOkbK2dZU0P7KkkzRtjjocO0DwPIacrd7TGgi1Fs4ZUo6/DCf9jAdc00lp36Q== msg=iLUm5qT5Wx8LX//5BVnoBW7dfOzFMiwTCIQGSHii+nsDW5VHGn6UCjx1/BnjxsG8/rL1PfO8wGX9PUPvutHDuA== sig=KoWhS1UGXexaXd+vCzwV0ux/DR2hX6z3Bsb51F/GgIZo6U20y9+6NxG9Y4dbd3hw151FpBUC9jsAtvQWu8X8qBcTgpKqHtZdujQQwjVNbAmk0KlAa7SlV+wmx3ZMgyGZ8XSNPuVhCdCis0yqrgNuFQUA e=found last=26 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMNqGdXZ7k4qvRX9AyDajA5oPubKk5XivLLdXAVGeMt/VwUCk1cea0VyBjyz+FYsYGjnKbi7HM/MA priv=MEcCAQAwBQYDK2VxBDsEOdZEEavHdR9SkFeE5aeFYEIqcouHEph57+0cE30QHRD6cm9LnOxx1YC/iKfFVcet3BmDeh08cwrW8w== msg=p4VgQipyi4cSmHnv7RwTfRAdEPpyb0uc7HHVgL+Ip8VVx63cGYN6HTxzCtbzqvL5U8ulSfc3AkQu+xlVKgye4g== sig=u3U49zCreZUwZdXMweAOAmRnlUNrImkTa+tcsG83ayYXf8VRhgH/6f+5foDcffz/LfRNTnhfNWiAr9Ux3iVlrPLvhrVCqre7yOHTTWFHigXtmVfC2+pMSH+8TEKarfv0PWLFpwJCJk+cUq2xRdwOmh0A e=found last=21 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbitGvZKGxM3iy69hzNbFgp046xezXdX9TjL1R85uJMmtSfUjOowJtQX0JEVeNldOODQo6kxI87MA priv=MEcCAQAwBQYDK2VxBDsEOUuqQiIKDZOlXdQxfwwATCtjvucUtOe5v5EFIG53/Iwfa+lmbFHPvnF9rGxxqnOsHRiZVGE0IA8rPw== msg=3XtpoA2kmn3wPS8anFktRB2L82RYgK/VcFPLYPmFVWYmJ7ebH9b9rsvjTjczYMO0oivBmiPr8SwiYJjCnhEZxg== sig=FcLE1vyLbilbdgpfEIqF2mOMFySuSONKuPfwHEGL1HgqpMIljA/BuMgfq48YfnS7nqxFxSYr4yUAAShbMuB34/QUYYgV526HkE3Kb7RIvtVkMMDatSYJ8PAT2EjC91GZrCYizt98oCFeQDUb2cK7cwYA e=found last=22 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2IQy2MV05CDdNoH5sMnNTQd4qcqce9DgRSogkbAj1QhAlkKlyowKv9hHFIkoVwFen6DHXvU32J4A priv=MEcCAQAwBQYDK2VxBDsEOSjeVZVn6bhFyfjAlOEolng77Sz848BlQ3R9bRkkB96BP4pynnvmCSHDxJGo9YhrNariYHLPnIxHJg== msg=BiB2iM7lfnHlFIMW52iS4eeiCPa9d496bS1Y2OqA/M5XTxA087cYuDs0JVM8JzY5dgE2yRBWqTPF33vUkQQvTA== sig=5/lx01T6VXeXwUp3klswxjMDSjkiVmAZmYaxXfDxr+y0WRc/yQr4qt4TjQbyjaxwzKaHNzztXDUAf+HpBGQ/iKY0UIf1pNYahb+MFxYk+J9hpq2pkfPJxzif5aOy4Hba2HHBeRlukNKgfsZnUNB2NS4A e=found last=26 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAkuH7tBxRhgjsEd4rh5rl7NOaHhE4LRM+xNa9DdLIkESvA0JvJhVPHKx1zUN7B7LdIck8KV4QI7kA priv=MEcCAQAwBQYDK2VxBDsEOdO9Ity+S/yKuo+UmqkniTWaWx5rBdEXVmKynwlIBobGT7sDaG/5S9yy3UYLR+SkPp9B4ISCDK80fw== msg=juQOP3GmFNVbu0XJUz9o7N+EiIp15Xtr4Ho1in1Ml2FYPWih2S9Gc3kK8HTueXWUclsfSgM71R7HEm37sU829Q== sig=j50v2Dr93YgZdh4tbW30NqGdXq34EXUibFBdmuZ6fdWTiBTU7Z9XpEF3D8OdPZy/E30PLgCNbxkAy9q25evvwYqHbjbwDtfwbkKKXbQBi4ebCD46kfNM0lsWfSXrjIkmb39sV/rF3EOrq6pBgq25fAIA e=found last=21 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOvZz2jTZSO/+olsrqpPYhMDcNGS4Ze9NozWcxWC0SzEa/WRiRbP0/1Eb1D0hv/tx7/qQ5XSVJ2SA priv=MEcCAQAwBQYDK2VxBDsEOYgesa9sZW5G5FP3q/Xy7oFKJLigjl8wNRvuv92stnOFO3QXaelJqsD0o527JZ+sazwt3RQ3f4dhiw== msg=NYAlJydYRQesi8Ru8D9ynhI0ISkiuTZ4HV678IN1iCuMYa7sHujBrvknFthHuS+QQ5182X5H9X/O69SVWQXrKQ== sig=sRoMPcj5pBpFiz1NbN2T6V8hrosAzaxcYN18oDNEG0eA6B9MCxJ1YE1mOZG2OWJmJS6jG6vl242AZzoIFlUNw6XKr74W8iSuFKoTbXJ4oWVf40meTdv7Pxh3qvcYG7/0JDEIateU6KTXKW/mkX9GtwoA e=found last=21 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAksgCwDKAciJODYLiLaJZMWC/a+mqvHOe0GrV22LYHvpMbQHj1zzXLJ3XTBb8ND97V4xOTr9BAdeA priv=MEcCAQAwBQYDK2VxBDsEOfV7y//LBQr2YAozEfODKHp5jb3WhbiI2ON2YHSWDi6J5G8+2aE+sr1hlnK1/OT6lw/4k7u/U430qg== msg=DnX/aKr01JBr2m2jDuAVpiI595EmSUWFQSVK4w39RO0ZFA9c/ayKGEjXEEunsMwZvfg4w69TLgsUmrmx/fNROw== sig=dTafrcOsVcTlwVG2RD3q7K/DbzUMefDgOrythxhLTomEH5qdNV/RHK+nWbgu4/M8dLssYaDvFWWA9vhkYYdS8EjPPsMZ/lZ6FuZ3awWsR4dHZh8jM3xKNC05ABxuAqghipPgz3hOPjMoDceYS2xOHRMA e=found last=15 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMewlNAYQPqyeG/SCLrTJzj0fLux/JE8cLoJfWfoGXkWMYjgpOfccR6RVOKzqmv5wykFLiBvArgIA priv=MEcCAQAwBQYDK2VxBDsEOcm889BUi0g9G010pbPc/in7TltQo0oZfpo3WD8+uomZb+53YP1l2+iXiT1mf68V56+yqlLfuS15Yg== msg=Rch5UAmXcVXJFoYwbCgrAM8C7WG9VrJdRPZjIDNTY0MKr59HaqN/AGfoqE47gaHeTTzmPFub+SepBnW48nU0Zw== sig=s13tzTgNciJ64+iaxotVqRDXNlF+fmQ3KcSoczWpWONDc2wV4q7rWmBhvpybHU6iqohgQAg+VrMANX4u4g9UIQcxxkeTSX7JXrI8rJM+iLyaMKIIklu+Sg522vO9VqKasZxxZQkQF/rp0NT95o3vKzgA e=found last=22 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALCi1MWhd1ml6v4HRKNCs/DkWhisEfNS6WnDstpuOyoEefOvFK8PdWyhG/BolYxVUP13domEos3GA priv=MEcCAQAwBQYDK2VxBDsEOd3SioWxUTG0HIKbF5XKfis6PkBWk7uSQ7Lke3m6HmpPjuTWwwUUeyNcyk9mRC4dgYluvD4MqZbL2g== msg=18OCGtbzvpQepn6Pf4IsZ9Buf2qRNdnfNJIi5rKDkb7GpGoSJ5jKW/V25xDs4+7oytfkwdNQ4k+XdJk54IH7vQ== sig=3GNCNbD8RQ9P+E6wV5txsutDQJLtW/1/ewybVIy5HXyyDmWNpNuFm4Ly/iuntqia7oL1w6RVGkgAPorl3+2WqnZy2WgQUBCdpHpg7JTFg+fGEUux6Qba/A+ZuO0eFnbKGmDaRV8DzNSI3eppujw97TwA e=found last=23 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGbnXqJZlGlsFQDLEAEhuMjHKuLHOu3enUZEAHNqNWY8J82U8ttJIiT8YbPv7HQtS8gf8CwIxaqKA priv=MEcCAQAwBQYDK2VxBDsEOSrBFmntdtxQMiX8dLZIBmwUlDWuM0jl/l9GssGo9+NQFYz0qdHtiT3s9yvJC5gCEdUVfDfoFNPeYA== msg=UDIl/HS2SAZsFJQ1rjNI5f5fRrLBqPfjUBWM9KnR7Yk97PcryQuYAhHVFXw36BTT3mBKqBcbtahb8LNRVw4Dpg== sig=B+plNiJ4bAFT4IfLvxxKN13DAZYkQEc1jnJndOp+H089vaNPo5OaM788HPw6P88fgDWWGDLgB8eAU7MoXe4tV2V3ykkS3EV1ZHR39AJQc3by4H5AkBFdztL+DjyVRwtrA2ldFb39ha0OP5ebhnsvFxQA e=found last=16 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAHtMp8XZ6kA8rnjUNTBmv+WPAU8l/Wa0rQAvar/axlSr42nEupJVPhailhCt+Dcp5B/igfmsFm1oA priv=MEcCAQAwBQYDK2VxBDsEOdmDBBrW4152M7uIs4/OyVX2AF3a3CCmteMhk025ho7RwiBHDPZhBmQdnZEc8kj/Ve8pABKOgFBx5g== msg=3G1FB4MbbvxdxnhCV8RoqLZknv3fewaSrZP4HwR3s6NRqesOzd0JFEStfZn9rura05O0ehqMZ7/X/plpn7hEaA== sig=OoI3SqPfgnPIO2+UGALQPe4rRh9HVrBSprvjXRlFvxR7ZSHOtV78ML3Eftmd8nnFjkvDG/uOg8YA8MWWLKYLSQyyanboRS5pxpJpx7VVT9W7D6eP0YzZjuN1dGVOdcUHJ5D7qZG5wI1ggw6fspbQSjYA e=found last=24 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAxO31ACpX0zQ6O+c8yY4lx/DbDYvvbGcK1X9/xLGNeN0Bmxp2qeYwVKeKSgrLWRTdOkEUpmOaogGA priv=MEcCAQAwBQYDK2VxBDsEOZVtKaF9rVJV6B3NH/mNEzVTthNjL1zKA4oW+RNqL/xdNwJm6HJys/hyEqOp4ssftGSOq/zTHy8okA== msg=0IuQ6+gZKCeFRT/HolRvX+sAj+Lz2s40NqUDpxQ+Ri53YHk4sn1ZvVhtsEs41Y5mXSaEt7nRQgqyQpHtBUT6Xw== sig=lnyoKt4OnNzjM+fA+Pmq3QOMhxjB1VEB+CsZo4Odz5xZxPWoBP6dq3E6beoCrieE5FwlOAnt+JCA5dM2qV/RdVvWMAmbnorh2K+nDsuTZHIqawfM1HfZh9rTr7UGQA9kbsauI3j8+D4aue1zk1lpGRIA e=found last=26 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7jti0snBnT5qi4Mucb6qAT4DN744yAxZYLuk3g0t4Ylt5NiPhZcF8yIwoTg+HQr6oclR4GLmrXIA priv=MEcCAQAwBQYDK2VxBDsEObTiVrHHLpAGm6G+IYzaQlpYMvSwvRqu4kceHgoNh7rQudIPxpWJb9uTT6F1wo4ORSf8ikARM4LnZg== msg=GEm0OQ59gzpy0tpOSKDNpsDzIrRyM1YvuID8JVU5swnNkH7iOFVt7g8dIRvPVa+WiM1fIKNus94d08U1upMCDw== sig=pl/KeuVl+AdxRcPjUv+X7mf5TusTFURKG5jLuzbfYSe0g/1Twm6hYp+mCRFzfes1ZGkVFnit28kAOVZevM7cF9/YvNZ6FV9MoR9gRMs/VBPX3Vj6aSfu8Q2UGIhwjZuoCDgR7ke9KFHsX37GvlZrjxcA e=found last=16 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALwhviWTzM7CQ2CFlU71GxGAF91Z7JyPcW3bo4amTtuEAqvL4PMSkmvfjIKBDJxEDZI/6N26DvwaA priv=MEcCAQAwBQYDK2VxBDsEOSmnwPnQeL4Q3+6PPrcpi1+kNr6qO0ak3kXme8ygsP4jq+gJNAzx6x2rS9iE7IQwQPkaG6sx84qJvg== msg=1T5qa8P/X6e3vJ8LWlfQF3+8StjgxyTD9Eo9pwb2DCkrslT9o8tFqWKi29lCSePDMt+CmdnWULxOyp2OfozXuQ== sig=q+D27XKj15wW8Awqz+ggjUYBnBUSObw7VcNbGDTkoVFWZJIdmNAiHSWGXZiU8DCYR3wMO9yLx/UAPp4j4QtHN76cuvlrKvR86zUX4pyXWy27dWADmvHp59GCOHZPeSeaixNjAdQNiGcV/+XNPWsVRQ4A e=found last=24 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFy97zhTH5kI5BmpVWyaQuErchWwgR/6GklaKBpxmeMixkdZ5dluoB5orywuNJ6oHJTFpU0zWqSsA priv=MEcCAQAwBQYDK2VxBDsEOUELpmDKrDAC8C7SZeeG9ySixh3QvCKz5R/FKI6KbwEYFa3XMnzX0ZZZPT4vbyTJDXwEeNAgTxICXg== msg=5TPi4Jgek9l3pYpuTI0RH/HX3Yjlwf6tu8ZP295g40p37CbGBFmNhXgfukejnYZZEjz3nDw8R/IDXpU+3kq2tA== sig=uT4PzP7p7e4PO4BrxLToLgoiaSQRIWTHFjpKCJye/fqdMqff8W8q36FJlTnOeBGd1vv7da9pDjYA13AS8GmKxrn7qYs2fNnGDpdNpMAn143aX7G1mU5Z/mumK3kRil/OQR97eXKgq0zuK5/Pukcn2AYA e=found last=17 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdcAzsfzTI8iqwBEdL8KnuESra6SRg59iDRFGX+27U+m0gsMzUWrUVIR43l8eJPqL95HxI1CHgH0A priv=MEcCAQAwBQYDK2VxBDsEOd5KlM3SgDGoiFxMEtaTs8K3ABoJFX3WQMixlZQY732QgV8HSriUYztAcp+kBO+FeKVwig4kQsWdlw== msg=kluX2cQnKs7gfEmMo3KOJEw5vCrswlZuUwVdXw/RHdBmVDBiqW+XYzU6in/qibziK7aWU4yRP3GaqSb5414+GA== sig=fXcmL7UMoRC1DMzwtp0cB+Nh85wcKbzyu0zxwv2K3P6iBerDiH7XCQhQleKom5/oUreWcTvcTDUAno/O88q6RESl56B14Fn1bpWOqXp5/pIOcOEF7MQ0VS8nh5uLTYq/sl3oj4qsHAg+OfWMtPyB0jYA e=found last=17 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAI9iSB/GK0Tb7Ptd8fxmqPDZItknaDM73JFEH14n07LqvWYX8JoqKeK3Z9Kz8xFB8SHr/pMMxRiiA priv=MEcCAQAwBQYDK2VxBDsEORyLI9uhl49al1qfA1a2LYSLUkZ5XfD7hNqx6O2FXzhvQ+yiL+CZ7/kBCzeO4w2qL456+qiNxeme8A== msg=MSvsu6+ajMarWCn3Qecl20QZQY9mCOkGZVIJDXFc6y+nmOWwRG4HdJGDb4bpxJbOCcql59RuNg7Hw3SxGH2ovA== sig=I837tPJtOAJ371feJsK6OwKuFMCI3I65agsJVSiVXLsbo8ajNExGLrJ0GqceSuBsz9+4JKKyflwAqCLtVYu5FSf1nuu/VfmmWzSorjtSz3vosSWGF+x6EKn0O/DBVbTQRJ7M4k1inlERVDE2MwzPPhAA e=found last=21 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAlUQBESzyC0lKF58tvreCOO5mx//f8FWbFwThTm4fQ0+qP6/NIv8t+BYTklHABunECI25VbFtC7sA priv=MEcCAQAwBQYDK2VxBDsEOSJCH66TYlK6ioFs7vjA/T40CH2tymEOGV/qdK3Fz9ldIVcv9b3sd8qZGbf6LeSxDeIdePztrD83Cw== msg=nc6gPfn5jD4Ld0Oad3MgCP2CNuNqpt7H0RtBASPZi5AaNClHzgjaP5s30c6cFHLiQ7w2iQWf27Wr8Ar5rVcgAQ== sig=zZVmyFoWsOvKnM9JGbqOIQXswfVauEXrTHDJCCSKU4TSAWSPbkDU0Jhi5sbn/kwJ8tE8sYT8lJ2ANY5EYbAx49A6fs0SA6Vwe2z/fbwsaTzOFqNquXspW4IgsSZ1vv9CVRJAhFDYYgN7VddQThWLAB8A e=found last=27 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAlMr/BEcQNwJN/e32P1BD8/wb/7ZaAGgCRK4PWWcRGTxrWG7i/gfxuE1H3E3sI8/BJtSGS5BbHbiA priv=MEcCAQAwBQYDK2VxBDsEORI6JltnbPnL9cmKVIYqyOL1ErXtH4CYW4WcKZsII4CkRy/u5/mG1rhPmE/mbXqMXun1GjuBGlS2Vw== msg=/yk2mCv7PQG1+uSWlWrdyihYsRguVVh5j38S4WzYg+pEcpYhjEds8SwaNlLEMpcB+rlGxpsb7O0BnRsPxydBYg== sig=lGVOVflLFDPGs2pRv712ZXaeNyuyI6H7ZhuYjqIqzQDeEgvq4rbkX6RrcpxXAT/3sBSN4u3i+ZaAekNvhKZHN7SyEXvCcjUGUjk3kG6R5MBd4woVta1OwlC2tLCwPL1Vufpy1bmSD76F3t1/jM3r6wYA e=found last=19 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7hKG61WJaVDT+HiLWPDGM6IbkVCmXVmnneSGSWcLYAqyg/VSyW4n6M7milcB9aCtvgRQAZ/yas4A priv=MEcCAQAwBQYDK2VxBDsEOYNePAOtOjL6kq0L/fLLLqYAC6PZXsiM4aRwo3sNhLbmh2ZIShZ2ZMNpfViRxjbNIBaETyhHt4u1LA== msg=A606MvqSrQv98ssupgALo9leyIzhpHCjew2EtuaHZkhKFnZkw2l9WJHGNs0gFoRPKEe3i7UsuDMRA1shEGSjJQ== sig=40Wt7GBTq0nN5nh/sV5GFt54cDAO6zaF4FlVCqv/wDjXPw716tRTDNIe0aVIu0F0mB8AWMGIFEkAWF5PJI5mDROxSP/KjhdwU3/To5Hwvbm45MuyocLLMtgL4J52/78hK4G8hg8rDRbQXEHAIPbPqicA e=found last=24 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAjgznNPgzI0Er4aJ7JssrhmdaNFWrNvEQpkiwhnSzHnho5+aLSpXiD7R4LSM7JYAk0MoidAiHQCsA priv=MEcCAQAwBQYDK2VxBDsEOVRy234RGjxtI4El4kSrdqvkjQR7csFpa+lK+f8Gje9pLrYR+7PfnFls1q5H1F+sFxEic6hmNcBDMQ== msg=XAXjpZY48TBMY9TkZDU1XJbg69iqxYSfTwuypERLV2p2WsNDM8QoIGxm/W9L93LKi3E1IgIptbvdtGfBsCzjhA== sig=UX/zvuOswAHSL+NAykedGe24NgV1mtRlcVrDRCLpszpPIRaiYwveqMDCx3XDWRjn954CMZF7AzyA2QXaXhRR07uDA8ut0OLGaCwQYuDZ3GTy18h9dg10aBXOrkWsN3iKVv0st0uBpLw4XWpjLXMnvhEA e=found last=14 s=15 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAlmIuTgPx/OzOiIBJl+EJTYV6O/zkv6BF3B7clgkrRS5izUg1ac9bP9/D4A8fzkijawJho+tdpdCA priv=MEcCAQAwBQYDK2VxBDsEOYb4ISZtUIsDtJ0KOZ235+6Xnx0IF+XdXefhl2WHkW4NDigOrzP0Sp30d9y7g8i4n/M4KdfG39yESg== msg=QMw30i0G/GcP1IdN6woHI5oXUW+DREg/HA2SyclvRVZ2TEB1vzq2i4gqDLbbBdQDpVcvxga2GR/lWkhRgNTLLw== sig=TZYhtnJWxELfmR92uAaoyV91c7ZycKiiSl3IHMdkTe6bPiGxFJea910q8ttZEYXpl0oD7FeFdM4AbSMc30eSqHIDkNnMI6bWPHZxcm4bxS88V0FKW1oBxsiRjBcRpXTWpkHd/ZLvzjxRnahZrXQEhxYA e=found last=19 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEo3+Yb/rW/jclbnoEBQBSXLAWh0lDKZN2GAbiwKBsgtA1qCYQp1O4v4tsRSwNTnRLI4pkVV5I6CA priv=MEcCAQAwBQYDK2VxBDsEOURpXl7r606KQRiHvAogyVgK8qmUv0UbQdNhipAVbG0nlxdnWNOVlcvp1y2PopYjAXpbDvR8r7jW9g== msg=q9tt3XErpKlzY5UeNyh62PZAM8aw6npPKJLgtI5SDuYIxrM3lzkmxMwbWLCbv5O2V7dBZZKLUsFta6IuMa4TqA== sig=CrN38aYp4KWLKlGW40yVUbqsf7pl7YaKgTIIUurPS30FiZZnA6dZj/KJ5nksH9EbkDtadWeVT04AGIwy2490UWYbCQejxiXDfzCzdOGMvwBs2iw9zBZGr/JcVSDXajaShNnyz9gU5Cb+2edgiTavTA8A e=found last=22 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAj33flTNATo9WZbjcr1z59AA2LxUAj+IxJUTn6WRxPosRH0fdBmVRgMYFPXoXTidd/RbpqpxbcPGA priv=MEcCAQAwBQYDK2VxBDsEObEGesXuuZfN0BxrVVqsUpyDZf6neh3PL3c9FD+9+G4pe0DhqPvhRAwTGMWO9xCrDg8QNbqH40PD5w== msg=oMjkHJBIO/BtrMtElC/gkhL32yDbsZEtcr00p/yorQ1h//ky+yKt6fE93uHpbA0PjGm/qf9inQSrJdwdQEq0pg== sig=GWMcB2SVJ3B0b0EOIx2ArqTiqGjlOHT7cA5qDETQOd/ow4VDqqjSN8sHJX7ZFxx+TS+TAwtFTsSAxSLd3gKnfXmsWu/FUbMc+VzoHR/CdKAW4UXY9MGJ5dz8yAMM9h6WaMjSFe6OKBrZISH13HLBlyoA e=found last=17 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAzDKq4afZGLAQns1pqu38k4Idd51xihaLgxT1i13QiLwsNSNFR3UB3JjvD3A47W0r40funajkMzIA priv=MEcCAQAwBQYDK2VxBDsEORP3eU1nr8UoPaGp1YD04cQQfl5aR9GKMiEmN30h73Utsoy48lbLEpVsnagKxelwj7s/wTCGx3XcCw== msg=3AstgT6ZRjuugKk6WCuVj3pvgXBwMxhtNM2DgrGzTCM+T6Ek7QimL7Ye6ofcnFPjqx6OKJdvkpCZEYB2ZLVoiw== sig=2Dhg4UgXGI7QVgSt88piYG7Il2VYkpiEXbkD0++Gjdy1r+L0rjhOfSt5syWFsd38APJpdNWi0r+A/dFOgZOA74XcgRJkNkJuLk19Lu9BDk5IGtA2QNQi9tk2sAEigVIYUwo29kIPKIKPgwLU1FCj5REA e=found last=17 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATVdObvZ/z3dmqefkWYajTlWtjOtV1giCnUXNTyA//lHdujUlrXnlS9cDVPGQ5IfLlWpFea4bhzEA priv=MEcCAQAwBQYDK2VxBDsEOawBe/IAspzOwMwQz3VAzzEvWlLc4jKllBYtW4nf2x+htCWJjKNduX75x2XxBUp80j+Kie9PHFXfYw== msg=UaxwFFGA9BcyzdkGhrUaEA2QMBA+4U6bz9omV6OEe370xl+HTHWsSpO/YuHk+a0++Tul7/emTd9Kvy82s/sG2w== sig=/AeNv70J1muos5Dxuuo/FAMoUSsOzdpj7kh0m1H+b11cM/0n/d2Rdie7xJ4VU/35TkyO529liOmAHsMMLaNk0um5GHDkCuqBPqi8Ngb1i3JZRTtCFHswGzOpuuQJ/dVM4i8r8Bp1ziP5eujbTPQQBwcA e=found last=25 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqLmW9bV1aMactoJIu5XinFcww5G1IQBQiV2jSPmcDJoqWdTs5buJ+UscN25kR4pskJ1j7owY1j0A priv=MEcCAQAwBQYDK2VxBDsEOXmj5b6TB5vSHM3VUqMWXSSObvaYPAXx68FGMGhr4ZKrrzc36fAaxu3W/D9kqlgyhCZRDDhZEn5Nfg== msg=TDHK8nBjj6yiFbEhRDTGEwq8dmC86i/e8QC+GsPDweTujT46jxVnfFtjoVIQitmYv4b51R3pNwVzTND8GFYZWQ== sig=Acw3us2AjxXqcO3G9rOnKEjEv8ODcEYWLDxUqsnqvL6N70vMIqqJId+tGKQlyP8qbI4L8hqeQHWARg+vawdiyhnjn3aaQQ0Hda1XsH2VWPHuuDgVAnv9ql1d4OpHjmF43vIEMRMNq9gI6diLVa1LNxAA e=found 203 iterations",
+ "pub=MEMwBQYDK2VxAzoAVkDhOFTRVEZKDs2b/ALsy9yAv/SN9pKCcVuqSUcsRcVGwR3Y37F+b3LlzEZ4eypezcJqFtATqa+A priv=MEcCAQAwBQYDK2VxBDsEOS6gzl8eHWu55rHOecjgbhYFw7t6yOobg8xvHVfdirN/vFxlGJn4K8KNky3urqq3hRY8xtpKjVFgHA== msg=8jSZd6chwMkQu7onUeHABXACHdjVY7Xz5x5Sk3MVGcHDuIh5N9UCjO8Wr4vn0JaWzPMzruQd8eI3o8Ht+wk/UA== sig=iIsGt5hNvtPCTpq1MRzBkcrJ2mOuOP3mr2BVsR4P/Iw36HDeg0Eoel3a8T3sdPmDX4DzWDsHfDaAWQ06rK3sAUNHsguBmya47wARanZ8TPpvzPrDvJyZvZJaHI6vCxQ1oXALedPSRAnAtAliHgbJfRgA e=found last=15 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADEW6pOi+o8x7Xa9mcT5sMFTnYJrvA31yxg0oonmOXfLXzVqykal1JMnBiMrC8BhEmD2+OdZdBaWA priv=MEcCAQAwBQYDK2VxBDsEOSnWmAukjKw9qoKNaxiOYycZmLBg5A5DSrN4QuOC2j4tDwO7JE2PEFA3IISkgAzjt9Sz0OsdYN0OtQ== msg=WmsiFnKuj1Ygqkb7ttfOMXUmw+lVznZ17S2cmncuqpPW1qqjRZ09EP2+n0T8759rcd1PladPMMUrK7P5/+t2Sg== sig=BdN4w84t4zn0qv6K+Uy/GgNy231EvfJdAWr0moGhu0dDcndGaEBXG4MjRVHDGFHExjr7yyey87uAmEvjtV5FR1aMKA+z5D5MN6QHvZO7zWrg4/AYqM7vTOYA91HCocOMLachou/TXgX4ViY5KRvt1C0A e=found 135 iterations",
+ "pub=MEMwBQYDK2VxAzoAJu/noZ3TDN921P39e/HAqFLnQ1++yeFWz/FZWVGkUgMkoNFCV/V6CYVV3Z8GtjtblNexU6fX3okA priv=MEcCAQAwBQYDK2VxBDsEOdaarL2FzOLHkOTzhjUunuHgmt/+d+VRk/+YtDlGrV+SnDSMf4AJzFnj60Nm1YYKCk3lhKj261RMbQ== msg=mSE4hgpQ5DcJfJTsTcQVipiyoX0HXXjF9BykxtP6bmr2dE/vbReNZyd/pPLBXA+lMbmQJx+oxX80hHmjc/z9pA== sig=hBw1crgoOKuEGcuyqh2l86Ic3IfH2JwWIURSU+JMBuLe5dt0kebMGaf47mZIcW4gKJvjVUKNjJmAHf9+F/lIzcNB9z8Es5cpoREqR6WlcDR0sR2jgPr6WcY25XOoAuU6qiH5hlvxLEFS4BaBuqCs8R0A e=found last=27 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhhXrcQlrSnpGZpdVjlCG3w3Bwwxgl2dS/pVwY2dg8W418BZeHmeu3b7HaFgYNMnG5IqWGo0StBuA priv=MEcCAQAwBQYDK2VxBDsEOUkPcCUPgqeB7QtzWSmzXwLZNhOAn3/+fjxEPu7OJ8s3DxmA0jxjIuuOfyCyThJ4KRowj47KCXcrQw== msg=TxLFqyxvg35Wiqg1aoWTab4CehHxuMHJbtdWGh5X9bOucTo319iEcXR/49wVVUKZeNbaRvq6OCVzGUszvsev7A== sig=yMYQ+Kkki8BXnL2EKsc90N0TzqoNQTGuMarPnGXnympmWBEr2v2ge6FURbLHVCwV3539cEVQiYWAY9nrmqvyMbacK84tkyIy7GfPDbDcuux8O9GTLokcjicI3uW6VG8uagP9q+IfNG/koUZDkntLQyIA e=found last=20 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA0sQYCmADUHSNYfA9mjMy98u7nOgrBXoxPgXMM8D6IxhIKN0m0v8UhEDnhXjKkKlSznDtNYPor9kA priv=MEcCAQAwBQYDK2VxBDsEOeGoEBsqunhw4a+ZmKFIuUYfZvbFDnyjPdD87bxLjAFSyYIb9S/bTdXWbsR5n1BbrJKe9sylBHN5GQ== msg=OewxmU6ERCFVNZD1JHQ+LfkDUt8Bsy7glFkkg70BNd2U17cawxUEdvmOdIVbUnRQ+KlS1XTnDasLHEC6pucI5A== sig=PnBDqEPJxWeXhdU1pZDtUyxBg31k1KdcVAfWIvtVuiegTHM9B8hOwB3wpFISqUbqs7VHp599NekAMpPFcPZs43LeFJa0mbDaEAjSqD1CjGfHePYu3QtqZLy9IrHKWGgNt0wygP58UNa8SPzHeKrSHjcA e=found 202 iterations",
+ "pub=MEMwBQYDK2VxAzoAqPpSuGNSB6Y68vConl966jmTEvWatF/1t8gO0cS+ZvDXDAKrOEE+QRhd0G+u60mqaSxuFfvAq+AA priv=MEcCAQAwBQYDK2VxBDsEOX+PLezpXVVKI+FZtvLuE14grjpYvYyeWKY9B3YdH6qE+LhdlJNnjRS9GppraajdRAEkJVGPgNd2ww== msg=ciVnpSzvZbfJe35uKgISXkAzWu6/ezHxLgmFhCKMP4wZX42Nf0xJYhHwbfbJfpYjE4LkY5JGw73SzGL+/puoJw== sig=XYHHO4X5ZTpOKMvtLur4cIBD9Ue523iIkn3fUJ1mgjK9Ou5hAyF6+jyY7r/qaaUneUwklslUx/8AQwn3gn+J29xfOGaOwjfcPuLXjLLL++zjBVHtqyCcuGl9g4wlcVXPO7e4Z06rX0Qd6UhfR9tjySoA e=found last=27 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAHSfNFXJuMECOIF57dY+mwIESCB7q3DJIgcuOkQTqRXtW+DBj7MfFvTznmGl35ig0Gbg1CDqdBVGA priv=MEcCAQAwBQYDK2VxBDsEOUm8eepug7p0kRzFVIlu4YcXKA1xDH0XLGSpKMJ2GhYLWihXvYLn9iktvzIIOlb+aZrnygSzQtiuGA== msg=o9oTn7X7nZ15Fy56UhUET6XKy/XqGfkhrgaf/q8abSFr3s6dstjzsIrHdGGfunmgxgaTbosNlAjmP/zKBD86yg== sig=TJPleHC5oZGI+0Q8PxsFO1KFJkZAwJH2XbtG5dlC4JFVEj5+IszRp/CfodbmqZsYlLNzgaGU04mAipctIY8s0i4UDmtATABZ3nOkuhYLIZ8nJtgJbe05RJTq0tiiC2/XRIVetq+pSHBxGZvx0WtXWB8A e=found last=23 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5FUyp07oHVjnzLH/Lyg5FVFx7WrhaBnDDSPFN4pjZaDqxWep9X8D+ImjkAe0qE52WqxquSVj+RyA priv=MEcCAQAwBQYDK2VxBDsEOU2XSK0yVMyZWnEl4JGkFt5gk4i17jv5HWw2/97B1v4/rwAjlwIm4gZzNZd93pV6nOcGMPBBbrQUbg== msg=2LQF8cPR/JLyuywB4i5+lXpDg4UEzMtNMYIOo5HMoBu6GI09DgRRWRapo8UzPthTfBIoL3TptoCEHrnquZtWNg== sig=BrC6Im9bHWZhru6e0t/ndybX625D0hYnGjkSB1hrtg3O+2LA4DpOlEHQxcwnXG7YH3v/0ksLd6eAdpHzkwhPp+8fkUlkZPI8s4mICps1bOksMTGetgCUDGVFma8iefDtjuRodBIpHcYF1ZFxaSWQ6SUA e=found last=26 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhdlS6YAY283k2Ob1N+YZYIPCWMI/mfWc+ifSaCqSJR9h3kwP+5CaILiBkAvJrh+6KYB4WULS04+A priv=MEcCAQAwBQYDK2VxBDsEOTmsGrR/z+X6YjtRJ4wP11xIpq+3Lqyq7Bz9UsFHctheXjTXCead2n/txLXUkwkcSy5/gYpGHivoqw== msg=cS1951qzvg/suUzad6jhvHlsusHjvTnEMpky0yAyG9VoGIopimTIg8zgE1zmhRj12j5Ppm+g4j9EDS3Wn11uMA== sig=ybk4dJ16vBX9qePsvvCD+ghBw7ydWLLFcFHXxg+520BcOvYO0beS9k7zy/tpxN/RDQIO80zLq1CAr6TziMt3n/N1U6VATVmwh9ANH6T204MN98CvS0jiz7S92xtAYHwRUWW6nN0W4bwng0UVAyfoFTgA e=found last=18 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAYJQrIbH9yOUcFUO1gV0MDl2SFy2GVPnU9Qu94OSpxn9jqukElCgfbK9xRS+PSVhzI2VEWCZT2KiA priv=MEcCAQAwBQYDK2VxBDsEORL0tisy/MPZvDoCBnkd/+9dS9STriNZsDuIx9ZEbE8FbIDg2fb9ZWisFvzamndpu7w53B8f1umc5g== msg=uuf37T8tlz5keScYezJ4c10a9boJf/oSB5Mv4pJwPWfHQOee8Xexa6U6kGvDaXMlHidZVeiVdxUJYLrAiz2xzA== sig=MLzqYvNyjZbxO4tFveFK9jH+JV1AEUCiZK5sCS7ir6LtA/4BLUWiCjfZNfMZvNIe96uJfKO0WM6AaijbxIUIZyRCfFkr83Cgyc9Q6zecF23uZvrPFT61xzgetK1zOqQjlBtogptkL1XT6yKaI6n7hgkA e=found last=27 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGJPbqLOs6pyEUbk+gz5yi2Gx+uKxMwP2Khb6UPRK5c7ZVSTLRC1i9vX+dujXdg3727sIilJjgBKA priv=MEcCAQAwBQYDK2VxBDsEOV+vL5ZOsAcPQ8uSVNT6rKjfafsApuGHAJqDZgk3fdsTst5nJ/A4x+PztNPeWuIYhBAjZPfIOPtb4w== msg=oGKlZepSQadEvzPganO8RFiCxZsJ0FCQiGzVCHJlVyWRBaXRFlSFMd4/CvTQMsLOFrH/7yA6JunskKhF9Crsvw== sig=5caU18EUs1Qsal6wjzuqySw8pHAmx0cRMKig5R8qhyLDgG/3BIVoci/U/DraxrGgsc52vesgt5gAc9beshm8VjuUo8aL4wVDfBC4l5ufdH5OhVjAM5/yApMxkQZg+7PoBg9KYZMVwMQi2VQjGCggJzUA e=found last=19 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJNbexWimtatekhKyNgZid4hIZz7u/MD0YKLuEn0Rc88afjoHpO6mwSptfD1k9S/BVRTvJhYgzJsA priv=MEcCAQAwBQYDK2VxBDsEOSF0bEQxbT0svY9qyapiBTPujX8WC6yCb3wEUPCB55Jep4OsL129eEe6F3IUWOSk+d1NnkPiXjPE7g== msg=ts7UVYvPSMST8suoInZlSkcIUrAsGFlmS+6EN9luktbR4b7Odh86nss1lu1NFxqHTH5VrkdrywO3OkbvmoXlNQ== sig=CU7RqiGX5uWO9z4fwxM7XzbJ/AXjR3sDQ4a3kktX9VYdoptXpxTclIq2b79jso+FS88vqQyFhJ6A9plQLrHY4JmNdxExWIKcxLLGgu/rZkeqVOp78ZGwzqoCLm0dHIIlBhYWxWFrRQxrjbiDh/PfgxkA e=found last=17 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAO5CzswjGITCOcJS1zvfARE/pKZDpdkIeQoyZYH19uFwHNBMqSTcdn8Q5f9IYKHsFdamEIl1yfd8A priv=MEcCAQAwBQYDK2VxBDsEOWH3lTaEsK5HY5EPN54zNQ6WrXW8aPP+NSSp1r9g1i103ilhEbKseqmM1D7hDP9ryTTGDObekJ5R8g== msg=eqmM1D7hDP9ryTTGDObekJ5R8kd/wdPbdbFCQ1Ju6ut/8mknhdPtxSQss5r7OvPKi2hl3BMERZ+CLIOYHJ2qUQ== sig=HC5PFXbjpTtQnMpWsNHeUTgwH53qjoXZBGYRjMblcm3fb8o1dXQdrKbVCLwZcaoRqNWB1yvy3c0ACCeT7diW/d60V1z99cyCjzpVKtXg5K8dr4qpNUvOgwGHEkfY1TBgXdSN3GGwaMQgxXK6qbgV+y4A e=found last=16 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWnZj74nJYskgqK1OOffluHkQjWtQn0Hfv41KxZZIUVmmbX+GufIGMPDqqGlEYE85VyuDvijfaK8A priv=MEcCAQAwBQYDK2VxBDsEOVw+JhV/3VGIr7TbWXds6+xgHwVqgmuy6Uu4/XSEw1LiPNYMiJX6w4fnKvfFnPtuf1Iaz2HBBxieIA== msg=AzvCWtMWPuj8VBC5sSh+HXPdGn+XgfwdMoMyv0hDHW5/+bP6ABUMrjm/JRHkk7GO0XROkpvZMJz7EHBEQwKIYQ== sig=luFO/brxeB8st2Mfun2ipBBkvLdRmC7+Irv1IbeUrywrB6+uCUOe9h5Yjqx4UFx6qLPt4c/Ubu+AlnS7olvC/N0PR8X3CKQC2nUKCN/EcHbDtpT7KvfEW1FR8ElExsYApu/NA7bJE8pGX6e5e5CxaiQA e=found 136 iterations",
+ "pub=MEMwBQYDK2VxAzoAzpJurZb9wnwuZuVhAYrJvRsFtCfAPCleqN/VffPybOmhrxd9hexO2mktcCoCQMDQkrFa16aCGZAA priv=MEcCAQAwBQYDK2VxBDsEOQ5t5qTSfcX1YwcSwPWe41T8bJ5hIGCayMpiAI2R5zwPAAQ2SwKHuoPMC76EfpMoQdD6x0/2MnPoeA== msg=syI3WoZNpcKfQIcah8CYxwpsKuEXyppidos6eYystSqLcV7OI9xsJP/GPNnv33oH9rR4X6FA4iEreRApZNi6Qg== sig=qvQNPhI+5nJuCH+syoFZkjTik/6iECE0yjG6U8e4BM93U+NzyGz+WHjiod1Hm1CYiidc99GpVvsACPPuRUXimixq3I4xmy5AXmFGYdmuB//ANaI25T+TQ1jJh2K6itBCLVCWQBM11OrukLi3oIjZwzEA e=found last=22 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6omeUPtGyx1yrLodNk74Eg0ihigBIISZzbdpcyp0XfPFpUiMSZ9/OsE0c6DuQJT0AIe2n22K/r8A priv=MEcCAQAwBQYDK2VxBDsEOfzwGNswanchnswGBWnPvVybP6XRz0WwpXkdGG05Hpkdg7gVXOaC4EY/237ecbzZo4GGikEfMq9KwA== msg=X27x7i2+7pw02tWrUnncdH3y5SPpQ3k8C950iCyNaqIAcoV8O+g8NQQCBTa5pclfxjsR39BFrg4HvC+R54/IeQ== sig=BKjutl0Ee1DwwXAPl0mUYpedjLLlVWIbJU0qrxNOxBCATNtiNQEIdlFO7jskFga/BPWjuJoCWtKAB+eZH1wGxiPdrofDnqf+Lqb7jP5L6D2IC4RouspnqzXnJr9QhCe0SV+Jmjymqrmt4W0vt+UTSDsA e=found last=15 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGkDXQe5+XM7OeY5kpWt0R2dEdsZzWrtOLrJXznSEyXF27OIEm4vd1pZlMGe0glInkB1GiXdugXKA priv=MEcCAQAwBQYDK2VxBDsEOW5Mmam/LqNOx9gDUe62ALCjFhoGiqnl1fuqmNNrBWdE7S7CPeZr9RlhBpz5QBZ1cs+G5ZrSleHaDA== msg=D9CyDTq57kuRvuesxR0eM/MFIN/77V9phiDl420hpOeGNN69Qxi86hPd2qYb+Fz56Wz8GQQQnNFV62kxOARFKw== sig=m1Hv0KYLep+iAl9jdKiRLnkOcFnfXMXwUmjnTKxVKbw/fYHdZzRYX1GMUtpYeHtT5oTeaByooVcAGOj51GNqc3AAJGsGx3DyTnceif8yI8TO4UMQhwMSyuZro+6RTehJDZcqB5rAbYzCXunJlkKP4D0A e=found last=20 s=17 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7fd6g+eddrO25BoOU9XFXr+xPnjbsnEKsv9XxDHGH0p+dQomn4KUCgpDqDr5a3jQ9L1mfUn2IYYA priv=MEcCAQAwBQYDK2VxBDsEOeChtf/0D3zRh6s0W9wgJspGl9/aXQS7m1PlvQNIKMY+Drt+6bB0Ke6uYRkoY2Pvl7bh5GYyTzHNJw== msg=5bHuu6iYAabkvlVKD66NdyrrmpqBmpNoI2dB+8KAw0oPnl0UHKFx9aGDn0/8BLmJsTeYoLT0rMKZMQ3nBlp5qw== sig=n6QKn4MptScKrR06PtEKre/+OXKzu5xvBpL++Uq4mCCKCzU41Hnlg/9R36ypJOz53z1oR4l1wskAAdLfDWZPjenQrPjI9qKOtvT/5PvF9cDygHl7bgu8wVRx7qaO5AhF312d22l9baJ5qUIxCE7D5BQA e=found last=26 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPMm+xEsTlVaPH11TSg8Vdbw/H+J5BAefOnM6OSbpQUyegjGJa5XhhEkbBndYEMpikKFl01T9VYoA priv=MEcCAQAwBQYDK2VxBDsEOT1RX4AjFWbIjJ6UDZWOXA0VGHoyykivEBo/d3jH8bZrhXkRr/t51R+iz2jG6aLD4T0htN2y5FeJGA== msg=JsN6SE7pD/WRqi5q3VqVwyLSgILsHt7Fi65kF9dpECfzX5XDl12NqATwBCMIo3tn5h05/AB7YM+P/arXVNnSzQ== sig=MyZhqp1uVU6EARxLeZAODYrN18rKsTtEPl0CQjEh60BmBd6418QTwOrCr199ihLdsjRkE+0QFHmAJGpZxYhLbRGFbcfZNqBxvq3jYUqYzGtcFlrLaCUyZ0aREIbz5m7aMAu0CWiG9mPU1w6e5w4mRggA e=found last=25 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAT8EjX/MKLdsG8kGN7Qe/MEUVzqVKW31JIIC/JiJZ0ONqCpeVYrv1wbWMMZBuS8gtxDtuvZ4/DP2A priv=MEcCAQAwBQYDK2VxBDsEOelpRr7LiYPt78Namlko1x4wAJFkZTKkvQKMQkbW/Tzrqpb1CBU/6XTio0Qa6fvRY7hw24T/sKzvbw== msg=xG2nz7m6uXR9/in7j8YCBIPsv8StNSOJ5WjoLZmUuJASstDQcBXx0KzQAgaPvxOajvR2vbon7AUEGbPpSS+deQ== sig=SgwFKgw6XctcwbyseoQ3U+hozNsjj9lWounR4RNIl2UgkKXq6RAY6BEfJJtHho9qocpphFlT7BQAA+SB4U12ERhGXRRnuh327SilzgpDc9K7HktfL7XhX/dI7aQ2llql9wgMFptXB6c1KCI+8OB1lQUA e=found last=27 s=17 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEmzPc4sZbOutezx+mJxHzUHoMKJjQ1MRK+L2o/G/vVTQnb0q2RFJuDQor7CpSaDVun1R6He9+wsA priv=MEcCAQAwBQYDK2VxBDsEOY3ooiDYO1Al9HAUluA4nEDgVk4u+n2D+vGKEQflNGyy7h8MUVjHoU70KeL0JYQsAVT0EpYUZLit0A== msg=O1s4RPFuKYYH/WG/25CWB7wWv5aIMxq5x8GdjvPl2/KUBRZFUlT2m7EIMh8hr+NFRIYumTlbR650XhbEBBNU7A== sig=LqMa6eEGCOf4HpBz9QPu7hkqqiHYiWoebqFkGd3E8FC9PXkdo7RK0biRvdKs4PAVBZsIkuWPRWQA6ECZWHC6txV/vY9CzEGvRzxy54aUxpimI2vTmdFzLXiHmAozLg3E6D1zXwulkzEBKkoZdQXiox4A e=found last=19 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAkxTEobgiXr6Lf7HABWkKupFarn+MmPKyPRabEHPWbhIId76Se53w71Vx2as4KaJudK/Mi5xex6EA priv=MEcCAQAwBQYDK2VxBDsEOeT89STyw7ijSITNx9Ij5GnznYlFkpQP51o0dr7S1KmFlFrxq1mVol43s64IdjvkRgwwlvDMgcXt0g== msg=BS9NQ5/aUcBvGb3HH4VHDSNDzK+UcV6pDwy/YdSxv4X2V949jZda25AzJRc51Ga70AWUo1MD+VPPykvjKph3Aw== sig=YguRgiKTWfGYZoM03SIQUlDSbrzqRrFekeGPYFSX4pTsztiW1rzOWw2XUTw8YPZNQQT7w+pAsmYAOJ86HS/bYF1G2YvTQcNBPUDSF26XB90MhnYu5bJODHunr0YiQ0NyTDc6trFcus5e4T6DttqwNiIA e=found last=21 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAV0kfDVfUaEWrrz0M5AwiOknmZbL6I2zyQhgI7aW5+WUqiJxraDZElUmB+gf+AKfwarFYhEVffjyA priv=MEcCAQAwBQYDK2VxBDsEOVjfLkmOvyhZfwU/1CKTAqyN7Cs26YkMWt2HzO1r7rfX+mg4pv8kvAa8LBZI6djtbBTRFkuNQWaIxQ== msg=/csnHx5aMzfBoEJr9HU36otGadGHdPs6HhQsG43l84dHlwI57tpYojq5niZvsMmTGnvfmEjC07qBKmWDduqNYw== sig=cZ96uX0E+o19s36VmJ6AkGwaU2q5akX4wyDJ1u048SADOZylM9i2Nj12jtkyeU83zzZeWF5ssuAAlI7nx/w8pHpWRhbDCnPTu4aLYc8zH4/Yo407biO3YRGHdkbHoz+HoQIF7R8G6QEIwCbLELhOaxAA e=found last=23 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAY1MaOgGS9nAxaGOX5tNCYo1vquLLsxbR5HZao5d2leOnw4Z2iX+8lk4kz10Fe7nHirtZreW7AZMA priv=MEcCAQAwBQYDK2VxBDsEOcRNX2swFZcaOMbSLR2bT1ZBRrIPugEgr339+TrkE6JqUH+XJJBLE1pprTRL6OqIWbwL5rsglkI2Ug== msg=WV+Pk8tof6v+DGFKT/x5nTurUIqV2rcUe/d9agGBV42OV1gTVK3dsz5sRbOu/Yp+52k5LLhYX/v0QdWWKHfKPw== sig=/bixQ77lvahj0OScn2kVhlZY5/NH+vS2f1S5SAZUPFrXFfKINp7AGz5TmJYX6dt90Nvuu3znZLSAW2H9F8Ujfnfm3tQnC6eYNqFydI/etP6hTZTwWBWFa9BZ6GgSCr5LsLAxZ2XvEm1ncfbTLbGtaS4A e=found last=23 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA+3SK/8IGcyjQBMNPS1auf4T+9RCbVU7GN2ZrJ+Wkz3Ybtji9e9tTXgFdhMASYqnGuCz8xsTsZEkA priv=MEcCAQAwBQYDK2VxBDsEOQtAgNKWIW1+T1/4oL9CkiFNtld0CZWyBcScFLK4IqkN+JHuapLmms/+YhYnGxgWkFsGADVhAmtcjA== msg=kwrJgrGL6K9E04Tx1uY9Y9DaNybdGMHadGZ0e0UuMT8lhVguebsMIY7Buabhkh60F7e/oqLxgKxKTUdC/GsUcw== sig=mlTkqh5wtSiG00q23CUJC7aQRG1sPm/hQ3twGL2FdCgWYn1v0/YkpPJ87WiUGqCkcQz9I35gcfgA1nYGWR8ZYoG0h8q2MH6FCbHmgppj31TLtWSUhi3dXxtdLzE4qKEVS6Ic3SPYLU8WPKIryaOkmwIA e=found last=22 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOT2WXg5VRHBKyI7ai/9Cla8RJ5AYrlpi3rAN9cgd1JSUgTNiY6FOHyuhmgcpKPfIhYewdeAGcZiA priv=MEcCAQAwBQYDK2VxBDsEOWo3iX5MT68KJAxAXa5QEe5C5DSUs7jnetx0H5K8pTZeJD4nKOm/XyQcHFMa9TlYP4v8PqbWXW81FQ== msg=GUBGb4H5lk1aNPYhQXPWz2u1GY1OFyiaxE03PdyqVbr+uhE3uJeBbW45YiaKdhkLojU2q8LHdqsO/A0l5XlYJQ== sig=L35eMSrW/fr9h/aoYNHAAcsyjhMAufi9FmnYoFxCOHhuIiNdkRhiQJ6d6+Pa1yaHYDP6r/GdSJsAfef4rTpVhIlcqCHbMlJR5te3uWn45EB3VnS4lr51RrW2y/sxnNEyYTDd4lIQ7xpub1NZluo4dwAA e=found last=26 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAaOYmeAzaLG0LI9MQOVh7Wmr1j3y8piWoGYEcHFGqghstqvlpeDKsw2NNjG1ukGA8oVZjY8iGqRsA priv=MEcCAQAwBQYDK2VxBDsEORDV58CL9p0X6m315e6Ekthq1HKNclVTKasQ5C36qjKq9y2dPJTtOMahLrjjj6QxK42pA/MTD1GzLg== msg=aLXK/qs5Uoo3CosrBkfh2Uf60Y+uEF5QcCAoyVrgehbdPIPcojJqmVdYvQ149IoYuqfXyBfnnBMY93xtuekDIQ== sig=uv0nvtEoAshvt/WkCbsB8/20AjjkqHkG6RQ++yUVEefnWvgR4Fjzs4pbqhoRwOY8grR8yed+rhiAx0sAl8+896UUUOdBJhTeQck1vSMyHl42b9ms7JCTfl6pcTWkVtrQ+qrSeGuxGWtzw4YkocS4ZAoA e=found last=18 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwjcOZ/s9VbBFzCwOw7MS29Ix2uZE3wXldi6MVCgIn/KVYu1iQT8AJucVCFMs5kqihNRGqZA9I60A priv=MEcCAQAwBQYDK2VxBDsEOegWRIb+ueV1fWBHtZnbSUyA57oSjiepa7UxanV6BExx3eVJi/Y8snGCCrqSMvBBxTh2GrqKyBK8WA== msg=GAEP+n8n8vRkVji+xjq8xQ1PNT46imoRL/ZLR2/tSrgtZXTCGdoG6flRrJ3CwmqTHDJxo0CdTqP2JrpWtx4JZw== sig=tTem1NBoeAE0moH8aFmsc3grC7nhC2e2qgQtkpLf+iTZsdJgb64sz2XLvTo/ug8AXsPJTHu0Up2Afw5VBuC9kR79N5DtavZMPXkdF4qlsRFhXPV1iIg5ISj/alje28JF6LOQbHO8Lg0D+N6jSaQOdBwA e=found last=21 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9M/dWHXN9TTKWiJTsobCRJrZcFQDHeecDmN1oSveZgsNyOdRloh3Q3DM36OBQ8QIEd197CkHIfmA priv=MEcCAQAwBQYDK2VxBDsEOWv9az+s5Yh9YKxhw3BBUCxO/fWj5H8j4DTuC0xnpHwlP8IyJ9HMn26tSP+xN59QAycE9HAKEoEWpA== msg=ludwujbER9TYRhFmWrFe++ggqbNOAYQcHqf34NqlldPquTGu09RA04Cm3awj663LWpaTX1bTjqeeQvufX7xQcA== sig=Vq75Cc9HP/tOwvd+1pR0DH4Ucpho3DXR2MMEPeuzdN6DjvAxNArdPjala2ENO1NeBhB0Vud+cZkA3wlCqmv2d88BJa1nm3x72RMPLv1BJOg2HQv/MICc50rinRNq0eAhSncsk8f66bKVjfbAfhTRYTUA e=found last=25 s=18 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAKcx5cg1N+SVsflZlfBTMgaTAG0pMJq/SLmI8XSl8B3134S+wrYWoKofk/OkW7NQlueRMPLtR+3aA priv=MEcCAQAwBQYDK2VxBDsEOd9grUuwt+SC+0QAU0YPPa5ERsToXftqFCyd+RcNv/nvHwSqPLpZpAcvTXpEzMVH7inT1FF57bmisw== msg=IfgO6a+JniUzQRXeoCKj53v/nQchz0L5pVYZgqP6kTt+b4CMIrcFEzRdzls3hlfvICsaVSBgZU3OSoa5JP5UBA== sig=XXbMHG46DrYMwfrZks+hSqEE3bqL/j3rtaKlngMj9z6U0T55CaiBdW1HY8kHLAfZ1UEHnO85dGuAiYpRmDAX95m8QWqUE7ZXFse7ZxUHzzwt/TNZ93k4VmN1v3IOMdChbbXBSmsubhtbWrLOIrU08yUA e=found last=15 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATwJI4SEf6gbTmtfTsFjMRF6Vch8Nfp7V67uRPkVpR9mRRgVnwbhvbLdRdEZ1c2P48atvPkEjtBYA priv=MEcCAQAwBQYDK2VxBDsEOaB7OW39OrRFsPGTmNXv44lwfjXWFs1+/5LoRPeQrrLR52l4ZqydV8itD07c0Pv/XXCbI8W9dwMS4A== msg=DfJ44QtC/IqlinmBWw9wANz9GXiUSf9kdpLMQ/pBz7gPLiPlL1TeFQehgM81UGOlKWubQTRLlt8Fyi9Evl8T3A== sig=BiH4PkwfKh46obM/s02kvf/9GjVH1uW1jYi03Afh0QzvFEyt1kHTqR4lSV42ers+Xr61xGC+DpyA9pRsMM410zr2eAUoiE9ZeOmAgL6NInLLiwQlVwD/+Dmvvm/0K6uJIPHXzHek1u7/4JpJwkw+MScA e=found last=22 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2lXTi9AzL8t6V6Z9W+rqyv3qfhQwarg1o/xtWa0I+QXH75zry1HKNL7MVOltbZFqPAjfBYFMFXIA priv=MEcCAQAwBQYDK2VxBDsEOaB50RK4i5V8F9QmZ0CteRGb9VHn9FaSSnWPkz8gAd/go9Zq3wtyxqqLXh/9aEyVbQLED1rfKzNiyQ== msg=5X+aXRMGaVzzbH2OIxpI2t3qpMalI0YOtHVK+L6B75Sd3nMwfZsTnnhOn7aHuYm3tkStsJ1rZyd0Xj+nzygU9A== sig=Du8Cx98ANlCYBCpaSONSGTysqMXVbQGwn5+2kFHD42mPQ/LLgCHMrSRSM60w+iuSXMmUqR+3c76Aw9xrIAY34fLu+iXzdwFZOKcVTHJVX8yVEqEPd92YMJabSwP0qgItTkSxVrspdY4gN21TU9eLAS8A e=found 133 iterations",
+ "pub=MEMwBQYDK2VxAzoABIOBKI6T2ukjf6SnL84sD14mSi42ITLoua5xmhXtPaB8J6dHj0UGRvRpuH6/JSPKa81LT91+pUiA priv=MEcCAQAwBQYDK2VxBDsEOS2XEb61cjC1M9p3zOU93BExWaf7Xp87qPVmejTx3kAs8oJsjFCz+n6OI6mNqABHpFfMmmqK1S4FUw== msg=6hWW/lYxEmxCSyVDEzcBU4zxm/ZxWKtVfWFSxE6g/fBNa3I7hHZZK0nFNP3LdPFUH8KBm0YIOHcNp4uTkvwfXA== sig=zlNgkD+O8Tb4PqKVL7UnK0tZ/KkX/EGtsMRnj4R/n/f5AC6Srk5eefcNupKdfsnQySQVZaMI/niAvNTw+3EAVaE2uHw0zDl3UPV+UhzJu7y2KOU+/okBwIQSsQB5FciByt+Tl2aa/ZhGS+4wxGjeeB0A e=found last=18 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAM90h0YKMGqbcXNmpuy33e9C4v/q8ePlLjR0NYPUV0z7Zl7NQw1gQaExBDtp3sLJWndCGeAjmbnUA priv=MEcCAQAwBQYDK2VxBDsEOSc8T62HOr0uuhP7sGZSvO5cfnc959xj1ASaJEqcQ131eHkRIhc5GkNBZnFGkMcDzzGpTcxWIBZVMg== msg=d4IyOyzCRSrfP0loFW5yXl94XqtwOTgfEHYVS25RsG5+KLAfk+Vb3IIfKStPFXeGqlb53FuLbUTKPHHto/2mug== sig=jNn+j4rJurjJRc33bXjWYn6Tj8gFfKKy0pBmtu3najAUOEG3kvgLNsZvwttH48n3/KtWoj3nn9QA3n1n1fuwv3qDB7outxljnCmD4i5L9OdK2E07NK8PHHn9rlAXgVQ2Oh/QMRfZXaH9yQqFej7dxikA e=found last=25 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGnsoTpnLaeItrD/bjhujrYVtFMm6NEa1A2ZdfBia2R8IQeGbvD8SRy0sR3UNvZbAdVV9CMi5X+aA priv=MEcCAQAwBQYDK2VxBDsEOS+zBj8dtkQTdLTrQlaHu4JRNZ/Mks+x3/ffEA17/lCOpjWdM4wsP04ShSK7XXjoWirzifmt0FPJWw== msg=2rzwsEgTDATs2ymN1BP2BvcJZpo0IkhqngwTUvOkHdT6gDZ9gGD7kvtT98zw79NlefcL87J+6VyNANuwU8BRFw== sig=8pKKmxeDU7ZD/JeMTDegx6B8cFUbYGB1Ft8SrP7DWNXCZF3CZHU5bgG5mOb4LGMfxaVsYMAPRqGAk0xXFZ/jz6jwFXjbTV8FYWmxntmnW0On5LlWC2KNIjTLdWtqortOtQ7REQAH3F5aJD2UeQULUxgA e=found last=25 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAOn6C0+MvF3gJMDoKMYYGjPbkCPoXCC2rX8aY6P9A2QQQtgE8Qg8F6DxqHZYXg4mS8cM4A2GT/fEA priv=MEcCAQAwBQYDK2VxBDsEOdeS0DksDiFNvZ5m/04b4CVCTTKMRHkVgsHo52xkTwmBD8Tp9KymN7qt/oJATUHNFi1pQFfzk79+wQ== msg=blYYtq0XJcD2ghHcBXYKFeZSR5zKRDQ9vmXQDN2MYzNVLFPB3/m1DSCrS+b5c4WFUnRRLvn9hrPdOgcG/cC1DA== sig=MIRUxCMlqhGBHMmDkNxP+zHrOZHuwR0QUqQpqwQkuhFKDtocj15qvkO1oITPP1ULKMtaP5ZBgQGAWgTgaxZ5FtJQC1hSHl7GrucKI7TCYgvYg6MeEIyboMQSia7hgthmD60VTuG8GAqZg+PNSbO5ygoA e=found last=15 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASdudRv9bm/GXtWb6QhAL6sD4luG8N60S/QuGXK1dAwJ3fjtRVQz7eK1PQPdUWEvDXzBYc4Z9YWqA priv=MEcCAQAwBQYDK2VxBDsEOSK5Au+Dj8vtuKF4efB32gdIUHlI9Uy1auHtwxRsL0/lpsdeFQITYFoKZ3FDW67SX1Om/v6YI7hVHA== msg=vDpgY1xIZuQ6T6ZfRrVrFgCrxTUKkH6naWzazguJMRsYCBcChzrNwf8sRCM6WO+nVWJldaezUifCE7aWvJf9Eg== sig=W9En22WufZsQyDvEKqRtbIPyKVeHgP5Jn1pk/OgXM7BqEpBq7ZLIoTZ79y4ciqnChOlmppkZnD6AWqJ799ZzspWFiKfrzmablbGi+uP24kJ1H+SGmdxGfJJpT44jY1dZEE8tTYQJwTuyf3f9xLLcpTwA e=found last=18 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAvU3IUuPi4um8sJZvsuO8eSG6WETCxLHgetjg8lXqJMKdeObSs9v12oKe8zuLmE9kTbPj9avy6AUA priv=MEcCAQAwBQYDK2VxBDsEObZDJ0FaUJUh7Srt93QHZmqUUydYKeW1YQeX0B40dTjwU2SX2VVnP2t4A4y9934OhOOr6TslnloEEA== msg=WrLQ5DwVuIyMR1jpegk98WqqqSLV8en0o/vBkb+qqiXaqMKTmJSg1SDGulNmfk6q6v33ZVCwg1zKcQQat0Emig== sig=6gMy1Lqkbv1QJDPgnzXKYGillwA/FVjqqDbkml+Dul/mJ2XcY7UjAvcModB+oYxeaN/bP5GihGcAq2941i0o+92D6EQNYAYOrGPxwCTwhYyGXUNVgYryOtIc73shc9Po87OMXr7A0w1IlweG9GhooQ0A e=found last=14 s=15 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAA5QPD9bmb780U+UKedVsd3qTyRt+PuWzYgsB6r5/jbwvOwVDBed+KF9ke2waXmTCnLRV0ycUneSA priv=MEcCAQAwBQYDK2VxBDsEOWrTDqWPtuJ/u15qYFd5+gf7vc2zArRhB1YcZBZAEy4eVvs1kPAL40M8Y8GmcI/JKF1fwl35KMqZdg== msg=lyBoY8GGj/ppKRCLXmXUnwrKcG9PvAaEuZ04ugeqbq4gIpakOagRClJv7z83g6mo6n419USB13+Om3Uk8LSeqQ== sig=7cvyaTv2pY60lx7p8cLj7hcC2/TnL3PiRooP+NFGUIZ24A02rMSDlb6YUtBCFUEijW1Eols9GjkA65jZuTfH89Rb9Y1N+MXiqJv1egtt21KQJVnqMOW6drHD/t57HLOqfKjv34MilAst4t3xeWXPahAA e=found last=25 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAP62NdVoJ3t7+mtmN+ouxiaChHXZsX3XA/UmIe5AIBsc0fwiomMn1qCjPUMJ2RUmtcIYkQC8Y0POA priv=MEcCAQAwBQYDK2VxBDsEOe52M7an9qgktTlZUJi3WLX8UlA/b0Ar8DD8qYoesAEoVy3cwrGW7OdOjWkBwNc3sNXv+RUYmG6qzw== msg=cigHzGa9wxsvlb2fbi8k1IcI6QO7pQYNPvfzRyvxRMwdc+EKfFPL949i3hjPP+Em2Uvpmj+tdsJCadQ0/YOeeA== sig=vsn1R+jpPGj6zfcrcZLejfb96GDK5A0/yBjUeaHXPBZmgIhwaaq8JqJKgHC6ybxujnfp8T+mFgQAHB/nLnchPQbST4+xaLkcr6ysdMmLVoHLI5mjqox0091ySadZC5ekfg7pKWCIFcvUORUMLt7zWjMA e=found last=17 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9bHa+QMevZozcVq47QmgsZlCmUxX0j67KuvWVvEF0Ok12N5AU3vQs8xgWdA8z5bx62u2VjdrJs2A priv=MEcCAQAwBQYDK2VxBDsEOerGNGevxYMG23Fby3XRXi1cliuGS/2+vdeLgDFGoItJK5Om/ELQ7EOgoy94odJFgrJlvO9oM0Rhlg== msg=jWS9lqdoOMBewp3HiKiRfzktgpTswzy1M11EOBj3z9s2IT07HpOZNfwORy+HoSKqRDGXapAGc8tU3nFZwvzGOw== sig=a30C3AVOluIXZsJAtews68JI5+bCDmZLIGwwkoP7UuQroycqwexF84knDMRFhbd+iNdJsX4BhkuAkG89Ycg4YC2czowH9WmWQMk15FJBban9bc8wqUh6cwde2Nuri0v4ptnnekzWU+xaGwEJUsBQcj0A e=found last=27 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoACUTCL3z2dIFnvj9KaUqPVbyE7j5eeSdbWBAoK66yXotxQZLF72qA6elKfLhQQAokpCsDXfaoosoA priv=MEcCAQAwBQYDK2VxBDsEOdiR9SC63C1WEGXSvLXDsM8RBd5jKjt72QqgpVK52B2WmH5YCR+cRGGFqR+KHTrSHkBGEsulMDVYlw== msg=3/RtxM2i08HkrZ0zC6WVfX7ibvvlOcFHcLGfcDBlKS/iVQ500fvt5NXkiO6NljEAgXag1Zj+miJaOX1cBcV00A== sig=t9R9gGrdyoljlZUh84AHhbcWKLqJcqj2xo3H6bRDOzu6jVsq18ycgDp4SldzDt45HRy8UvjaqsIAiZST9J56hIY7dlQuiq6KwKPhmTyaObdp3/+v1hHAS72QR5GjTvQL1xKVKqZEU9ICYzmEwIQlwTMA e=found last=27 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAM9uKQY/BffxAFofPK8tnEO/ORnNcGIJglCzpq2M3zRz0FP/LU0KprkXBDHC0FyB/GfcQY7+9N42A priv=MEcCAQAwBQYDK2VxBDsEOYKztArfN+CrevpE5g2VMmRduvgKpc7OJJdhEQpOHxis4zwPFxe7Rl7rff7YQGjhYfC7sdNZx00W2A== msg=1Dw+by5vOgkiDlOEeWsrVg+f0iWmmnKPRNkTyw6Zd355muytl5CQsHct5zQBPmNiQNchrDGAx+rAnT0vRdiC/A== sig=gM4ii+c5F6396V4l7JIBmqpct6s72+QUl8vYlHfu225vwsXstgShLWKPOOJX08rmUNJiiaNpSYaAn4YXhSHW9JpzHcpzYjWh6WeAHAAWtDOgGt/J9aQzzPRqgzoPh6nTdGkFaZ4He2yTRCDjI/P8YAQA e=found last=27 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPU4d5bVOeverX1You58LBAwk/GTMKDNuNQYv5Pmp7g8seosTBmOtX6xwnR55wrOz8hmQbBuyeE6A priv=MEcCAQAwBQYDK2VxBDsEOQruAVosxv3kGpQUw+g/WDbTaU+rEPVhQWMt4jwOUsrzfRgZZ+FtvZbUSiUuFP0n5hzSWiHkL4YM/g== msg=fFxDLUoS67yA5H5KuRyRtwSBsSAzHx5NPuDR2/JekXRzTj0dVHvzSVHa3wF9pXOhqmysbR9JCyWYBkeD4jg+bQ== sig=h0Qq2zYU7EJYmeOZwChFiwmJqnguNZ+oPKEFBqOSGoXl0dE0mQ+Klk19E94eEQFiFG4BT9RI2rGAvt9cJxJpc1nkLNBso41VTsklshi6QuVE/R+S5I7Zsc1rc7ylXOCSLD989vin7vNPeLwanxAntR8A e=found 131 iterations",
+ "pub=MEMwBQYDK2VxAzoAaoQ0S0obkyvLn78vkuQHwjC8KPfBxDKBxUj3HZFU+4rUUmDCE0dvUVLDoK84gcsCszurIZU2iQeA priv=MEcCAQAwBQYDK2VxBDsEOc3aW3Sjp3wDvutVCosueHRaNU07Q/gGzzALvHVEcOY7RGQMxeDvuC6cOVlJ4rXqKenaSZw4JVuJpw== msg=rLjOOn/OOMWpA8lkEE3wzSLS+ok8dt/5JrM7W2AG2PY9jMTded8kbfQUnJHeVe+Y2ZeGHB5qj/n6SDRG9JQ2fw== sig=bSV2g8Egw4qiOEen3HaJxEXBoYIXGAIOMjI6pky4+edMGf3N4Z2MStLx1a9szkLOMUNnwDgAVsaAE7+zZp2FIFGOT+pBqor93UifYqnn4y4TlEEeh2Bow1lOFU3h+MnwZ+yG/8Ey6YJgU+am3QI6gRsA e=found last=15 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5nUvjYoN5KT29B2CBIbcNtHorWa5Qbv7bxrl8LgHvNxyg9Y/A9wz9jkIo46s/0bFGFZ9kKRr9/6A priv=MEcCAQAwBQYDK2VxBDsEOQ142Nm28prUqmaB6YAlJyxY5u2zWBbEda9g+PwfsML335eK4hQuhFEMRhM0KTjn4edjFcU13u6pNQ== msg=0rnECeVczeq0KlGO51w0ePCwY7kjGzVLNBbQ4LuIJZucAVGZvfwjQhBV+ShmjzvQ26kU7qvKtSUlDZsxd3Zb4g== sig=w025B60TnciSs06FEY80U6nLtkatKyPKSSn4eTZFiKuRrrKWCAqaOs69vU3jfN4AaFFHzIhLmcsAtZEDjVNxL93l3RfcClDXLg3zKOg9U4phxrE5mByCfcR8NeQxrmYeaWul2D3r4zMuQofAmE8B5z8A e=found last=27 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABsZ4UdSHoslERKgOPNg2KZ1GFYpC9NSfZrt+6NYdyZquVYDVq92gD1bFRFFv4xvlQNHms5f+dzSA priv=MEcCAQAwBQYDK2VxBDsEOchUpsloA4NKuqvoeR8FoAeLuxNdxMBUg9M3pgs+4tqwleWTS3hie+OY8naxiiApIeg5jgOh5hvPEA== msg=YuwaXDWtH5S74B39GOpWg06NTOPN9WMLhWbZdVQcntRqRue2B5rtMQyRjgIBenzf0nnX2KpNTkwWihf75q9row== sig=svtVcUtLO3Uv1Ug//ddYmVHMW748vDh+a7/DFZ7zXkQgcYOgTF0LLGX0IQN7iDHwe8pc8Bh6icWAeGCdhjfHfMVZbGj6i0qwBgtLqJZpG/ki98v7UcwaHX+fbOZMiGI764x1IFuFO+5BpmVFVksR/xcA e=found last=26 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsv2ShhQeKDRmrRzKq3BQRqIP6x6w/Hbgt7Uk6IIuikiifLud+eCky5lV7J18VS6CglmqqUEqnIEA priv=MEcCAQAwBQYDK2VxBDsEOUFSslV7ggEr56xAROHR92lMN8MvBuO5cKginmMMG7qfetN687rgVZGh1mdbH2J6rvdz/98VkOyCOA== msg=y/Wlz13nsWKAtZyLhG5dAVLfBc7sPok1N+bVgza1t7O69Ql3UHMD5uaDUh8dXaOXpCebE7hzWeieFG5/1pOWcw== sig=7On8sPJOqrEjrklwaJ9lNRPmHeCrJWwGFuraWioYVuS45MHeNbQPEYXtXOYgd0sSvRhYMzbEKvaAHZiFNj2GHP2abxtZE5ZedJYKf1Zk7zWl0CTwBvRX6hncJQFXbx1ifEDC7r2+KFFPO+oFl/dYpDYA e=found 204 iterations",
+ "pub=MEMwBQYDK2VxAzoAkNybpV3N6UgetauxZAKbrc9WTZvr8ovfHivOPh+wZWJu/Z4PgMIyyWBGQXaTvJCcFZW61zwSO8KA priv=MEcCAQAwBQYDK2VxBDsEOUxB0rkbbOxwDOHoY7OZ/5KF3TiT9AcrTG94t8in7O91LAFkKOgjc2lG6aGxQHqnlOLImrMEcwu+Yg== msg=59KA8afO0CfWeH7zCGkHaiAFqraaNleSDqxRc9J7JIspWLt/nVUXPrfsc3p61HgnW9INwluEInzlGV3dBosJiw== sig=cGw2OF1gX+lCZ7h9rkNzKpYwenL6lcXs+apmInN7RSERUrxjk6FcJJfUssyIg1M0bebJ1Jqy5oqAstMp5PBSq6KZM61VeDDysmyQtpSQPO4yd7mfBX9Su7lyALLda7va7/GsNg38f4pRirp20S2qsCoA e=found last=16 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtLkEQXnd4ul2e1hcYk4xqKUJ1kyOZBVB3AdECHooxsUhOk0JC+dc8ge52eKgzUu21SaefqUH8WMA priv=MEcCAQAwBQYDK2VxBDsEOcU6YUcWF4d6o1XALyNljh4zsuMcP0YpfPTxkw6h/NheodtAFYo7o9nhLe0rhfnmW3GumiqFQaChHA== msg=xMBCUChJzDd0M/u7CjEWCY0eCt2YiIerM8JCjdyxyrhr6nnW8ak53TrSJ61OigZrQgb2zEWevz4jcRj0SCgT1A== sig=riMTfCD6VazwZJO+KQWB0rBUTXgJ1+4mvJmWFxFpNywiDXkk956YZZextwLEUojISkd35Ra39NoAR94kqZ65VTiBzkCaF0qZTTZV3VmmQWmfIhkNm2n1OUIB+5R4wwfjbOMc/RZBF7fB2DFNQJrIJzgA e=found last=25 s=19 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6AYGroALN1XFbI708Z6NR0OD1YbLsyUwpNBw9Kxf9yl4LKavhoatAzaf7KHau0ZVMB0kG378uIyA priv=MEcCAQAwBQYDK2VxBDsEOSOUXRjQcPADklz0O6H6TN367N4YlYSULZHVDbWF/qKOtzyFwV9pqrMF4XImOz9B6cc805QlV3j8Iw== msg=y4N7/f5wHAPk9enhXlAsRNepZ4oVZT+VchTzQsnO1ZV5M9Cwprow98DJ0OFSNSgMbvd/nBuBsSXnx2cdReTzag== sig=tA2BukKfpIhVDBHAkO9O61Zzd64hEqfWHJ1hFItccCIoJAy1QWJobWHN0ttz6ac6qcytU7AM0j+AdkM3/KT8zNvxgFPdNN5eBBCQmi+2o/D8pMurQgR2hS/Zi+dvOh9z1AaNW4Fh7U0ulG1Kixd9TxMA e=found 208 iterations",
+ "pub=MEMwBQYDK2VxAzoAfjecVKz/BjWcQztaAWDr8rH7QFZ7l/7leEotsYa/68szlpiid3mVF8d5L4QgCAsdORCYd0KgI7AA priv=MEcCAQAwBQYDK2VxBDsEOXQS3RA4TxqIjQH7aFz+qadhz0YmCL0nv2GcbCFLxA8uDrqsiigHEH1gQF9NTVJPxtd0WNZ7gRIxYw== msg=uxUqFk3n8go59R+/e8SsdduTMy0IPVPf/3khmRqHU3ivxhKL0F6EQcf8OVySZH/M4/uWMONU1MN/vUC6OM+G/g== sig=VWeAgEjmjuol55iH2flvs5HOztqT+YwXiPtlCHSIZqREjKi/gZ80/gLo76SBa9JURBCyLYH4IQ0AHzBI49uOWN1Al+anG1UUM7Ngu+TAVcBRTQRcnrwU0m09b2HOyiBAby3mfJrFBX8BILYhdmSmLy4A e=found last=25 s=18 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApipYyOO8TkJpArmbwTsZF/akQlFBqJSskF4wi7bZfceG0H9mI5UoOgyjzwv73B4CCvqt4EfwT4cA priv=MEcCAQAwBQYDK2VxBDsEOQcF1ACd5viYCz/7Q9vjrbcjCiiZj3sI89hAd0jb66AvBdGw1WFIRgJ8eItJ43J7ykbcKFSaNLOZww== msg=hOI/noa4Ti4m6UppD0dCxjZrbn8Lk7hNN6ub55O3RNBKg8+ZG8WuUeVxeP9qDUMav84dqvlg/Ku4Dg2eZSs3Cg== sig=XUgWb+Aoi+oUO2qcHhdZ+9jZ3thw7NtZiHB1z3hi6fYHOQpBGgBla0oiK3O67Y0D4X2PzCC9X0YARVqPBdUuW5Wu69ufwKMmQF98t8ze9NQn6PcWaNVCoB742I1Ui03LapGRF5vn7XdwBJJYtSvcczAA e=found last=24 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAzVRZ7v/wn8Y9x1C1lN8w9Iz+oCygqgT4YN55ps31UttjRNWJG1dIOKml5fIv+tIzbSx8QhzX7baA priv=MEcCAQAwBQYDK2VxBDsEOcJOUeub/sAPmW2fE3SFypQ0C9rT9ljqORB7XlVcabYpjAg7BZKfPyuHKirtVY+7ojiX+FbyATYFRA== msg=76VPn7lWSjd8OtLQeBUV6oraiTKCrjxoysjt4Q3fW15E8Y+i3S7lLJe7YcFz1JGIpE1T63RuqDnRjbO+YIoL3A== sig=1L6Ce5+8xZjiAIxXqV+UqtczOzZiKqUOabMi3ngC0Z3zTy3Tw+qY0ADfS0YDbpZSjQHc2/HumYYAGXStskEf/Cc3WSqtopAa8zCrcI7v33RKZwqsfCN12k9K3gWZCa+VItYkCuajx+yyefyyTFIb3yMA e=found last=25 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAX/pFWEHzGU4Rb43VJurbz6C9nUt5absd6qeMNUypv0TTpGOvOC+wCXnWEu/1ma/moAxevLIziGyA priv=MEcCAQAwBQYDK2VxBDsEOaRQ+g4PU74nmnYusfcSxW+f1m6DdlpjVEjyNVBQgFeEDIgNqGJuOKr8QGY8OftR6dsb3rUrqsgkzQ== msg=XpU4bvBngboN1kkgBgFw+ZuMoY0eQW2udXyIjheaC+A4JUbLNDplLqPbDT4Pr0zDOgiYQ8EVyl66y3+K6zbOgg== sig=mg0SEYtRNJMwUKLbOUtLUpoObZ4lvEnvFXgly45mgHSJEZ3/zqqdwwgOF1JFJoi9XvvfrnLb38IAC/aJ111uJe2LL/280JxcEMzQVpcBc4atbidHXmD6+UFG3rSbsHWmZXeVIrhN3yeNZ4IoyUxG3z8A e=found last=25 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAj2Q7mNgN9U2FIamdOYtPg7AvG7V0vTi/W8FehRMiz+zjNo7g3jjjvHOIloB/Eh7uH0Ak/OFuqOcA priv=MEcCAQAwBQYDK2VxBDsEOTDszovOzfw2ck+zcMXMRZamjZm+0dn7MLOX9DdKZc72nffUqI6gwSnCf0W6WBmkrWnrw6dG9s9JwA== msg=xJcKnhivIcuCfI9m6wxMNMRqTA/7VAoCVyKbXAUocRVUlhD6jzxwWcUbHU/nURHwe/myDpHzAJskQEs7n1xhjQ== sig=wiUQmMTBoPyRoS0QH1k6/c+loTISJA1xU9PKQwxWMtVQ1613UOiGaCYsp0ioCjRsCWBSsffZZ0KAdjOTlcilny/8toGVrSckfFM6OzKAVK41IAb6LTqGKeb+lEgNRR+X0BYeYUXH2ZEmmU3FOBHSTCYA e=found last=18 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATeBv5opvvpmNsMq6o2lPzRd4eRBiIJEAs+f2SwrdlE58F+MqSVsa12LUMnkP3JlRjZWYpieKQn8A priv=MEcCAQAwBQYDK2VxBDsEOTE47g+tg3u5ofo5Ek2jj5lP8e131yWcUqCgnVOTzDD8UqgHcQ+6n1uNOzf9FqdcMJp/sFy6vaFJZQ== msg=wuwqpBjTkwRHxhaRdhLAzYWyL6GyqUV3QVaavSRdx5eT9VrV/ypBqo6UsUdmHcRIRTOmsVn1OYGDmerzH5ntNw== sig=13Q3mSGVT4GfNHNjwueWfnsGsV+kIzcMUO8uTTvGDj1CTjOdFqmn84mdDv7VgiL3kYDx0pHxk/CAKseaaHW01CbbuJBQa3MmNgh2snQqr305uQ80eESuil9RA/cklDBoR2XurjIpZ+17ByMLiEfbxxYA e=found last=21 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2lBs5T+mTvnWjjr4/CpEuYMd4tsoo0dgGAJBvs0Cxl7KhwQuW04Fgv96pkzr56qsAIIqBnNhwZ4A priv=MEcCAQAwBQYDK2VxBDsEOb4wcwZkGe0YhmjhvmJgTIAulTVXlSvIb9eInNJZiPt5rOBvWjQgEdTo1NUw+rFX4SqNPaGXTSGnJw== msg=G4/sYcfX9bHq2hAm0x2PYWpzQJyy915eZSfIXkSvcImrmDKTdiMpFlMm2btHAWfdiSgk9oYOH6+gD6e5mV3aHA== sig=dEg3LcAC7J8kiUOBOesaU66CXozk4zmY8jj+xUGVIcfpLL1sbyBRAglVRVIc57rMP3t5jBW8JQCAqLHIPp3uLI5M2re3fH4ao6DM++c0KUDThZZ8t/cdXtB24XQHgUW/tJdMw5ZnI4mm3QEw2a2XtTgA e=found last=14 s=16 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZhP39O4k2LC300p5zC601Hxjjj+CAWvhnw/qkr4cuC21fwRFvfyp/sD8KZLqLSlnIAv0eASk8pWA priv=MEcCAQAwBQYDK2VxBDsEOQikIHocnvHYHX0pY51CdJU3a2HCjT3pOLO8yGfA89iCsjc+GHEmaAIN+2rcCpWjJB4Ghd1KxGfU6A== msg=MBvxlDltsIh3+bz6Z4szhCyhVma71Heh+FTQQkJwO5iZAfArOdlWB8WWCp6Uie4mr9eZcs696drfZ6cVXl5EpA== sig=/miXf1RdjO0fRI8Gr16H66Kbs6ZHl4dadXnjagxhTbDmzL0fkkYUXu2Lt9LGlfEGmDK/9Bwn2X6AZfbD8qaLTm6OH/cjY81aT882XotRQNtQ1E0iUUqZLvB+zEzUGpghXKUSPJxlO8zYiCVdQl18Fx4A e=found last=16 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1QKDsV75/Zxy5/eA0p8/xX+dWd0TT9x55lNmEgexTWkNItKtayu8o/AIIaRhzGvxJBrZZJmIYBUA priv=MEcCAQAwBQYDK2VxBDsEOUWAYUx80XwigPXTeH98ntuQcWzYMNqEHbaw0tFgRo3LqM/bHZoEA/mIku97nb4NhWcR0HeCn8kvhg== msg=+J0WEPdFMkJrJZ0yT220n/R4omFKuqtV2RmwGVxafRkIBsjh4m4SfB21Mp8g197YJzX9IWI4tBsXsB9wBi/rhA== sig=pmwFGzY9xRIkvhrj2EE9yRL63AMDXETYjJFGdPH+NLPjRq3d7FMNJit8clpTLTAxD/267koi7X4AeLGyEd6r4fuqdOHyZmS95QnDkeq7pcbm0AIo98ySxHeA4RdaknIoQftQ4j2dptuUYXDfPnGEhQgA e=found last=23 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5CAygKt26PhjkD5+AkcDj/2GRAYrYoPgrFNLHVWBECn5gD7BGL1NodU9TAKJpUj+TjBJlLlUS/aA priv=MEcCAQAwBQYDK2VxBDsEOYOKfPdNsyvdr9ksCBjcMQG3g+FIqE+xsyKkjS3U2oQyLoG1BK4fRJAKLpOfZooH0uHhucrHqnWrDQ== msg=+f+Ekucd4hagIzEZAHZmOkw6a3B3SHk4lG5rvt335gSqpeKKKvxSgpCZdgcbbN0gFbPk6ElsylxoPAHuQK6bNg== sig=ljuh9fpeqm2r4jTSU+jOyMTURXILPMfdEVorLbCHW25Vel7fh4bJcgjmPTBg9WBut4xVD0oE84+ANaI74TLD+YmQsn5VS63bw5xdSTu3Gt+Ni12GJUlvr2rrX+pPnwBFKhoopgfWSUsyFxvaJwQwhSYA e=found last=22 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWPWfYO7rXtknaGzq2/InN4sg1Q3+Xtw2s5xDd4745dg1kwm2sKz+ECS+MAUTLvSiZSP2fPwc7JUA priv=MEcCAQAwBQYDK2VxBDsEOetx7S8Zb9tsR3qoedsAUpiDcahgYDKX0F48OX1Q315r0UM4OYU5FnmrY3anz8d7kiJz/0moKqXjgQ== msg=L/aJxQGhOg7tlT6hCpcZ3i2qKiKTegpSTgk4IyQDLg/1RLfEIgwg4u8ToJdbNf8v2BydRqVimpnNjnOQDD2+Fg== sig=3OcrL4nCbNaJUG+rWOzoNcgHRzUtGYnWKYYmxEYvbHOAnvUjc/17bbT/S22M9V0BIW5/KVcIO5aAuykSuM7fUhPIMTNjXAcLMWbxtb6BvUCKTvHIuKmJagK9TdvywxfbqqgI6e8FqQJ0LzgBvNkUngoA e=found last=22 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAe5pJ3Xt48TaLJxn9d5fiVAErnJAkwjIG6dscXBalq7cBZ97yLQ5RY3DD/ulds36PUvQigBWNKPuA priv=MEcCAQAwBQYDK2VxBDsEORxoQJthrt2USmuQzQntaqP3sCKyUJgfp67MEm9/k2FmX/IMYm07c+RxuRxDwe9qugjoDmtpVOIi1w== msg=u06bj/0/nPc+vXaQL1xwYsHoIGY39dZEZC+aOSrLApkv/DSjVNg9Fdd2keTn7dUywOCyvnT2TXRzsbCp9gLuXQ== sig=bQ/yhubL/fBVTbMzW2tbkLYellhnyKjX+SsIsufcc0nWPcDF50VYdbiXzZqA/zjwu/wJaWGNJHSAhvZrOzPKGvWxKWWyvb2gzjNWJ1vdlz8MWuD4VL/Y+iBYC4GCSF5+ApEQdtaJsQlmojOUchnY0xIA e=found last=15 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAQpLE9fKHta+GDjKpyl2z1IJ6i6cy21MDdKns+ulh+kZyYVxa7/DqDZFNru3cxXN3caiJKPUfTBOA priv=MEcCAQAwBQYDK2VxBDsEOUExJ89RNGMMaMnRPMz1PwixamDhYqHVRkk/kvycayZSJA2zmsa4jiRr1GqyzNCuwrm/HV8jgww0jg== msg=tGwsQn7oYwtbqSZy5qOmvGCaAsFWLJO60g5IvOn3jg39cq/tZEtMSA1WL6K/sPW7h737aEJnymCzZuVHwzVxag== sig=uAHoswgUVS6EWkDzBqtAkZFRU4OvA7o9JVq50nNz8f+ltR2KVJLw4w8qKHtfvK4ZNCRpG7w9SZUAyBDCY7vqEktxvuVvtMnrdHO7ucoRLExqMTQ9t+AoF6YiGGPrrhYcPenwwTbtiXYxrz4t8EbA0yUA e=found last=17 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAz97ilD74dx7rU4edMiY4hgcJfk5LkYES9K3FioY5ljaaGstG9OfdNz7Z9LYnxcJZjwOtsrbIFkmA priv=MEcCAQAwBQYDK2VxBDsEOQsObxJrWiDhRzuUr7YXTJDMa4gO/Sz7IKsxOq5l3QQ5Gnd/Jrs+gLELlChWtrhJkCTr+1Mu4WrSaA== msg=qqp9Y+xsWEz5cYypy2EdST6Kb8znkpWFfOpm14hj2WZmQrGYfKptEhDfqBy9Dk4st4uj9XGdiIOuwZ9MWHnO8g== sig=13USar9R3byTe+eeuDuQJOJWhySGHThWXP5GOqsK7osm4c8QKlF0K3l+cqbX5j8j82u03w0lNayAm4mDhLdWsQz3XujUx/vGmBoTDXyQ6NEbkBD4133r9BWiNAEGRWI7WaV2Ao2ZrYIkerLHXtBHjgsA e=found 132 iterations",
+ "pub=MEMwBQYDK2VxAzoA2YqbXnEttvoJd2ixYFzoP7SPF0ANc4rWvXRVB+0dj0xMxm9dUzpo2+KWAfAvSO4s5rISQBytJtYA priv=MEcCAQAwBQYDK2VxBDsEOa3J3SwPWJyKBAh0duCdikJmtl6263vxxjy/2iYTA7yb7xYYSoi55zPwHvCZxW3W3WsgZACAaDHAhw== msg=nr64dHeciNM91W+3fwvtFYe+leUW/IEe0rDBvpoqhwb5/g7QHowEJRQTdDN5uH6Ua+wOFhp9IvmtmEcMS2AL6g== sig=jeS+N3u433ybIFMaMLEycARNxr0AtlImExAJ01nNWNvAJkh7z/IYmNdzW6ZBxufAEba4e9Nb5ceA+djZcsf5dGu4WxNw2ikDWuMwxMqwEWdcwaMrzx2E09DRIAOSyByHb/9UqpjH0J9VxIOw4mUH2zoA e=found last=27 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXKUwRys2h/J07gjpBJp1ARpTTpq2yYNjzDcJZUvcXWT/NEJH2H+Y4XKdnT6LD1ccUw1wBb5voPqA priv=MEcCAQAwBQYDK2VxBDsEOas8Z+1zfLogD9nHPySQ7Y1180+XGLlDPlPwysaZ7cLub4L5t+lZX8hsOVQZaG52tj2iF9wB3BMy8Q== msg=JTcoJ1dTNoPdHko0CrvPfpJP1SzJk7WkeFkToTyaeC6fRSb2QV82q4JgVeKp08AW9Y6vDSqpLvS1JK6mDJavzw== sig=N9oY/Fw/WDGgWaMumG0ojeoKunzpGe0iAhEIDt36dqfwGqfWSW560OlVBBIRhvta8nXzA4WpDoiA2A3Fw+A6LuuGPlSHSxTRJMJNPdwk6PHpB//wNJLQajq4CQd5sISxbJliqqdisDpS6HW9up4BOCgA e=found last=24 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA0nbQCEIXVQT6XD0NzjLqGCrGSqz4VsLTBlYZfamxP4wClQpg0L2XIHRAK9urceRy53KD6/SJHgWA priv=MEcCAQAwBQYDK2VxBDsEOeyLILVkhtlRXDXB7188OaU/BKwU+DAf4Jx+l9nfJhxruNqTDEIkZalKP0JgVvWlBejsG8jXoLMGag== msg=vcJGxQbAzJ1KQHQlj3cK7FkhlNAddRRhTseTwBW08wpt+w2+YzQmf0pMFmgU9UkJk3BunFZenqwB4gvqRU8z4Q== sig=7xav5nE5K3ya3JVnLM+p8w+Niz0teM2qy7mOr1dXKjlyGA96vewtZp2Dh9BgRv4O1y2flJyswOaAGwFSXhA0fQooMApfSrLNCPb6pZfkV54TKR8Rl0XG3oJTu1Rcf3RO9RyYHtj6JpWfl1orxb765S0A e=found last=19 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALPmhFKEWYMKLDg2H0X5cPTrtWNvfckrvsHHH4DdI8YijlenqqMhjROP2zAXBAUvh8nbWRscGf4mA priv=MEcCAQAwBQYDK2VxBDsEOa37yoaNCfLngtNn3TsfqYJEFlgJfRCuAV6DTjn1x26oHddFifFjw6+MmTpr1A3FnVQnzjcFFxTccg== msg=13nB5q4zHOUvnUDrCpgjlncZcnd+uTD0GbcEEoMV+hUN/uhiIx7VsI8J6cas6DSffw4M+kMGFqFNbLo+a51xiw== sig=SVCH+zuf1i7asNN6LIc07ExHZVOQ+WTc4Y70yGuCBJOXBmSPdnRW3bMhIt7KpWDOpJJ+Lkg2mnYARLQQEMM7+4ILJbWPh+gG7Z7mwOnrt2Vbq2xsdRqbyrYxEjs/eikC9PPYexUa2F3MWHgx0ys9ThgA e=found last=25 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAH317rpqqo+jyBDbHFQg6nKQZ5R106gIXWKbUeaY2lPDZDCOzGcxaBhAW3OqT4ExwDDfvCA8DVkEA priv=MEcCAQAwBQYDK2VxBDsEOW5jViDp378/swnZP5BDSJ41PR3HKoc4ai6JZrEk06A4mARspoCJgQi3rpXYs3D1SC7W+r3C1WcNPg== msg=aIRoEPO4CNe1lZa+6mcZ5jFcv6Hv7ucIRA4OP0lxzg6ot9JuKjRla1IIaqgU4Af0SL20t2bY0kaFwpYvsoj49g== sig=lVGyAvp5rzpIegEw8AA/LhgKESYd/heERiWc08XyOJm43NEyvcArKRYCHD45LSrDifaFFWguLAaAaOrr+woFCB5zMlQvcNhGenrKQQCNGL8IjWv2digD3D1sRiz49LXNSA/eqtBoH0j2v/gjPGgKKw0A e=found last=17 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZrUjOO3ZUT4nwN+wIIQsbesgY50ut15mArJqmHqXXORxGI/7aDhrkNSRnGS3frS11/M1Fpb0RAQA priv=MEcCAQAwBQYDK2VxBDsEOQEtAaaVQC0AgHtstUmGMhauByzGp/syy4fNSiR+vtVU0byANMWQvviAGvzKOCqVopjWVLAm/2YcjQ== msg=nFDdRyOaMTdahzj5pNt7ALpG5YYwkwWnaKBN9I2wi06/QG19o0ck1E/M1cYgCkY5AadtrSfW9AIJiZvsXZF8+A== sig=ODe76NNU3+PDUpU7dxh7ny8ijQapo38jbpA0TcIkpRKKWsuAMZ8cR6Xzm+7mOjYNFvZnLj92FHGA0Qx8T0SGbBKMSb/zjpFMINJwr4KsZsEDjZp0afp550hkKdsBusPciCm/uiOuMppWeJGbySiKlzgA e=found last=19 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAssCjhBKKHH1RGi4nJoCopU1gIrR+uVprKiD3bznOhDt0RdTA4ALIw08cK9i2hhFdaFfC4+ADxYOA priv=MEcCAQAwBQYDK2VxBDsEOX0GnN07lE8pgbzzHTU2/Eq/2Qw1lgAe1ACZbFIt3M0dOzS+MhmA4eurn8xd0sbZ5cHuwgq3ptNTLA== msg=6zka8g+Aa3aZycMjWc7CFEs+hfQlX3a/w4ofrl0+WJT0Koz1f4E433yTHQZvT9BjI3ulTdHTIqKMZ3rGrun3jg== sig=tufC34N4C5b6qnipD2zXw2CIsPAMyolgqzZJZq6V2rECfeASwU65lEERqRkJUe8sHiYabSPOGIYAzKq0e2gOtu+zyEmOpoTzOFUQsN3fTjcJBngvLUiBHY1nyoLMe7kplSll4ZP9t7QtUq9ilf6aDg4A e=found last=15 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAeryWT5+Ipb6gnn8DbsIt2i8mMvYQvDxYR7IILHWeyV/ZApriof8BBZGcVBEWg1DsV8ZNuU0m4tuA priv=MEcCAQAwBQYDK2VxBDsEOQmpOCdpQ4e6puh7t46HKFPDF89SCd9yp29Z9EZoh4Ws4qF3UJHLI5NX0LBfkFvfTg6Gv4J3pFTejA== msg=XfraonZ5nWoIart3/OYvjopOr5OKeN48V+wvwiXNDKKxKamlPUl8VJxmk1mpQw1XUFNmvCF6K/XNRNNywd9dOw== sig=75AzH12gBrR/ihH0sKWK+cYemEvQwa7sYx95U3XJ2lLMS2WdiNBT6xD696NlZu3Z0bBpUqdsZ9KA2Jx68iYlqjnKceuy8VplXJ9M+iF/+wy3ASqezan16UZ7x44EgmIYoE5latjYQpou+XoQitwJJhQA e=found last=24 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoANkLhUJzNszsUatv8nO9Np9lO/mePgGCYZtS9Ln60WqhS+wjLTALxDZO8W0lKhY5Ga7e3AYqsa1cA priv=MEcCAQAwBQYDK2VxBDsEOSGTKkoiaKZgLERf2GtVahzWLRHIHa9+Xnq8X38yVm4SNB9INPazp3wVeKPz+cD2vNug+HFmysmmKg== msg=rBggMfR0g2OJhr1yiq6N6lYVwhztHACSHWHUACr5LAChTB54vD5xPXCZDmqgKfwsYQhZF1+g+N0/nH8Vqql6Ng== sig=PCuvfwuLpALO43oh/wt7+e0h5oBx1g7DuyfWexJVviPxD+CY2pY98xSMo8SkzHM+514GAr0yfIEAmBGpHi9HoEYYINbHhuk2VJM1QVTTXxt4OP5dvMWITvoiehrgu80xtMu1VRoO3O0lj/O+jnbiGjIA e=found last=25 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqmD2YChCNHvGL7exTb1DYlAYPkSCvK9IjgUrhOuwh7ogX7iK8uOkKbE1YUZq2MW0trIiF2utMlwA priv=MEcCAQAwBQYDK2VxBDsEOdrpFt28maF63uIY04mvF8uyCxUlwMtlkYNEaoxJEXugNN0psWQWluJG0tay5nOKrV0zw8sQ/yraMw== msg=Uw3xHvnQA30EvwMKCjlXqXz3ij/4NINilTZnLzE0K9Q8MptS3OPR4d/QDwDybhGMCi8KeVxkruHrE/KzdK0mhA== sig=bp0W/AduUYIDHWyv7hK0K3Yb4oiO/G+Wq6IEFkQlC1HMyP360yYG5QhgOK4kPXM7R6L0zYafjEYAbMObJ+w1fbU8QfexlszyImqrdBU/6ZYqVChUO9T5crlJpFKKGu/g80sQAIrpufM6873/YKTBkCkA e=found last=24 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFIb42Gu/ILxMIszdZSuscWlwDUZs2vcSy9FYv6sz1H30h/3SOZcjhjMzygzbDwDqIVBLJVWvx2qA priv=MEcCAQAwBQYDK2VxBDsEObe6/NC5yQfUKbVCyuZcIL8oWu3rMWgNffRkefNn45aJH3f2kpjYUSHiqOH1EBu/PfPq5uqyUjUMTQ== msg=QVb/MliQ3GH3UEpsGXuJnBkZHZc60K7pd+U5YmTKJCwoMaeuyZjvFJyYgnuLXh076fjQZbm3YdCbUlWIU0Lk7g== sig=ib+XTM5ow1CaX4nb17uLRBF6oiN30MbcdOOhEE1x2kFTZ49c8v5KCDgrLvAgV1lCtDMaNTAdA+gAfWEYj7UZkSEkDvR/wNV/bmbfNj4VmMlunTqL9U9MwhhUkTpGLACkQsv1mtjMWnnDPTXKXjAJaCIA e=found last=17 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAoRRGnhaq5qKGYXlqOi6hixSNKmxkcPasi4BiMmLt2Aj2mR19DusKSQZolYyj5fPRoWw53G3N9A6A priv=MEcCAQAwBQYDK2VxBDsEOSXhbKkLjT+woObSqEoE3HF2FdPSy+/nkiSGZazqlZOzgwqYKo5Qts/CDplgkOT5foCQHpYOMDQbtw== msg=sNAI5Q1FSwGegPPZmnwDfkPd4h58scy9KQokbe6Ff8FHZj74c0e4t3ySfq/pTKJJI8d6+WTltsDFmHHUmUlHaQ== sig=GDk9iAG5nbth6Ax/hvrKAaYE19ln3JP5MivrXcCJ1DqdPCseblt7GqqG54Vhe+BZarWaMLkkXC0ActuXNml+WdtjHBt4Qi7sOu/P8Iw5M7Tz3hJjzdckeTiNpMfL7y1fi9xgk7SWps1UqljmQ6Be5ygA e=found last=16 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABvv4DraA1i3OJEx09auugR0W5QSRfuMeDCWX1giRvMICjzIZ9Oe7sLEEq32PD/GshUHrVarhwg0A priv=MEcCAQAwBQYDK2VxBDsEOdO++3Dcm+AxWMR+iLLWjdb36PgK3l9QVNN257jmShLSBlGuJdypazXFfunkNoDomjLlJ5NutqXC6g== msg=6aieb5wuNhM+a6hc3Dubr8njhh6sPERHUD094hEHBe6tU8JJwoXiEVo76uPG39pVthkUhxR1RmEmJpmTFW/xnQ== sig=NTw7fTxUNiM0iR1IuOMOT9zZcl6aZScsByJj1JOjYcvBZy7twgxIOsnsgjh4JCw8JZwjqoz3R/mA4gCv0giZmvSvvUXKIa2LRfdBNx6XkED+ve0IB+a1J1cHE32iJQDvGe70L3n38qWPU37bMXWUfCEA e=found last=24 s=19 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAx93YgZQJpdyZQdmPE4OhXa/KaOlinycEEtLwAumBlUit1ZzmQRFzwYANghor9fpqe17m2EyKWxCA priv=MEcCAQAwBQYDK2VxBDsEOZXNgy/Bpvej97Ov2ePMswfOo73+fSIfoVWb7UyBOUDj+QrynfQW6EeGa9scjzlLXmFZKr7+cWYtzQ== msg=4dhYnuy53X7fJz4h26tBXCs5UTbIUT7jIrAsCJPLrGssr8laSHIdzUuPS7QXNGyxVQcghfQBgo9QYG+nrV+ZtA== sig=bCEka6IC6ggnZva+Lyepq4pK8ad+F5aTCD4YB+WuCVDIZE7DMlVAKzCS3Erh828FVZM3DAO2TOwAohv9Z6nB6JOejQB1c16CV0ml0ie55up71g2CJnGLHfnyfuwldenBeDmMyGXPWrRDuH7dHlbKHTkA e=found last=18 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAY4kUnYO1y8o5ASN5605hC172l+tZx67C3M08n/vhAr+sbD5MD63Kqw31+6WijylaonseUcnIqhGA priv=MEcCAQAwBQYDK2VxBDsEOWdD8rRFl6InaEQqj0kXberF+KQ/h/kqdBpq6xKKt8vPf8tlmuUQTHlzOT4mHe1R686BO/5uYI17Vw== msg=PdvU143BsljYei22p7UUPIs8mTSnq+/UGinvd36E1kMPUoOFlQMz9btp4rnvxBHJfgWZyfTe04ogGpnXnkjNaA== sig=eus5SEU971pkM1bGE4jskA1kql40Xvq2D7BsTYOKfsJn9eWcfNbu3pTHJsYx9PHx4dW5DQsSmyaAUjiKQy4CABV9uj9uqNvOYVBKz4ctMqBQSRnhVp6/A18pz0uRoS1nmH+uXLo3fv6BCubEvzKWAzgA e=found last=18 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWW3vAlGaF9IL5sj5YIQmYASBV+2pTqKlTuk8N/u0DHjXYg3vIhAJH6MhG/JM1/BRcAH/BDGSGHaA priv=MEcCAQAwBQYDK2VxBDsEOcWmgcOMOrjiU2fkI45Yoxdpi/sDnyvWv7YqxZurGu8QcP71IDZxYkkv9Hzpz7iq0XfqpOCbyWS4vw== msg=D5zoTHOSGPpUDFhh9WL+C523X+B1TIDbJLFErdrYXsfGwA6oroQbhMosMRcV19SL1v7crQ9iLGpZDaTzrvUvfA== sig=3s2Cngvdf9W18ldyy+sve8R8ZoPJsEym8vZk/xtmNbOPqL/PwYo8/r3/IBAPgvWdvp3S6LZCmYKAI9eV9xDwhfgpXhO2s57Y+Bn014KS2itDwL36Wav713LC7zeW3bAVTMXRfQO1IPd1Vu8XFIqOxzAA e=found last=27 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAHUXG6NCzSezhQ5h1xKY8Cb2kMjqR1oldngvUsPKSMPg3u9d6vKm/bBxi+jCfR2H1sB1uGX2/TCyA priv=MEcCAQAwBQYDK2VxBDsEOXJjdC87Jn32ZQCRXFM9XASXhxhRyrpnFQ31YTPJFo/daFT+qZPorWTP3o8nIlK/y7Jpzsm+w9d4dA== msg=TpEZwQNHAKhoyHgKjAwsJp1Km3jtg3k5sGmf97dbclrZnj/YnJMTL3LY5SW3sOsz+FFiQLan8eWZgaTQ6Wnx9g== sig=rzxcG46Hvy7IFrX0jBO8435lnGNzHQJHN7ya1ZQbyqXC7thE4/+h86JLnZQYBt+ruURXxl4IH30Ap/pj2i5LO9dgqPStJwQz4AtHX8lE0+vRR7Dl4AQ6/h0H9R1RbQEgTGQSlko88J2Jelo8hWVsXhIA e=found last=23 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAxZAZ0u3SCDv1AIYcUV0rwBgD+eRWTBYUdVnKqS4U2vmVh2qQn5zlk7UqS8wxu5wRxMF+vEOVfjEA priv=MEcCAQAwBQYDK2VxBDsEOemMA4CMUopOD1b27T0d/jgzl7zqRiP3zfwxt/DXYsewqGlu0nqN2HWVoub4zhIZUyrR8jqTvyc5Qg== msg=05yYk+uDvQlsx5Aozx1i45y90jtqbTsyannw2u38UolReMH99Gu1OCBkJdT2Enkdl9x1+DfW1dxNNdQ538O4kQ== sig=hu/ZlLPR3jXm/uIhnbRBvZPn8pxJok6Wx76K5+hiE/CxuQ0m9WEkIChurIoi8Vb6NyGddzZgSzYA9CStj+Avvp8xdsp7Ue433RNI2KirNsA8yi8VtQUC3eXchU7lPomFxHUAhd6UNrN9+Myo8BoerAAA e=found last=18 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAnb9yXm7ff1oUocX8vYofqE7SKCUyf1O+4zVbNoVBrp4Du4Y2bEihmtlyHQdBKsoDYgEcPE4VY0+A priv=MEcCAQAwBQYDK2VxBDsEOeAW3MaAHkQEUZCuSjxcf+nuHoivqzYbNQLmrkTLtmcO94bQl4/Xe/8NccYtsiRb46PWfXRyWExRuQ== msg=XE+GPFQE2E5hqBLGnnyrHmXdCddqWmJAYirDsph3Q9t0CQ/d04pEfCimGcfZWlJidqJ72ANBUB9W13x+sXQbKA== sig=eB2fz5hH3SVRZNbDuzTa46MZpe+MhZuQXWkqJQhlci3m290zaF+Q7K2j0NbFGZNL/8I3tj7hXmmAu5Z/IqfMaHN2zGWFhgDHXd1gAAQhYhKfixpySqF0EryCIDPG3WRY+nKpS8zURN4FPfUH/8x2kBcA e=found last=23 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEFIve3x41Nw0ihfpeE14hAqz1ei0Eaypy1qjEGBi/7POkwAyM3W1b+4Jnyqi+Te9u1rcvJYBXScA priv=MEcCAQAwBQYDK2VxBDsEOb1577MvcEjZLvkS8hPbmYEnokO1E+QLjW/D5AHCDzqPw3ZHTr/tDTypVmWMk/0tOX0Ez2HWEvFx9Q== msg=oMLI3Y0BK+5ZfCtFNzbRP7JyQHGlUGsYDZ0RDQxybk4B6uo49I6G0Hi/aR2QJ29opSWblajqkQH9BWszHO639g== sig=msBYN+8xNOquylJGm3DkY/YCmVx4kJLtzccse+rJDUXFWjIXlCo3TsxxbliDRFlSWUbGj7g7A1WA6CNhu1/5km1YmKZcUEH0pBWn0N4yB8TfIlM1HkKturaho1SduePrTn+DeXYK055gkd5qIHn51RkA e=found last=16 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAc954HYzbM1Q8uDt9es5xVYHT18TaCHTP62RbXUb2qMTDi9/lScAWm4UI92+YbBQOrsNnt8BjnZSA priv=MEcCAQAwBQYDK2VxBDsEOfHU5po3yu+P1/+rVKRa1VkkWLY+eSohZA0fXtV6tR698BkyWlIJ3wI9GS/xy2LHUweI+CQJ8OqSmw== msg=c+mEsbiiLh7tUFEvrRGc30X1he8GCfUaf7VunYv/SPSwnUzqsiUtwhkw7WzRuN/HkZ+NGIz1JfPgc9j+8rh7bw== sig=cZRQ0OKAURiBdYg5l71yNqt2BZr6ELmVRQ3kX1KPLheRsU49Zntd7LFmvwr+2Eh33eF+Z8aZrDwAU/vBRhfx23IKobf5+iIzFxeJV9B5A4oiwcC1ix6EZ7BDbPs4yuSfRr5oSGOo0aX/nuZKCH7KZTUA e=found last=16 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZ0JpA9J7Oqq7AzYAY15pqe0MeQe6bbuLZbo8AD0o/knQsnnIbpex232+JJxN6BUFPxTzMwEt1Q6A priv=MEcCAQAwBQYDK2VxBDsEORsv18Yy7FdRpjk0ZqtaAPMuwO+Oq06pM/Rjfcz0XReRBpciAfuKIg+pa+5ydbDjPoPxlQEOnoqdeQ== msg=Ppza16EVZMaBKYgFjKVKvRS88JQDLYoRfyT9aea0e2UJ+P0hmk7QPxcd4Rkx/7s/MyBmiIUyA+iMeJTw392WKw== sig=/0OmxH+iKjwSNHjYhZgGVf+Fv2Y8/gYVXxvQK7uEi0xijv0D2zS++kHYRJBOMut2DLW5Z3ceMDuAfSFyyJ0mBJ8qGVjuPJfjA9nJWHNR2+QcwSke6fCFUENq3pGLCKAURiANHy3CvY3BC6/8Bpps+RMA e=found last=19 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7/Ez8Y6usIB2yiPOKm0KJ2qvJ7ELRzv/LjbLDiWAgKcJ5Fc8PGMCUWWSqhHQCvZj6F84EMEnNo+A priv=MEcCAQAwBQYDK2VxBDsEOf9GuBVtGeZQq9HA1/97jzVRF1kEl24m3+1UaDLUlZUxPfpdLVjVN03TiuHtwH540mMIn15RH3j5nw== msg=yoaI5lmPni26xK/AIubvxzEK9qpehu0FSH+j1d4i0lnjcJVgT7fUR2ggIC2ht7edvKX9QOXdMvzqHBq613Zqhw== sig=e/XG1xMzAeYYJ39ccO4++ivlz0pKE7YDFxnnYBEQZniYoUYNqjHsMiKe3z23GOt10knc/ZZpMSoAf3NEvKi2KV/CJ8QjVnZiFOcAVgWlY42HnBZJypxlAQ7A1pchK6HrQLgKH+FhUvzEK+0/ER40Rg0A e=found last=19 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5RtmF/AjwC6Y7S2JC0qFZsa9gfItVfHZF86hCW4AccgOo+tVaDW/ErhSvy6rxXZS1JFS4FF5kQQA priv=MEcCAQAwBQYDK2VxBDsEOa3fobt48kggET5G0frtrvj7/Zf5rQ+JxacziBwmF3PNlFzFRA8r+o2E5nAm5f62N9lMH/A1re9+5Q== msg=orhdelVLvSNtA7u3zcNR+BjLLZUfq1ToFCXYieiAUI0DxFvtwQCvBLpoc29+7W8wcFeMk4yxSIwfRmUiOhKR6w== sig=Lcrd60dv7YyPCmBt66X5wRRzlPmS38Idlt/o9W7l4hdn1swuagkubVGzIxSFWAZG71l/25rFsg+Azle3167t8DhjmqPx7ElMJgJV+RQkn5p/vZRD1AuX5CurbkH/kqNCpvqkjDEyFUq0xrUKEiuxlDYA e=found last=16 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApteeK/vmyCw9Oq86lyMUD+HwONXYBa3gaDM3g/yJrBEwWF4f0BW/y/ey/NalFKmpkWfCb7nDVikA priv=MEcCAQAwBQYDK2VxBDsEOWJdMv76kF4+euHMD9g1oc1MbgUnXtSRDd5R+trD9nWZz79X5PGTQ8R5VGl0MO67tRUCm5hj8PYkIw== msg=MLNsVEWTwblnBBu7ibjc6SzlZFLMH+CwcF3wmRvVSsVu3j794uKQpdSMDmkpAnT2ZTtlgZMJtuoHCNrkm2X5Mw== sig=81P2f833ZlpAyP4MEb7deZChtV672NpidU5wWq1o0Pruv0iPcWOrxBKjn8q3pRHlY5C7IVkdg8oAbzKj+0sf0248nlwEb9q5B6KwXFDPE04rku9MDz4eMObpuJTob1BiOGQa4a8D0GRidtK7QukgnhIA e=found last=17 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA76RtLUeGB7SpxMCiPpKlE+tAG59Qjg8DDIDrHcoTtSFfEl0/Pp/ASFZp4RIGiIgaKEY/e1RNHxEA priv=MEcCAQAwBQYDK2VxBDsEOVdLWGC2ynOjdv5tgeBVIOq1K6nENyxWabjsCH3LcEZYqH9odJ3aYdhul6nR/NQuH8R8UULGlPGOZw== msg=fHnwmTk8jbgjypQErDq0+LV9xud7YrBO+Edj6HaL8p72RPyosn34PHWm/WKBmJcyLTeK7v7TrJM44dn9YioWKQ== sig=U5MNlNHF3XauH5FQhBxwR46vaVAuaLwRMqSAeoP2Ujob8PM4ckoshkTjkn8khCbMvhBomcsflpOApZ0bpPcolsIZh4LZnH7czCElW9tbYuPvctJL3Dd6o4NFblb7TUg6S1B6g6uyksrbww661Bq/eAsA e=found last=19 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATXQXxqz8PjC5Moa0Q4lI/gyQWe74jhkouUujwD17bhqTLHQjNRKEQ1+tcMANsW/SMDZh0J32BRmA priv=MEcCAQAwBQYDK2VxBDsEObqrvbTvNwwxE3tsfHSdqS0GiH+5AMprNGtvnv5+armMZdDGUpLrqJbuUJpzQVin0uQdop0jDfW0yg== msg=dDVsQ+as1HnbJJYHdvLrFBmvXT4z8wdY6S7TpRjvFPDrgOUZ63lwkSOUjqZVbEEWf+3GCfZaH6j/xiD1j239bw== sig=Trbkdw3ppg8Ghe+nCzNcbT5aSsQRd8D0fDwf6JlUq3167bv2MVs+1TbyL6dU7L6QHK08nlrulSOA6gz+jOVbVQFgziKwJtyK9IzxNg4NAEsQNkOaPLX56n7GmL/vUYnHKNIAlspa8BFn8rQol/jQ7xEA e=found last=17 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4N+xId+Z7V9hq9ne45tvBIg6DVLOBCqyGO0bu2g/yomBcd1jd7oVA3vO4UQWBi0Orsz+TSZQJLGA priv=MEcCAQAwBQYDK2VxBDsEOf5Wa34ptSPIXH1XW+rgcqr4TvsQ1QkrorNWEDovV5eSNXiJWCDIkWqlneKKYJtVqFnCP9EeykJ7UQ== msg=Xdh1zAw/dCViYzlsN5z+27FmB6uNL7TetiWnsLXa1vzjiN20Pb8Oy2ioRgPHW5ByL4Ab7MC2pjtR0YvF8yA+oA== sig=UJ0xJnzXIfGKFS1RF+OU1rMkK+7KDkRYRUMH1ijwVA2AvPJLUXc+hxENBhOdO3yWPmaDBl15DDCA4Q7Sx0PiFwnWYFEVJDy0UHSWevR9BSYAvL/by/IFyeB5gjCPRzWzYQSNXt+YMdrHjENmaqbf0gYA e=found 205 iterations",
+ "pub=MEMwBQYDK2VxAzoAtr275DwWol/hBmB3xp8oTcCYhugpcyqUi79DPz6H5JywuT97sXnBG+IeEGSb9MNBBZQyCborVh+A priv=MEcCAQAwBQYDK2VxBDsEOSrS1Mwgs4wAQ9Phl+nf+cz+DfZkbA1QqDZTE8hF4VtRydAtUnQNrHYK5+7jTovU3kluGq/CcQgJhw== msg=6xVWopjO5MqCg5GINcdb4YbhzR0rpdPopLc9vVYATgyGvimo0nifXM9JPhOfWSD/2c5gZmB6W3FtI0uCAzoIVg== sig=8ONceHGNVnnMtS3smGHP2wtWZYiUofnZE9URjTvLImlWFy9casjROcFu9f0g0NzS2J14eSK+cMiABrN42r7xbma43ZSxohVh+Bqe4vSiVl//eDfOHRo71ZPlp5DmNvemTtdm8rjCep6iTSsnDYDcnzwA e=found last=23 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAkDyCY2EewqVfcrWsClShtmW3nr8bX2FaSxjAMNBK+Sf9WfjY0r7axj5tbsrUQw3BTb6zOGSYFJSA priv=MEcCAQAwBQYDK2VxBDsEOYHAOU5ndvb7/yOjwD2QibW3ZMiWSiWXogUZu63fO3IsV0OrqAj0GsSbl3z/CJiYAIhbsw8YP4wUqA== msg=o4ggKkPFx5i89aKNphpMZOVYrV07vjuf8rySnJEJRh+2xXaiqU3GG2nTLPZCiie4gyi1wK6BzrB2pfFJbGzhXg== sig=NW95XSXwmtU3iQRqDr0EvwPwyX6zyFKsyd4t5ZyFCd8r2E/H4JjwzN0oSq3X6VSTVS74TYnUx6iAvzQZZ6H90uroNeeeZAllgWPula7FowfqvYTkWzs3OXa4GYwPScF6DifxW3Mhvaq4PWXSQR5oUxUA e=found last=25 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9gMZ1LESWNjpdSb+Lzmb6YQaeGaMp/kUB1pXvYyL9Sesj2Z6rN5mNj8/4GpXHqHY0C19URugRjqA priv=MEcCAQAwBQYDK2VxBDsEOet2OabqLTBnwQQyHqX6zGYfYZX36MdrxFeWrJ8momXd/F/uJCKrGv8zylrvxUm9STKLvR2V8JZzHg== msg=FRUQGhptMUSYIbXjhpD3avv11F5LQgS/Cb8dOfAq95kMTPtG/ROlr2LeRKF9/ZGMkCVxps+gN9G4EBSkyYU+oA== sig=Bp04AnizReKxjb+YXAenMx4S9AMQATlUfjf178EEWcRO27rbH6E/lcu6r146CcwEikUC3IwnRU4AZJIiwzcW4aaQuCym4zmAFwlsU36mMoZPs2GAOS0bt5TnCGTg/dDdDe6SC1Cfg6msZdSzmzPPVgYA e=found last=15 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3AZlQNbXwQJD9HHfFCJmNuvVSfT8RHjDNAedxhOZi/VEY1UGpTqbt2u2hqYvbTGxGhhue0ADYNkA priv=MEcCAQAwBQYDK2VxBDsEOR1dwFx6NSm52lme24wbQIOBp61QTIKDSxzNxS2TF3BYyaJlGaawQhkn+LZD/bIkCTx60fkIGjmDVQ== msg=7dcIDjABbzjfUD4N+RwXWbUt5Zz+5FgoWYd5Thojw0bpdIEq6Kpf4smsl7t8sU7tFRwLZgfvdQKA97ecngkEnw== sig=sOMc2821Ote0owvGvD9g1Wb/wfu6O+prDBsxq7sHRPD3vm2SnC/Ej1sL/9M1uLmXo1D/3T1inKEA8x6KNIsBHTcuu70iv1tIOEQTH0ArkPbDPph/q5IeGaLiz5FMGBMx+bQ+zqQoERnYyeHqHneSMRIA e=found 207 iterations",
+ "pub=MEMwBQYDK2VxAzoARW1htLAQ3EsHpHDXwaM+WNGdHWO0H18Ygfo1z82nY5u222Ho8SDQeNm4HpfhTXz+oJ5Mu0tdOD8A priv=MEcCAQAwBQYDK2VxBDsEOSuoS3wOkYGc1dSwHwPxLteUQPyW3/knVoix4EJslBuAdbmiUUrn7ZyTZEPxQmagfneozA/3HSGX8Q== msg=3PPB0U3xf7KtMnQZxJ34b7dhF/RjEK/GXmXD2tUb4+TSYCdUucKOkUo1unTY6ZWbwIEX9ZhYS0vmWVsGUrrRNg== sig=DcXtXLungfnAS8/Gk9XGvgnGvhwwmAR2hqncPYHbbblHRdHFjMXtC2Vjw0OKUxyV9ryeWXHGv0yAo9dNw4SzZGUTLh8S+EEw8duYgCFzEGgJfDzHfcdLNr3IvEXJHjlOpXeKZayIxMeMniPr94QJwhAA e=found last=20 s=20 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAzbvBxM0UHYN9d4EjLM83SH1n5v45dlxoEfG2Rf66b1k9EEaMCPeroAZ1aOBd0XCbyY2SXVnVVj4A priv=MEcCAQAwBQYDK2VxBDsEOTUUFNmqbzWVzYl0rngF+yvrVQcU0rOmABZBReLHizrfnVi9FrIvqEpk1Y6RbandMssFznHruhRL+g== msg=9SsHgGYhHv4c2z8qBNsOCSUgpcB+a3hMk0tVk7qFbiz7LhKjTj4MuqibVCJSL1MoNBVaQuI6LQENNDmRH+MlGA== sig=sXKz7zj7+H8Ly5JsQpilQt+W5sZxRxjmRM5q1Zwx6bGNxzGL3Se+vMoCsIoJ3OunwrhgJrBdA9SAeAyJfgTpUj0PJds/DjAhATdotWnun8BsiCPpG0PrxRdnNQjKZgi6f+QwuOUX7lrTLTPY8j9BpjUA e=found last=19 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVRaROORO8PWej/0jnIV+W2fwq/YHBD5qSC+X5leLIPeNSYX8U3u4m0cO2WFd3lrAHLORdfmTArCA priv=MEcCAQAwBQYDK2VxBDsEOZqRI9bP/8xeQ473MmMwfKXETMiOUBYitAUqevwsjqE5te0bz+QJEKpGQtcyFQKkPrwiU9INwPxtrw== msg=CjMLIldpLZBOnEwFFAtz3QZ4dH6Rwmg2mKKlxQ59B905UV7rS4BTj3ZoEX4y4/9Cchcv2QJu2ydDDSjUekbp/Q== sig=gzzedzhY2597gF4YzgrKdhrWeG8U213dyEi/FUonfank3ltl7Fvrp4zcTLV5JBxy3Ihrao6KX10AAiYeokaLSPdx/RGRCgE3FEGVxWjW6LUh4sJpUs30p6/OrrGKmIOO99e2k7L2ATtny1DkbJWh1z8A e=found last=20 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAzcGf3yPfTh35gObTix0BKmT8fLH0+hDvhrh9RvgTldG4n3plNhOxam4aaBl4RcB0znnxP9UK4OgA priv=MEcCAQAwBQYDK2VxBDsEOcZeV/sAf51a7lF5DmTb3qfuYRA8D7RzJjbizu5/sM2k2GzRj0cawfnslvz8l9rfYiQbKyA5z31JaA== msg=CqlaRTPFNjlVCtqmIzVlmjiKMXzJgkYTCPbuqmFyXRrDxoN3HKJveB48tyojGJGmJ85CiWnepoty/h1uoCD0/w== sig=/8eAII6p6buWiYnIGhiCrIkGEq0HMA5mZMXhwr/yOSaRMJFN7GU0fZxmWLowY0qiFfFZKGi96x+Ayp7nhus8clOafBj8OcPYY/GFh3kIaxccLQKRg19o9eiU0HWae6mxaJZkbE6FOQD3GpkpVuozbyMA e=found last=22 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfG8NM6dWyP8qZlsiqCh3gUMjeenAXYSHd4yTlo40Q29H+60hrS+qflZEEyYXiVSdXfEGp/OpsmkA priv=MEcCAQAwBQYDK2VxBDsEOUEkB9z3Q0ZFjW9mUy5y4z6IqKVSOZVPc1n+j3jYAFB+B1wfcw1iBMhdrgeDv+NWm7dKs8TNv4Tk4w== msg=Mkw09w6UKXAM6acyD/AEpk65SVeVU3AdW1EHk7Yz2Soyk/C/7q1kygKK+XjKBx1SbvBWuoZoSS2o+w8nHFcntg== sig=VkJR/KLfI+beykZjOw3g0ZJM2WBO3Z4SVY5+ogWTCBkAaWs86femdsFBB5tJnQd8HunY1C2V3iIAhgl3Ass0YI+Ngq6ShvfiQs//Oje3lIXzj8GqNB3dBEiganyHTGzwb3T1XG3GuOUvk1t/FD2tCh0A e=found last=23 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAruItia6Jva5n0QtuA7yBZg3GKcBGz69RHJTwrvzC6L1Z9G8Epg40x9NM6KHseu0Nd3NsfXpoTL+A priv=MEcCAQAwBQYDK2VxBDsEOcbC9t+Vbhve/Bc5an/PZkDGCEJTsDwoGsWf0yfKUAUaGDbnjaVckNZH/tBgzHKcn+bO0fTKeYgvsQ== msg=4Xv1Zx7G6B7ZsULGTB7s76Fvh9Fpv4arh0MFTaXVV7qzo0RrBAuDN0rSHAXhFGQNn1ROXF0TBI3WVCH3xey+Vw== sig=z7c+rCuDrX82R34FwdqbgjoAYCo2ltL5cmMDOWagt3IpRZK/Pl6UrQ+RrJ7UVuQlksoghcZzpCcA28kf78I6aNpvAtywcUwQcQavGNX7Z+ncFwjO8OKwKQEF9frjFUMl0MydDvOlyoJZsjAut008NCkA e=found last=16 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASpgsy2bMPYhbUz2282z5tvgNboAlPld+XxKMNyy25FtxkA//QHLNdJX0uef0mDyuKC4zA0zs4fqA priv=MEcCAQAwBQYDK2VxBDsEOY5dPy9Qt+3QyInHOchHlsuqwtIg/jsTnCZZC5R9CVYCdOCIWWor3J7wu6p9kRPCdr2IJKkDYulGRQ== msg=TVKwT05W+SqwUNCUvbx2M3UUrZoI2u2T9WXtM4niHQvO9hM1HkS3h1ES5CJe3XCN8UB730Pobk9u01dXricnPA== sig=vjDRteEYhTcip+TH0n0LmaGsy3uQDoSv6hst+X3JdtMLA4X65Ji2LV+q/WnPxmAKZ5D7Sr5DAr0AfR1RmMSVPJq7gqOCfnMLeBVtxzwtqq7FmInzizqYcYqd79K9QU6vwbs190GsyYLbDczrmK3I8AcA e=found last=22 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATbNsyt4UFrb+0Dvz2oIPIJC3MSPgmB4HJkJFM81modXFQgmcAJEdZJTznEz25dsMpTf8RF0857mA priv=MEcCAQAwBQYDK2VxBDsEOQhX7D5Mvc15YF3+FGuG5VElqK5zAxgCQJFaDm4UvzO8dGJ5g7F/E6JrJvSwDJmH8MMj0k/o9viH4A== msg=lI6wzk5auCw8wgxWbHvxqk5mU/QH3bFhNOLOh8MrCVm14ETqW7TlIt+ZUP7KpikoYqbADVeKeu+NGpAnG6tiAQ== sig=ZNPXPFBCzXn3+99cl/8BR4NBLi7acEJSfprt9VMuXd7ZY7hdorrrcWvE6uoEvnx4XO9BNhjwAe+AWfyJdT6m8fMWjQO3sEznlwmmOONzfbmpcTCnzqy4pUR4Vx2InPK0gShOn6xOrQT2g04hEl78sCUA e=found last=23 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAQEhJPO9yKPR+4qE6OKTjJbBzoEfFeuadwlPdqK36h314K+6dDyH8CgSnoQLAM544ImVEp6KJPgqA priv=MEcCAQAwBQYDK2VxBDsEOQCLrtB5AlKw/RaXE++sxYBHC6r+Mfbapg0eu5LzyBQ89pmj3js1Ht7xfdPheEhJ6hpgsU3v47AQNg== msg=kG/iu9mIyHBbyac8tgBUwHIAppwQ8OaP5JrlnOItI6s7ji7GHIeof39F+AzAxJaDAZ/hVMbDjYuf3rn3WkMzCg== sig=ve4wLNCQCpb1+u3qLgNppbRjoV9FZ4LwJC6nDJ6+M3sAB5v2aEmWsmOm1h2qNqYXrZY+fqVjuy6A5xUtNrvBJliUXhW+6qgZ7pixS/dMoA9aEZ1ix/BTFIWZGuXh7Qnim1MV8w70SW1Gavp76lzCSCEA e=found last=23 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAl+952UZRKuVtwMUoSftNRVEMoKg4scY92c5Ip5trxsZJHOpNBa4tk2IPLaf0esDSd7/emn6CeWcA priv=MEcCAQAwBQYDK2VxBDsEOfYSDjquiOYg3hxEyMYPl3FHP+kPq4+8NPOsbC9cRCRP2z0QVemD1r/GyVNwL1THmATT1/Q/EkVn4A== msg=+uw8fM7o6ZaPlVEQKzXv3mlsBGB5hNGO8w6SdBGKAFs3IX2A+oEAqEIC53NIQS0TfbAwT0vpwlNdO1BW4FkznA== sig=ncj51GlwM5yuu7uPg0JzQlrXLnSJaCmr11zQHgags05vBRpu33gQxMMt/FlGjqSABr2R8980IEYAbwsjy94I1jrxX0vQe05TfYJj50uS1BaAjq2ntRTsLMDLGMuYeV/DZlV5vPTiZXraWQG9jIkstQYA e=found last=18 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAa7t6ZvTuTMcbwcE157n0lB51SGue4vu5Rhu00swvIQU4+BNlHDKCDBcU2k1B1ch71iJCEaa2RzKA priv=MEcCAQAwBQYDK2VxBDsEOV0KYQ/k6FPU5sqR1gLiFP+XDKnrPDROJvux8py69ZH2PqN181xu5wPH58/ydTMmmcLi5W9Mr9qP2g== msg=6LioBe6eb3srE4OOwVuzpkm8f5qcTU0wQAkautpVxxtwiUaG0BgYnnRQUKXgn/UhS4JilLbI0AdsX7aOogNioQ== sig=rW8KbWStHImIOMNcTLDu70dsJgLPYpzjvwNnWGaoDTVAOJnXw7cZICGMqwLSNs0NBlzxJuMpyg6A5m3aTQdU5tqI32ScRi2JMMg97cdsXObVDoDwJK13kLDbvO9Uc8KLmzBLhNTIRBug0c3nA9cfRAwA e=found last=20 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA24IFRVv6uFDLZaa/PPUR95t3CoQ8u6rPNbxPy9p8BtSt7D9YLNwHcIQMGLnaHJ2QpMV4VO4w3pgA priv=MEcCAQAwBQYDK2VxBDsEOTZnEhjgY0cxstPHitIA5OHPs1DClwx3TIvRz3nn66KjpcmBNJiiv2uzoMjJz6UNk4M+2tU8gxpckw== msg=BsKNh8TYSPllpBSHfnkjh+zDYtt5bieZEYDl6AqeY1kR2I6rG1S2q7WhMwzWKvmHu2/3Hx96LnGelYVJ94Hpew== sig=AUgCGwHSgj2OJCWN2O0SOb9+wri/bt2XWvfhlp4dwKBCov+dAt75heowZgAqtLsq/ouBkhqAa4SA5nVacCE37koBgaVu4YwVcs+k201sRS0xfkTTLnxRo342gVGuWpFOt953pezDEWiyfkdK5yQQPzMA e=found last=21 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVg3LpQOO+/vz2o2geCXbad85UiGqh1clI4Ce9BpAYBjA5mbxDJMMrjN0MtbWFrQTlOTomSExU8qA priv=MEcCAQAwBQYDK2VxBDsEOdpfIxNBWikVAHDysipdwwDUAUb6/6OZ+YwA5tXsxpkIMSJJp1/XZ8/LBLCbZJ9P0skONYSczALb+Q== msg=d9PY8LzPtRsARaWqYVDL/6dVLVvtPAL9X2FWw7lDPga5Mng/AE+VTBp3E3E2pXk0/j7PkGTlo6SD4FMx1wrmZg== sig=e1TjieuRoPMvuWNKu6Ezmq8pQRUT2NbEooJRA/SVwD6SzwoS/pBUmc1fG4kSb+C8u/wM9g82pICA7MkZe/kOdYvdiNvFfa589P94ThXFWz20Sxfbn7SvaGrQiVTDvbUFnEzi31Hyy+w2LAYfgt71gCgA e=found last=26 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA+tzqsElYIJUib33o+gaFG0P47gPFB0zuG7WsRZt70En6KaGWuSjU6iv+P22pmuqyQtkOv+zd4+cA priv=MEcCAQAwBQYDK2VxBDsEOW/lhAaiby0vPTzdTnITFYlWfNlT3WQG8bSVgxsgy6oAQeFoAdNqigbV5JrFZWYSCW76m/U1uMG+ZA== msg=Ob8opz2glx0471uw4LzF9+33J0jdlNN/h9gxTGIaqDTHuNkpqaanCmtA4MsdIpZL6qQW9lAjXa2/kZCnQIfp3g== sig=Sj04r/I2jtNcIbkjtv79rZo6fH9c/j4/5o4CsiaMOSk/nKYQAwAO1kMpI9qeaM1QQnBuBS9rPLqA5j+7mh3VtIoZzLpZjVvl5cP1+XV3eAbSAwK0VO6zlOA1Ss9tHlPNmx+WDTjlyGjG9UgXFiL4cxAA e=found last=24 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGk2ORkO3AnzVhUuUc0S1iGyZwg75dHQwvQwBYKe3ZunlvPgPz9EpLF5P0FH0aOC7zismBXZRb42A priv=MEcCAQAwBQYDK2VxBDsEOeSU9d0N//S2MbbgHQRDkqgg5sF48pVZ14iAk00j/S03fAaxsyUn/D3JsM3lEr1hY+OHYb4ze+XPIw== msg=jURp/EWat6+tDzV4vOZk8mVi2anyxButH5Zh6d8VvZollFq3tDRE/uLudGwqF01xzRBqeGhsFax+Ut4rO4rB1w== sig=kmwHU53cITu/UhR3dwoqgTZEY8WCd9MT+mpI4MYhpu/YoM/fa1B7me0Z+nySogV/f/S/Urd+e3qAaUOR4pb4dluFblQrezXIa4Z5f0TuF9ehB83JCm2g/GdjAfGz/oZK3Mw4vzffS8eeVMkiK0Z1kCgA e=found last=18 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAQwyOHuayufAcgnJ2vwsdu3II/6hmVAm9UaQ9QcYXjTSVrf3rx+M5ZIaOOHBMxLdV+4297qgoYzGA priv=MEcCAQAwBQYDK2VxBDsEOVBN/mHuHQYPXUceghNVynwvdmgPhF1asE1BYPl/sUicXovD70h7HQcR6d90dDodtyqg0GMPhVjGEQ== msg=DHfC8lf7WzeaKw8rVuFbLcJ//nbS1PJ8xl0hY/fBrcqi1G+X3wg1e9+yUWLE/imotKhwtWFyhhuaXr2ZtsGi1g== sig=4n2dIrTKPLItJ/YRTREUeyKeIQi6+xDicKSDowzX14azWnGnFHJCkcxwp4stgxcumoQUmkwk4M+ANux/ENSXSWvJj94wAR0LPj3LlH7Ik8TvcsqDhyAMscykz7H0b6KBTFImELgzbydE2jkmPMVk0DQA e=found 128 iterations",
+ "pub=MEMwBQYDK2VxAzoA4afFv2Q03UGcJNL4ZPcXC4u/Za5Hr2oKXvWN82ZWrrZ1JFUG9giMJwfvpl3Kc9Z6Rr2m7eVVCDiA priv=MEcCAQAwBQYDK2VxBDsEOc1badQF7SAjxen/bNEFntnSijeRsYD5xOiP6zXv8EIkumqMOgwnS5VhkdeSNIdl/4QzkYZSqMQNkw== msg=AXvJjjPQwiQJidIWSAmiGBDwnBzUYW45S7WPGfkCFakoVgFU0kBuW4YrnY+DRBlbqU2X51DJMl1XO8VOwvv+GQ== sig=KAdLvfg1wvDcXkMgUym0RxnWUrc3hmeZPMjRP1TENCDGXdN3DGzrSW7qfDGdhZcvzjexBJv+cOAAVyzbfmr68GZQvUo/VAFLtEdk6QR5oYhkZXFIiBvED9DjdCsVyefi6uGztT94gKAXdgbUqQm0XDwA e=found last=20 s=21 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA35uvsvjUhx9OeqjTQmNI22oKYxjWlYRxPlWH3Owuk/ySHzsb9MzAZyGzkUpLPdmn9nw/kHM6/LqA priv=MEcCAQAwBQYDK2VxBDsEOanScktQKapYu3MuDqc7/Ouoca9x4v8Ufz6Oao7WEXsJs/qEgaNIigysrBB+5zEFQqXHAy4D2JN9wg== msg=YXIUSRjiMZYtDrMXOUIyMeHP2iqW8r0/D+HcQmDuGnkHaYzwVOMQjmSDyjJOD7RFiFEWQCa2jWocKygxrwQsbw== sig=Fk1MqRh66p8D6zCJdiK9NSs2dXGth8eSa3l8WuHi1lJXnSm4Hlq5BPri25pyTtYkcIqSX1mLTIyAORB8jUNxSNPGRpJ+2YLQIw8zGDDpOE2IGkkKfU85qHlgwNrwTnlvyAuQSItglIMurLa3EicHxAQA e=found last=15 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhzau/Cpt+waw74YPDEqHXAc1zwpO3QMlC3wzEmB/O7cPQjB8qKwQvDN1ScG53jbP745v2Ttw+ikA priv=MEcCAQAwBQYDK2VxBDsEOSfIy0D20TXAYYy1T2g7jXKVIPVrjGy4GW4FTMdL0DRM6jCyjwdw8Uu3B5M4TJUfEjTVf7wBd3uLtA== msg=6mFFHWNUtWGlYte5Bnh33FgWG71AEd+QSpoWsnGO0xTDlv2Djq6SUun4KTpE9ofIvtOUmLrOu/uCcimuVqsZKA== sig=kETu72JphmebkugiLI771iq5Bnh9Z5PCwQa9mpNl5mCPWwaUUdrb7+ib79uR0ljGlEJPBTKgO3eA/6jnsU3z3sowQaYdIM0NS9TxHkKfn5J/2Gnglxty2oxhYJJ+29niN9UzkWxd6i/Iji6m/5A2EgsA e=found last=17 s=20 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhmEfxsEXdezBweaTXXBdhaDJsLGWP7ksEzW1q6Ezr7JUF0KRIeO4EKmqaXPBnaOJY4bMA/+xgfaA priv=MEcCAQAwBQYDK2VxBDsEOTe/RSw1r+R3S9CKYkh7SgF7326mmdsuApiWpNvCVoqyT0AMgrNkZdsRunhBgbYkGFwqlN0ZSS5yrA== msg=cqBD313fsvjiUBT8gc+CVoUT+7aRROgtsB9tiaWQqlKuwj7jrMqLvUHJ/NVHGgGuXU29V2nldPq4nVB6dwy7DQ== sig=tGtnPHtviAtlGSX5/TjHWaQcy7oKTbdyurDCMYJ0FgpEVqFbHQvjvZuKTMi/RRPc4b5E/xIqOcGA4hVRjKG8SDtNGpGwi1mU2mFIAO9MS2Nq9YGSd5su9DqCussBtdF4jsSA1BRtr+4nOOuwHywvQCQA e=found last=23 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXnSkruFvadGsL0qyQHw2k65ZYHDmbXh6piY6fqQIjr/cgPUkjzGxQ9ZHmQMQsQPn8LDhv7Pl4TgA priv=MEcCAQAwBQYDK2VxBDsEOfBLBSxx5tNfq1L2Go/7wesLkXYTFTyKdCp+FCMnnomKj3S2z8rX8crJ2L3UATehx5QtSBTVqIlBuA== msg=MAAGDKNxypCUTZLKgLfKunGJK+MAAp2aWBzes1DvxV6Irxx1HBq7SYNYigDVwDJ+p0snNdF1vLiZxxhkvoNbzw== sig=w/V+hFQTPKp3jUK0pTVPITjkN8euRpQIAYOGAxcTQ2bo9zCu5dGkgAFtTv/MCwh/bHLVVTOgf3SAo/AqTP03MZv+2BEGiIRbNbHuP9w/BnyB+Rl+Mm14sTdMwdvjRLUapGgziwISVBlLITZFNRnSPQQA e=found last=17 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMqZDBj0SC3zSf6inZVDAuMDfQtSlu84p/hOKSPUbnTrNK4GIGGmBtjrm3zCXueSAjdnqMpqmsUSA priv=MEcCAQAwBQYDK2VxBDsEOV2d/iytyk1i1e4NHc9rhTvDO4zO0uXgUghsj082GYFIRNb/UNBxPT1XV7a8+rJgD7jGxhu8J24NmA== msg=SX+nGyhZCXHB50QiVHVKApebcV7EWmmB7RelYG09/CDSSbKDluL/dfHbMPrb1aTRLWgRgkfvx93WEIN54eIk6Q== sig=Caf+ElU6Pd6+aAQsdFQWEh24EAFxI75t2J66n+/t7AtEC+mU2LqdEkvBRE2n00WoU1HVN7eXhjKA3BxeQVLu/UjlSqoy2EhQ2pPYlFv29Ot19qWullUYzwlegm9HckIPKSLyUIVCFdfias8bdLVMVj0A e=found 130 iterations",
+ "pub=MEMwBQYDK2VxAzoA0gjOKR6kXD56pwqoo45FMTPoJvgOosC4CVzkNc8LroOC0DR4zEaxF8TpKJXQuQ40dHGZIzEADGOA priv=MEcCAQAwBQYDK2VxBDsEOcpur8DsvRq4TcfWrs6UZGnfHOOijKX3d+cHXGk9vtXkO90/oznNfI8LeWixp4VyuQSFNxTSTK0Q+A== msg=0deQMlAqQ9ISZcWzLTjgwGPv45/JSRoyodNnrLWvbucismY68IBetB7P84Wq1q5aQJ8vtUJljTeUv4VOgIptnw== sig=jvKKgi+L+WLZ7R5F21EZZx3RSZ4GSKuVG577w510tu68J8/+mRG/UoatDm09SVBINKQ064HLrkwA8MgZDlKF9EAgU/CdR9w+QNIrAISMzcOsy7H0z2dRQB1PGQscHduq/+WKkwJhUDB5c1IzokqnbBEA e=found last=26 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApeoxZSgMzZCCvtyURzZFvS09tZXmrW+X2ARIKPSZc9uAZHDeSTvFtmbu5NpGD1ToIXawWAezT4kA priv=MEcCAQAwBQYDK2VxBDsEOT/pGB9CE6kXj4XmBjQ5wdYI37SxuhzizQByQ9efmif5nbHnzvupd2cdueaUZ+2tttG86cijEK2TwQ== msg=xkKg9caOOIJZPIGUkCbLGBdojn1pBWs4cTkioDc3YlzH/7FCcuc2qGsbQsKFk6DAN7U4qqapDCSekb0HfYW9Rw== sig=OduLG5vWi401BYa8q7k5BxlM+aKDlChlSSn4du1dtfVeLcMo/Gd541SCUr8/QK+inHZICKRes2wA8rEDEpQNlADXAywsw020zhHGUVevYzb0jkoBhMwIcbdRpErjZ0yPS16qMfK8mCzEuazqcmRfmjwA e=found last=20 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABwlrLFpJlVk8oBXtOU4r9JC+K9/pzrpcfDgJaUypuY1Yt3j1Sm62xGqkIc51Jkjq8DLswJQzxJmA priv=MEcCAQAwBQYDK2VxBDsEOXofx72dkiFBDZpgWwrvMELzjxfZckIQRGTvcdP2Hovndquy0zb/EHk9peZbdrrPHOVqniqw6c5jBA== msg=fVQY+2TkiWoEULI5J5tH77Y88nmZa3hiXNv2xfpGDC5fJBVncoc+jPfjzbnML6yq2S8OmGY5qhUTsG9cjCzURQ== sig=HfbUa5Ex5FvoGiRkT2a00RTqXbY0Lj8JbQpmw5I0HHUYy/0y8ZEXutimuWK5JTcie7gBTj3ZpRyAmyi8g92oNVejxTGCVAY59nHVPpucSpGFt5E7WVTLeyOpmTObHz2ImM5THHTb7/BPF6IUUWIZGwIA e=found last=25 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAKFQ8s3QK1UQsXWJX+9QkDWVB7qQ6Ed3uUfC3DP+5/3S2DmXoFumGXH3dJ8Ute3iPphC4niiCyyiA priv=MEcCAQAwBQYDK2VxBDsEOVcnQeuwsgNjNH1wne25KSCd3Ju/vEVUJPyaFbwLUGMiCBU/qK3xCvYs/CYq7pMI08nSyxXWyUVS1A== msg=Sls82zJg8cm5YRdvN00vnbpyle4ukB/UWS5O5rHxMbsMDK435TOXb1mSOtSKEnl9u/LgYeoME0VhH/ho2cTYug== sig=0n56ieQRHOJWUy1q7m79zJpWdmhueygR7h9DoUSTObh/iRWXWDCwoltFBk4OoSGbaaiubR8b5S+Ap/WBy7iN6dBvxeNTYPloBh772JBAZmj6ZzOdgDjXgmSbBm+NyBtEvSF6fcHl8CN0Pz+/Y7tbCjQA e=found last=16 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFaR4usBZHjMU9uHTzeVtzRevEqw/GBxzPemlNcnoEfkvSdxuI5riTI6tTwS/it0see6gh5zfBnkA priv=MEcCAQAwBQYDK2VxBDsEOZ7TrtVx4M3dNC/vzmWp8ALjIlrzohvO7TQ2vjjihrMIY1sBVY/NN7d/NhvgLauKVo1LF4JaWaBVCQ== msg=7tmQp3X+5wj6F1ZYIPq1nTP2p9mLxq3w31NmQGNvOpmz3oRCeNgzw7qrmGFqZMabuH5uidLX9iuMcF2uQZsb4Q== sig=yx6u6n2YeUf11h1HjgX4LNQaUXaPaj9ptqLVuAtB0fQ/z4BH7CWWT3hZSoTgBZF4wEl3XPMbtN6A6RhYCxmyLUUO3/IzHvfNzlJev8QS1cPDry0S0diGzaY0XL07nIx6p/qHeR8Ns541TE0eytkfIRQA e=found last=18 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3zYrQ5gB3J4oXfyoliEisxG0WAuiz4ZWJy2tvpXZPV9Qsv2fYJIzAVau5nq7iIAFXaecuRtGB6oA priv=MEcCAQAwBQYDK2VxBDsEOf5x93ahv+fFRCr3u63jeGWj4yhOWPdw5wmjj6JBsSHwvDSdEQmcrfIkw1c0eMgNF9qW7pSHi2vFBQ== msg=oZ9JNN2hUH+b1V/hP4k6aqkvOTfp4BQBR5gfnYIcy8CpQ9xC0EDwEgTHMRwme4P0Z4ztOq0eJ3iox1uHNfqKcg== sig=k5QmAM5F+jYYLYWYyPM7Xvl+KWh2HgPpk0o45a5zC2QceX3cEWDtSisJxhH4ncacExqOA1NmPCuAN1LGIjEEFrqQKvf6aaP32htHswkukqScTslSX58MdR0PaJ/n0z581LUlbR5Q3DTmLRX94P2PAgIA e=found last=22 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6TQDbRA+Emb49F5Ub18xRUdBwWo99qh2x2gMHPdgAUELdbucGaVhoui5BIQDWpYrlohtoGPspm2A priv=MEcCAQAwBQYDK2VxBDsEOVy1/dRAQvgs+js9f4Y6nJZ7cxhyaQfPrL7WclNPUPM+k6Chq4VFyReFgUecGtxPgblY2Hxh3gbGaw== msg=K+jNS1ZCg8d06o4ejP+pgXtGTXBMrKOl55DMEPVf4zKG4kbvpU9yMNvp7VzU9gWXbxfBKWLKaMuro6TqF8VlfQ== sig=n60MyYEppNyJrPUum+3p2IHx42wq7mOFwHjO/SphAk/T2DNKZiqTeeRTTbDVMovOMSmdm9FpfXIALWGO56w0OlBeLQ27/X9xeHzr9Ro0kgHs8Wxo367fHiRv9NSE8pkdL9o8sPbpAsg4n6hT4IQkGQcA e=found last=21 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAeWLL+Wt0K+8s2eirZwNcgV3sooyNmMSSPIJrXjoMJN6NMVJ8amXul27QbhKhXWCqqIdsd6dKaLCA priv=MEcCAQAwBQYDK2VxBDsEOeHYeCMwAWzBPMsmiRy2YQTExUDA3MrSATFhwXCnCJaoKrIIf2oEdvTh81UeF8shTN7PTpusve7RNA== msg=nJcNCEqTO3A4qVfkol2usWNDzhiDReTJVZYS03/YgwNrrSvIZ9PEl6JkwGzbmh8dTU8VnNmCgFtqqQHKDyDX/w== sig=hJ9ZKtid9hUYoKhh6aHpt6YtxKJ9fvavnP9JOet4WaxJp7aNdD04oMqHXSE0j1mrMIS6RofFiMwA0OxZKXUe5Ij2/pc1+T1HC0FnPkMaZ23dFYofD4M7rz+Rs5ULNztquNCqeRh8Qyo+2QN2341vagsA e=found last=20 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmXLBiUkY3WGz6ekoToivWFdB0yJR4St2HrKHDKYrxkKx37+ijh+HG6guTydaumaA9sqn8asPSEUA priv=MEcCAQAwBQYDK2VxBDsEOfysTilDfA0I6YlsbQkx5jb3CqhYGexOZijeRKUrWStOATf0QIQYuHfzLRJvF+s8gvNhKmvW05rtdQ== msg=z17RCwRmaZh4BVEzNUJ31SGqZZuIWFR+/VenC8ZI1XMP5zEchzeAfVHPBmepRukuZSocxv839zciZl4KDkXKUA== sig=btKc+O87iaZw/DwPtT6fSVtO/ZrEYEpCeh2ylpEEkDUX781yRcJERx6gaBDMkzOE5OIJUCnTMQmAs+w9RkuFnmFg/VRXR//6y8KhybvdqSkVzsrVWmXuByJLQxoinvbKvJ3VvSizKtvywnof8Y2pzzUA e=found 206 iterations",
+ "pub=MEMwBQYDK2VxAzoAHZKXZDuv8rlbprKc4+yonM0+/SIyL8hb9jgg55c9xhow0u6yhD4BjP8sO4gpaHiQ4TJJVD78TFmA priv=MEcCAQAwBQYDK2VxBDsEObmkQKh9WhfdQD4TYihzgCvSavC1eI4zA1fVuongIVLEE1dFU7n2vv6rC+0a2yo1OP0kmVQoXIBTiQ== msg=7YFiJjCAjjRrEWUtF8BfmsrdESqcdtr/WqTw7OiK0uBCw2KbRFM1/JShtIHnJGkfEpni3UEF1keD3u3jg8SqCQ== sig=aJwghfHVtSYzPqjh+LEISQ5lw8O4MeDdXQ8kAQtrB6R4YfmMRuzRSKCmTxtyuvMfM2QiQjQ3PBeA5CCG35rb0TBj2OVQNZtalLWDNTl7bSVgXFfUW8vOEed1oXAQH1SQuH7leQNA0VQLLnXYKc+wRQ4A e=found last=22 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGuiyVtm2GTYnDt22vfISMpDbm0QkM64LdS3hnG9JVFe+LbfhqwdwMhPlAqjGdhEuMUvFDJMjMsoA priv=MEcCAQAwBQYDK2VxBDsEOaoTP7dJ1NEwrYnegmfJQKiSkWrkTd8GK8+RzUER2uB6Vz/64i3IOK98iHydQmxRbiGdOSBU2biL2w== msg=QdCmGkkWXGrrpQjxxmFHGBF8ZpnZ9gPaF+qRKx93HnqE5UufBU91angtymiS+WRIzZjHQZ9yMCwHYJ+YREb/yQ== sig=z+q4q3xr8yXsqzOIoMqGosaRxQ+sF6F5z0qkHT3XxryqPjzNmEM6WpePxy6OgwxX/+kDxJbdHZ6ACJSCoOHt21ojOqRxMxRBB4UMnHPiUr+l/8D38TdrJurljFtU0nTD1hOK6s551face6XWY12jtBgA e=found last=16 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAF+feKtxUi4U7jiDjleaAOKRx+KPGzXw4znSxyDg+rnaNvSBNVNnxsUpikKdpxB2ziFe+CWexph2A priv=MEcCAQAwBQYDK2VxBDsEOSZo5F8OaVlk2bKlIYuVe1AoWlnVspWPQYqkO3X4kScQG9yAZz3E0uebvr2iFCa2rXjS1tgPb+GO6A== msg=LbZ0PgdonxkFn/rECjesHujHodPSLssVitbzZBRJ28Y/tTL2rqOFQQmF0C+AEDMc1R62PKGtZlEPNwquvqcDwg== sig=ISsc4Yoa92suwSS1a+3Le9hOiItzTGp9QfvnFFntxqbF8mgr2VnhdfwDXLPZF/mN7PE4fRx0IPsAnG44RDjbCNjDcRKgPLWCZwaMXlaAvg1JqICa8w8OxjqzyRm8oJMlMGFCI00eK3MA3ahorqbyQSEA e=found last=15 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZcael69l6nVPJUA3fV5t66ZE/9MeJlmIjaz6lL6XXVmhl8cn7rZm3zCVQQUNIKEBkNjjMiAo2EAA priv=MEcCAQAwBQYDK2VxBDsEOTCqnh3BZCr6EMrNoWSbi4FQfffNgpe4BVR8j+fYCIW+hAnRFmbYGiq4DMLPMKG5voCbDEaAofGqLA== msg=6AZOGjvnmZVLMJrPkO9/MbAb20RKtuI8pMTpv2my0xfmzRZFuaNfWFYM21pUby9vClEXQky1C1JVHSgQu8xnyg== sig=CoSZmP6nVr6URWmPfZnLfkjmBltO8/TWzbJAcUAQXnrKI8VRzIoUKdE+TqWIJX3mQxKLoTruoI+AVrTiB2Ni3pO4tasAIuEyH3ntkDPxO/hX4vmPc0jKM0IJUBft2RXUozFpMr9o8KGTxnzXVEW2CSYA e=found last=24 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2ayGUojDrgripY2VHZbBbNk6YbErqgofjvmta+4LLSP/QQkdDM5zQpI71ED8lYXuzivsWjfIDHmA priv=MEcCAQAwBQYDK2VxBDsEOY43koxFggzJCXPTUI8kcQSW35t08UTauyUOa7FbAlZh4TlZO3gUFEPixYXt3nSJx10jrWgTcsRk+A== msg=s1oSFIrxU3bW5YEf5FHcw/GvhvpNHVgGhY+fOMVFsZvbfQjprRh2EL4G5tayVoyZ+mN4yIX02gAw5iCJWzctFg== sig=dIfulntyhevJR17JDL8NmNxohbIFrZmyXswvOaMTy/g5BmYXxD6kgj83fbVaUtLlHuh5KZJE1B+Aj7wxq67VK8d4gYEOkdd4LoY8QIwIp3pxY2MovRzcCIh5t4Oggjd0gr31jx3ek3SH5h0TJpF6HCoA e=found last=21 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1X9OJZkl4XtlNrwmgvLHdCvaIQb4jAuERuuHdbLLzQIwl3XliVndikD8TOdwkD+2/AnxD63bQ0mA priv=MEcCAQAwBQYDK2VxBDsEOQtjr5il9VCvpUci+rt5yWCPrtAfdkstaWH7T7hL/gh73NKBJfLVmjzC8Lvp+RBnOgJOYJzK6vSSAQ== msg=/+DmblN5tKsjAsufAAZgf5h5mrXCz5n6a7polThzwpcYMakBEDvOZ3mZk19yYdMzecHPwnLfENtl5AUYT2Q6Fw== sig=Lm7g0i7lxlCSiQwWrHpT4OnoQ2sRILKT+PMSrt/L2Gd7bV2jXuFZjRjysBlZhbl7+xVRTzz6VqOAAAjA47ucQu/+fCNt0sdsBqCV0ZV3uarVFL9aE2YPv1P4BFXiZMt8AsdCOoW6XtingDaPreR+0RoA e=found last=26 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABbO4cke7pDOFo4bNtiQNBTYQEOSD9GL6SOjwZOHGnMBWu2UBcz+m8ODvxdxQ2gj8W5c+HSp7fLMA priv=MEcCAQAwBQYDK2VxBDsEOWsztqyrBPedqRohhkQSuB6GxgFg4ke+OgAYOFta6vsyHOBRb6mUCYHR+83uyWNB8LL0pg10yKw6Dw== msg=nY6N+auY8Q4Mn30vvqrNk2bc4D+w+1xK5hp76A+wfdWHwsxMxF6RArrQQYIcbwH02vJ4qLpMRiYQo/rEnVlDWg== sig=RUJZz1YHXggd+oux29w5SeDplTuLLiZJu/haT5RuGcPvXs9LOoOGbUKsgX34V2/UlVy0uPxJ28WAlivNRWZrnq3x8CSw5WGH5P5UEgBgqq212KRyWM4uWgeN3ZAP8bdMPAkrTFXAV/hHI6PcfmitRBAA e=found last=15 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZ1fgJ/tRS410b6VJ+4oEv65m6KBjfqc1n159gl05LPlt6Qz34lhBZAuMok9bT34X6xQLEgDJhZkA priv=MEcCAQAwBQYDK2VxBDsEObIm4NBaBAaqBLpgKZKETAOL7YLymYRYcSiz+rhghHv+QqkkAS7D+oPrw1LAMqxVshqGFlpc1q8n2A== msg=nwwEvFq0E8RUJcNlbgUwtPxlmKL9KK6E8QgVmeEj3DQ0O1Pfo6MYtr7WH0iaeP2ZZkBQHTMTpqwYs272BqyiEA== sig=XqgwIIdhKJBdTI3Vq7unEbk1Rbo7gtmsgoEvKGEX+XCQ8OVZpqRQmNNJP61P2W4b95TfNbc/N0OABqr+YhYn6fGH2C/tta/W0eQATVzE6jlAxpK3GrsMELRzHFXyJM0vHyva6MDvkECy4tsbMe83Ti0A e=found last=21 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASVqSsYc2X7z/CcUm2lWz7G6Sn987Qe1wAYeI/DZVwlBxuiRpEi7MIAmKTmgz6OUATziqHGWzyxqA priv=MEcCAQAwBQYDK2VxBDsEObm4st1nyO3EDtAoRjxNtbofl2S+4kPZq+/Nm59kQIdCquaLVw6ulYkfIadH8xf2chCksv1xbTiTvg== msg=ERu0bgPhrgPqS9L4rS0yaEoV5CJIURinGnlL3u4kT8boWKj432mM1dQIhvSvKJ4FwFSnnocd0rMGTEvYtBT/ZA== sig=AgUwWhdK6CRzpYslcKLeglF0wAyIX0pFqKdQCbQzgER1QwJksBc4n323b2mpE7RldXSvxyXcZMwAW/JanBWagQU02eFNzDQgAEpgU3cNDY0Wrl1KlTuefnISHpLEv2xJz3ODYuNevcVDPm42+dIVNTUA e=found last=19 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4dHRdgsVlYr5JxaM2sY/v4nR1FBgP/iywDJ/K+EyA0Oo03LsBceWKmyOrjDkpcT8I73IdAJmX5iA priv=MEcCAQAwBQYDK2VxBDsEOXVoxu4ux2ZtirerVZb6XLlMN9PFQCk3QeiPTya/09FJOQdxIBMs4WJ2hdDQJeWb68L0owvpkj7KJg== msg=bwI0fNH9QUXBR+Zrc6DZHStNvxismLizAQg2XE0MI3UKoPcZdUzRPmGQG9rsaPBPDhPKcqBEb4CTbQalvvbXbA== sig=DyYYwwxtnHDnVVh0ghgvuqTsIPD2EEC1gi2ds11dt/kxGWenSNZFmSOBwHTGimmlVDA+McKw6f4AbyzqUo66Kys22xmqqGRWKCGVzv742rdqcQpFQg/wupJA8VVpThinxmji/bijBfW0RpUJk96PjDMA e=found last=20 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4irq+m1t+p2Ml4omiTP1nSz7GGaKSZ6y1CCzz5MBkdvm5g7ONi6p1wbeJ0r/eLrhm5FRd90Ij+MA priv=MEcCAQAwBQYDK2VxBDsEOaKFdEVtjVUwoolckBJeeJmmnMUidNokPBgj7049pMrsJmYG0Yd7/hBk7+UxPsSAzcoI1aUQtmweZw== msg=NvR2yXcX+oF7x6U8Le5tQ1O2301uW3rEAcvDX1pkVF37YbtXYR3x9oa8Cut2/nGysK0kcTJ5MOfDIHLrbuhT/g== sig=4ak4+E2Iagcd+NerfI1tZuo7quH0lpVZ7tgemI1nyxwTnQdNvjwl+snIAqBNdwEqryNAZ8Vrio8AiMC8DD+Qn894vqxf+TLqt0eZj2WXtfIL7TWOcUAWkvy1jI9eo8ndV1QmpyI86yK9gxVJKB5JwTkA e=found last=17 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAc+V2NODcjBP4aDXvrIIjuhidpOVAJYsEY4hITC1MizjOcDkJgz2FuLZ8Fop1HiqRfuqKBZnIooCA priv=MEcCAQAwBQYDK2VxBDsEOZeQSEHuYcrtU+5VnQbmhomAQ04V/MoIYUUXthH+QTM6pWTJkDjaWT8j4qxvD/yJRZHvoizdvoHIeA== msg=gS9S0dSuD2jP4j2pN4dyPXOoyJ9qbcmnEBVTHurq/kRXKBlb4ty9fjbbnbu3uMCFK5YOvNHOEfLXs4jyvvPwHA== sig=0zy2TcJjDp4od2eLSUw7p3BmBuZEdqTcxGht5rjk7n/k6sJ+eCkAEHKH2+6SMilusS90YtcCMrMA7DHsn0oyybLE+sdhVQYfJiU1AUjWAvh+n16c3TVoyKgtOF1021+bg5BXmj6dNf7xuF2RSOiWzg0A e=found last=16 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdTp1hTbsOvKmF3ROLwxbTeAg3Q0jmhXhyqtjg1e4VzO5rvIlQwDQ0/3qR7hV5diu/Wv7UO7XMUQA priv=MEcCAQAwBQYDK2VxBDsEOTFG/h7A5FuWirt9BKtaS2EaT5ZieH9A2JLspy4BySbHSvyxHFXP0/aJuh1wnVGlafDgjFL8m/hmnQ== msg=Ez7nvb8eXmfZbMziah9vUViNcEDzvLazfljtFKxPdDV1cMN2G8SnON2jNjWBb4SD8snDZXgEmvytkkESrx/U7w== sig=Sd8QRdFInJRARylz+/NCQo9mY4AAUTCID13pMunwSp5OsoUHb5JrAcJ8bjMHDabgwEBpNoe5cz0AaCfgDoCzBIL4axDW+82bDuwyjkZja5bYvdz2MhlPWSxsdwUaQZ68W7eSCkDfig5y06yBqQSzGScA e=found last=24 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFNIxd8MnI7tf0U4ahzH5/26lUmVmlo388dlv5QRfph9iFnigmZx3i2jLvK3y18A5J18kFmWsIlYA priv=MEcCAQAwBQYDK2VxBDsEOQdXMnETX82x1YQJ867dM3uUA3STXTeUzeawglJB1tY8SJA3pvQ5Jlm8CwxfOFW5E74blPyMQzKBzg== msg=1OCqosd3oRahEM3/szRaJorzk8kD00oecVXxtHxud88gpCWnuLFfZ1LZXK1oa5BLgi/yhCtmguhgD6Cb6kdNdA== sig=n0AIw43PMhAsJrYQZZ/5AH0gmSsb1lZFS6ZQtImxlspiX9McEkUhzA5b+vfnwXVWMaC15+KattuAGTj5GuF209E02JSCFE5iC9o4s1PlcNMJZKphVRg14BFL0KQG1F/KDVtIseKhjCZQgnl8kqj5vyQA e=found last=22 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAQ5PRM+pcdMDvdi+U8eHo/qY6S1VS5Y90vv4ZqdF97gTuboJTrgbByRmq9E6ff3m8CaQ6HiJ7C52A priv=MEcCAQAwBQYDK2VxBDsEOWHufrlq7c+maFllREJZOCoVXVbDk7F+hVozYYnX15mYKsM8B7ZJ9ifrdJTA3iz+EmQdHZxpXCS+Gg== msg=fFeaWplmudmWbeh/zvqMUVim76Ge5n42RF5hWutX4esumVyo/4edZMoNgd/pyJ1Giqy7+pUyXBwQsqtQJ5WlOQ== sig=yzocS/WqAkXZxseHoyuCFL9XYhpRt9IrgTqX1VDTsYlAtlNzr+EN5MF7Vsk5wicNLOqefPv/QlmAuFDgUv3VA2RVWoYBNnq28Obh/L4SyKbzfvN6dntgqWYzKwzj0JwGe/Rfl7CQJqAJXxS5MtVG6ygA e=found last=26 s=21 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAomE/GWOiDCSBPc/vEJTHwUHhbY3xi8zj+haCO/WEK7s7rv/8ZScHHAane85zgAXkXmeTCXlY1wcA priv=MEcCAQAwBQYDK2VxBDsEORJcy9zJZACoPwxK51VDzjVypqj4AaSYcabBKo0xpbwRMPQcEU5obREHs4BABJMrk4KhrCZoxFdgDg== msg=0UpxOb1VFoLIyv+di9YYWftemqRyRs4bKBQNaE1Kj3R7/+rGsmYeoXxKDVXfydeelu82GslpWxfuYVd6pVwLJQ== sig=gKYTnO7r6cRCyw2JFKNxrjG07i5RRQGDvd2fqlnzY2d0WqR9vLlqZ8WzON6e0WVHzc0QRKRgYKaAyvD7ZQzw8hKAzbC/atfCo29NaiEPypz8PRet6C1gwFZqkDSsf8k+bDrzWfwHDW8RyIDEMiGfkikA e=found last=18 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdZWVR8wEz+40iBjBTBpZrbi+vLnfSPxnDotP23Yqsw+W1MfDq/yMuBTwDqLSoHYZ5VpXrZKFfRgA priv=MEcCAQAwBQYDK2VxBDsEOVOalig65uReNkEoxdzkkY2S+aR2Kffy6gQJ4E8GKBz0ykIHeHb+PJq1ESBqOD0Yp/97Z9eQQrP32g== msg=O7X3oxstBs6HXyp/2cq4wYkPuxKkyYTz/FYkmYrs1D9+1bgsHxZxtctmxDnp3NP7EhauF7ChL2RBTkGzIwaV0A== sig=FGkxOK3Sarvv/1FGJbULS1++zW1J1qnkba5x6Wol9i1L9d1nQsvI53vBN13ezuE/4XW+OKCXrHcAORyRi30o/q5cjAEfMcp6eVk/NKKaNC3MIl96MvFgIZ2eYuDWi1OCPcTcKxHMdwbJ7TBG01+PiCIA e=found last=15 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5eemk/wMwzrsSF2UprZYvTdfhj7NksprFMVR93QnYwTtOItiRL/DPMygjt1bjFhypcKwPiMwdSeA priv=MEcCAQAwBQYDK2VxBDsEOSVZkEZmpIfkY1GOgNPagjKe1UHYMJgsQn75DS+GZzCM29B0AaaxQv/am9XZkQ0nsrQ0+oQIYc1PGg== msg=aUTFwPAViOOmMYWTKOA2LCcFzTSMV1U5Lp64jXJb0pkP9bL/yt6uXbvdvoRzJgHj63RE9qsdfW21G6zrtgRwbw== sig=JScwBySCiVePK5YGamtTuunn16lEnR6IXU0Uo5hXmYEUg3AT+MD/BuIO2fSnRvabmdLQezNjirGAwQ9nqVoV7iWtwSseBQS4h4E7m0I3Zm5q234AOXCaU9w11oxmYW5CdsYPgsjLonrxhCL0dE5CBQkA e=found last=26 s=22 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAgbcGC36jXmJtT/eWJA3lCh7UpAwOYC/Zj2p9AtATlKFiPQbvQLCsShDtDWYh9meIYc1qggA/G0CA priv=MEcCAQAwBQYDK2VxBDsEOawqlWD30Vfpah3iy9NgNqFMsm010jTAHFvpjuuoFwgeZrfuPsE5dF/UTGJgZ/MS0517nMtShYJ8XQ== msg=ipm55TycgV/qeClEtjCVlvwxkARfu62DBxsCwEBIHeyr7ZnX3PiZ33F6lKhCmL2wMmL2BuTV6OxOHebe+7Lf0Q== sig=sTkKyiuCHZhOlcpIo7+9rm/S7J7TExTWYvQM2xLaewNG8/GrT3eRNz8C33jJvZqthPhO9pEirt8AwLPfHGTyvfClymeWPZGMI2k0aOBgDh1ktof1nNn+XGWIG1WY9bPr0QYaevSBzPiJC/g0pJlARCUA e=found last=16 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmUo+sdMj7W6YiW/6SacpONuD8oD93gF7w1wTFVdngdEhPMZPgm+7YNQCSt8Rsx271Y1wEObRUfeA priv=MEcCAQAwBQYDK2VxBDsEOQ6xZeuNuETrjZCdgchQIHAURt8sE+1uHAsXQdBhNy2+qo8vi05iSL1bK688+FmgfXlou3DV2cnAsw== msg=7XpMXUZI2uUY+oIbVYVnCM6+nvBcw3vIhubUBnK4maVS+QyvYMTs6wG7CfvALY9lIXRzhaoSveZE3bdeexcqoA== sig=dMqRjV7z20Arrm1MaYjU9DqDd1ho513ApiZ/l5QrGc1+nYp08YY5d/HyRSJ4XgqY7pODP0keHwKAWVyiue7VFoXfUHmzzsX2/Z+IjWvqR+rZ2h1tpD6NSfFg1TDm7m+fkWQwqDrbJ/vb2KQNyR6PABUA e=found last=20 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVsOyq9Z5ZrZci8rDoUrC2zmJnjX/8tY8kvXTLaer+0eBXq4IpR0yTWkqKax02ncak4B0Govk4quA priv=MEcCAQAwBQYDK2VxBDsEOerZ11V2+/hSsdsHySy9YSkAktgtjnDmX5MMJExdzksB97Vi8bLyV6uis9vbZEQYg0+jXeM+3pOzJA== msg=rkWrslT7e6SJjX/MfMGOvc5OeY6Gh1LPyseNQq9aVFWxZ9hcGnUMpaZh38fqdeAJmo7l95+cKi+xCmhiAr7ZRw== sig=K3t6Xc8GiEe3qEncukMXaR3ao9BXyUtRO/UqCMEtaSoq2hN0UG72IF4N3uH46apfZz9pL9GGdFEA/YUC0DSmj6HTho2bEXon7iZxCbbIRG6ShD4804c8w5eR4xbt0gX/jHnmQwxdeTzGdoZv0IyDMw8A e=found last=17 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATdJgh5quiURgKTSy1+2Vft76Q0rqiuUmgpLBxnZAAlmkHoMgJ+ba1IrAxyhF0e2tGg9HgqLIF4mA priv=MEcCAQAwBQYDK2VxBDsEOeuTX7BgTn4DGB/+kwAQ/RlpNKZEERYR41xclM+XO7aFYxOtuddLMUTxz3cPeB5W/6fzqHflSclL5Q== msg=zDhpDyjnZQIXmr0rJI43YJ8lPILskg7RmZt04ILXNZFMNA2xN9Bt4nCmsVY/1AgmrKGFAfswmcoBDADaj3ijgg== sig=q4CxmVVirV/wIMTbyZZ51JdccaFjG4usky3bxDAZw9EzK3VRcjhxlwDeZmfTui3px9otbkW2MMcAK6/cu6GLlsolGoRnR42xs0GF/ON2rH8n4GNcRa2qSxz0/oStssI3Xbg5bbRrugW5KCcDrDColSMA e=found last=16 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAeL/4fLpqMjSIobmri/C7sNp2uUq8+YNL6JalPs5CkIIVNU3cWiKVtK+8KvvafZ9ksMSLnZcSgK8A priv=MEcCAQAwBQYDK2VxBDsEOfCi3BC0i4IqzKfT3osX/hJHHdtLAsIy30/HnQBiPSAhPj/IbfzrWSTiJ0Iax9niaiLvDJWxHf0k0g== msg=yUbkKdGrldnQ5DPfpDRM/yRsY0hLRT9SBK8859+j/VZiFt384tBGoBUquTkipSSX1X9S8WlisD2hIw2yKMgl/Q== sig=X0fdCzdndkd1zppimg3bfFQt3A6BrDqnom0mmVlVZsQVbT45WicTsotM0zRDn28/IfRbnc8SkRYA6xGO5IIqABtiNLfe69iAOJejNO8tkaOiiU+Kccy9N7BbtUy+LPoJE6XEL1dHChUwwAAXflVt8ToA e=found last=25 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9yyUXsjw0di5MJPG7EMyAPSbcYLyF3Nbybp575itVYWtz/NqOzpiigkz0wzu32sm87LYaym2x2MA priv=MEcCAQAwBQYDK2VxBDsEOZ4Y4uExFgmpEjfbcy2DZsOF0K30+KjQNKVfeCrscVzbt9IJo7xjGRA+qINiyK3IBV8b1f6MAgsfag== msg=uz/36lf7IG2fJqIYaRC8kulWPR2lVvzuGEITad/0uJYhITw38shyC1vrfruFN2ptJx7fltm5zjmqDo6FBqLeCQ== sig=EczxUxLtVd4OO/fiicyAEB2JwruubvTkGZbzwBs+qB7Ncfb0yEwxgqhAy7qyOuJ9iYJCq8uHJGeAvzZkIn0bepAZ2G5RjypWYHdMfoigv68O8q8zZ0R2GvF80jy0CTLXPvnfL4Q8qqthniCcNTSFRDQA e=found last=21 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAkYVW2J/Kgb0J2Fny4QUj42yEH/DnvLcPxdAqLnCKk6NUZtkYRQCGtvnJQ0kqZ1nEkF3y0P4VZQKA priv=MEcCAQAwBQYDK2VxBDsEOd4D3Kbx2bjzngniargaRc2bpRUvh3nWPZetjmRNw17qQ4+2C5CR8WWl87e5KEa0cWAaWmTErR7Eeg== msg=KwIIedprim9sBkyt4U5cnbWKuD9A0XK8H4G/1nW87KufiQVxAqn/Hbq6Qs7Aacm3G4Te+K5OXKnp+4Y7FPFm2w== sig=cE2+iBCse0arKzG/sBO3qdHI64a5A87mywhMDp/IU686cMzHfftfjbvY1Z3Lyd8iwBLREHjiAO0Aitq6nOhFyfpXv5EfuIVfH7OInyn83iYe1tcNx/gie2RQIb33V6TJxzXoPDNv+7phGeb6WV6+ri4A e=found last=14 s=16 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAAe6mbxUfMnQXdwU8MlWnxxz+88JaMPBpDu2uRQ3Pt532ypi6ci//bLpHhZe8Vdx1xx0dsTnQu5+A priv=MEcCAQAwBQYDK2VxBDsEObKHqdqej1pZegKf/+x3E735yY4lQ3eKi1KN9tIVGSB7bv/r9Z7VyZOY41SN2PW55u2jGd4vOg7PVA== msg=PyTRVql+XeNwGbFRvE8Jfiom1+Pl0DB5tl/vfY7BhJEA6Iarv13Z4VdfUd34M3PTQ/6Gt751w3aWMqkGXsIOWg== sig=Jt+kSyPOKAETPj2Qvd+3qcmxs9mHx3S/FnuE1kSiGIslKvNqaobQaJZIdM3OIayG6Z1nvnJ8vyEA6a/czcpXt/Qoih3Q4Yf+oRdffRk1gkat9od6zsu8v5FZvRJE+p6Ek1VtlZ1I/PCv6cC06dn5lCUA e=found last=22 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1CfHkSF/Esx10HFxJInTWr3aRk7l/l85nHR5XJ4ssLBnx19HN3u3LFcgql3R3rKxDJbTs9ANUrqA priv=MEcCAQAwBQYDK2VxBDsEOc3nrzAqnLEZjBs0zUelEvZTTKnwKgWmj93bw9eEqHiOhDrhjkTYsidtx4Id5LnJS0SxDild0GR3Xg== msg=7EEzPLYTYxJJPoU5O7nm2PMVqVvZLnFU/ZkOqEtjFHZdxI4VwcxaOk9YlfpTpOngng/JZhvjXPeSC8KL3v591Q== sig=ZWSrPxUpBp0Qgqgh5XKgJnjlidVNMk+aJ8YkU3VUqU5vNVAp5vbblu4rndnUOLZL0qq3tbkvw/uAaHHeEEBytKOO0UsZTObyl3iIw7NqtL8fV1DpBvxmsYMMhOmzJLNOUk5nzUoDyDcxmklpHahjVhoA e=found last=21 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAHVnXYcz7R/mbfgCFR1aYWIZYtkKP8PHxh3MJeqjTKkglxKfw4YX07KpbPQi82o/wPhvhYFA9zZWA priv=MEcCAQAwBQYDK2VxBDsEOXfK/CFxwsiGL6J2CWuHfA4j8lea+hHPDw/bzUfe8zA34X61obxuqpcFMpp94nNJ38dffdtSxEra4A== msg=DaM/nTwfy+sP7bCoxyIakUdUa6Nc2z14Qs3XnKMWXERy+32Q3T8wAVFGNbuK3XeqDeVrvxIXLL0l4cdbgTy8Bw== sig=kTAgHcXQDj/DbqTxr6+2ER6+pm+lZcVv3wjQhnSOubDICMtKLeLgE5psxUfKPzZ0g1MVQ+fIQyIAVDJ6NXNXfFDBmPSaehTWShs4QHbHX+LQtOV+oI4uLpOjIMeU+7eARSiVAjVH502TyiIdufh7HxUA e=found last=27 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA8oI4ImnDW4NWZGmZLgDwTBTtkGHCFTzdsOSNMulK6maUh1M3QJ97ZGU+S1ycGtXfPVWVc4s26AaA priv=MEcCAQAwBQYDK2VxBDsEOen3cNViYL4cBudxfT+jfJvaYSyNcUHZL47BiG7cJGIuCQ7kBs3TFbKo9+0z7Zgg+W3V4YhIny8JKg== msg=yju24NiSjbDTVElT5qe3KepVK2p5smxsYXgz1bJxSbhYeBY4WIONBNtMBwXVTJhQxtrxR9HLJLLDf36c8vaTCg== sig=3lztNW25Cf9FSsjA952dtz325KMxU9PjNnXDdpL55lnOfxMJqhjlkFDYNN9DwWM6V53g55e2LSwAycEmPDE7gYjYYsJaU2yhsvY27HrMDbsiQs4Mxm8QiR64XbLFAFXsLiRKmTkBzwswCVeGkfEVCDcA e=found last=26 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABZIdqAvebd1isIfm/k7LiGdWLFNo6mWzW2ijpuRjPSEhmBWbXG1tlOB2Et0Wy6/zEGWwWhwGNIaA priv=MEcCAQAwBQYDK2VxBDsEOWFLoUEoR5vKObzKbnb6jhRAaLew41ogwA/DOI3iIToIh9g4fzr3bCMEVkQtHBFLzlMBvfBQeUyMzA== msg=Gy/sl/og8oB1F86lRdCTbdkbaXGbH6GK6NjVALmg1lkq+rvpZZf/QWoDWBlX01O33q7OsSfDG3kU/ZXXhUQc0A== sig=CNxt4cf5YaiRMkA5S8E29MlMC0R1U/BfCvSSOjx1f4hyZDD343JkCa/sHlNHvr9NK/o/Veo19ieA0dNOuJfIkbyx8QEbHFg4f8FTsoSzi+qXoTiBL5Hov1QjB/lVXzGDFf7trGRI9S6pzxIrw+niTAkA e=found last=19 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAR/KDIdIN0VkirDpOwhRBZ8XeGvk0XpqmO3LbRC74dY+QTIibpvuWD0kYPfHB0NTFkxct3iwnI5OA priv=MEcCAQAwBQYDK2VxBDsEOUjUMyUH9psn/tGIcmMEDvAk9ZMYK6WByT5+D7wytlLhPbaaS1dpiIWQpI/+L/3dYdJ6Nae7qmB8iw== msg=VA1R6HMg0Rpsl+CjvobkGG6EdFYxwBUbVmtFMbxlJR0gVsf7ZLG+Vl+6UGcth6IoLy6e4G+Zo3ukI/5fx2r1nw== sig=TErUDISwNYn9DRu5bt0Mk8iV/njn6k6cWQKgFoxieZoWo1af2MByAZkZi36iw514AbnyNakUxk4A0aWO8s8BH5B6TODQrI5QoqkRM92OWrBFygOvKJzH3U2eJcgr+E4fsA4myc5Fmj0bsGVpNftxXAAA e=found last=19 s=22 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAvSnnVvsyU+Do8rwa0gza34N+EoqN+eBEINbEGZ1RmlIpyYfuOjKbf2QurjiavJwHiaIhO5OX5YEA priv=MEcCAQAwBQYDK2VxBDsEOT7x9KePI8xYwDAdeaIjZM0rBn0LVG+heXmO0ZVCEjwFwO2qbD2mdctjNvIy6CqJMg0b6kIyD1yKpw== msg=JC5NMa33YFKUkfVzqtiNpynkhwDZBuIgDWdPdssEmCPkUo0XxKPI5oaFdgxz3d2YosIHhX8QPJt2SWAGs8uoxg== sig=oaHXy//BairZzWgHn2wM5Q8hlQdAMmLe+LJ6qsVlte5xaJkcbaOgJyV5w6f6PbObi9bQpM6lWtkADD6QyUhLMou3OsHJHxz2mviPxUHHQHo5cyMnuqJdOgjmgTpUXJ6kC2rizpdT39B0OPS9vbhdJQwA e=found last=27 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEIPsVzetc8EkjuUyLDHYJfhgRjQgiU0+d/r9exUcoDpX5MRDsTkUOibeA5mpSA6R4u7x96xsmgMA priv=MEcCAQAwBQYDK2VxBDsEORbSHzGh24MyC6Qh4vuF7Ww9ul0069CBpmE4ME46FGlhNLpglqe8r6Y4YBa/gAK47GWROCe8w9S8pw== msg=nV4tE6+1xMlFM7lQ/CvyBTx9U8pcawPUbf4Ly1ZsBWoiTUH666mg9qrNFQE4CPI4pM9x7FfMQ5ugRmqtoCgsgw== sig=n92FtRT/IE0XZduXRN0cTDhYRh0MT33CVuKS9Z/0U0cFxuHkz55j/bYDZ5RFpyTOSmzIgGGNtsIA9phT27o9dSJj6+eEevkhS6EeXA0xurufCo5zXbw0BJ2Ckc4t9JpW/0FAHfzXLUx1I/Q0pucHAREA e=found last=24 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdBdAphNZ7QqDcT9wr8E8RuhFMOArg6Mu1ZXv7xgNSEahaYtuZ3aAVGmBEJz1VT6xVbs9R/wBdqOA priv=MEcCAQAwBQYDK2VxBDsEOd6i4gMQgHTS18+Uk6AFaTcABNDziWiep7685A9ZnXO6/JqumX9g2i62HJUpNgS/8EM7lQZgsPW32w== msg=TgvrrwqW7sQt5bcZ3aLSmNTNqO+20uD2XmLB4McNNTYhJapurS4+EwPQ6PIXJlIDOngcOxSuLxaAJGJjykAnoA== sig=rEzT+dwMCX5mSFe64PoUPp0nzp3DNNug8u1WPpMg+zmBF1ddn7liZapxjY6ZHBoMcboChcFyfMSAv8xsk8DuXM9M92jEYnUaETh3fQFRiDb92QGJSRdvCeaC4juqhS5hR9JW7BG4+HN/CGMZgVGbNxEA e=found last=24 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5opaVzVfG8RSWPTln4dp19Y0teXMDgeJQEyJDxgSksii5FvtawYBDWM/oZw+VoIbaXz24LyjpAgA priv=MEcCAQAwBQYDK2VxBDsEOXSHRmmj2LFPNZx8v09NaswhGwRD0x1kzKJZLEEW4+p57OXd7XZbBjjF739QEXvRXZZwsd1TMQZw+Q== msg=n3YGZPAQ/eTvLUUh2cWTFINga58FWSRN4mImghWBZ8TkUCooJC7nyHnSgD34nlDpTgNFkKw/05ChA2HuQpKJbA== sig=BlzTUEzm0rAm6r4MnGpy601SMv+pWp2YLWhQ0W6uvYBl36oC8kzglA3dU8/Ru2vMck7qfjygPteAvzFgwfxDm7CpcarDagjKluiyJCZRCyXcl5K5Ke29kPHvhlN3vSaGbsamxTjUtR56Pt+a094TvgoA e=found last=16 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtyKMyC+oIrQRFrtrUePoV0YCMgrtpbw+hfab+Sk7Tty/rp6c1/0B3DTnV+fdTxQOa5mPBWhTlJiA priv=MEcCAQAwBQYDK2VxBDsEOe/pG32oiVp4vu2b4fbdwhEaOzzxHHxv9wlwvAnDBekwbdFN5QfjbkSZsXAKme7im7vHKJHFEqQSNA== msg=X+U/GIEJw0YeIuMwAj8C97CqgP2iVe9h1LxsQ6WMvwiXdyplqS8yNSvljAiBf15iDD6Jw1kMIUoVXn2vr/qggA== sig=OjblSUt7JK7hi5e1FD6e6mtuDtDvwxwFQEgmxCjbuxgpHkg3xwuP/UPLtzur6g83M3Z7jbkQUliA1FSg0UnqXnzFRzmtlGWgazArGriURRoBpYkoIuqF6VgZZEMRs8wzXSBvWUaJ0CnKdkIkfJpZTSIA e=found last=15 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAirocZsVuqKD15CwowjLDl89/h4csj6DOvVJ4WH55WBj03DXu+gQ8gNv9d34FwHwDeLxebFriphqA priv=MEcCAQAwBQYDK2VxBDsEORrDo6zqRaWCqEEMZAXBdxCGLXvqWzVPPCdGLKWA9svI+zT1Ur+o+HHwcIDm95+goOnNz6DsTauQ/w== msg=fJ/D2KBA4FesBltES3ZScR4gef0itKAQfNM7fa7R/V3dgfI1Wperz/sZSgvKW43YP7MW6LFFiaJePZQMuRWI7Q== sig=/r80MkWzpgCfsDFZvX10FJrwKxyneEocmv2gjt2bSqrIKKHiu7onzm0KnwWPnKBSVkQffiyXEgCADpZi8shJ4KdnqU/TKy44ymgIQkukBMO9zC1kOHxfwR80OJAnk1unHuLdRMhji8cInA86XJRVejQA e=found last=16 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPnAH2puP/6qA9jnveR+iDhcei6FLWrzC9LLBlwecuS26B3bJaoG0OYCC/Ml6QXw6QI+7Ue3SKGaA priv=MEcCAQAwBQYDK2VxBDsEOZ2BYGFlomgvzDzfjNXdM+twDSaA830n1ykpWlsWleAo5+VTP8T47Sq0f5iDZfwtyv+rm9khmrtW4A== msg=IakKdzd1JmGjX50FXsrKG9FHKICmz9McApAECQVoYIXA9wB5tUmKnX1iWt0OylBvpxKs6+IwxFWJIi12LGTdSg== sig=i4Jyl2h9mWw35WiUYmW1JWmT1K6BjPiUI2IRJB5EYJPnOm3PBxK0Y1aHsyWmP6vqepWbSr6+sbQAHWU81PO89Y/q1qmuRrAg2sPzV6tifdcyRnyMgLN3CrejpAu8RxxUsoelg6i8CdbPVrO9lgkpqyQA e=found last=27 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASUjcPLZf2yi4ef6aqcaaP3R2ocMplPzOluY7xPD03nBTJDdhBE3925wKVy+9z2+eSvOyh9WvAoaA priv=MEcCAQAwBQYDK2VxBDsEOWHC/Fa0ceCsLaMs501CNDcPXK3W7bGj6AcOFQtpHm65FIcpnPLw2vP8A8ndZWmp/xRx5IEd4JVelA== msg=yd1laan/FHHkgR3glV6UlfqR3z2mnhOj5LO9Xxk0ytl7coyU7hSMbuerxQuzLjQW+uNedowfj8a6EJYT620rHA== sig=CNXtVB3TzQ+u/u35E5W6Rug33xKNZ+Z1ePilj9nJnnHikffmizI+KQztu0eV63GqFF+DFJPDnWuAZ8s3573HQEcSQPxQeCJQsRPjGNRy54WNvCiiLv+bA9Yh8nHxZmVAUttnGTMaeBFpsM0Xnw54whUA e=found last=21 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoANbEivT7h1tB7JMhdqlwZwTpM7J7fMVRc9p0eiYxaj5US/9byiK+d5BekVPoJNC61aket4tI5y+8A priv=MEcCAQAwBQYDK2VxBDsEOY8yLyrbFKhEoX+8WFzj9CySMhg1hY5ieIqQJ3Rn03To5TZBLyUfgjcHsBT0tR50pUPK9+62gy9OaA== msg=Yjk6tTPJ2ulm/qPgfwfd+BBnmA7hQbf7Jn1/HhhJIL73gWRwLQuwmlFENkFgLA4ZLXFYc1sEYVAJMwpdF7YcPQ== sig=EJMu48dKk4DJlBl6iRi1ryMJKBPuGxBRCnMD3EdwuaqSzZGBOK0RhWWWermMy2EPcmHcryFFteGAgiWSSWwzwCr3Vj+GcI3ll114UZPDFo4ICl4ky6IYUciDNNAjOp0AE3FkQdvaYlJxdyzIvpCC4gMA e=found last=26 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWcUTQpvfJPN5s4z3Mv7hiNOxO4Y2Pb3c+ZIfx+hoNsEspTL1n1M96U4th8d1Kdnu6EOdjRtmmrYA priv=MEcCAQAwBQYDK2VxBDsEOb+S+1e20DDdzRWmurQVpHcOzzSOxBh28JJhmOL8NVGnAhDacBtUSaGjpCIOEy+z0E0YfmFlF08w4Q== msg=29bJSs0XxIfv8Oem1FprJtXxeDy0ekRdCAaR2ND4CgY6Ahu916lBW2trTJtS1UcQ+xgaQ/KFFedXRrY+4jmFqg== sig=F8Ba2RboRS88rMMFvwT0tpMO0lQnOHXRrBT/+cGROV20JWs5X4ZF6FfqF9xf0hf3Mk9Pv86ZB8IA0kUYiNfDJWS+LXlf9JLZ5SQLf9TA291sjywm6ZCftxP0gWsvaWKed9oi2olp6l8UW0LU7LuSQiUA e=found last=18 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdNYg2f/eC2RxvDH7k48A/7lTLOD3Kr4h39qCRFfUC3Redf/MiE0uY4qAaTzxQ2M7Oz/dglw5cT+A priv=MEcCAQAwBQYDK2VxBDsEOYN6aLwlVf6G5caSu0jQ31J7BmMrBxEY4qMFU+bfpOeMbnZyv+VL9MNJGBLe4elqLnCxYQjwmwLHEA== msg=i4xylrbe7cpiXIDrQnNUkajM5epi1j8yt42Q4/UHb2uR7YUkFBho+hrqWtglusdVlFkAw6QcqRCY0X06/TxNFg== sig=HtIuC6kWIW+zacrgtcH+4mzSWAW1qrSuFWqlguV8EPHOuda99u8m5qgC+esBIH7cMR2ykLM63o2Awvfw2nxGvlMVVmpbQLY8GEbRXi1IQp0XG7ZFDsQx+FtdQ17N14e/zHmOIVmQ088UQY2JA7oTnCUA e=found 211 iterations",
+ "pub=MEMwBQYDK2VxAzoAnnPjJ+CyEI/r0a2zEuSBuU0mnclLsRycHyvOtB1xh+OseLVjwnKq5NNusUNw2+3SSe7BV7alWFSA priv=MEcCAQAwBQYDK2VxBDsEOfC4Hz1d3GZpSsIGCDHrRcp4Nv6NKoT+QB2qPp3CYU2rvS462xYJRR6yTJmJFfHiFsR76Tfulc9HUQ== msg=NkKiullL1pH8HaaYEH7KcP2BFVzxxrmw4IujkuTh6LxY7w/JfOpcCbaxZB2u7/En/gzwpTk8S25PCOGls90Kwg== sig=d9mWJbROGQFmqY1H32NRzHW8JvLw8tYF9fwYtCl0/3p80zp7Yy1aP+9PmJhegrZkzOvtbixVOCWA/TCqnELOPVULm9RYgypq0WNijWxSt2sQqe681Fn6F1N8hon6XpJgIIDf/j5m1k8vk1UCtXzkhTkA e=found last=27 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAx2XVzGUWkYwyB9TYULwOBj9xbbXfou2WbAqKjMLFkiLwnr+617XRG+j2nX1Yt7WAPhXbnla8XdkA priv=MEcCAQAwBQYDK2VxBDsEORtWW4V30zWq0wifMIdF0Y072YctZ0G/M2i+g3JyJmEWDca0e7SXm7ikA3KX0cPWV8eiWCo5BZ8+lg== msg=Co/5gufJZdaHCA+PQFvjAMcIFTvFmmoEJ5ZsrubIOsquxHNzUdg2R+K2vtStvmyNDHVX3IeiK2i775bSuoFpDg== sig=S6ee7DAM9H38KCAJC6oHEKs0qFPrdVdcuPc8YKrADjICutIKAL7HIeBbtPR+BuylyZJJC31AKm0AHL/6HwJsk3hMNot/1JPpi4qd7x8aphPp6qgz+YhoWyB08UReeEzQgZRGp6XQCPbz/wVzmT4YpzUA e=found last=15 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAohgMGuHgfZQG2AS4IABkF9Wd3tWKtGpLopUeE7wkNEMkpxMiW0R2K50JpcJcjc44bVB6AQn/rdoA priv=MEcCAQAwBQYDK2VxBDsEObMQOkfR8Hd+i5sZkExV3mFHVfsEGzqIzjNt+uwMaQQvRS+mvTmz0UNebxnMdSe5eUqS+95ZOHBCSQ== msg=VmCrJzV5BdhyxfEsKYF7bP4kPDMvFmPtVkkGjvK4Z4cMIBhByHzumyBqPYq78SIstTK9OUldW3+ohgO+xAdfbw== sig=LplBKx4ULbo2ri97hV6tGVc15rDLehvbokV5kxFr/BE2xscQlt40CDnxaOnWPdsnZI0qwcBCR2CAAJZpW7QZ7jAm/wVgc9WtYlZeflBh+Io7hgloGkbn6cKIaH5tvvbbxqvbL2dKcMdoxIAEUVaiMikA e=found last=20 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoArY4wSiKI64+8DlpxFf3Lt7hHs8dajqeWhaJodsSGd5bpaJSJFrdSUKbM4r8oMWXJBgM9/1oObEYA priv=MEcCAQAwBQYDK2VxBDsEOQ/iQUE/ocA3MaoQqP49p10rUw80LWmFKMh+hIiNwkhLFxr6Gf7/Vy0jxeY1d2QFW4axr7RRCuR0mA== msg=MbfXCb7ISUyCJr8o/pVucmibp3gbQ8ey6S9FsLwKZwGwxC9i2Tn+q4EVaREgWB8vlmLoPfFd+agNVKUwYaMzpw== sig=AduoLqGpb7dMbpREci0bCOrgn2zXOzlfTp3I5GO94ai4afYeWA/Tl9AXbMXV60FiP4ys6jg/i98As7vy7yHKiJBz0a25dzJbZGStV78EjpPjwldu2SQJGrqqFSSo/nlYoEJjbfqFZAZLvfks6q94kxcA e=found last=18 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7E2aGgWyqwtNXQIjuY6JwJmLlFwgFcO5NkchtmJyKSStUcE9HH+rGMEeQW/VnL+DdTZYMFQuyyEA priv=MEcCAQAwBQYDK2VxBDsEOVhTaKXol5grql99tsVdLD0pmKRbBhf4DD7n/dNEfoaOZrmzgDf8j+QRjs0N3Nrkn1RLNLJaY6EACA== msg=vGnaFKO/mRcppALJgBCYdsaoPgIkKn1R4b42V+M/HTwdthFJjBaSVD4ql6diGHQZxvaeG1aR3kViHc0rNVmWQw== sig=xSzqlmEdLfzYmCOp4FG4YboPs1lwtYRxPQBMfOMsa5TMi21eN3EpveYArcJArEFThkqYBl9U5cqA6tGye548u55M9AV0259pRXPTmr6M5qfG9JmJuVMDzOfnKb3hAoKYS+FN4pJm+hcDvjyKe6Du6z4A e=found last=21 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqJXMo40rfnnDwF/WLKbV3VQ/zve3Sql+gFJ4GUWQjrc34P+KxPQNIaJXsEe4Z3DX7SWXnOrI2m4A priv=MEcCAQAwBQYDK2VxBDsEOfwBh5fbgJXwtY6sdaD9jz5JMKn14bv0ZjrhNYeAYs+0MLNaGg2XUOXFA5dlo6E8E0GUJZHQ9N5yMQ== msg=yyoObFNBx4EG4SRGZMGdESrtPYbTDvmSnbnqREw+vuTNfBUFrpl5hrgDw7VbjuBj/CZF/nhKA9tDpenJDjhWcg== sig=rH5WJgjr9txIOfFoTYtHJRTahcajzg527FV6f6iIegR6Swdrcm1CVC/U7XnvlDjQkLnfmfRooJIAx6JKrAJz1Iq+RFXvXJ/tQlhGWZp3DAfcARV1WPiTq02cjACHaGB29ou8dxVKvcVM6fTOZh7FHAcA e=found last=25 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAxL2zBc3PZe1egu3Vj5PD1vYJC/yg8VTCqJG5DphNuKecVdfzM7UZ2cMUF5/gZd4qrkAyAOJXTNAA priv=MEcCAQAwBQYDK2VxBDsEOTrG/sQ1qXkTipBAct/Qgsg2OzX++k6Fh7YI53T2CbAeZeB2GqDhG5j5/v0AaiIo0R5Q13mau/fqnw== msg=hRsa71toPymVSMqpCXRVstfgrKU+AMFFeauNnSk4yhTqJcIeHo+iLzszgRnUlK7C4FelV0VvCWzLYxzpV4jOSg== sig=p+p18QnGtyTpkeg4Q0kbxTxJh3W32I3CTlG2E7ZBuJDHsYU1nOUbzikybHlSdm2e3RtJLXEFmBUAKnLBYJrT3hQz6NgRrHpI/eAb8nWO8L+wm6HTgkB/Ak7KUACxRjFlEGdB+ymctjbtVNM3ekE0ZDoA e=found last=17 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6whQFIqEZYROL4KK89bwNZWAs0xBlTwMpgLet5IHC3mZYXb45xA2voIMWk5sA0hA3j5QCLDoTQwA priv=MEcCAQAwBQYDK2VxBDsEOZ05ns9oZRAymXLiTKtmcjLVEYoKt46rZkBtuwmkWqXTvKv93mA2DA8NnIJepjFr7ljQVoUyPvlBTQ== msg=EG5J8XnEBJH7ZQCAkJZWF65fkQG2kJczOW4JcMOX9KzITbYXdWHVZTT1NpoFaZfiZbq3wtcz4C+t18B4jJLXhw== sig=x5MaBVx2E8sNLY7CIl33AldRHe4Sk7w0JEQCPQgToI41EoxBiVf0kJLL5VoeywglcuE2DlwIYFeAXCGa6GRYLoCqiGlteA3TNX6fUzhKCQ/lvKt48BEqwUOJes0BMOu0cEsyHFEQzpZzX6N258ai5hIA e=found last=21 s=33 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuJtPFt3DoG7OtET4PRI/y8A/ZrihpJtnNKiEePpnFIYwqw0kBbJQb9KmT2doyFwnIM54SWrQOcEA priv=MEcCAQAwBQYDK2VxBDsEOYjWb7rer6mAecI4cNBhh+Pj5ZI7I4HfD9Amiv1LDNVQ8t5skhLU2tiaNMB7xqdx+MSqvMESCBFhrQ== msg=66zlTqMYZ7GRvLEKIaJVypcictbC5ah5/KNoS4TW28oUUlILvvkHAxbtjubvBNGVkFBOz/QAXcYErB0OoKrTDQ== sig=MTrXPkTIHqlkMitzJwjE8B1N+HgDbL62RT6Ol7M8jzaY6gHVdGDOKrP7zxGMynB6e7FOfFI1ie+Atc2XykQWKvWE2oSQqTnKZjcolXvFa0DrrFlW3GA8aPSxJsvfRUAUdghGnU3Gh74eVXfvopPZCBcA e=found last=22 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWRnCAVn5El+hZtgHUEFStIrE0AwYhg7Pu+j4cvUN8o7BO5NxHHtoIKAZ8rZztK8q80rAjZI1/roA priv=MEcCAQAwBQYDK2VxBDsEOfOx3NXSXMedd0nvbM8Z1oSGJRUzmVz9gGFoZnRCtw/JvEo5XdFd+gF9DVuHeHcx/et/sFya8YPOWg== msg=p+GE6vgUZAJzBaxU3mQidHUEOwimxiLcEV96NHlXwN9YgiUfbxcY9vs1UrPmeYHcgGJdSM6OO9EvrY30Z5Jvhw== sig=5DlAfNAvdxow5wEpWM2v1DoAJ6eMnqFW051thBuLEvdbG0lzgI5Jle47xm7oUOxuANYGxSOMV7wAdRfOiBQOAi1AKN0r7dwVk7ETI/C7Kb3ssccnUaSSWLY4TqK3iN1LxfX8Lg++nqqUHtnBi9NyaQgA e=found last=21 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAP0w4iyfab2Y/37yHcdxddeKaut6UwLgWt/n7UgZXMAfcTgwUZapn8CmlXdkuJXK4hnrm+/qDiu8A priv=MEcCAQAwBQYDK2VxBDsEOSsMaC5haNFvBAizLDswHhPxzObc4krga/o9SVdu5vaK+aurRtXTk3aDU1XVh4Vwd+rVqBRrthX4lg== msg=ccszAupl7RnUvIBetDA6gsPvkycXm/eojNwly28xJb0QLK+KZi4nv2mabplqWsb0p/+RD08YIxdWRQzCH7BAoA== sig=Zli7mPEjd6oCp3NcPLAUuGLlPCjIcWkziLcwj8jUOMBINzbAzf4l2ye4Iez7iXvkd5P22Z+n+fkA+nXqi20iGb2sT5Zgku864jmd/38YvlJQ/roGaeZUi4s54X/WN2r68EJ+j/ULHYFeQlwglYRIFjQA e=found last=22 s=23 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoARw7gj489xwkH2SUWDILgD4M6D3wp/4ho7pXbgkDmyIChEipyyxdeJXBaBT7Y9fs2zrYLPG8vrteA priv=MEcCAQAwBQYDK2VxBDsEOUlaQt5TubjT6ARox2CtRtLmwFhBESJWQ4pEKkg8qT9CuHlPgwDblAFdYFDkrxzG1v3hpYTeYjB3nw== msg=2sGZ2xk26dmUWHLhPv0w0KG0f/CVhbcGdYcVbvZvXmDSBXRcqooQH/SvV+aiBCZyVLjjpZWyoor2BbNF/dCqaQ== sig=eAQkZ4SRrJhWF4CurSKhGB124aLwhkj4wGYRVm3G884s743X7EshB5ZQlLg+Uo+HwSuwecTZMbwA+VHu5B6TEvJO5oGv4qu56OoOJ3qsKc+mtM9Y6L9PPBEbqlupxep/crR/6K/YOD29GcoFIMqVci4A e=found last=22 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUi8quCwlVUpYB6DZ7W8+CcM9bYGfbyb86HPnw7ucIFUsIYT2nOTnE/xIvngcEkb9XgQNagyyvsuA priv=MEcCAQAwBQYDK2VxBDsEOVyVFCnWKFU/8y4KTLVmqWuts5ojpiBfUFweaXIPWF3x0SEHjF9cgzVWnZUUbqNueGWqnlsuXAsd1A== msg=0ihYBS/tuh8MwrDdCBKxygz35u3Kd31zXRzZ/QLiYzqzcrwwlOrSHPD82YaPEupU5t90/6x/wjyxvBazNlje2g== sig=UcgfyPBQCE9YtVB3iUouVhOSGpL30TWGwSn6alpwH5xbu9e0yp+no3XIAnBP17BLRG/RtnD4jhyAWv5pmrvdcAn8qsS4TD9/5uWVKm6hvr4S5Sg8+Zb6D9NC0wYiORsVCzijGGvE2h/iBp5j9t97GyMA e=found last=15 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoARGx43Orjpk77yeNiFVY4Htv7FV23P2vlHE4Ip7mPcbz2RgxF9st1ozg+XvMLPlj/9DHyZ2V+xWQA priv=MEcCAQAwBQYDK2VxBDsEOQDmJnYPoOMQSvQpqvBYQ9N1/yuUicU2mHTbLV5f4Hz8P5m5IsTca7FSKmihSrWSYOlRl/MbJM867g== msg=WyQGNVU8Z8ggI8D6F7Ng9XPO/XaV8gA0hTbwipWkE6yIVvBfp69JoYXnMur4Qt4jF0jh99GuOU11EeBBb8qP0Q== sig=Oh/JGihIHGsFcJbWao0ilZRWJ1K0D4GlEz2GQ5hdM7HsOFKZlUpBgrvEWvgjkXKaVWgbU++o/lwA+BxDugKN/fVFIkudPLyp6fviw89irlhp5Atxm7JecRTMttHa44kOX+F+u+m/90/T9tCalJrJaAAA e=found last=18 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAM9m07np6alOLSfCQGR9Z/D+/MYNn+yE7zUbh3mtjIhSdkbLEhG1ionGXGhJ6gfOUs+PXqcqQw+mA priv=MEcCAQAwBQYDK2VxBDsEOackYRAg3M/UrHwF791wHrCgNrI2zezTyVJwbZY+t+k8XyBYLeOHNTTNem2wiS1RHaTk+eePluROmA== msg=KUx2hnuRwiavhLifLlzKxTvQS9VSYCGHT2D0REaILMuH/GPchfk3+Yp3JyTF1JjZyQEQoJgWUsdN2gHLuzshIA== sig=PsHvXuQ+ADwpndT6Rm0bMHLT9QZSH6qKgjnhm0tWKCP6EULyYceioxDSTvHI/J7KcVxfV4E+bPAAuLHhvWEyV/qw9ZXX+1EycyM2pW7564IE/VrZ/WeE8sPlxTyU0VM0hjFFt2kiMWVIqtYKTFYFDhIA e=found last=25 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAu5MPMJQZkUxNxtxUINqPBUggG6mknY8Dq1GLlDMBsFXPoJT2SgQM3iw/MZqQtYlFcxyLXae9R4eA priv=MEcCAQAwBQYDK2VxBDsEOdcsBIRApPIbi8gpUqZSt7AzHCBaJ5EmhRHKTGborAdhQfPtubi8SfZIRQjIixcx8Go1P0tZP/gblA== msg=ZREvSeAi/KO3ZBeoXge8uvFGvJZPv+U17xZdx3BmauuMRyv8nMRP8qXWv6UUJ8Kgkex3vLNRh7z8zp+f2UFo1g== sig=CcvXFloPa9K7yZgIBYbbjmlJv+pNoOqWHo/aA5d4dHk4Dj9fK4JeiCehb08HAiCzuRth7GRgbyeAx/Twcm0NwWKhvYifLnDmQ8N3GaJq99Uv3a5pCBjSixT3pynV6e42+XEsFb0WwJba/jUJ95jakj8A e=found 209 iterations",
+ "pub=MEMwBQYDK2VxAzoAy5GWQk3JE5E1jUjxv0sQkN4MsfY/pOd2O9Xt0epCqaZ8/kDoiwA0wbhRGU40wQhUyhZl+QIRFCuA priv=MEcCAQAwBQYDK2VxBDsEOSpl2OW7YQe4h0taC4/LoOcIuje+mTNcv7tnTIc+dE4Bkg+oeh3NqlDT57Ic9AoKj+z8x11tiyF1nQ== msg=dKWV5dRiSTfepHt116QDD28Yolt0GQS9IygM9N0+wJ4XPpMaTdNciStPrXnOktYh4/X7tOkcInKmDbqa/+1hOA== sig=cSrWe955zXa4EFOd32YIj4QmVyvoCG3BUCf7Z3qOwMqx+OR6d0LnpjBMymVjkBH4PiF+JRG1+PCAG4p861T2Iyr5vKcTEpCoPFXiS8SojmJ3Zvkw0roNH9k1JLYerYOfMm6bfz5J37kE2ZXFM2LFih0A e=found last=27 s=23 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAQT0mR4WyPwq6MyNcI+FgNfB48fZscoSmaP7NtMbn7IocCXOPsi7xufGkf/nTiahGSE1vTz7LxPSA priv=MEcCAQAwBQYDK2VxBDsEOaBaXy4ylpC6XtIdJMXJMVTPUeU5En+UgM7xGKineoy5ErSjeS8txgbCROL8dCtPq3rfuxvoU36uJg== msg=Oy/bRD/fiKQv1Fi7doLqgSxFLlhDjYYE3mqurMzzPEMYNpBHfyPkiHgs8GCwmtqagnFooDowuwHJyts803Ki+Q== sig=45nCi8Dlbz30GI/F8ZOPXLIid/fYn0k74rT52ZQ1VmsZfmrBhelpSBoFj+98BXjNnJD/PnwRekSAWPsmkzpPBmmSO6grjSUcBU9JOUEU3ncq+XTYPlzrKk0oMpPisydh0I8srJmTPk7bk0jwVeClHTUA e=found last=17 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbfQVRd9AMYKTrtjIUFuNyc2BYpbyvuQQN10jObYbS9WOqbZ7cLvvtlHeUf4dgFfAl9paffhgUScA priv=MEcCAQAwBQYDK2VxBDsEOfjOTbvlywlKu9BmAfqSqCik8yOENLKFsyQrmTt6F5JiZyDzFhJpoURdU0hZsxc7v/oWvtCwXL+kRw== msg=51AI3Q+qpWUROpokk+SeluLsjq59adCySVQXqQSjH2nVv8otMo0qPBPfe6NL65Cn+xw7H8KkCwFvrJUVOwkWaQ== sig=pJXY41IylXgfceB1r14PYCkqbrTVA1XOh8RTJQT9nhSgnJVv0xWMfU6NkWK+/hcli7PXxKqw+aUAF7jqkZOaMq49o0Iq1clEnf9e6kFIXRPJhNH2sJWaGjcpH7nNTx+v6ZTbjX3uCZBIA4JtzkXFcygA e=found last=20 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAyTjPAykmPP6Ysito7iCVyFGlFoCI1aa87ic167CRlCflbGsDTwbOeW1Lz/EmvDCbTJREfSLAZ0KA priv=MEcCAQAwBQYDK2VxBDsEORA/zX48l4LvtTGudbqw5Xg9kV6F0QJLM30DfIW2bwAo3zspyCbjjHyyi3YCopD2whXXKyvjJAmmKQ== msg=dq0a4c8sAaiyHc4Dt7BBNVNXY5FtY4lYWVB7bfUX2/pBSrpLUTiJM+Q742tAYLFZrKulwQn4ogyyVVGr9t5whg== sig=TmXLQmZUoy5PVTfCRExcpojBCcCbFi92aPaACu2Nzajfa7RG8sZ3enMFQaUolPEINF1rQ7Xr43AAAdZ4J4+I/+qFmnU6OjY6O+/V5F/+1WKlnRAQ+Y1OiVpzdlFG6W0lGoji8/jIoErnBUGjUnHyFxcA e=found 129 iterations",
+ "pub=MEMwBQYDK2VxAzoA98wI4/W1pH/jS5r7e+aviffaD1As4UmILheb1uge6jm02kGnn9qihfIjYOcHUiOWc7t1D0plnq2A priv=MEcCAQAwBQYDK2VxBDsEOZcuLUD9y2czS0nBeCOJzhAhnbr4bWnmvjxCICVJLVov8zyrgpd4CqP2fzGo0fxWta+QeggssU7NOg== msg=hhVqqDcHkFVviZIN/X8PMzxRF0MpHPNCraEWLGbCklGXwnm5JzvOf6Q2B2G6V8J7vYnWGb1vr/I4T/QvQ9y/UA== sig=+kCURkdiIrF1/jzF71ViUjpLY3rZLfzmnKnCTsUFlHq7Z70LMxOZ3kVL0fD/YFX/6kMLROEgrRQA7yHVuzxMu/iGxjQD+XQnepjH0uU6yqBleaiSWvGmCpbI0I8lacve4YrDrX7r4dxL0RGtk2MXcigA e=found last=17 s=36 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAgaIEK3jEhV+dpD5itqLTzF0Iw2VHOO85rmWCUKInNsM9AVMdjqRStjtxS1ov7csob47pobI206eA priv=MEcCAQAwBQYDK2VxBDsEOScQvXdhocR0fqC1lrRM7SyQzpqoFv7UqnNiq3sqlesO9iyi+kBEpycFQ9O/gNo2CNvzRIbtJtPIiw== msg=D1R2eQ/t39jGrxFsXK57xaPxoSXJdjjSQKiT2r1fmzYbl4CtP7VF/57wUss1F1lxyx7D3Ngt4zAKNeTXCmEE9w== sig=RZ+mmatttuOVzBnRzNmxhy1CVbl5iQzDPVojo+Za0Hi8aWJ4gg26mQ+SnYapFMT71FrKvWye0AQAy1IsSELmPa6dfQhFyjPmPh96HVgZDQyV34hHMaL2moUgzCubhlurb7T6B9dlEdBvdFLuCBN9KTYA e=found last=15 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAaZWucWTb8iZ5IfwxL0mrnVhITnJAWdPrjJmoekj2TwWtewJ1xYBYQj+70s81K0qwlSeOTuXld9kA priv=MEcCAQAwBQYDK2VxBDsEOSyftUCFiAyRwTlS6ZkLu5FOW9VBSnJ+TKDp+glY+auErWiR+XcgJfM6gXnKqglKlGZ4aQZmq3Kxmg== msg=ASTqxTETQZAIQQ6U+NHy1GP2YG4boXjNMIdVNn/VGJ60DqiYnLdW5yMeiq2NFPs/eVUzLbdykvz1C6Bc9SmWMQ== sig=QDhiKCVatcKxGVBlaom8IanHx8B5aHPSLEzzy8ofh9ohrOyzMEdqlv5kf9gDuvxqv9RVhOWSi6KAncJBXMnICHS+b5M1UeqRMjsI6fkdXwR77rFM+BF0N//v57pJPtvqqvLfxkC4o8XQj/fJA4qmOz4A e=found last=24 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAeJDeb/brTbG+aVtwfyFDli+CpcvS/t5wfTzRh9OpOtzBDCXcHqgPVNAnhl2kjzTBCddAxGX7SN2A priv=MEcCAQAwBQYDK2VxBDsEOR9QhtcAkWOsxlEduGI8NZlut94GfXNnvCMBA42i0waihTxpOtOuJ3fDlmWJUH12vQUg9n15uD/UPg== msg=aGk9vrRMGq9PKdGlQsYB3kKSQ74kdFzNr+6M/dCzDaTa8DP77/w+nMUKjib2ECab/MPS7852KwhpQppOmOkHEg== sig=npDD/sHMgO5uYavZe5mRfPselcUc9qskvF5n1nZwsnUOR65wtqU5Lt23i5I9QX3P0/q6gKPsuyEAHjZ/rn4ufUQl3xTmGw9I7nP3RM8gLGdVtS5D+YCTw7Im8hJeAFKdp4bNC/mSiue05boiBInbJAAA e=found last=18 s=24 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEZwfvA9cDFPgk945H7Ju+jYVJpK1bmq5OLSHmOoml3cXCWHnAkU+1S1xMBKGODD/4XtXq2ciuxcA priv=MEcCAQAwBQYDK2VxBDsEOTBXgIZzd0Qq+HPcfQq8YWULDjD2+WwgflbOiojsHHKGcdM9QxGyxul8pxMYbkWlL2yvoTVAadbs8w== msg=Lnfpr+kWeRNxVDJuGa+8csc5n8svPYZXDccVnTmhFQLspzsbUELyjbd+L9meYvT8YV7xtHyamgGjpeBpe2OIYA== sig=vMc7Y8mSnUsnvItk4E8ROlumdj/VnuEfj5WS4QVyEFfpU4f35L2vYF+YnjDmxq8P1K6hSPn0CNaAxxaTJrjbdV0tix7ck+RbJC1HQ9uHvXDGYgXzoSsXGSLbKLujA7+AwFk6bFvizz9pod2xtEJnbAcA e=found last=20 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAnCZozdlVMtf7kyX4j+ixIJUDW3uJ2m4DYAPkcRG95JwXY8beEfG8rn9YwVnd9Xeu5RC5VdYQXHyA priv=MEcCAQAwBQYDK2VxBDsEObSDINQFpIvXXl+flZz5I5cd1+x6NnAIKGTCwog6wfCUbWrgYQjlmwgwY3CLdtSXe0DabTRVTXG3oA== msg=1ojkHnlheJFSre7WXA8NJGuyYqVtZd0M58zq7ut737k8xPoW3Sj3gYVzmqZAyW/hIwGXp4KOWaed2wwLrWf1NQ== sig=LeXrGxEUXRdEbBPH4TY8qSWo/6EQpbo733vyF9ecnQa4oNEgk7wU5ujHvALm6Mm2NdzcAosFvYcA0BPx0TnqDevxgPbDrgpMdbbcHuTSsXQSpAt1DKXmOP+LPB2opFakM4fa2Ds8wGDxu1q8Lsk9vz4A e=found last=22 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4uxaiolcI76JiX2FBPU5OM222xmsH8lQhDH8z9bfEoGdDuNMWC4VQbE/9RAIN+B35qwlpIQRWA2A priv=MEcCAQAwBQYDK2VxBDsEOX5gwUdMKywUVhm7MCvWZamFT7ub42Zg5oSqZ1Jg4/tpCRRIiDIDWWmSkIndzop8eEP4y8NP+hJfEg== msg=hgTkvAyYB35NWU3R9/g0jaoBLQJRwNDNsBxcx+NY9LEIfzKYuVJ90cvyzTCAptmt1MjhkqFzndhkKqbaG7U5Bg== sig=2mQpr9v736cXmKPdw7qmkFG4kf0l1OlPpBFKDH0W2HCTNjY89RrAD844xQ4+/SF2+0sDPs3gsEmArHh78HXToaaDqz8pvntKZJZotrGuhsPeQNVWHK4b2yeKdeI2cWLGUoJW2Uxv/fZo/qcZEAjZFjMA e=found last=20 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAFIJxWXLipU95ONBhxIYR1YXXWQX2QcdDgUsW1MIZAFUUSf0yvD69E+oHVIKCCkPF5ZOekjUrU0sA priv=MEcCAQAwBQYDK2VxBDsEObhFM82pDSmAgbEvNeRGDt9RKoGFftCiQ8q7c+fNdonimKrKBaSshE7HXt8prd9+NyqKaeyWU07cNA== msg=pZUgZQLTL8XLAkmXFajBlO3SpgCKquIax5pKza79NMZEaI7UC/aucUqYlhbN1iKld5nUHG4XV7LQOSh/AUUj5w== sig=9k3v7dOsLWASQW+aWWoU7lzii+ns7UmmfofwrjYnc73t4qlTBOiKub+G0+8hhqd0RiJMzu8gkBSAz9uxCGsHIQXoYvDZiDw+HvAZ/5fBsUzZ5AA6VgtMyzd3r0ueY8cO8ba4bkFIppSxFdI7hurtRAIA e=found last=25 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApWQJPi4Djhjd6BFy07gnpMQ+0YsnOCB61rtTWNAjcZrEx0NSglFN9Lk8NJpU2bY3IQ9GOPUloN8A priv=MEcCAQAwBQYDK2VxBDsEOTmmcMEBp4yB9HgY2mw6uz5FfG1FbFDwv70cuiaQkisTZHLSmrJsV4st2kcRjD1d7ZxJ2lRNb4/fVw== msg=EZDIMzWcQq9bsU3mSjlBz0l0eyttmZR7RwdeAUW5lP6RGwWsFvOxo3eDx2BKFoGVC0689Ci6fxzGbflBa6JgMg== sig=b69eqBXX5f5CN73TTQkJopCHtIYglUtKuIN0gMiwDeXx/Uz+j9WU5NsbBX2U0+kkbXsmE8I174qA0iWHUS82h75V0DXztnvXf4hAVD4rOF0n0nhxCw6kNTj28peA6I5Vj9LgUyDr3oczhpkGFaAbxg8A e=found last=27 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAiJKjvPiVSf7wZB1iAHxdpV9E3OHq08ZMgQvZe2gm2BbBrQWFD6e0VlNcX9vDFGu8afF3YQqbz1EA priv=MEcCAQAwBQYDK2VxBDsEOYcxtnPZi08G6QXU8OfLy62TYXs3mtTx1X6fvLOwbSzCwydBG8VLhkF3mfdCcq5CB/ZKWe5Rikt2CA== msg=Z1MSxB477BYCBjBq4EGnHmUsbqU368x6DcaJvJ9YYq2lkY5jLlT815flCBI+v3+iMSPnAIGuFUjIg43nEvpDJQ== sig=6SiIwj8C/vAYBXH665sziyyM+EUQFPXqRTU3jugIBUZkSVRMxncCF505OPR43jYCGr8A+DoFRIsATJ1yzt/QVT31SpfvaMioMHuJJrDYPRaeapHeh6PQ1ab02zKY+8KIouO3RiVytlquAlkxlg9QghkA e=found last=24 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXZ3Szs4fIxTh9U9ht3gJJd+liRrfbk5VA87l5mnHXfZKajtttZmXYQAAh9ibNCbgMo5z3h3BB2GA priv=MEcCAQAwBQYDK2VxBDsEOfE02r/uIz/VkN9rJFgZF++TJNP2w0YoskMbmEvLXoneUjSLsBC36QnRl6inuH5pvlsKbPYX/dgiag== msg=MB9sGUISvYkYvEZbtsiiA1WILfTOnezHRaVV6gU3dXXia5ELtasFLOsq9DTzUro7N+aXR8WlygyfIlPX8IGltg== sig=jET1M7kLGgHHpx8OGvp3P6X03L9MwbDbNtbAjyTGLnC3nwecJvnSOLuKbIIU3FMoOoATBuKC6n2AnUTFX/AyjJ2F+qvPQvCZQFCYLgoRkVkR16X+qBPz8PcsAdFpuZpIkJRmYGStwX4NvtG8IK3GKj4A e=found last=17 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAftXNwQnvoCoh5O7ztk3d3vyAefAkEavF2EZ2IKA4SRkETk2D15WgDA83A8PBXbLtjfVH3aKI5ZYA priv=MEcCAQAwBQYDK2VxBDsEOWUxgQkyXUQksSh0/w9hZ3pgBKtek2LbDoTw8xWiuX2Q8GJSI+/3VEVRmgpHWso7Vn7bpgTbLSsBdQ== msg=0cdBPWT8aPjcMa2gLJes1KKDBe4cIFHP7VcEJMY+WZh7HFtyOCfPI5+ZHcLEVj+EKC2ctlEgw+2nqX64xKinpQ== sig=s2XZK6KWWmk6SpRvIce9xYHb4Bs51Jny8OGROAPaaz9E81qjiRIrwuoLpGkiv07Jh+4CPH+UjAiA7Um3QcBj/ul/BTx2gWHo4LidQoBqYR+0i2BXU+Deiwvp/+/9vZqNT8rnUjh3gLA23K3DijtHzgoA e=found 210 iterations",
+ "pub=MEMwBQYDK2VxAzoAPJysi+15VaL0Mcw7bleNA2hkdEvCSHlfHlx7DoCtw735h2vsRwbY73Rv9rbR/1FERCq9A04kLoGA priv=MEcCAQAwBQYDK2VxBDsEOXioXd30m9bjVGkHQIOxOU+JrvdbcVMKou1DS5w51sScoUBg855vB2sYzxWrGO3LMoad1LYvjlbUMg== msg=fqx969XoZi8BXDzleGqPglbfXY+YKT8B8HEn7u1k49zar47ZeDiQOYMO+AftLmycdh1HnzgvSdvE+1SAmSCKyw== sig=BfBpb06wYxwoY5RRDJ0M9zz8j1JG3S1fGr81MZzNvXGrIvzEg/PmMgtL+2XNgcDUedSSe4Y4vLcAoBCLk0AH18dMF0ogY3utNcc8GLP4W01uYYvel6zeK3+MJIC7uwDUKwOJdOwM1HY3i9D0gIWn+yMA e=found last=26 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAiJ/K8la2BfxCNwd1iRx1uCyVWSqu/JmYcmtI9djKkKluvHSvcIdYqCSBKwc6EAnlMb2lLSvUMQmA priv=MEcCAQAwBQYDK2VxBDsEOe8Yv7vsJib33W6sAizaHeqIcVIzwmnstfZLmK09QSWgvBaX5xR2NLZSR/rFI2ywS2AttNjyvRrgug== msg=sGg3qRo/Tl/kEmuBh1nuFEDolphrCUlqRixzELOlo8UXhJ+U+vdF3Z5FJDIYnobcfuG4vuvUM2BARKdifcOK2g== sig=a43TfJkZI9qcsJ6VgjTNYT80RDXNZMfZgwMgYWP6VlyfUSvT5K7zUXuyoO5r5qAEdEMLgJEO0Q4AXNdbwvwKAMxBa++nmH7oS5T2wqfBeIU4IhTUGscQK7odbDuqYo4/iG++FlPV63PSXHj5gEyYZDcA e=found last=21 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABPj11mmzxmCHg9DkORDpnntxKI2xD1RJ7pea9L7wC3PVfCWm9a8LxPcQRLIXMaBgTWEkXd+DW5CA priv=MEcCAQAwBQYDK2VxBDsEOfVE6DEUgI9+qFygCCe4F2x2lc5Erp2kZQvgzRP1gnnAwhIQ7plLRAbCCM7z/BIgEMZZZpLWJyGG9w== msg=Dd9V1GrRsGBXqwedG4iHxh1XxgYFyvL0E7OxonCustRwFC8Ls5Ll76KEwL9D58kAEQaXqWE8lPyLO0bQcWbH8w== sig=H3riUVqzeQzb1gVT/hUePFEWC6J6rL05DWggTs4KRKHr+a1bBDk3Bu/HqQOcGuFLy9x7WywLxyQAEL2/Ci7z+N5w3zPghJLqU0UXjGwGod89sVgOVefy1z80u8jHOdVcWup/Fn22RDsC8wdMqwCmux0A e=found last=17 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAL858ZojxkuVh+JrrjGvmd2X4hIMCJUujX5ENFjhY7+gdA19FBsO7R75hl/yUm0okU9io0J+3HEIA priv=MEcCAQAwBQYDK2VxBDsEObMOAaS2WNdcpbrI2xofjMGn390GWJ6Lxh3eoTSW1EQZjuavemuC8+Cr3Fdl0vy+/XBuo0WfN8sRdg== msg=LTODIG1eROZmuOa8jonox/13cQEhcoRaS4wssN0JgERIPabtjlgyJSgCl4HncJuLyk+5DY3WfeE3K0/h3dPljw== sig=K7+DZv1DBasMdvatgnuWBRTEZa5cBWT18gn5mhGK8eiX7cE54Qyw1FG1yOUffkJstqtaC1ZlRZ8AFspCFwr78+Mp+ix6rZxyjh8JY1yxHaYOjfm2x35xHB+1WjWjAnjQnXU6sTqOFeyLFa34bxrP3ykA e=found last=20 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9qOrbk3sxhobWSu2MmIBjCkDpXL2YcZpk94spz/3k1OwcJyDCnNURGgSOKrz1IXS9ahjxAL3M2kA priv=MEcCAQAwBQYDK2VxBDsEOazH4mNHeTtnKuGSJbipub13MGMIWQlQHFpilnf/t1XieyfG35dyADH/Q3OJEYT/mTh3xAaDrlRvKA== msg=Cr7KLdy+ybSO/Kjr7J1+7wV5gsCO3mlVBf2ao6hZn+TL3uuKHrlZnY5IAJfIDr2zPykbBcMQ7lQS/dcoO5SHXw== sig=0764FgVtiLMKHuzBI3dTEGzNxEs1zZJcwF3VSJT5CL5SklFGoU5slW2Ru42L/Hc5lNQw11+6zfaA8JzcQHJOvl6pFMpf3cTysOWJt4WgsPjwJFAxSaIYTAq4+WmN+Df9p/yH3i6jz4Lcs11KaSVRsxYA e=found last=22 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1PjWkLLOaM0N9qtbz4H6OgMfIuut/fXs4jUb/ubin2fM+w2t7L44RoHNsR3qYIVpjWrVfY/XPn4A priv=MEcCAQAwBQYDK2VxBDsEOei0pGuYP67Ry1R375i/qclmaDgynAv9EyN+q+yllSh8odUb34GCSWC8Sm/tNczvOc38wBvBG5+eHg== msg=tWUzqEgQ9PHROXdlryraW9hvuGJuumnFaEaviPd85FHoDPRQ3+gZdv2L7EEiWUpX9Q57Z8eBw4/4lMY9o47XLw== sig=pIM+wEC2oqkynJ4f4IvCitbN62wzuLH+EfecDCFWKSoL79FB4zvcJ4MgSY147fp8tko1yqxLkvsABgn6rjtIFoP/3K1sN7JcUGiEUTH1a+PvKlVOmCP/0uzrmlUpeD4vOJ63eGDnoBF5CXuDeBpmVSUA e=found 127 iterations",
+ "pub=MEMwBQYDK2VxAzoAa8UPd8T5RvpdXlbzh3sM42rdOCoGLAcFpbet16AcasfuQp/AWQ4P6Chp1+TpjyWkOeAdL5F67/EA priv=MEcCAQAwBQYDK2VxBDsEOaP2QGwunqNDY3muYDpBY+64JPsKJ6shjMhweptqRY0Lg7H1iqRaRtMr1MhxBN+4Kp4VIj62Q7XA0Q== msg=0boR7v0BBbgrXHVPly6s8Xrq65pVKiBIBUD7p74vPk9ynuD98+sBI5u9q7x3QlyFC5FnX1eSwWLtlU4KUeWQJg== sig=ry4zOt/J8WoT5GW68LhiuvTmp8gAd0UCoUAplOmFNFSkVQaMbw7/VtwRP6+n4bwbZ/DMJHpW2sIAVvhHqKwMpF9PUgpJvvCU/XM3WAnqq341P/jOJkzZOcIxXEp4QbToJVdabwoydbnT21mmHUhQzgkA e=found last=27 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAvIGUR3zYIQxqksCIBkQSykubbiI2xeJD2Eyoe/detg/0wotNSOK4dTaubfSYy7eAH0++jfWLxNsA priv=MEcCAQAwBQYDK2VxBDsEOQ6MnfgF2YkKcDB6aKeu+aPXiucw8yalGjJ82CXBWVeKOVh9rP77ohhkOZ0z5Qj0xd6P1uquiDDH+Q== msg=tlfdtz4QK3Up6vPfNhq8XzmTuzk/qbbwYd/tiVwMo5MzK52mLqDPU6hLyQWtdFUcftpVJLikT+0Zt69OUy22bA== sig=NLectELX6XuGM1zYVDdODz6gr5NfxRFpoBUbtasvOjTpSKyB49Amauz+Lf4Kk4hpPhMhZBmxrlkA3P+pLOgcNyUIEQWMaGjpbEjrVehwFJDIRe2+AgK8y8MkvS/wm5Uz8J+ND1V8j3KRD/j+lhnwkxoA e=found last=18 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADOQ6jgXNUOm9+Q/Ae+ajR9ZWal9giJV1FkJmdImeqsK7joO+lPE7Q3l/QwFemOxzx8Oz4RErYC2A priv=MEcCAQAwBQYDK2VxBDsEOQ2Jhl3Lnp3Ktyftmtq9qWekzO2fALJkNBfqTT7uyDNNfLWdrUEHgt2RSrsV5ENay9CN6WVzUO3a5A== msg=Vvm8ytcOShQJ6w8E9+2PObfcJc9LBGC4SnRmy7BKteyW3UYoKrGz0HPU5KgFW7YlRLnHwY8NP08aUWPx6/IFOQ== sig=mYJQC5ptrhwJre9Q8CqzxnIhaG1N9+TrtxFa2FechKvNX2znkoVxfsM8eWNipypejoQEDn25KKSAFV3XzTD9ZiiXuM+uirtEaXSLjDjzmhVFTvLRBVmvoxmPGXkUfNmPmgxNOlXRFGamxDSHrUG0yDQA e=found 213 iterations",
+ "pub=MEMwBQYDK2VxAzoAXUIX4IEtC6SAvUlVXspQ931MHjufqzC7RR4vb5v7FNuy698KbGnCJbeuRgeX0+PxTgop9AQjca2A priv=MEcCAQAwBQYDK2VxBDsEOYrxfYKrKWGShIabGgvynt6byPUAbMk2Hdl+0CgknvXcFmaw4M5AIjTss9oDugmUOjkJAdp6wJpANA== msg=rbYyIch8Sin31ZJxbmnM40CAiv2WyrL2auui7lgeazZwFAa/910QPJcctUvwaXQMsfCPsSz0a7zbM2l35xHyuw== sig=sw7pryFEjdTOdUFGrHPDg2eFOJlCQ2sMJK4O4r/Qkao9tgNvujxJe6ZuVajeIlSjP5A2ikc2neIAnQhi5t5rs1qfRuAvpBegD/WBOcu7SAKkBc0uFb/qCP/gv+CqHcuJRYxQqpdQl77jk9/un3VBAx4A e=found last=19 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqi94umVf4WIdPcRv/7Ran7musCCIfmtpOMYLxaNQG+lsGpfOryJhkKl87BUfhQbQehz8LVq4mdwA priv=MEcCAQAwBQYDK2VxBDsEOSNyPWzVCQJ3FdefZ6b0T2ds9ur54/rFqE/I4L8NEM42OfGdqd+iV/apG8qLa1b/xz8Jj6qzCjXUYQ== msg=6tAfNAy0EqHZ95fXiil3SgaFJSZY5JMazz3THBP6AuI/MJSQ4/P2/NM8VeW1PT7Fi4zavShvACC3TGI/oGt3sA== sig=xAa/ra8T97UnE9jpPIujKh74+zg3dvA6SiDkF/7qyJDtpjKE8vQOeQEAmVKT3/NZikj3dmP+sWWAvrQUp6K7WfpNX2kGYvXN2wbdQyV+cifzAfzDPvyyyIFTC+Za20rmH406clfEn9ywZEDNFK7oTjkA e=found last=15 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAteUExLoaBng/RikLTriW0pkfPnH3KpUE5V2s2GrQ3j49swBPpj/6nd8WlvqCxRBtmZbAPiuZKlmA priv=MEcCAQAwBQYDK2VxBDsEOQpsTsWQ1lnD9iK/o5VEJ/1L2yHl3D8oiZbjvmVX1p1Ym9Z+gkVx+Fe49SMi78CL4tOaqBmFj+bKcA== msg=ONJwqONyhe0hI7gXoNg7sX6SsI18/udsjIjRRpRuvtPE2UNmfoGwqfBHv4qkXC6LKdXMrwOXLgw66+TFc1bhag== sig=Vt923Gh0PtHg/YapeWqVABY/JvAFisjEGNNvREnuV0CRlLNd5O8qBgpNihrSe9p7cU1Bi7Ufl0wAMQWkhtyn1out/x8gZ5fkW5BsPL5bRYs4R/XgaVM/qVB+56mSHC3Vhqxf3qIfZYG1PQ/zQaWmBgQA e=found last=23 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAggiXCrl+l87eUsvcab9QnS3+kGGA3Lv+KokaQjnvqH29v7UjgDyJeIFNp2qiJVXs6KhSRq3eay6A priv=MEcCAQAwBQYDK2VxBDsEOdfQCLrr5X6gLEKN+i1IFtTMN0U6gKJuLXF2+IVLBl43Brcms/Os9S7TwqBaEXj7002j73h2XftmIA== msg=CpAAgiI3l7TOvsyUGAUIxGV8JMGl1CWQhx3jYxgSYzuqgpXexx0Rx0QJhoKB5OJljtyNyW6lSYHWfvKta+6w7A== sig=aBzniq2eyhF8a0jz0MlKTXPO4T4IiwNMvKXlWe9/tV44clBvWbUMgVtg690bJYceO12mhIdtSmcAARa7QpOdLOmlFe8pfp/0UNMYRxpPyjeIqPbMK6xHi3cNv9LyjsEWPZ+5SAdqk8zuFmGxEoabIx0A e=found last=24 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA8qk/fJv3V44nS3Xa4tinaf/QpN8G2EitQ85TIApEh0jZCgQLi3UsIZRehp3jn8kMWvDm5geIJ72A priv=MEcCAQAwBQYDK2VxBDsEOR88avD52a5F7Bccg2OSrWnLZig32rvS5ggQVGWk3Hr8Oi1+5Hm4jhudKVMhvU3XLuzP1TuK5jePVg== msg=Omo/w5GjzxircM5ech8AL4BWdwWFqKZR88lwL5ayBvZQ/BiWXcCTOgn0GXs7zK700XSxc4VHsa1NcLkPZmE7TA== sig=nYhR5UUvRkAqtkSQzUUmgmJ5KeBY/jWS0ev6c0XEruDSR+55k3JFJuWr9brCKXerH0zeVQvOyy+AtoCuWSGdvA5BK62JKnHDZfA3Juim21yymIRBPdtdKpkojGMnqYSS5NRhT2kjRzSZZhccHiUvgiMA e=found last=23 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAvA3mLEn5X/R2NVc8HWNeRLBMR9dEv59pdUUdnrhLV44F5GD2TNbQvIAsECIqC/Z9Tg23zCqEMRmA priv=MEcCAQAwBQYDK2VxBDsEOToaBIGMDQwYDvCHyYh0wFprTawQrnE6t8G70sbkPuYj6iJWrjVpnpVpU89EU6oFP4G5DvsYZxxY4w== msg=d4ruc7g9Su6MjbkqHtOQt2e/HVYgZp0LgbGexCXEvCBwv6tau2BAk0TVp18/EjnmvdUVt9fhoOheb4y4rZMpkQ== sig=X9tpe2YiQ0/YTNsmMu35/lazW2b5npG6M4z+6l8vuDKwtr8ZzWls7Nzo6mZRVOtm50yglmXtz4eAoX0RPLMp0UktDl9x5IHeS8Zxl60gU3hLdTsQ7xL+H147FgJEEeyytXtBtMT23ff+kP/aQWNVVx4A e=found last=25 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3dLFkOqT0tUiVTEQwLfLhTNBcPxdALoMtpIFLMIP6VJCG7dahI8bSwnJl+cgQqHlwffbLRUf4AiA priv=MEcCAQAwBQYDK2VxBDsEObOVAJNXVpvwYD+WfqrGhGpWTzRKojHyxEEkIQ2SdRfGzCns9O7qdHfCbFLgMHPa26He0X1Y+GEwdA== msg=3ufCFyLjQAzkqY1QJjZG5uwLQ+gR2m3Vlr6nO1kbdB1UIRYgjNCtECW8p0DzhVbAV81ewetULGupCgLumGG45Q== sig=aClDo5S+Nijjjt/Ik4MCtp4RQt6y1fAwE1TKgH66iA2J19tpK4e26DowcYlXfoRSWhjN1JF1o+QAMs+8yr6pqxY/xEl26emmaoV63knpGr706q9u9hBjVUs2WGN/iZ4AUmY94MGpU/3P2kIPxmYpRRkA e=found last=16 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAyHghR2FCLqhw/StrpAdu+JRCzkdu4xaGwQfVd5o5pPhe+VpCHVkNwgu4LLr8QZJzYeN6FfdMK0QA priv=MEcCAQAwBQYDK2VxBDsEOcZewyNbD2XQ2keLfAFSHdEG7SLr+wwsay/862HqvZruBcYwlMRd0cgeuVnKHo9i3+LAYlYsWep90Q== msg=W0aPE0sRJ13Qdhr2M+rjcrTki9b/Ii7/3L426++yCbN8qZ+m3jxg+5TVFBvDU1BhWFdO4yAPRju5UeBxYzAM7Q== sig=Pt4d0I0EDEX8ebMU9mYZZ+70x6g371C6dKgMyejunFwLCfvjzAQfAeqIluBSURP5Zl9pEROlO9mAqiXn+6tz5yh25priXAPw4xZ2Ochwzz2Ad47gGhxBJdALn8WjnPr4UtydCd/jngfV5Lza7bVWzhAA e=found last=25 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoARnX050PD9ITihOlZ4Xs9lmalpywWP8P27d0D0oSAlBAzvT1WaVEWNR6r+rXONiFz9mn8GBVHqJSA priv=MEcCAQAwBQYDK2VxBDsEOZeEH/n+hLk1wFLW6rpZtV01ht/D3fXY0bwVE52qGr/eausgaEVcOJhzQAU9QRCCN5uhRLc8ryE63g== msg=/tolfURlYe4inVoE5j1mEbJ810OEuMMpP3aiMNVKFi9dnu0BovWWthavKDxgpKvtrBC3xZm0b/hwY9DC8QJbYA== sig=CJYOm+8iNaO6XEQM6KK9OReyMAVaPTD9m71V4cfdQ1WCcsj8Y/tep41a+jRlFMyDsQQx+IMSwlgAMkqOuL/fR2jneWBqSsWneMNTJ4LBdQEP2POewUpWT54+XTZJhhtmbTk2aX3F5m0LN1ocnLZ6qRcA e=found last=20 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAT9nz4tSvIcn0t7M6vnUajhnDgJvEP+rOHJMnSRyAkSrjLcLVbhr6aw44TvzwRlpM9K2vwdGiOhqA priv=MEcCAQAwBQYDK2VxBDsEOWKQK9cMJazCSAbntq6PYwQTvD64bDNx5b9PXl8Uvf7ZAz2pCRRkvJ2KDRmZfZDD5FcibhhKHU+RVQ== msg=BM6GtC2yM54ItsURLZSU9g6BhkRMXr6GQlCrdMz0VNoHt5QYYyVV52l3Oylpb1g3zoZJI5Ql9jcj3UMhaYU2hg== sig=CQptH3cics4zTz3c1fvr5wJrZ7la3TsLt+rTJwSCh4GF8xh94CTG2r8ODj5ID2VxXrbBRrvEHVuAUmUeUxuzdMb5JGTf8quesjMEczx2sOc8Egn5CQnQO3vJvPFsKB0IyGhEnVlELK5vW6HDIBnW8zwA e=found last=19 s=24 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAveS86TXGAkcgzM8ifon0Eky3WQ5r+CTtN8xe1X6iOUHjc29vD1Kuw3OUafb+YtD3xzGqCrt77eUA priv=MEcCAQAwBQYDK2VxBDsEOeBy6v8vhacvbiiTKTYk5hsI2ZssWY/h3mP1AsWQpFrvgQuzEhubGd43tf0+dhDz4oG2v+B4mRNJNA== msg=U9UiOtpFAmwBrLURlBicqMCBRZB72Nke6612w5Z+WlcNay8PYED/24OotyEFUHriKp9aGXKPiUBndk2cECVgMw== sig=X+6bCgwAeYfmNb/H1ySvMEF/P/HRpT7gr2mU1QApWlf1vPhHBsc40weekkktkVOqrrz3655Yi/MAZnNV+HOdooDe3vz7B8exLiBKLSJJ13ttgwPrkdz5eCNshWoU8IXBj5lioVyoel2kndyaLLcFBw0A e=found last=26 s=25 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAHlX2CR+lvUk1oeICtq+tXelKazTfsMmfYDUtUwSXqWnqWvpSvxric933W1mTWmOTTi2rB4t1sYYA priv=MEcCAQAwBQYDK2VxBDsEOd/Pv3csU47EiO1FPKjpRXqFz2k40tfSzBtuPCvlvr12HmeRZmZYQCn+So3336Mks7ywsbfUrHt29Q== msg=3CcO1K1JdIZvZSAG9R1q9qTYQ8Md/nwSMIVaPq5ytzJlA6DW1v4TFcz0wngcj5bZGgpF74HUQFZkShmlaUU/AQ== sig=AS80Aiil7HWWp6aeLYCOLD8wHu3hFFo8QNRIBNtfbO5JCHe4Dzat2KtkqTUzZFM4UKqNkusHMRYAs0LaZBy0TYF1EDguCPOXmg7QK9XOXXM8OFpZ5U+4fjOjaEVwvNhwZhI72RGPqphT3sHYuhFxKh4A e=found last=17 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3KouKLeSILHaB1YlS0+r9cxInvQFR5m9Ve03lxCHrDbSGP6+nGhA8hbwgDEu+9uvVgz0ltldxuYA priv=MEcCAQAwBQYDK2VxBDsEOSEutdd7bQzZLmklPTKolSUxoFV+5T80jyL5wrMXON17EP5WDSYp1qqls0djxS6PbfvsbmQ3fo/93g== msg=5YcYkon+et3TGBL8hdhj6OGZpcmNi1l/RiKmzfQk1/xJcemjTyOEJaRk/pBPtwEQj6m7FJSkT0XLNQDxLbfTWg== sig=CLwDjZMZUy3dHUDTO5NR+a6MuM54RhUY96AswiqbMdyaCsoHy/JTlmcSNJHiyGpzakc+2WjsviyAvQ3TgDjNoKxQadweTXtr3NN1xUYBoU/lsp1UgyMk1ahNrkYbHD7nCR3TjrW+n2Lk5o+LhX/0oQAA e=found last=23 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAolAvq2VtZG+1nfSxwYdFzQ5ay/y+kP8XgXlnFiC6qrPiSt5G+BPwGliPL+SSeXMatMI9/r3BqjMA priv=MEcCAQAwBQYDK2VxBDsEOXEGofRO7mdtEtRkJcBOdAx7/DrFdRnCbLIsAx9IDxpJ01XsW6Xmidgouh4BnU/Oaud11gO+le8H9A== msg=F8IZ/zjzMRDKUh9l8WYfHV+pKC44oL5Irv6gHvWeJg/OxoIdFjHus0LXQfaH7EFn4fN+kxtX73TcO2PT0aLZOA== sig=2DQrKWtfvldbRiaN7sHKpOd8gr2DcHHjc+Q3PlMKmXs6Z3TbuExOH7LGGqZXezygOR9wJH+l5FaAAHSOWivFJ2TfJXjCCZ7XQVo/FtUFnEdKt7s7EiFjNMoSOFKNTnFVPq8yzTxMiII/pfUBc4K7LC8A e=found last=20 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAce92lmRsjJDEW2vQ6ZxebWk/qgfeDka/v3hGkW/yNXtFH74zx14UOsSR3jSaD08hr4JWxJLEZI0A priv=MEcCAQAwBQYDK2VxBDsEOdCcpU3JXU/LTVLSD7L1h7za/4RG4vQdSpgjt5JlRwok4vuwhNOlG1GZXpftoWMMPlxesnVQ3SE+EQ== msg=tE0es7doJgOoZJpwGXiTe+dJgXqkO0u53VSSTbRN2G/gnFU/sAbVboe9sB3QgVLZDmgHipEibtK4pPT6L7E4hQ== sig=Nx1nhwW/6yHCIKg5t/5Y4dEtmFmTcrd+XZJqq4HoBgcJOg+2n1vJq5cSrAH0piGHW1ezGX0iMhSAa0VHNMMt8wGPctFOo+5jCNmAJ4GXvom31Od5lNNdIWpdUUSMBgAsphkmiBppG5mxTD3ZOzpPixEA e=found last=21 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA8Nu9Fv0HvD0SgaKIYB8W5kuLzFIH8HWHH3uBLRMQlbIuwB8LdpfJpCpOYXsQSjlLkPOTnC/T388A priv=MEcCAQAwBQYDK2VxBDsEOX/b+vPS5/f5+BP+B0X8T1GAreRon3YD1sPXH5SZBf2QNyRiJOcUDfa4C40+X8BwTGBthavyacVqpg== msg=MWwisy9jD9obMmX28V027KGOfUSUwOa0bvv8j/7CZdDL+RSBndyQFgq7zSVcGSM3YoRDfsxAkUA0owub4VJfXQ== sig=GrJJmRaYD2xkGDFQ8WR5YzgJ0ZlbqvFXAyi5STviUR1OD+4yeMrmSJwWosc7AopkM8Rs86xjHGwAT5NOonQk8xFK4/mi4LFiu+74+X7mk61+EkAwNf8iL1q72n1deoVJSjYZN+WF/qlFAQBLYNjUvTAA e=found last=18 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAA+HWEB68xQSYwYJbaNXICD3omYMfrLvdwktCPwVy71+usagR0Kl0h/LpLx99B8yrfDJ2Fkh07zsA priv=MEcCAQAwBQYDK2VxBDsEOTSHOyq/BHEPkZy1ei478whPSYl3RMg0mymYanSLPVNyjo9hDFalWGM8mYi8Snh+Kgq9HD5byD9ENQ== msg=xyvRkhy6ODCOlzh/67tkc5LNJVJdvV3VmpL/PpQehDhJPdwXRg/arYu2zBUVpZ3IonFmcSc1+RNACGEofgtJ7A== sig=u/k/jpTz6LSH7D4GbYPESculatBvGQO4Uno4e74PZjcEp4WyvexG77xtXnqk2fAsg4SzdpCQLHsAtZdB4wvKQSYgE+efpM+5vJUwECN4aIofR0Q/BA3595j/z8NTb26BZX73TGjoVPoivp+trUaNsA8A e=found last=15 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAgU9K0ISvj7AMag2JqPHxmfyfW3IXZFwQJxvHIphxRXBC7TwVlc/nxTIr070B3vML5N99y04feocA priv=MEcCAQAwBQYDK2VxBDsEOR+QUu7ISL6V6wzI8ZkDVKOYCtfTwKC+1MgwkQi5N55EVSvon1KJY68lx5ND6X2Y7dI5WdL4BgKxxw== msg=EFKwMv2iqTzu173Zpu/9Zz7PqZpBSSyYUO43Mk9WoRM9ZWy6UPEJWJIKVRYcQMbgMMUQB+YACA+Ivw/wHwkPaw== sig=Sl8g/WFZJJ3nqBA1ZfODjO7heEwHyJLRgcp8zfu6IX9/MmnuGz380YSZeIrQSUWBEVekib0I3uyAJpnzLOW6BMLJ9vy0CyDoR0LUtJHvYeYdCiZV0Qbzy9nKaVBMComWj2barVclz7SH2XSrLFECRSMA e=found last=24 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwcziY0Yd5nJCFngBSjqkD+nQvWO4F+XANhpQpW1W9DQxbQkBh2J93I4dNwf0wGNzUfPIla5YUPEA priv=MEcCAQAwBQYDK2VxBDsEOVzaK9lNWmuk50T7Ry5FawJmDUzJ0eu7upiGBmcVAn548tq48/V3Dfl5ZWMSJuyA23kPkzrJsf/u8Q== msg=7+WO25N+cDQD4J8kxSFR47OC5jAkej65i/7U6XlbkUNXhy4w0PefyjeWUZYnLV4uEGVNRXb4NhNWhM1wj7CvZQ== sig=9hnDYp99WBPUyVeIx5DUKadRwQfFYUl5GM54FTkBI8g9zsVThZ0cV1P/Rl+baXPELlECKQmIPG4A1emeYiG+fhj5hVHMkKAmcHKoJIMq9S6yrSpg8m9la/B+qqeD46JmfCuPbWxco3UXkTV9xJPAWT4A e=found 125 iterations",
+ "pub=MEMwBQYDK2VxAzoA+ITVf0xusPE9AIvZUtWfknYiA+YH1x8jZjZBTE6Tm0KOrFqmm07T6JIDzumGm/gvR6B8SvQcgXUA priv=MEcCAQAwBQYDK2VxBDsEOdFOPdrCR3KdCsCWYm8fjdSohNTMxeym9KqENrsQ2TxdyzNxsakS7CdNIvuhVtH9n5molr72WGYBkQ== msg=hJQ2gzpa1+DlkX6DannPlGuryVw0wX+nQudDE8lNHTu93159BXfNrB9BihY1g0YRo5qbC9aMTnT8vH1f6luLgQ== sig=aGZAJrV/zQacjX2L7J/+HaMWAYip7BZilHmAai4dpHw/2FqSgr/d6H8panJfdJ8FE6dgQ+aALviArx7jcA3V2gvtzw9Or8Fej0pQ97bRdUahIsIf+YmvgWH8QsWNvex4ceiP7fUq3Fu0BEG+kfAjoysA e=found last=18 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXiTaWLGX8q5dOil27Y/cPDRIEDJ1bde6Q5Tn1kj2xj+vx1du2ogSn6dAxuIPCzEcgdDggoVMoUsA priv=MEcCAQAwBQYDK2VxBDsEOURZte5ndyMm7I3ri87MF5zf1i+5r64gesuGc4h92++OyxCC6salc5uglKlFy9IXwhpaMtDIoUpTVQ== msg=E2StlKuzbQANv8itFrN6xJCwJcDClzN5WyrY3y6dFo++UthwtDzBXhCHTxGWJGJJh8KBhhwSLz4p8DZ8kpSdEw== sig=W9blKQmlv27kWBjF0QZfjoTWZSGwyGnRPMsFWS1a7z0AQt/Ui/QvVkbu9NQiLSKZHAC2/SwdCB6ARWvu2M5WatZCFMl6fEuOcNORa4IDYRYpBvw/ev9vRHL1H9UJXFLLp/gTAZU1AcUJc04D7AeyCQkA e=found last=18 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAw73SZvyesCUj2ok1fzCSM7xh5f26Z8ioLrVsYyclWPtGOIUeoVi4yQWIZF5Zb/YLsoMfdQ3uZxAA priv=MEcCAQAwBQYDK2VxBDsEOUn+AxQeG8SVdcBhbUsIRNW5TkmEv7qj+glYGsLpUJDv1TN7PVb6DHDAIY9UHfm2FRTZR0fBQby0PA== msg=ZjfLZ/y9zgkVZzUJuXacZOJ6Uam8fBcYTin6c/MZYRe61B3esnuCOeqFhqASXVcj+tpss1aItWNUMPphR69VXw== sig=g/YtUHIxFEdVGHjW81A++bosuSn81C2j7gT0cuijF43zKPTx83fEtIMcmwIQSnn28yq63EA2/6wAtomQ3RIxc8RalRcUc9YPs/YpWjkEFLYch8NIV2f1Tv9peFn/66CtI739ezaJwFU2+A1PO21oIhsA e=found last=26 s=25 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAW9/+COxyHwfDhTMB84ErbFhXCg9UvxIJOEZjdnjmIcFjG7io/UkVJq62Rw0dzoTXFcm7x7v2IuGA priv=MEcCAQAwBQYDK2VxBDsEOcvnJWdkyxg0mGfJXj6XvMpBO6TR20pNMa8BPOPIUF2sOi8g0NccSP4YOT8y66PBvkR6PJhGnnpYpQ== msg=HzjvizYTacPS6e8m9LYTRFx2+oFRrviJXkL/c6f8qW/Z3/woxjCznQjPLEeArcdtYeWJYsI9YZTws+YXLvHJNw== sig=TV821DM+68jU83qg+BAdZv/fZ2erfT2d5oEDdO2uMXV7jL3c1oW6lkCgz5+9Jn/tt953yL/xwseAGi4yuypSphzvdx3PVuwKRPhlY6qpMTIr/SzWvFZTAtoEdpY3tIeQOltUxz/I7GydXAt+ANsRlToA e=found last=24 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAgx2JDycpW5nTKfgUVoFUqocqewbW3rycBiHpnsFd6J8cFqOc5ks/36AQKf1NGqIourg8N2eW3FoA priv=MEcCAQAwBQYDK2VxBDsEOaXwdvbU6ticdLim2Q0FEYadH1AfNOlCB06PWtg8Nnlkicm1B/M1C5GrBbADlTchOEcDm29U/W1/Mg== msg=hA8SjM6LQCbpsViwgdC37Gbyqr4sq+Hx+w/427XCSqabJbOypG8GcjDBidqZUjqH0fJsf3JUHvoNwrlTNVmnXw== sig=lfrkmsekdYfxm6CLukuNOeMUNcUIwOWmR9O9o3LPidTDYaCAwPmWLHXSOdCIKz7FHbZDdSo0S40A5iiEiO8TcJrYPHYHRHave4bB0wrv7S/oDT0pee2l70a0lz6t0lS4u2JHoIjjwDhWMgqVN1PAfSsA e=found last=25 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADuQWRgI+niy/IDKriSH9aXL1BhMi2iuTexLzePyU2KUdJerZS9wxKscNULRtoJNHRzVrmDPtcTQA priv=MEcCAQAwBQYDK2VxBDsEOYlu07dn3Ur/eAbqZlDBUee71Y+9f8UhF2BQLwD5+kojGeW5BaPU7/jyKBIQYqPLUAWBVfOnLUw+4Q== msg=0h6zWC4DILQL1mQ9tl/xD9W9NinDViY8SQp81HW37ZgKpCD5ifB9S1a2weFONi1P6tIVIKtiDMojKBKU11ETSg== sig=U5i5GMxNyx5B18a07ydLA3adRe3g4dyLCN3MlzltCI2IOqnZ1EkRaou/wzBa4dQTSe8W9MPK4l6ARO/Uw35i4XRFtboRvzSmnPqwLEz5nhAoJoY0cbuifXU2KMQhD4jJmBZ5MAhNSLkXXR49mSZvAyYA e=found last=19 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAI4U2li3YTgqavHDdbjNFjLBGsTI0gDwGgkSnt9jGBViDzeZEwA7LUgP33z+8teGrxS9BikAlx8yA priv=MEcCAQAwBQYDK2VxBDsEOaa0Rj2B4tU6NnDyueiaoTRCCltewTI1nsvpWAFg6iub/q4ioA/T8sxAWcbEvntaAHiZKRm6fkMkNA== msg=wxrmdtdjzf0S+VplySnkOm+lV4Dia9iIm3KKEMBMGuaaGYlf6FCRfT9F0UcUpPzfEt636ziv/hKiWB6jUu6dAQ== sig=My5Dk1LEhAjpsltmfTqH49ZscqUOK7VtX6bjYW6EkDMvRQOXMf7N0t5olJ8BDZTvXstvVPX55d0A97OdvMGZ/v5QvfscNRsPZnFkaR4r/OZfDLRl7acEvGHwsOl5A38nODyOLF7ycEnI5Wg1qT5pmSUA e=found last=17 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAcOSehC71Pja49oZFTXrqWz9IJiX4QLdMqHgafU7sVA4pRE7JwjEvZS7bYsw8K2Kiqzs9LmGs9xWA priv=MEcCAQAwBQYDK2VxBDsEOacWJcx+rloLZz1h30YFqgSDiPWrooMIEXND6YdKsSON/qxCpaUPxupkGuXTjV8skgNqoxX6rg9SOw== msg=L7/7L9C02eEYs4UyoB/0iICr/dpau9a6AHc/axhpXnImKg9pVhl9iuLVlztvkVtIxgRJcl3tLhttF+rrwX2zeQ== sig=nH/IvtocwcMsgANQnHpAwgIBfNg4qN9Yhe4R0iPmsz3PiQ72/TTjZY8W11TLQVGKgsJUQULMuryAsIdjt9sG35am3Z8t5Shi/kck7qk1RwW8Ak/8Bqj+MH/5+dFw0t3zorA3UZT6iY6IBVkZldivizwA e=found last=27 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAt6r0s+NWX+clMtQdT8d139KdJ3ZafNnzmzweJL8+u/AlWyFttXLjULWFQD6/KlzUIXYDpN54YDAA priv=MEcCAQAwBQYDK2VxBDsEOTWXU3mugLPD48W5SS1H4U+xuTWMa2/xSQHeqL/rDD1HtU4ua7x6tJGpw0m2P0/TeOZuOdOMR8yUaw== msg=LujKpTXuTq5MYT3oAubjPqtas5NOn2tDc2mmXGMhPWNi4tURRVPxM8p/1zU5+Xe4p6g4r13rbwlyXj75CFskQw== sig=bpibIXEBic/HhhJEokISojOm+QoQlX7CNx2aW+UuJlLMPPTjsdf6qPNaTfIk6Rlb6U6vtWrekmGAZl4+Sozfmsx7TgXooN1fUGeqCS+5sx83qdx2eOgCIZ3slDluVRojDpWjLIyuSA1qeUGkiS+6LjIA e=found last=21 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUE0UxWxZm3PXmgudRCTHeUQubloT0jr+2H9Fc3blBL3yqz1c7r1Lw1pmUrCB8pnfK+X9Pdq9g7kA priv=MEcCAQAwBQYDK2VxBDsEOUoE+peRqtzrhGhsJedHfWgxmA3scZ9uipat4pbZiO7IRuWhabm/d4s2jtpnvKiXj6xM/E51sJwsYQ== msg=Do7HCqeLQh5ImXD2U7umOhqhKVL4bG4YZ6xYurIbSkUhd/PDidBpO5hckVD/vaL7+tXxtbRBv8R8dAUaLBUZKw== sig=7252Z44Psr1dw91xZhkn+EHovkC1Rfq0Izoq1JI70r9F1b1VDB26n+H85zybWmEEYtDCKvT94uyAuHi4UOQpXNsnwWAYxw55n6dnnEBsvSXvzbUm+8X0tc+I+lBfH4mmX9ygFVkcxZFPVD8h6a/xCBsA e=found 212 iterations",
+ "pub=MEMwBQYDK2VxAzoAonuP23Lm66n1XndEQ1InPrP/aev/R/fiBF2jI7AGr48PPHEev2TqZez8/Bpqda5i1awbTRwa1G8A priv=MEcCAQAwBQYDK2VxBDsEOUbR4lewhbLYkLH7ZNodyPvFopCJ117mb+ZpprPKKguITXYpGT3FkUufJFfZrYEdKo45MNihrNrgKw== msg=h2n7ZYKQcg9yk8N0o6oudqNkUvWkg/nnrASShftDn2oA6MyCW39ZMagk8ePpwIbCOtcqhYipnyRaZ2d+JXbQTg== sig=8S5BVOC7SI4Bkq7XA2LC7Ywi/2rf9Lu2Q5yj1H5goc7S7ATjG1vz9/EnSOPCJ6CSCT6xdKVcQOqA8jzNz+HmS20pn3ccuVnAMBkbWg4tfvmBnwbAIzVliDRcS/aOzIHog3L3xDGPwme3i4sRndEbtQAA e=found last=24 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuYLHMlWHSJKpBCLWnKIihILacKadOvXtt/GJWU9sMNt1qPiguQO4z9OLb46hiMyzi9C+xLuNleiA priv=MEcCAQAwBQYDK2VxBDsEOWBqYzcCxJr3RmZ0O0vmsl57RbsIbKixGMOZq/kAoK0VDD6gbZL63GvcYmRmG6unaxUuUv668/OMlg== msg=jZQImbdAZYf6HkRsfC38ObURGZQiHXIsMAFgTzPn1FzTicmvSzpCG+4rdvpqWtq17m6v0wIbrIFeiVposivQ9Q== sig=0Ml2x1Q695t1xUCfY0Cm5x3WOft+cnY7wmesk6H9nyKZNf/qTENu/TrcTp7NI3i8/d/B98h3XWAAGtNBl7GbRMAon2+Kw/6tCR5daSHnvLGl1p04BnLGzvRIhnTHoYcp0QWeUhhw994iJp9mD3WmTTAA e=found last=19 s=34 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAYIWEQ40XaM6tBvgLBlczEwkmNcneYVnSTNFm6KG4L9ZdYycKvDI4Ulypyrf15barl2IQYGdEDzIA priv=MEcCAQAwBQYDK2VxBDsEOURN53h5YFM3vfz9Nc6+YmEpxS/IhsQuccWHgjuujMaEQk9zfYB9gsjtTZSBDoGLcaE7CBBjE9oGiA== msg=HGMj2y/t/4T2SdsysAVuT7f622Qaf+xW2aOFQvMdbN9r8LtHbahtTTFvOyhNXW7cjNyVvL8TVEyxmjHWngUiyA== sig=nFekEkcODWUoUYWzUWTRZYQ0XCvJ9qwjLrCRpScvi8kCtyQJGQl6lRGZasGyjGcqiB0cQeCJ2TyAcW01QqFSsGfFofp4dc8S2102hVypK5afc1HnC9+jNz1zS0Xya06uZMH+wx/SgUaotEecvICtDQcA e=found last=19 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAI9dXoi4FikuceMPexhngWJgeFHs/t1R/82R4iYyCn3VFeDn8dgPDI/cw8QgV+ZS45XWNCNgmdOeA priv=MEcCAQAwBQYDK2VxBDsEOYyEu6fvQqthjTjUICrIIRm6KUXtTnbZ9p+XkFBk7dbFWMXn7OG2uu1PVHSOiz0u1kw9nReLOadniw== msg=4ZvRt0uvVi/O1K0Wqhbdbc9VMve4WDkgFbNbsYB9XDw1Eau8PY8jxjyos9O7ZVEFa3s3NVQLkwcaxLIc8tEfAw== sig=4LgCsgn0xbvLbv3rvMcvzSXpYYsiAQlc3Sq2pw5TXo3ukJBT4uPxhxguvKIbFDuQRh9Y6b4oxbUANq3iziWoGFIVwEvg3o1HxEzehT1ukuXQEn83JYsrBcz3uKq5QqRUyB1dh53OT/6A3zrIKksOoxcA e=found last=21 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASjHqamv7VTAQbth6ZjQnLP2pnolTW+mojImdDtzLv4VDh+88AdmF12m1T4Mi6sQQI9BhnILAd7wA priv=MEcCAQAwBQYDK2VxBDsEOewL0HPNIkdwMYIWKMY7RPy2KraEWb7F0PNz1Fxa5E5KtTMtGU1v8lN3vtIM9nncA7x75qSPJU6YgA== msg=W+n3NlA2QCFzbAGjaZcwa9e0TK3RT5jmsKJ+T3o2b+eFlOy6VhQmNfdZYRn8y6do+wszFza8h8yCQzzcwebhDw== sig=MJHMdfIOZVqwmVhhqJE32Az2PgzbygEfpznyvXpMxw2C7obo4Fy+X0R0EWU533/O85a86kTor9sAb7Hw4PoKhI3eAZ6Kc4OhqUfmKmwD0XpzUPcBQ0sgArkFAEpz5PxYPHzjAdvuot55gAAwkCJzESgA e=found last=21 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABzQXEKTFrEh2TC2KJrJ6RrEURMaFnx7fA0CZyjdjpEMB7xVb//O1pQwgdRQ6jcgmystqk5FymPYA priv=MEcCAQAwBQYDK2VxBDsEOTPT7qeB8FkWYt+mONMic76W1pmy0X7icicEpe1BsN1slqD2F1Qbuoqx9CoSUR0np27kfDizhFq5hA== msg=TMHYD8SliZEuWyJSsc2IdFzBmyak35eahZkcaso6VAPmhRpaP2Al64LOpLbN3AFjL+zCnsOfSXyaVfkOYcZlUw== sig=R9yRuisG4gCX3MEgRWCEAWx36mZRr+qgSYvjsqazJvtOx+NWaokiz5QGa6sBfsCBJwDU67uQL2EALxpcGANWd/8wp1hk01/7CRI/KOpNRE5R/3OlQewhOukt2PSPYxQw5o7iQdB+X/X014me5W0/KQ0A e=found last=24 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA942guNEhfqEzd1oLkuOu8m9NcTkfr0pKw48me81PSSsxOzYjjmwr6Ebq+xZpJ0pX8GNje4RwPciA priv=MEcCAQAwBQYDK2VxBDsEOVoHQXz8kzRxO1kTcTKijAOYj+YptXkCwVtEJ8noh0EWvTLBg+u3Ue4jwtBU2Yn+37PC/iYOmWIiIA== msg=p+5zwluN7V9/ESMaxWIpz21qazjafUl6hjnjhyG57qbeJCCStx4LXk1WWQr8WtcPP7EhSB/X3UfmRvJxe/66Vg== sig=pTbkcw89mFNUtS60nhm2NcNftyM/X99TILw5hByTNB70eEdNSCPVm8e+rosRb2buAEMA9kJ/NmqA4VDKt84UkwElzwzFqYESruv/ztNMr3zJadbZCyTFgvDre1wXHoZtRyOeH8EPYo0JC6jA2HowqxkA e=found last=16 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPOyt3oV6aOz9jRLJxJvka9W8S93Z42YSy7nY9uhbWzpVtVP0zTc9UyRhPf+sZQGhcqG9N4z+WL2A priv=MEcCAQAwBQYDK2VxBDsEOft07/DLp93TB3q9WtZFxhVnB83fL5+q5qZqlnWDEQ4Sd6Lzuh0RyLrzbUb+VxHZeJntw20WXJ8w9A== msg=V4peADkcMqSfqAq83aN2dp0rac68zMWZwOYUjrGIOzxWJqzzG/OIbvydRTuYN2m/j5CwvBkH1YXVSoTnAeWdDA== sig=jJmFwTKHRrC1FSzIUeKv7HtI/CdZx+oj9r+1apOAhO2GUfVvaOoBuJPrnUlesqkrw3lkysRJMrCAp6AlWFHz0nYbTOkeaEGdRxRCZ+QswefiMoZNiV/cJLBHtSsd9oqZFjOxX44NJcvJ/WfeJBhsviQA e=found last=22 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmpZY3bybwclotMnzS2gG5edD9hbwC+2Mb8rvogfXUFgLlO9SdroxnZPj+kuWMwzBu9wQ7EpRtV+A priv=MEcCAQAwBQYDK2VxBDsEOTQ3ouyR1DTEkOlg8N9pNFxh0gUeFM0dT9zSyFbuvEMSerP00VRet2p2k3rsh1Gu1sMC/SQoX2fugA== msg=pGMCwUqVaCIh6YJ0B7e1jZXyoXXAA9ymrWeTXXcceIAp/89uJZSZiF23WbqF2VCIISgFiZXnGJG5Qp8foZugPw== sig=i2ZhdtGT5Kdk7pkscQwXiZvenbaW+18jqChGWv/8s09IcU8rugf/gx5FcmOzhG1foGz77dCp0YSAehEl5gdmK5cTTIFRKCSv/s3IqWYaGqTyscAWwn1eXwDXYV/HxEeQg7Vv8iBsCEwxGMSpeeqIKC0A e=found last=23 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9I9GUmAlZ15IGCBE0uy8e6D2pHwrOnknpvaUtmHZ/fGlu+Zw++HCi53N+TGNCEPb8R59P/lj1vIA priv=MEcCAQAwBQYDK2VxBDsEOQV0t+X9hmztpWn/ZUT55ct4Rq6f6U8EIRx8p4QRch6aOqZCRoB1wjK9QkmJCvV7SF5li1O1HAqm2A== msg=Wx/Q5xTdqvheFJXzHj/VudMWq5RD6hG1Qi6SP0rqbJyUnZyAw+Y5SjzKOIXDPDvtgL66rtumH0JICXZyIwJI0A== sig=7OusNpTKNq0nUlqmcufV7X0m7EnNC6m1uiM5tCIH9LAYEbFv1n0bgXLZDqbDXVSqUvkyDQStnbIA/tpRd++f7t6laCmFB1iLDSWoxHfwgClTKOIZshjtfzaQAVwPPzL+nb4r89QXgJbylJEPKX6jYQsA e=found last=18 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAvSzEjbHckF9oAGKx2JMY68LGYZ7usF8AQnYFp1DPT885m8BlrBQ945MjCar5tE0k0f8sxOPeRzyA priv=MEcCAQAwBQYDK2VxBDsEOfNdMJnWq4Z7elBaxEyllRs1XRNCn8Y9Zj69sMr26PU9Gah98oie96/kFGdVt8Yziqfd9oo9fJwsjg== msg=dHQJTGxhSCv/rSqtfLF2BIsB9+urnhAcByxLxAAWISiTvZ8I80QX1IyE8PCR9lKfF+0cqsLhbPbgZtRgg0NppQ== sig=2UoiOuqExRZsGO3OfTZFUv+5iAAXy8rrY2hdUAD5qGIpbcLSLPqxvzozE6EDWVkm/3LVuawhBCEAP8GS/QYBB4xEBMCgNkLSZpWWsb4KvJyCeFqXOuWSkVOwVQvkiHgm5YYKQ9wXA8Ao2JGBGiOKDhcA e=found last=26 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAItDmyEJd0SXNL3GHtekHwdRiBRkBp79yI/FDTM/x2LUrkLAf7xQAsU0NXPHtee8b0e4mtGV29kiA priv=MEcCAQAwBQYDK2VxBDsEOV+DUJ6004Wey9mYolkWFDSAoIOBDW/QbdnHfAgq/Xpa2on+5X4BtIsDRZ/OFji/EinxU2S0lag/og== msg=WvdgH8c2u2bT+zlwkY52oRREG8UWdBL/5kNksG39UiZVHYStDUquyrOzGtay/gdzJeah0zxdvwyVOekCU7waww== sig=2m/HLI3mkIdrciJsGxAviVpCxpGf/spjRx/J9pd7Mto/Is7FFqYhlM8vxALc3mcbSpfGGZM/nIaABIb2vVyAUms4+nBozPvL5KNHcygUQvLnH9BuVeIYY6jLW8pbs1ZsK5/8Pvn2G67rvT+GADevoQYA e=found last=25 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAi4xLbRNntef3gTXu99Wjpskgb8rjqGINLQ2lfQ9R79zm3gp3oeJ6/8dNytaLS2AXY8nF8P+BvbyA priv=MEcCAQAwBQYDK2VxBDsEOSpxepGwzBujoOEzmrZU1SJhkH3P2nKiveq6sioq0VuRS+RILKByWZIjQJwKezqwofueKwHeBiyaDQ== msg=TQaGvbt1b4n9FyQgVZuKTRGsASfr5AUMhKwo2dulVBX+rFXZtX2zd5vzx8tZ9Cm6FpjcWFajkhaOFiGKywhSaw== sig=W5wZYLJGrZi4KCmvi6KJMCE2P+Waf15HTakNXHrRWOU9Br3qb5Ye3c00AhPCuFb0Eyc47dLw2x+AzIv5V6lsjdX9ZClZ80i8ARec1WzmRUETtD9PE6bRFiQVnhDF7JMgZCEhi6BvDJt3eTrtNoC4hxQA e=found last=24 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6OX+wbU6VYzXA/f9oD4QmU8BTj/3ofY7SQO+nWNj8hB3tG51oVT3Xndh6kQh4s7woCxKJNGutI4A priv=MEcCAQAwBQYDK2VxBDsEOW2pBOa2f1KJ07rn8UXwVjJsWJ6EcOSQzV+XRk+sgAkFUFxoDij3Xv8qPic283DU0XbAAyghPtUldA== msg=xM878uzK/lFG7nGma/TgmIu6f2b5aJTehMZfClY/CeouIeR3CRgjIuVEENIVRtCjrsiLRmjI5KkvV/0tKbl1mw== sig=qiF/j3xXYQoJy++9LKQ91nz6F3xGuH01xDIy8L+eNQS/G9MZY7xGBMkkeLk5SvXOuE7+VckPLFEAUXJOsghgpe38yS8ZDpNfkiw85y5ecdyaD3CYBRCmDmUwXnLxDLEVlgroefNNVvp0jtSQd2LO9ygA e=found last=19 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbq+uvUtP3KqwA96C2nyhtx23zk2dqHXV5BPDDiKDhIHySxrPyy3PXiKrcw/BVteVE5j7rac7+TAA priv=MEcCAQAwBQYDK2VxBDsEOfZiCsjBzhCQlVyjUp7cUGvqqVEa3W9Tkue3PqQ9f0dGZzs4wHXWY/CbgxnvLFVx0qFlarj7U+klzA== msg=myerLjJgEKf9BWizAYAy/xK1VGrcVxIRkCGZ2UbwPTXXKahNxpPjuzIVXxAlaz7pe1X45+///kLRoqUF9qBdwg== sig=Zen7oT1jCNHY7oO4mLa2qHbXUahq2bjp4z8/HpS/0wDc/T1K5TSs3dfysY4zmMHMJSs1xPSr1AAAEgYZNS0bUX22WjN46uxJq7wmHz57FIsvjRlwYB33BkDQXLnTUVt2TZdwKwVzgfqSlTEU7khNZCQA e=found last=26 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuv7Axzj4qwCEzv/Tp11NWdp60NkapcGrhHlFkL3fHeGNu6D8+p0nia3nA1lHQQ+qQZmckw+SBDKA priv=MEcCAQAwBQYDK2VxBDsEOVz7jwwdiiPT+cP4NIQpZ0iGeAf7qip64J5KgjEcjpJi5jYc0XhEcNY+QHeE2fyquMedCsWHGrpF6g== msg=4f3nwSVJwBo/Zwfu5Y40VngRVEaImmNtUSXcFNMjlhQGrr6Yp58sxJgxkn0r4LNfZNc3dyHLxhGGx8b30tZ6kg== sig=YCDjpMPiuH0uGHKqWeUkTGsYmD/DrgWPRgwvrkeG3QTC/0w00zdty2L6DWNLtv6nwqe8apWMc7sAwZtbVbeOBeGI+BOHFDJv3cq2vmps8kp6n0kY5OrdsDZn2fCfWLipE1DOSE9QKLcXTmAxhZVhbh0A e=found last=25 s=33 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtbYUHrg9xhJ0jCrcVqdetDG7Mn4/QQDTZwkDgoChSltnQ007zH7Cf1piF1Fzt5yMqlgzKIq+u4QA priv=MEcCAQAwBQYDK2VxBDsEOUje0lD01a5levwe/NshSWwZyCX6tsqhdq10C1+8IQNLhQiyxRKkSMPI6iI7r+rMIgtQRwhscctVJQ== msg=mH0edlDnjhRhG8u8kHtcJzxfJlq0PO6IWfXV8t/XWWZCC/d2+GfX3k8vA9UozNOXe1FQcE9MltnJ7JF88k+2SQ== sig=T8VlbpxhjS0nQVEFGSI7yiYzttaSwJhupaSSkWuY/dsbDT89icqo50/RmkYfbJnjt7BB0W+k6vuAZTioXt0PivEYk5vgdRbXg68R46/ZQD61HR4tliSiB4LihpAC6bHyz3w4CZ/W/Sx0KZz6fUGsPBMA e=found 126 iterations",
+ "pub=MEMwBQYDK2VxAzoAYdEQFyFKNjGVhnvbiEyqVNvc6XdMJ4rmTAdIZrHUq3rt0mfRJN2RmEJjL+3AstveMG4j68hZHOeA priv=MEcCAQAwBQYDK2VxBDsEOVIvAvux5ltpGRf1ILak3qTp3qm4g4DjLCjpqrdaU73NCYN6XxpT2ezze5PD7hTtCoSGwnE+f/Htdw== msg=tTTOCEeWcYRtGLkHRpOETIBAvwZdHrguX3iM9ChHtieV+PRNIZ3ncw2vilaLWdbBLrPMQ60MJx84sQuMAhX/+w== sig=20pXjoJ0X7sepfg1oEbBIDvYhqpwP5/qUiv8ti4I4NGQbSp43NgtEcvHQ1daotbTBGpvQvgyjGmASEnbZkB+ZBnUc6sAI1u/M5joTNwf+1ffd5+X+EKJnptn8XuVQYcMGim19Wd8YIvwbSISe95nMhUA e=found last=18 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAnXeAVgl2rvOokMHToAZfQOVl8C9dZJq8o8IwXRbC++1GKllbygNi8Dy7mLb5YbJDLsJGttFM5bYA priv=MEcCAQAwBQYDK2VxBDsEOdEI05ZLwDJbLmZKzmnilHdh+dTegSF7On4zu2ICjFQGh2L5dVGs6ecsqkPqg6rych4nH7Gdj1IDPA== msg=zqP9mfzYvnCYxG/TFBKbXsoNf3MuL3/TkD494iEKE6L+9cit59PqkMu4HwY5T3Hgydk0pympbo3Cs61i4Kdh5w== sig=VvZFyYtXmWIIJGhRMTpDsL/y2FUnuli7XTv7ZAtHRaVOb3mzRHxCUJU5D65CMEqHX+wzh3Cn8icAPOD4kEjMMLNrMUuz8v3JAfSpe975Bkt30VR9qSMNKK2yeLeLzjfxdByDJbIDgufUGlFv4e+H8h0A e=found last=19 s=26 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoACnonN2K1PZeiEvr2c8jvf1jlruycFZ7ba2DCtk+NU7pBpBkJkvMOF9Vw9GqvPYsjbxVGIgVY2lCA priv=MEcCAQAwBQYDK2VxBDsEObWwcP5cj3/WpdYkF6PWu7Z/QWlYIx29FnVylx/Ene51tiunj2Wj8wxSmws1EcyAwcAty0vPHypoCg== msg=//55tsea6sdPctg93JhzO4bm6iIioM1Ko4OfF+xnI+GB6Wvpxb17pSz9M45yWzuXM2FiqRZqSNSoDU1mLBKbaA== sig=NO+HY/6yYToqFzYeausbNmvQT9RHmlc8HVlanTgP1oTdBxdnVmikne9+eaAHYa2LiNhBB8zhw6UA33bqlpHJOYRIKACEKGokzgY1gX0xEc2BasrDSBFv3x1MLLUo9W7sJ1BnEjY2WRmWYwc8MNnkgwcA e=found last=18 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsyaMpnpEiE73QSAVi1x6mij98MILQJYeAOJR0fS0ga99h1mf9iLMOyhZYo/H3XsdJFAl4F7/WLuA priv=MEcCAQAwBQYDK2VxBDsEOa8zCHlXFX+3yRZUagEoRECOjN9sPCERgRU/763eXzpc4F5vhBTvdTUNjEhPgywpQW6gqj4vn+QvEw== msg=1Nz7412QsYqFgvAN/4WvK+w6clMC/8IuYH/8sqc/gGswNuH+0zEY8f/5yEzHmuR7NLacL+bOm8WLZZ+I16DYSw== sig=ilcT7WjlEWPNuirbiRUjArpZQN9XW4P05tOMJs3gCFZrTgM8j5DRBMNDS1sZEsyYgUDlmD0BbD2AmEUwCQHbpnayaXEMYF8smMEKu7AeVe+Ndc+ff2qia2UOuihIE4YbBUcmvVGetHVPS+Hxv06dVwYA e=found last=24 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEGd/DKERzReD3R2//QhfOyD7dsx7mPROgZsbU9htKJp8HbXW9jasNieJA5790LUjLbAE+xIHU8OA priv=MEcCAQAwBQYDK2VxBDsEOZxd3gOuCXPQhwbSPlHoE6HszFu1RPGfYLmss8D9lA3owtkWnWl9jP/cWhJcmLOLmDiNVPJyCIr+vA== msg=8Z4tseAG6kWyhZmVhrLOU26p8sQOkb5HtZfHusha3y2rpN9RQmOCajkrwIj8PtOoVeKurHCaJ+FlQwV/+sVhIg== sig=+VBC2iVedQBgOCueXCUB8QWV+olDsO8Cz83RJFXVLiolGhZN/YkY+dwfggpS82bcj1Z+tK+w+P2Aphit54a+9qnCj0w/zmbr1vMcWgOBWjVWP3vyZKBydvgTJzCHomIDxtpqqHjjmScYS5x/6bYCXjUA e=found last=19 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsQYfE3wCqOGYeZRIuGWZPLnxfNZxZmBrI/ULzE7MBFKxNa9h+eiU21Ywsx88wu4JNF3wbOqIvYUA priv=MEcCAQAwBQYDK2VxBDsEOZjacAOAFoM5Nk22wQiA8hzM8ZcQW3Cd7vZWgSe/u3i8BXbETdtPkX4RPMcPPsosRkqC1WMP2Z8rUQ== msg=VgtvzMsEpKAlHxKCbA+NNaq4piBrc9urWb/95KjYNf+MMlFNPPzZ4qrRUZ809FVAo4CPRgfMu8tjU9BepaGFhg== sig=moyEiH8ojFRqB57hHO4+BtnShxUwKGnoF6nv1ezbI/ABjmnx2Dgo4rWegrvDlhRu5Bw4bv13/KGACKP/kobFUIV3aKO5mdaGyqc16nkCJLy7VUzRLdaD9k+EbPn/hgflRF9raWPyjZKFewzK+FHMHRcA e=found last=24 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAxqbPu7xzEdBFVeCraiAvmzjF+fCAQMUcrNdaEoM479NawVCCbf6t2DPTZBrcN2o7U+Tgv1Md/bQA priv=MEcCAQAwBQYDK2VxBDsEOYl9frFfNXXSzSTnKKHb/Y2jll3QIeX9bgC9Qlc6d9hpFKxzCm1dRyfXF76K7ZQvo29N9TGcbo5w3A== msg=toDaJFfjbZ7eQX0N5S2gLtKNQrwg7CQ1g4e5n1QSiV9zP2wITLKmcqakZI5xXST5OUav5Rwwgh1vBQtZz/IpFg== sig=OnYbPEIT/SssJDu1xAjd9qdnYZYYz55Uf3+eJvyCS6cnlNTqVbc4dBRmgZP8/Tf993XI6iS/C4wA6xFaqbzUYaUWKhb7+n2lQqxyT6Mfo6bCX2SEGlWiPkXZNE0Pksnrap1B1A6kXyg8afVySureEzAA e=found last=22 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAe64NqPsAI7CCgrDiGnyPJsRJmhIajC/96+sNqz0GCjrbHQe95FUk4rYiaAYaASs06ACojwP0YiOA priv=MEcCAQAwBQYDK2VxBDsEObbJr8ICGs997+IKovuOByUk7PXL1O7buoK7jL5KxT642sGTPGn+Ax/9jqnikA6eiQMG0XXagGNzWQ== msg=LTNNgz+cBtb8ZhYj5ZalZX7Q0z+sd/7YvdYEvvF1YMOw8pw13GTcIeZK8qum80HzJaOxCyc+v3chAUsUfitwew== sig=gY9wxwHRaPA4gadN5+BfhDEzwjbLAzvPjxHCU+OeVkMsOwqbogogGzuLIAfr1pqhlQiCKrzNmxMAeYl0+vcqpkGI4L81CQBwXNGYxH59ZZDkDl6qQ0N7YhLZ0nwj6yZD98iePUsbXUUPcJY0J/HuxgAA e=found last=16 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAkXpqqqtq23e+U28rjuOu//wsLklT9Onb45YXO4S8LI89Kdw1C813N6MkICosYf+IX1L4kLuMs3GA priv=MEcCAQAwBQYDK2VxBDsEOcxUEFdJ/tt1MwmOsPrfsTCWQcbDFXnloN8F0SY/isRivQyOaFcqOxkFEXMkcOIi0YS4IOV3qVUR1A== msg=FP05YjXswiLulY+10S/f5y4vHiQo1ffDUWYKoldJ/A4Tn3PSikvQxQ/7M93Z9oJK45oFkzNJnIUvuPMzTmncCQ== sig=tYb/VPnp/jtUY2ezG1BjmHKFK0vLwpqf3Kl7E/6Eej/AJh+jkkVGXzJKvml7Pi4kwBb7HvlCDOyApJu8lfCRsgmU8nCaRtnc1ujjAMj/o8k8eF/zy82MXSz5RTfFf9K+ODAMtJZwd3qGUXUhcnG0rxwA e=found last=20 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5AdRIfL+Zy83VQmNMHeN1xYiXfW5TzDgcYNpKG19/l3gbTUGhAfM9e+n79rpvlW1o1dKNFLjqBaA priv=MEcCAQAwBQYDK2VxBDsEOV0q4exTad9bfnMbUjBh5711/CPgNwvY/G9w0Uqq49vpxj5ZbibQL2+qhO/WyFyE/hCJIAzNPyL2Rw== msg=WAn2RXljnkOzsQ0yrZcHQU8iujzzJS9sC2VNWK7TMtF+9SsBSZSsHahbgpWQJ5jQTaEkXsStQNSGi4+ZC7iZvA== sig=Z2cJw7iha339wOKHtfRDIQQfvwYO1f1zpwbmLDb9qHNPB+bCWniegC6NGuIM2Qz26JJfQonjDsYATIqcK/YXfnJE26jL4L7gFq79cH1IiIlrlmnlNEfzLSJkJi7j7+CfbqsBQ+jv8pVMKdQzQWwADx0A e=found last=23 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/8jW1FiimgQPY9Boa2d/yXwwQDZQAHLdkP9LHIHJYS8g14KgrFHxVR/IiHjqhWfG27vH06iRVQKA priv=MEcCAQAwBQYDK2VxBDsEOa4P+Fct6F3AkE3GgoFn27ryTJ4TaLxVvuYO4Zzx3O8pla0LoXP4DcX7yxdnjZKjy7+0fko1iMaq0w== msg=1ryicMYTGrYfc/4NMmN/XEpCVGYaMkREMNWckRDXqDie6MA0t7W+pcPpdOYANaahQOKwQFo15CtE+qVClU+YZw== sig=OxCFGWgePNPWulcVujm1q881dnmQr20ZHfEvtYYmo+99KJV1BtkitzKRFH58QhhlJcOJI7/HS9UAkZlHNIz7cReByLf+TZLpDvW8EvBWlEMZz8baenNml9LnKFmgZZmmzPucjE9ux1yUntwu49bolywA e=found last=26 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUgxweh0EShntmrUsJGBIH7jmsHegrg0hGnsXoj6kTqwk/FZNiAhu/srwRrnWR6a9uzOA8oKVmbMA priv=MEcCAQAwBQYDK2VxBDsEOd4qxY8HxChS4QbtAXUpVv1T58M+PcSlkZOUl6WNy6JhI3FWTO+aaJQeUbZTI1r2SB4xKLSCK6HeNg== msg=DYn1rXAdcjEAReCQjnE2bu3GF1OP9FlObprHdLMt3x8w+G/Cds5b4jItCrVXW2fhdednAS1nEJ9Ybb9RqR5qQA== sig=Nhbt/jju8kiIo8VPA8YtQkyMdqAfeUZbDW9rZ7P78RMg2HB2QTvaPyJQN53EJfjfmJXIqhXCKJiApVqyGVolHbkm6D1iwqeFiyKdCZpYdp1hk6np5N83gk3P5bzcPNRv5eKgnvMYXWb/GAZQi5m3lxQA e=found last=20 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAvmdauLMocPrdOOr3XNwH1B0b6cfvsvB+pixN6dde1faF6hqw6FlYqwLOCwobhCxi8qYI8DzzpISA priv=MEcCAQAwBQYDK2VxBDsEOdGGqX/mEWvzkqZuJ7zDYUQ+eS5VN7uA4BOt1iNa3qrfGAp79M7EfyBR9K7cMrBc3eqMYDnXNkKSGQ== msg=32fY+zlagAACjbe/vz+7TDcJo27xofo+WnW6mT1UyzPoZHTAcM8dJOjAJk0G8JTgC56iBuUoNX8LhriDNjmEvw== sig=tHCYb7Keb6fegTZCTmvv4lOr2QFLfoamB5/jVMsoyzeketLSf6tF3UDJCeN22d6zi99BEis3hyEAkULPCp54+Zggs35uDYR9wqdeVmcipGh2pS7DC5CY94Dy2VucCCzcy2Vi0dPq1FB1vR8O/Rl9xwEA e=found last=27 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6aieOpXnd+U4l5B15JOIsbpxm6L3yaL6DtpDRR0Hj/sAdbt9rr9vJD9IzYRZexrqOj6782iUmjIA priv=MEcCAQAwBQYDK2VxBDsEOSb/QLH5zQ++z2CFdyBpok43smnBnsuDyEtIzlROKPYsW6XNYtG5ropiDCC1iE2jvHy30P4EXTp2DA== msg=YbexUtT8vejIiO16nBUhxCsLmtmruU66WImPj5/FWFCfMjNI0Eqybe3vw+EB22VYV+qTmmWoA52T0NVafe9wiw== sig=TQm7jVhkV+c+STxliPAtlaxk0oc3M6Jgw+9vNMB+nDh0oM+H/D4CtRepgAd9On7noDe6NkscHJ0AE9zy3usBqNnUxkBmJ3QMFtRh8muvDuukHox0487oUgauGLZKDhiqXjR+x3cVkD8NSmVW/l/ROCwA e=found last=22 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfl6lDhhJD/Ltoyyp88bzU9lEnvkqwjAnS+V3UfysNs0k4fQawavJ3RWAM9Ie4z1s18Wn1ur41bCA priv=MEcCAQAwBQYDK2VxBDsEOdDGaFMSrvVfEyVGRp58eUmQSz4s4bnhGV2EqMLrQlXhhBGJQNa26PhY+DgtercR2v4q2Y0e4AzVQQ== msg=8ezVLEjr0YqsuPAx0oPRrAIyk8FxJ182kDlE5nZSX94+ocCn4V6fS+d2wsskkqBMfK4KwGS+Fw9E5mwxx5k2Jg== sig=ocpWT1iwUCQs4IkvHmbedmr1fLizLM4M7xcBLfy1o60/CRBqPH3SnlcWBh9/14IRumFQy8Fd5o0ATPUY3oYVpF/SiWwfOEG3ArVUk0bEs0uDVtzSCYdiBvpm3/kbfY6xaMmKL50SlbSq5D0LZSqy1AoA e=found last=26 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA+aBIWlDMBfX/r6+eUWdgQp+nVYVVmWEMeJkuU8IWiEdCfxk+p0H8t0r58EVy02r0aSaiDs33+Q8A priv=MEcCAQAwBQYDK2VxBDsEOUHt8m246V+gXok6nLkxBNzlttgAz2/DB+US6p0a2TnZNil59gYTDS64mz9O9aluSKTo/Y1/wJAoIw== msg=uVK1XyaMt1A48Mcle78uLcilcyPBklM4S6dd8imRyGadMU4Mj5yIDXeq6YiBxMGus/iy8cC/u0Zy6fFKpzkYJA== sig=/8EecIej0R5U0vN6baBmIXaaB9GYG8WP/ljkEQSExQJwMPUfjbPYP5oNk5VdmWnMHhVuSPAsR5GANjTtyKLifDNYCQCOPccCkF3bairQg0BxunGgIDsoajk5mVuPtahDRD06t7jPS5sF/koMk8NzdxwA e=found last=27 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJ0SzYsSZGNrEqlNxcRC0j3V21v0EZAvgMWTaFIQlCK2T5HIDJwuWiWkySMdKCNfiHbiOCzpueusA priv=MEcCAQAwBQYDK2VxBDsEOeEQSH3hHC0XSdFoxcVdzdiE4cJVa966Z3v4xbSfvcTGHi5lVos4vVVije0EnesOWL+BqQ1w9Va69A== msg=1hkxaOUfFe1QH0EfP+EuqmZz8C0/UeaC7OU21cxCtjwFLFZK/nOmK6cG4uazTI91Qdophfvp5yhsCubEeeOy7g== sig=+2eyYs/LndsMv4A4MLULkQcE/HqqXUfcQqVfWoguMgQ/e1gE1ELWnd5bmwSGOS3nIq3toDvhi4mAdJEJAAFjZu5uwVHcVv9V0lW+7FY7eAcr+MIeembLTo2oWYS0+Fm5JE2HOHCl3JdG8U2Bz19IzwoA e=found last=23 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAaBrMxRgkcLq7RfwIK4IbkaNChtPp4VN4uY4pc5Rcb3lJlFRzfiNRZUxjXUXDFwECmUm8WJxcDQaA priv=MEcCAQAwBQYDK2VxBDsEOTzNAwpTYbXHam/FZxvyb4ojXDP2eicKg7U1XkrA86NeSnfPlKenyCHIEqO77zvcC2UleV4qGH021A== msg=wsM1JsR39C6fFCG/9GLWWzhS0daTNQspJn17MexuHgEjGrsM+ZQ4oiDeO+eYAfnRjxk038D0fQjzj4mbmdmUpA== sig=gnNVU/+M7jo/CvRkIL+39FVTcaz7Bi5wraESca/BA0++pd/0IuYFSSx3Dm/KcAj0l5d4wIlrVUWAJsORvueCIkHi1VA3Ct2mnJODiSqLmBRJFEo8KmG+DCHwvzKJHFCZocNIPeXS8trxE7pT7vWY/Q4A e=found last=25 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAlent6oufJLIAY17WciUn/VfQYli6s1lCZv1doG9bnQ0b/4yS2ANR2GqXZGLhN89t0a9kqTw5zBWA priv=MEcCAQAwBQYDK2VxBDsEOS5P/ZjOrYjlN9jE5XIoxDgH/uqBFLQo9f3Rh9+H6sQiUQpc0h6psJRwuEKal5RA+OiMNGlMyLwwvA== msg=OsdLh6j56Y1AnhTcACS94BnigCgKQDCK/FXFrXvBiH8xgLqyFqeVe09YSLzLEtF7eX88FHQA/lGFpO+bJNTH9g== sig=MFoJPiym2u5h2EpEwt9Hulu1r8AEl2xF8bHa2E+Q81uoWE5LB2LaQkpipLPZBV9AWcy0gFWHmSOAkr0s11ON1wcQ8dutDb6MBpmGUYDYLraP6qMUztfLRcAlpeYlsNp+3Au4JEiKu28B1yBfY6R6oAoA e=found last=19 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASwCp08CAtVmWuYPtQ3xF6QznEwrfDeGK5p96J7E8fnpZp+qAxHUzAFPFAacDznl6UUMPRRNckkwA priv=MEcCAQAwBQYDK2VxBDsEOaxALf2MvwFofI18ZiiXAIo+JYiQfmyFwUhF5L9QYHOOtKK5ve4wilOiI6fTnPFbMHXzn/STh6UGOw== msg=825TFx4U4QIFm67v20B8T9fCTSU4vES6VvQR2X1uJ45kDn+Urk+B/9J4VFieYThmISO20lgoQ8XRe+UghSa+Yg== sig=J99ZvPNULI4u/1kXkkXjBAxydf7kE0D1atc3wrR9+WD8MR+SsHHWtUB0spvVhkYwL6j8KO9/IluAcoq718ALsq9fLnJW4PhJontiB4Zd2Zr1oP1/dxo+EkvvMSVw3rkqUjW1myT4DAkRc58+qoTsfjgA e=found last=25 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4RdDibu+tEvOXHpcmDb7FxejZ6aIMm+rEYGwAa3Tjw5K30KUZnrtc1FpeNgjqnXIMTKupuVRSnaA priv=MEcCAQAwBQYDK2VxBDsEOeY6A/fpIr4Uoezu5wXfShgesvEBk5EWzxU8GNN1DrqQYN8yaFOup1Kh7abuOt6FyIvmjuiq/sD2cQ== msg=aWYRAioUqubFLfEMvxJT/js7Xw06P5LmBN3kqFFio62/W+dZSHXEoUW39hikfcj+9Qw948FdnweZCBST3ItY2Q== sig=YY2s+2+SbWKDultKxh/RtbNJ2kqUx96pwLY8n9Kyoek2MhNTyJYXiv8txUULC4gXqf4T5a4/kr2APLXhF9VZWT11ETqGCH8PsUfMNsPNhkEkixW9Pv1v0rI7xFO3rnB2UToqwFgGFcIe/5FfWVOa7wAA e=found last=21 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3RjNnHa+VqPI8Xazf4s73FKeltQtjS2tlZJWDNNrHE6H4D+JCLZ3gIxz3+n7ft56MUBBYKS4awAA priv=MEcCAQAwBQYDK2VxBDsEOcU7aq1/g6I7bCsIGX+dKmKLuwBKWe71wAvrvBTqIhUKqbLlWJkgdbALUjqDWpr+SpvU882wr4oiyw== msg=tmgswFqetNx4TPGTbz+Mz9pCasoRAgYkwTFQdstZXY7/P1viAGdxvb7C/g/gBtf5ycwEkLJDhySPT18hdPXSNA== sig=kCoVh96Usg7M2Tc0nYamKtbK8hesrQg8KSKuCQcAPh/1ehdUkKXluRxYmIIFlVeTpH7jdJxKGJyAELDRSTRISJzPJsUqLySOi10UeFHggZ+XEXybPkIJTybfAzfkTzip61R/n7W1ixsQnOB3DJsmpj4A e=found last=26 s=26 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA88WEcYdznwwYQb5z/EuvuopJaOqsb6FUSddPUk+5dJ9c09WtLXeWakmDme6zVnGiXRAhaeXgcIAA priv=MEcCAQAwBQYDK2VxBDsEOauQBMDgE14IkKGQCI1dT9RKt6B3Wy2YD5BAmrUX4QKScGM9507LyqyfCIJDSEhhzxlUxveUtlTRFw== msg=fJGR0B6NWPCUa5kDwQMYsS0LhJWDmJHSi1Z/+s8wbQ7z37rYa9Xqr6adB0JnQlserfvUItYTx+DPr7HnHWFIYw== sig=sd0yKm3pGLTf7kQ9Nrm/nruwNjaG9lH7/H1PFtt9nhmas8JAffyncQbQQhhmGKJeRkFfzEEi4R0A5sGhbqxKZCPUrCMflyB2y5Hs+WogrlVz4E82R1ZUuSlpg0fwBHUbnpZzlqEPtQKYvJ+jYfAF+yEA e=found last=27 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwJIys+LFfSmecNB+G5ebK8+uWQJ0qErgLeDz21nx6OY3aiwq0LsDnndf8F5C4yIb4MNypMOO4UCA priv=MEcCAQAwBQYDK2VxBDsEOQ/yuzBFr4ZJpH9ZKPtmAAuL9eamsv+lUe5WQgsMPjoMz3RDPyGOvO2xnsSGSlZfurOHQ86MkXJHwg== msg=l6tzMRkUfGcbYYbgzUUTXCOly1ltnaBymwedC8UJE38sbGAM/id5OCwZNbS8UdtNWx+TVnSJI/o4tCB+1edlfA== sig=DH/wZgZmjplDVzxtYPgGROhZM50DA3Sns/MoIsNujqFiGxIIp3Xy+xaT7zx6KDGRyVXwtRBZsRGAqti4MbfYPhXccwM0cGIDl2d0YikR/juxG51tgEjJ/PiOQVzetBp8FS+VJ6TiNP16AuM1RqVi7hoA e=found last=23 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4Ot/LuRimY6VI3b9+unNcp8Ils19NZ/p2P5TXnbIDZcG7vBP0KGF3TdX6j8UufYnXeq1DRfyF2cA priv=MEcCAQAwBQYDK2VxBDsEOdpBfqkPP47L9VqFGGUxWev7ZhnFIxAVmj7gRr/joRA77MdDHM2V8nz+dpqlw/lnCYx+8naaj3LAeA== msg=cZ0yOs51qz5hJSzo89vBJV9FJYa9AXGBskhV5Mgz9Krq9Y3LfoU9TpOgkNPiNnbMdm6hOtJmlbEp8nCL8+j9mg== sig=ZjFTH3sP4LCaNdKsAhs1jN865LKzhVdHkHS3jRfn9NyJ/t4F8pXcvoxFLS16O9mhtjyHF2SNxsKAwHmeBp7JQ5PgGVIfHgZDSYbGTY6ggUbGzludDpeduq1UXujLP1dkNwGL1F8gw+i4LaW0+JVUIREA e=found last=26 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9F20eTDl04xWCJVVq+Q5Fq9LHc3S3t76PtMF5dtax8R5FRMXJOVFRj8ah61sSauNaMFDJLLiPVaA priv=MEcCAQAwBQYDK2VxBDsEOVM3E0nGCcBDZfMxL5AG/gEXAYCtAtx1u+Aua4lB1pI32kX6+/1PLg8KnxTVWGoFZqE449UOS7oRAA== msg=fxFwc9aW76f+fqg9ekVDaJT0jR0QT1KSHMoMIK09qbZazscrSBS6NCrDlMcQoECMky+X2/QqhgE9QqWAm5wkKQ== sig=BfdTIA0HtGUXQzVBNs2iLBXAT0rAo6JpgF2OhUJsM/rfcAh6IpwRa6ZEUk+lUyV+mScZ81EqsrQAXttENvS9G9vKpHKwdN3BNj7hy/tJLZl+mJGuGO4e1daYvQFZ0WT08FihRqaSb35AhELG9rSODwIA e=found last=19 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7yKjwxhtF2jXWg/oAubhwwYq9zznQak/N4FcUhlROWyGsn4usv+rn7y5UeqaWkiN0qgDwfHj/zMA priv=MEcCAQAwBQYDK2VxBDsEOa5fErWxbgqbVGPCXX5Tn0NTFM2F5ER86+ltsLZ4i00N5c4L7FIKlU48hWwYl2w4euordsWRevBBEQ== msg=wxXELY/LaGzh5TBI7EMQu8vrf+T3/vMI7s6T0Ag7H64/dpv2zjCZIIq2iEVxegGF6L66dai9JCJMzAiQrxw1Ig== sig=dIz365iO26iZzTqOYr9RIQLleptxngukiwknIeCdRHJOMTgCUdADvuM9MXZCvgET1f1LOEzvOdkAh0VGA/uRCz8xOu0tPTvBnSwix9Tlpefxswlu2PX6mbn1auz35YEMKjrlZlbkQRHuB6u4wltF6yIA e=found last=15 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAAICA+8OSUHmUwZUfuqLwDXryNbuVtDqiRe/5xMLcWmBjanotW9dQRXH3PpasRPmNkrP154RzXmkA priv=MEcCAQAwBQYDK2VxBDsEOZvan9zBYBMaAeUmkAr9nDNghZ6nJ6OWaI788JuzbT+3e7zsWXUNT5XkrMOc6GR31EgU0z5ekq+4sQ== msg=niqVqv6qD+Ez7viPk+lpozLn1uvU3X3wylL8NTTrxbkSQZmfzM7uY7fP3YGkrvGT2FeQZcJLL7Jb0BKoww/izw== sig=4aH/w7RvOa6IGzBYcNDV2KTyDZOmi91jAC4bUazYMeh4UlyM0ez6psv2lGugbfJdKwevFnDgn+MAEefdxon85OV6vorhwTvQhfoM8TddR8uEFdEJUqq9smWvcbBiAOid+E0r4lkhxDGpaoT6G8xjYyAA e=found last=17 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4tTGFtoTYGGQSXb7dlJrf6qJzf54domCrKXRFj4kNy9r8psPGb1d5liyhyf6TA58/E+VQXlspfCA priv=MEcCAQAwBQYDK2VxBDsEOfTdxXw5Z2ZVuH5T/lyHIRih5E/Z8qy0uteXQZQar63cU1D/OXHxDWvkzZtO2xPTzZrrxR6+1FZy4Q== msg=/YTDjGQHogTIvu9u6FvxhArrcUCkrx+mB1C7Bxkcr75nSQdHDBBVg6JcmgCCeA4M8NxVWhzjI0d9NohAuxmK1Q== sig=RIpGAnfMDWf/4lJjMT0tbI0NPNJtjQIkiSghTvNL/zUM6WuxzeIMvsfIgjPckP9ujbcaI9hCWRUAVnpppdcW0AmIhb8qFmXWmIy0VhnCH2dVXH5vvaq7L0ykBg1rasRUF1fTmXs8hE6c/gUz4ZDGWQ8A e=found last=20 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5QcWhpwiLZ6UxqPBqJMfhOOybllE28b5SEqq7U5qnLZbsVCJN1Zs/VbD1EINyEJTmWZ2rXw9GVkA priv=MEcCAQAwBQYDK2VxBDsEOazgV2F2FxT6lPkEDa7VOQWajYNirM596VZx7/yakEwDFeX/x+/ejIQvvMksmd+Ga7coCjb0SINtTw== msg=6n4u+Ti2O0v8warwzpR7qsLHBur2USc1Ig/3GlbPf/1tWnDWMIJ+sVaSWW+hYKTlWART3y1Q0ck8LIboyceNug== sig=7j2AMhS7+mmctxiHM3SfPrCtRl1hC9GIA1KGiOheiBhqUESIbZZxCqVsZnp269so49pGg9ZiudQAhTF4ak1ngOuYkVHNPHuRTAcd7gaeHmpOEmsRZtmDTO4eNGCyoCgkSYNNN8wudqZ1VcGvyfKvqAQA e=found last=15 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATQtZMKa6gOvcudHKmqXdMSvw3VuqzXp+HpILlFH5YqX7W0fDid4i2kSaTP1HEe38aUrMQSH7hTIA priv=MEcCAQAwBQYDK2VxBDsEOTYb9DurZNszQV3eIY0xDI2WWYRat20pZ4jahP6dZgmwW4R+vX7eIbZ6xqjMGMj1+1ngVei4Jwc+Sg== msg=h9+eGHaS2ivmvh7/za7RD0MSwzJC6qF8TNEVxopaloPmaxE4lCi7zdzNdk177EjU7Xdvrs58xP7ngbW565DQIQ== sig=XD5ey2VnkuNThkG9rqajA4xNiovNyNlNxwGb9San6s70bSPrNvQhjXpe5A6lv/BtLoNX74sVvrsAYxu680SGRoZi0dP1Q/3PCNdd2e5K8JL28P09142D6ykHRfDGcobtKFQA/RUQ8VNWTxxl1LZKRxoA e=found last=19 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9Wr7pfCQd68DbBPPNqxKDNqCyinmotYQVCiSEKdZWKry6oykPthoXcffjcJ8/XHpSpo0z0S/YIyA priv=MEcCAQAwBQYDK2VxBDsEOeN1XPD70aC4ewJNrmo6+yJ2cjWj5tnEPVFBcmuBaz9lJSL7CXEDhOvnEK4MtjUsJ6CxK/pXM01+fw== msg=kPt6BXBXVyT1kgsaFVBXT42lD8vQeYg28wSqyC9VmkSoV+IEt8c1gvMoq339ITv1WbDcWHiBeOp/14l7iEOtDA== sig=VmfqvpF6gfym7yE+IXEHHZ7fVDnUN+DZMK7Lwn0oSpXv7qCNrup64eEXAM0AOQT0X3Ee+s7S/OuAKRRrynusyuEPHtE2tyjTFpTrmxSF1A67jf2UpoeU5+lDENJ2uZXUSvQgUSKyPMUGRIG+V+E/kC4A e=found 122 iterations",
+ "pub=MEMwBQYDK2VxAzoAXmFqhwAeW8gffGxbvmTlnh93f87YF9LNkQmyFElXwAioY/ZZpyla04YgK/QYqcOiu/+tISETO7wA priv=MEcCAQAwBQYDK2VxBDsEOZQFckjFI2wSvqfdmcKTsXXY7CxhElaNpjGQ5Qw4C5O2PpxNrjvxJ8hHYJiZhUyUzzUA/OYkJDve+w== msg=TuLnS/IyEmjZ3R20y0auk7kSYl1gzBRhlUVxD5UD8g0h5pLadUukX1Lo0loIwCxMzGSJy4ALGu/B0qfH+yItJg== sig=gX8Qp5iiq6OsvengdQsAXa4PZZSYoygIW8bA/Cn5McCPtX3twK9lvsMVK7k3tqR++pq9tyZE7o6AElNNLRMoQaQ1XOUwgqbM1HmrDTs2O4s8NLik54lIRkWsXO4tXz/zYgs0+1rfFuQG7aPQPZYpqA4A e=found last=25 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA/TGY/mKQYsrUNgRmQUHASXcSQ/EiHuF5GBXOv4G0Nq5Qv18Ingc1ZQ4VWucp7D5uI/nEyz/m39EA priv=MEcCAQAwBQYDK2VxBDsEOdzex8YdaXR9cVQSn1wm+vy3usShwFiVQoujZqo0AyKiiUJH/p3BH55tqiPFLdrc/8HGGEokXa+j3A== msg=3JoHoJEPH0jC3Sc0Uj+bLmRCbT70/n4D2ov5hRn8oZaZI+7R6gRllbGvJXt3PDOCsAzRKiOyUgD7vS+FtnJHgA== sig=WDQ+8fI5ZJTha5T/auYZnLtvm6A9tQJ0RKGY4u3m3zcdKyMUEPIzZG+BQvH9kloRHtanzfo2WvOAWg7zwB02gTYbzfQ8SR9DH0rM73ahcdW+h5/OsSYEqPYCLani7akR/LV+CkJk/nSMse/wSASkXT0A e=found last=25 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAltcWWkcjZ4Wlpbl1CxaZmotDbdCMYGidRVOy3UjmfwlG74siEZVC215cdzPRtDyaGsE4sO10h6GA priv=MEcCAQAwBQYDK2VxBDsEOZeu+3JKV8kZpjSZE2rZ5ezcEgLH4LU+3F7Iap5SNwf3nOIyNbpbVcd6gvoOoS4Fa+NzECOQPTTeUw== msg=l6MHtfLVliv418VO+5DOB8d8Cag0W1ams6vsuUI2BWc6wdRjP8XIZMDcz7K8mJYU6pRS1RJ99Wyv5YIFZZE4gg== sig=4/hByUZtDWdzx0/LtdfsXN9T8s+dF1Ua3rLYbDGi0iYAMVfgYz4ZZwZVrpnsbT9HEz61pN5pDCMAQEaUhjBFYc2Qh5nALUsH73KPR7AY3WJdg3FpAsxNqYr4MyaMo3L3dCBxUKYqQTmH0hdnojHyUikA e=found last=26 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1B0uGrbms/3tVkZdR/Vh6zjwq7rSiSdM6L564YA9qZy+1vD6yB8GYWlgZ+MtydTMgHQn/C6+ZGoA priv=MEcCAQAwBQYDK2VxBDsEOW8zcc/KLYDOPXZQL8K3LDgDreTQqX10fQdoXOu/JmTFEosGZPyIxAW2TvTYbXHZ/6IQFaR556Je7Q== msg=FXKzHTP+r1mU2eUGHjlsChn7LdrEp5tPvWy+fhJRrgOKqEK3oouxObcIBpOBpf7HQtL0JWukOP3gTw7JeN4TKQ== sig=jW9e5O5Vh8ijyc5jINHN1OMoPM0jX8t7XHhPnD+55I6j+5zyAA0X5j/cUQcRCUfgg36D6Rwra1WANpylSpPUwQhvl6SDGzEUqJ2oeGHEPZZQsgEVtuzhs09faB0uTa8zr6duYO0SneBOoVUEEwxQLg0A e=found last=23 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwVBFAPb4YooxvUDjCPrVDPT8Ajc9AAcXJVLkz6uJy9p7RWCfJXIsev1SWzW5qgX8p7437N7JHmyA priv=MEcCAQAwBQYDK2VxBDsEOXlgPFGd/UgGU7gRH+AW0+W700jiksH8NnglM++lVv9hJTzcok5mW9YO/9yRC9RumLGkSp51hnHhXQ== msg=48SjyAvcb5B2iU1qP3MoTkuioXLEw4w1bd/ssWeUvQfxmoyWVXfAIOJUD1hbAUIZMg2/w5QsI511IvwpGXjyCw== sig=TUpHDFeXNyPfAr4/yo/uWdRZcZzOxVxkWor8UFCdlwysXOXkgqoCJ/ZV+F2GoYT+k6OrPhb4M3aAmhbRqEeczR0YR4jmmF38WxwRZUv0AlqWlWZz426AxG+jWgS87cJUiQR/mw8Yvgashs9WKovdGhUA e=found last=19 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGO27tZNDCnaY7uJZUhfBqrfsEGtBx+zuQHLNHyfY+82/zDBMCUKHqUnPSW2RDZhmdQakCh/Ioj2A priv=MEcCAQAwBQYDK2VxBDsEOZBsPtVu767Ogk4V7wuvBjsfOk3S4kCZMMN5U29MYdz+JAxDPUAw20zHQGvW47Iz1bGHPCqlcsGwnw== msg=BZJ1RWZveIYWcbLO4Cl2SXe4udM42cEfAIwNhOZ9Lbo26FUSDj78bfbTs6Q4q/lxP3AAon60fzFBwjZLUDkwLQ== sig=LjIEWByNKqnYp63jlQrXnlXY+PE+trJ8wn4bwE0ivFYZaRUE7cXs0sCL42R7gcljdg2D7lc19XYAyHuNTptHp2TIZmYSFY5+nuH07/ADG2+P/ShYSEUkuPzpp2zzTJUQIxmB4nCrzhY6thx5UiVuOyQA e=found last=25 s=33 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIRiJOjE/MgZ5lY1Z38uW3AVuSEnrBUs3MOnii1Tnwc6u8WoL8X/DEfjoGg4inZstpbkZkJRwEhcA priv=MEcCAQAwBQYDK2VxBDsEOb/Ho6LYQ5XTvOR1kg7J4ujwVTfm0ieOz75qAdd7nXkP0ICXp3NnnQuPxaY82Qrj/F8aendWTMgvfA== msg=WZeYlVFz104XZBF5LbTDpoUIHESQsN4avflx3o7SXZ6Kyci5E74hMNiBkqpjvvyqF3u8CBVNhjx5310+srLFbg== sig=sW2hzCQmTSZV78QQbuwrs32SOG77OXIMaslt1I351zSjYtxCO+DtTcJMmY8ejYQd9YOULt65kpkAWHIzH6rIjH3SiQ8UIeJU5i4QK1GHB5w/IzBrwJJp/Z7ACzYAkkgW9E159Li1feDsxJEQ3Ig31gYA e=found last=24 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEzUzozZl+RMnCaPgdNpwKL5bycMD/9SPuMONt1xOkW+vXiIOpA/x9ECxz83lzRY8jMkERjHUD96A priv=MEcCAQAwBQYDK2VxBDsEOeZ/hON6o37on0iFoqienAnAIGOTSWDM7xLPlUEtfy0+GHw7Y/UFOdvpMmGbKn6ZOktrlnbQBYkl9Q== msg=B3rbZYusEeRICM68QL76wXEunU3KIHhUR+H8QL0MBY/omYHa0MaqW380+f6rrK86Ltsacq39kS1hIxJzcjNa+A== sig=qaj/oJqZGETwDYuGBnod7+1zIInVheu3GM5OopA0Pwjt6pIzrmHeqXuW0AM+FNS95yxGE8+wRN0ANE/M/kSP2mYq/a/CnHm64atK7G2hwnTU4CTojkFAdRN9QE8N054p3NrnxHQSjH8pTUtTct1YwQcA e=found last=16 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAZFhQAJJFpNuKVG6QGZcloJrgz60IM7OQGjHwWmC/Mg8LBcbnsiRs+lanBKHEItROd7oUCdKBrYGA priv=MEcCAQAwBQYDK2VxBDsEOfIYh8PIG3wE9OODSiG21R5Ge6zI2tTzkRFLLZIYrVwYIMEWaNpvO53JblmNE2ui7iEFZuxsWFK+SA== msg=SGJMlaoN1FbLlz6WddmaDuWr/wnf1HK4cHy3uWHwmvPCTANyVX5omazdla4pm0MICvt3w/EGLrhSj2KPBYmcQg== sig=Kq3Sy6F9AcwufV1Y0yeq3KVsfyAwPoKqMPjy3Hy/JqSpEXBqhr+2e1jlpt86kHptV7LoE2EIzeIAleJhlDXXawSMGcoJZM2MM8WkiWJhaJYqEBjeK4zRSo7buyFKVo/nAQb6zj6pyr8ZwPblMp4qFQIA e=found 216 iterations",
+ "pub=MEMwBQYDK2VxAzoA9o491YwGuReuOE/i1BudkHHlltV14+dZRBnFEP8Ar/C9fLxqdabArT34qxnhx90fCK8Qj9bXxU2A priv=MEcCAQAwBQYDK2VxBDsEOfsy4CxcGkSmXXNj4Yt6SX3w6P2KDvToPIT5USXBfaVPqXaVp2L/GPKsfdU8y6MjxlnaDAP6Nn8Xgw== msg=WTDHTE8NQtynOE7lPXc4jb+WNtF+quEnYPMyh6EumuEXUaM7lZvLLVAnJuODYjeiSfFHgPafxBpk7WOldcNabw== sig=/kW3wzfyavdJ3q4YYD874CI3YSVAdlYHDLM1eJtgisaczQGLKEj4jAKRvwgfGNMzk48Nb8F4riEA1JsY0rqzbc0ezKOCq1ZsBIVi5nEoolxl59Ibo/tF3351ae97J4aWyb4Hp9+z1lTK2KefJe9MigoA e=found last=19 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqpBfyvp42Zb0aVhwcrUE3Su58oemoQ6XkZMLx+prNvaJfH/HyXTW8auzGd6Zymgebodn+30q3DkA priv=MEcCAQAwBQYDK2VxBDsEOVnG87syHDjitafNhTl1w7KfDDfu0MVsC+PyGF2tSxs2wcchEVpWVu1r5Sg8DQc84EdpqTokEJuKNQ== msg=UWqVeeSglkyGGAnUVmCzNA55C6nxelMMYqhCobAEkNvyAjGCqXzCVCE25QafI9fh/NnFPZZY80tjVFD/48Mm8Q== sig=9tlH6Khf1NLO2lfcGjXhXG/CEJLdt0a7OE3AWyqM8C1bWhuwvnFMg9YjcjC/xOc71TGSsgjCspsAoh/2l3DNTvTFdif3wd9FSJd+od5l83X0FEEUtR5Co2BvJRugVpnJtX+GVUTLcz94IyPNepCsqD0A e=found last=17 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAvHo5tznOZHRWYyFrSZDIgeLsYfkR+QtQwor12vzNwNHFlYM6tOFWC18o+HkL48hiOovrhXZTuNKA priv=MEcCAQAwBQYDK2VxBDsEOZXlagCREkuEfNKD185gddlFOK1wa6yvw+uvGMo2j/d7ise2BWBq6fhfXro6YWyEgDneS6ObULoq0w== msg=yU45nRrQxHcRMshEc4aW2wXg/tsbmrzF5PzDQagcHa9Jih+3PMKcjEPZzhwWeSj6OSCVP2Dxjk0RtoMFtEd87A== sig=ynZbLrgsWvR+scuNT6GxmEyknB8/quLd3uU+4Zer0kLwWta9PT8fn5OuBd2T0Sg7J4PeD3WgAa6AQN1pNhsdd/fwOeM21ENxCYYebqbFRNjq5EqsK1I1Iy0XwiBHNLBGGTIbJxsoEecMKOngn3JW0SsA e=found last=21 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAgGF/hK5WWzTxKrpL6iO0VTETRDKuBVc9esxLKy90tO9EKPZmtvxQAOQ2lk6AuGzxUrLAQLAHbu+A priv=MEcCAQAwBQYDK2VxBDsEOUMa9ltV4IQgbz8cyZymdDp5/PI7dkdNplton16vJ1ovvkUNKqYlWaouwCK1CGmybuR10q88Oju3GQ== msg=euDJGiZNeMr4qT7rAK9y6/nVEMvBApZklB1uJcfPqSTov9LC9gj67HqR2acWDw0j6t92LpkraXs5wWAUpk28gw== sig=5uBoCjcho6lBHeD81ddY3Go7CJD7hS4ailWts84DgKSwI72zTumdNsrFHY3Jqlhr/0t/ClgIVkeA27/N/g8mvNZx90C+MfIqnT4fvHWYidrWLVaYJuE6h3VIl2/pfs8hETLdUHci1KLoDQUWrt6VFz4A e=found last=23 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAjm88DOVuaSsemJ1Z+PnnSP663lAWRYxCsmxIDpCB4M0OM7lcYQtUoofMvnFWRva+87IXVA9USZGA priv=MEcCAQAwBQYDK2VxBDsEOYNnpipIr3g0kagE5PazYqQj/W12AySaVh7cJKz/ybi5TXPDl03myIkcvOsoteC99ykFtuwyJIEK+w== msg=qL6mkINzB2hcEbAvSbAjI/8TxQKmJEHSpmuaZeRgBnm5xbwuFAMKu/8Um0qt7klSjUfzKRAW/Y4ixOqj9qrJMQ== sig=mjF4ltnI6hi1GoSlO7ag+c8zpGzj6muW788xdrIdGRfunND2zbmcRrOiJgrJMzpleh4yXnqEeY0AmajGxwV/gjc5RVR0jWly4cVGBKik/+2ldq8bzAN8TMDJzRNeqMQzvtC+nmh4EBc2EexEWpfTfSAA e=found 215 iterations",
+ "pub=MEMwBQYDK2VxAzoAGlcXgs/IHulZ/WTgDGDNcS+CyD5udLK3atLWVpYVZopvuxxO3kLMFXrIGVUFs/IfOltlTeQES7uA priv=MEcCAQAwBQYDK2VxBDsEOcR4uC1kOv292DzfPcFgXNTStMfzuydr+bAAfHdd9H9w5rHKsV4M0z+KPjRJ4pydaVqq7PnA7IQUYg== msg=8H9ZSIQSkG1FSoC/FQUW3CAA0tvUCjCfdkQZ8j5iaCcIhetwZ0/O2n8774ZNtrFpSgQBPRwqMht2nYlBF3g+Tw== sig=hHEhloQFqTouP0tgiAjIj9jw5QA7O1aqZV1uyREWqP3xtGV9pXf74ht2YVBArapu/JkKGngstMcACxG7V1l6HxnVUBvniK7q8AsWvynm8yrhrwFO4qZzl0WAbTGraXOYTUcj9/KJaoZ36DBomZZh9RAA e=found last=24 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5QfRPjZ2aBdnc0ipmyMOXnpH0v/9447GuLUbp3H9qAApquqLjr4/0UekSr8mQxmRSwIBq6afgbaA priv=MEcCAQAwBQYDK2VxBDsEObNUjThWtpDUKXJ1R7jj1b4NJXWyWOhzjRRsQ8cnGo+7OelTLRvulhdwJdm71Q62Hlb6bUqY53fsfQ== msg=pZeY+WrQQrZByJ9MwdTEWejk9+4wFla0ibO7uyZr2LuQvTZ7AFGZtI/ZRw0jvjfElb1xfQUDrgUlt81u/Phw6Q== sig=UaVX70VFyar8RqOj8e4dqbBqNL9wbZrqrTcgZ9O1E95Xf3Bge0s1ph2P5mWSO0Xd2q83CDFF1OGArzOab1dCBe4zx1u8abelM0O3EAex/HtQXHkj8g56sP16W8KDFnEcLmbeCAFMhywkGxJRJukUsw0A e=found last=22 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAkq5yzu7qbAHEqPnYt5kqkSn62rRb/SyQYced5dy2zv3VMJBoGSJoDZPyFzqsx+QYpeVbKg2nNrGA priv=MEcCAQAwBQYDK2VxBDsEOaw1P+39AiZzJ3zGiG7BiF9bJwfCjezut8MZxDxkhO0ZX8DJAU5lOl4TDmtbgOU1OkTz9Bcjw0fOZA== msg=SM7QHfhnCoigx2IWH1F4ZgLVTpFLVvS60ZISqYxygVFCpeAhMvWpRv1oBXkVia4fR1xl8FLyIECGIYQfTT41+Q== sig=sxVKzZntc4FoFdGh8XUbRXkXW54A1wT1bT0RBupupT6D2AyD0GrhcFTxsh6ABMm7Yf8vGldS+ZwAmhzgKzk4+e9333r5w+WJUjGbQaraopOAG63iahP+7K4mBaBhUtiGamSNfCjNGp107q0RedRhKAYA e=found 214 iterations",
+ "pub=MEMwBQYDK2VxAzoA3qXzkODBHljXKdad+YGBo8cWkbRD7zhklJ08vg9QRWIddN5nNXHn3kK8Tr8StBv+GmgO+MmT8J2A priv=MEcCAQAwBQYDK2VxBDsEOf/svq/cbwcRJB9sdh5RefOKpRaeSDC19h8MSxtI2ObdMWwrLbN8f4oCvnBSoWovJgzPM3jyALmp2g== msg=IpHHtbxt5Lz6aDb8fW8PbAg8KjlqflJN27hcHxrZmpAmxMMcNkRBsUY71u4a7NCgcS57GvhJcOWgZnr0iGUg8g== sig=/YQc/vkusY1sJ2C5wm/HCCwA4qxvz0ZutnRzVX4k3AtWrBSqxk+vW/tZ5RL4NK/KhB7DaZT8vw4Abb9Xiv6HFaLMf1jCa+5rPuJteNs5AhHFLCD0nABTY8OyHF/Qq4N6magHmaxGIMUdMuGJJORGozIA e=found last=26 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAAoEybAbRQ4/2UbhBExhI4qBwr0E10nCEb26EmoYrbJMuSw0BYpi30q9maytJyuBQV2qj+HSHrxwA priv=MEcCAQAwBQYDK2VxBDsEOVej2v5wJsdQ7Ut7sNVK4WFH2rlbwmz8O2SppeCYh7ltA/rQO+G8kq85RYgJ7DvHiEXvFVCiQN7Hfw== msg=p7oChTuXor4Ri+KTu4kjKo6RG+VIJ6uzTq1QsTc9oiCN/43bCTHFzRFaj0m5E4+32HrdVBoTwNcxzVUzTjPljw== sig=7tjKuMxnn9xy0KGh7fZD+j12d66fWwRYK2o364htJ29hvOG6xHdoycrdXS1TWiGRs6BDepUNE3uAeSs2MBMSRTzDbAzOYeklw0SAkcDTSvD5+udI5J2oSh+raeQdfZPgNGjZV7Dw/34PNMgY4ArSvCIA e=found last=27 s=27 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXNxreAEKCuwddkGW29/VFX28QoTyGY56XrIOvAuqahL356btdB7v/0c+Uuep523n02IuZez71HIA priv=MEcCAQAwBQYDK2VxBDsEOcRW8z459NB8wZJUp3wOEkA6oWDr86vk+gcmhOvdw6T0cjKGeieKFF48+K2yXtvIDE/oabuz9xAatw== msg=F2RinXjwo6NJ2ZPd77aMUwFxytHQao5uYeD3aqGtK+jFXrh8JAychnX7qZ4n7vrbiAg5IRF+2ez58/mgbVFgHw== sig=WFMX1OkOt2eTMbpobQmkas/ojLBy4XLq3JDMcIpDxi6TgEsyydq3fhRUGeXPQOq2MItjTe2qtxWAAflL/RBVUFL1tp8G7uzA60Ol1EQcqLiIayYTTN266DQ8Zo79yZmkhNvM3EQP4WYtRL+LH5iplAMA e=found last=20 s=33 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApzHRLYJD9lssuZD78DH+jOugBnghcmTv3IlXaeJyrW7WtQwpOJy8osoWjaUz+IRak2fF/n5p/WiA priv=MEcCAQAwBQYDK2VxBDsEOQ10DfQRh3PMIn7rMINLZRMsbcOQD6/hEyZ2R5ZmNlekJFTPNpxcw4aKT74jnEEq+l0nDb+ljouzfA== msg=DZGm8EmEwuCpFxxnVgNve3pfY2hRitV7UBt4INSNIiIlYd/30v9y75u79HS3iAJHt6UjO8VHdz02Tn+G/SoX9w== sig=yNgIL74Pvvjv3/279p+RhMu30oi3kVwU9HJRX3AtGnwfTYV/E/pciD6YqucXxYE1f7gHxNFBA4mASvp+Mi/+OSS0fuQGFUdEdk/INHG6jJRCoBbS5mn/8O3NWkavNMv5QJJyb0fmrF+zPlfY8D6QuyIA e=found last=21 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4KDWvJx6eGoo6Jx3iNnfL1KvoNNhF5est4XeUjrRhzo8QUh1bqN0rU/oXYEcLRrA4rjIh1AsqaAA priv=MEcCAQAwBQYDK2VxBDsEOThQQulKdVhLlcQuxfrcUFsGyL3q1Kt/cc0/LagX7rlxqFw1rncWoZ0qLtGyNlOp1stV3yTrzw6t3w== msg=T22xk4SUdAZMtaKmfwAeEFklJpKJ5IVhbC7cOMi0xBQ6J8/imJzBmyA4dW8si60vl0kJ8J7UaOOHY3qOv/O1bw== sig=UCBhZIh2+Yi1TllCB+9SGp1s684/JYQk7hAlmEUS1wk6z2HnNFubNHzZ3cIRey/s9rCy67KOsgMACs5miZkKAJyxIV+sLLhRUBabgcNDW7kTOiR8iNAvvm4TSI2uHr3We7otXlnn2mSNRIr1JY9IKgMA e=found last=21 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAk8Z5SftUO/rtr1lj77eHEyA/KxwiJe/dxiYB6LOqi5zcdNN/GFL6+Wje72ixcVbZn9ZOKae3M7MA priv=MEcCAQAwBQYDK2VxBDsEOR6mCYL02fQWBkim6Jo1gAbZ+XEADEjyMMgK7aY0aM10BWni1/KjnvNXTeNtnV+v8KfFRxzEKTu7lA== msg=o/z5FqufkTJA/5jZ4QSyEnB5rR6mCYL02fQWBkim6Jo1gAbZ+XEADEjyMMgK7aY0aM10BWni1/KjnvNXTeNtnQ== sig=BeW63iHDuLhyNNWFDceIDb3yZ5aHc/Dfd7nGVvI0l27KVgrQKlZRw8937s54OINwWfp2B/uQNFOApxD//XmNe9j8QQqo2NwWQInRE/YwU1TkgOZXTiVoHGZ+axmZLlKacbj6vpycNsx5g4QGeG0LNAwA e=found last=18 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoASB3gFDs8K+fmTCp2T+2v8jora3l3FFfZ6vCxXl+aonvBd7zrnjAt54A6o9+5UXffvimBKktBcsUA priv=MEcCAQAwBQYDK2VxBDsEOaGRpLsntDmKaNMrBakVkIZhMXRoa2Zc9M554nEPi0q0PrOwn8tOVF2R+oRTBfOV/cOYh6q1gtCNCQ== msg=xiWCcOnGUDqkfbeTRx+siuR+NrGlhV+JO7TcrCE6cQ2FHzEK/HRCIGIjoey5ezwcFcmZdVSpVYPu66ITgp1vqQ== sig=uNcen6M5E7FYrC35cTAELZV1pEzxzc9Na/IUDqf1EK7NkNs9rzAdj0uIWZoW4KYph+rLgm+ZUGwA0GQdqFUQLJZm3GoqkYpx5vo6WgG9lvN3xZW8zlne4VNdPVpWWyBIqd01ICOP6UyNi1lripQuphQA e=found last=16 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXfJ6RQfm+4qMYt1yBUt0Fdj3SVNDnbPYGH42DDJgZyPW3HJTUg3kqwnOuBAzsPjYI1Jtivo8BjqA priv=MEcCAQAwBQYDK2VxBDsEOYBAFg6c+Gqu1InFJwX+0z/SZK5vGXgqiZ61Mo1xjML1zcX9qFCwCOtX+aQ+PNLC5SX8Wp26VEde7w== msg=SUdZs0BcbXUuWMsUtbT6VN1u2VmuLyrleN36ItD1K1FiRQlVZ+mqvJl57NelcagQLsRnVVQcJSm911eDRzISpQ== sig=e+5AFbUm5/kLnSaT63j2Ifi4hkDLCYro41z0WOJlNq6sW/ZyK5OPh5zLouf04/NL8GbtOgLng/AAeWWhiree1o8ZXPqCotUcAZqM6LgUZyXNFnNUgT3mSd5fA4plopWDQ2ulU/AivoNKV9v0Pp/YRSoA e=found last=16 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAucynSYCGAVztIppIrH9Gm5vLqfMfbE2AuURBbcbWNgPncg1rc5oGH/OPvU0CZVLcaP7wGa8scPKA priv=MEcCAQAwBQYDK2VxBDsEOc9VxNN+6F+8Je5PXlrRTrC3G7AuMNkKHuFapPk+XsyhlFkC/JcWbBs85v64++cogR8gDMgckt/ATQ== msg=vA+EKZxSErF4pwl8KXeeXRQu8mqFcmPJACddowqs5A2k9Dx2+C/66AgnaskoBCkvLzTC/s7cigaQmxvoaUacVw== sig=2r8kMjyIwYV1K5qAhMTezWNfX7S6KGKTBQOHrv/iYrL3gh/VK+wDBhDtqlM5lbNTgKclqy6x1hyAXiDxZcwhCEohfJwhzyhTJUMBRmu9IkptMrMOaLXceUlJjbch48I0fOj2WiudYmEItH5imCzjcA0A e=found last=23 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAnTu+uRQ9AEuDujQ0CViPxS/lMdWCfOJZkyT6EtTi/rc2gJcFgwdjmnRu+eAIBtSEbEg02GnV8CyA priv=MEcCAQAwBQYDK2VxBDsEOYwQBFdzy74hYlUat+Ow/b93s1ywMXzvlspxjP/yfTQkZmscye0j/MYyw0OP4Xcxk2fAYPZ4WaeORw== msg=KgiUjoKU2PAimOF80eeg39cSTyUzum+uOedOZHayv38C3pnTdDJ6E9zaHnTnUHTnYQ17USRGNjXy6sPqfkLQkQ== sig=nh89NWuT/loq1lDo4oXCnhWugIGRLg9uengUNJInEpg+fQorXWgzlmLXyWUwwOk1eUPYDEUIu9QAyIswALznmDNKH5Y0fbTDk8qwL8RCEZp19xzaD+/Zb7mO9g8/3hnsbcJ6eVBbaH2j5mBJF7ihEDkA e=found last=26 s=35 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJi4jtHZWFLpaZLeJc0OuJyo8o7eLAH5V+5Mf9nQZw8OPBo5W0VrwArV0TnMJMqTGdi5C0Ee2XdIA priv=MEcCAQAwBQYDK2VxBDsEOSo8lpD/B3R1LVNt4SY4i0b6JF/VJpuF1+F+ng3SwpasHp1hBpCfuCPOQNkrXkiOHLDEP08GC8+R/w== msg=tB3LNeo7/lNoHuiRMhYOymFhqSQ0Cw1Hfdw+anMltFH3dwDHXQgRKY4HC84ygzqxTif9eoQ+Wm0tGsZzyBmdCA== sig=BGwlj95YKntmUsody6D4Br9kNmWXJbylQsSy69uf2fRA9laNuN6v1xLFaXn/qwCEukShM1f4XVsA6Z3sCdmr8gvOW6cPFwE3mPMd4scLjCnp6JRAJda/9hvitPBDgQdJDVvEtjq5BS9n7anjiPwbNQ4A e=found last=16 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALVa0P1LWYB/cgzXPhm2e3UPdnuWqe3T6W4Rr/A3yoU/amF2mGEsFXAXW/93eZ/y6OCg9UBX2Av4A priv=MEcCAQAwBQYDK2VxBDsEOaVSdW4w8687maNSzBS3GAGoYRDuORl1GrkoI7HunMMDvY7xcFqA0viw5WkOQ1rgo3R8Nfq7Y0FLqg== msg=Wb+JqsTUcGh3PDwxkxnczqXA5+StdkzjlRaMx1fIkjhEf67ClL6zXK5tFpdbKp4MlA4+psfsKa62A/AZDuPDtg== sig=TtO/obZACC9GQQWVdsjBVCG+nHBu1sd0qKO/6fp+gobjxwo9ppSSD4o+IDFsPTUFDseVEibIvWCA2FqOBRx4RgOe8M68XdA+yL/bWht+YhOoVGIxWcVhpepDILW31/na9/aG8tIbCqZf80QwOu843hAA e=found last=21 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAXkMfafuhtlrUpAz5apR+NZnG/57hkt1c49ovQGB5vZ47ZKfp0Iq+a5FKJREYrfOdicctREdM3U8A priv=MEcCAQAwBQYDK2VxBDsEOfQ5hPwQSDk6t7ej1Tr9FQBAUuGRMPBuQEcY4WuvtUXja0m0zKzgHigS7VeD/d0T5ScFxV9el28vwQ== msg=IDExtJC/xsEXaUwO4Hi4XwTFim+8HKY2+DVVa+CgozrYr391jmPsPI/UZhm6kSMIRbvo8jIoThSvY51DmiZFJQ== sig=avGkVqlm/KLl+dWNgIPJbWY9gerVLEoY4GtA1hnglQTtYTkAH1hr5kec4YEXFf7ytONLXH1XxPoAxekTukxFLW/0aeSoPLRbsYmiiEc6xT12Z0lq5hU/kYIzngBPe6cXHK/D1JXvIR/QtIQ5waf60iYA e=found last=22 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAxyzNnT0PQwdO/8w4IgRY2qdOHbSllp1h7WaNcAmii53+JjUXlVAUb/7lMxg4GH7hlsPIW80PwHCA priv=MEcCAQAwBQYDK2VxBDsEObIvZxJ26R4/YkPjjAnm2VaWncWGxprldwHiSmTc5AfBKZtxHYl6KWNyI357cY9gMgdkUUPc5rm0Qg== msg=j70qRfrseGPX1drlby8vaZObVx9yi0kH6/HGtBh4zDAUrKe/AAto8jOLHnR+k5euAkI7BNwxEoj2C43AMRC7nA== sig=2LmzMLz08KNXoRbAsW7IGx60sijqVd6KYlLHQpamR+rJkNLMkMm30idkMh0yzJlHEqX4KcIgszEAfqsfdFCjFQmSUyha9fTMZhV25B2G5lVkl5j9QL23wCLN+OPHTr17eCSKmLB3a9mCi/uHitnQ/zkA e=found last=19 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfqr245RSmVoMFWUuWBiNuCRZ+oykmsk9AsmXF5cjfXDNBepZaeQILtmnnj97xwDNL6tNBzseHSGA priv=MEcCAQAwBQYDK2VxBDsEOaiTW/2zDRbdnZLeoa57dIFctHkbU4tba6CqfFdMhPUs9vxEZCFNyc+brSUjK+q49KfgXOT1kFNpSA== msg=fxFMBdHbtIfOTg9M/NpZEpPveZZKXb55MWd+wRJmi/32c+xY3dXeiLb7MehAxxYnC/MhopfUGsGxgmMCzb+Fbg== sig=E5nPIgYoKOoyMYfAh4BS6Gj1LNOomTjKEpaCXhZMjgoKHxaM2QZSIPtyrIvDaNgXtaB3m+ZL5s8Ae8iUoEqI6Dp74KcxzTygSd/kS1nroIUwRHodKy2to2LLBRI5JBDFcHHgYqeKzIOwL+miD4s5mA4A e=found last=25 s=28 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoACyz2+RPQS826HcKbD+gR8Oj+d7M400SdpYXQ0lMWlBVT0KEGqg6cS2ZMNOvWMvJyQNEEogqrwkoA priv=MEcCAQAwBQYDK2VxBDsEOVsr2NppPJb2hpztdlB4IWLrD/enmOP+NwtITLvvikKUUHZq5mSeK6ZWc6VpxL0VHEk/govETgvYEw== msg=X/jXAY5tkHBqi27f05RC0hCxGegZ4o3IQwPpP/jU5Ut3tBqTSsmR3XIwmGbnbeJLZdjeo5PoVI6RVNUhjlKQ6w== sig=QaZCD7fASg9V+11f6AGrVS48Q/wMZ7WLFKQg7t0mC/tGKeBAyeNUsckVu9gZM2JFmWsVLm2UarAACr7ft+rTt22Esi13SPxGSCFHNSkiHAgOLcwFmOi3nfREgYJQB/8KKcUaLVQIiRKkhzmOoT3qeSUA e=found last=16 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMiz09cSmVct8L4zAbV58ZAx/QDXOAJnVVlP5ZaGwToNquI2fiBQxYJViFgdzlJGKtYYXXubXOFiA priv=MEcCAQAwBQYDK2VxBDsEOVaoryXsVJ/U8j+aMVSLNssrMEEuiH61V+LYgXmP7uxUJTrF+RBQnAPG782t+hpcgsqxwJf00iwmeg== msg=ujRKVaq1D/X9sz2sMqe0lwIbmzmEDAiXLVC5jY3N4+kw1RJAZi3jL72Q0/U00y//azm56cM+u6zCb8eqm9lCQw== sig=qUWHDsFafhmv06CNEdEBxKl+GzcSd6eGl2jz4Jbo1lbejmfxZFlygJ7GmH2BAH2wrT4bMCRB/tMAsoYmXgP5PvT3Urg5599TSDiUkbWP5x+SbpIJaVBQM7Ht9nJHVp/Va1G2gm4tgcw2ERgR6ooIhRkA e=found 123 iterations",
+ "pub=MEMwBQYDK2VxAzoAM2ps0FQSkuWmqjz6HaHVhPv0TfFp/IHxBPKggBiSzPJC9iwZI2eBMgHkEvLoNQNahsKMA2n0rxeA priv=MEcCAQAwBQYDK2VxBDsEOaUSKol+CcO8C/xdT4OKz9JXioS9Qohep5ZIw4mb/LcpPHVo059vy568/evr95P8u8sBUbZYu2PRiQ== msg=AXsRsCQnhArPf1CT0X+4R6auo2dP2627og/c1mKgyY073/HORErAdntRferENOEc3JvMWaBBt0ehm6rI08VcKw== sig=g3zU9F/SkcnLYceIlcvP9JFx6G1eF1M6yKVWh7mwL6X158IayS3gtSsp/7kFeMN/AFdoOoNMtUsASXbQ38ACYf3Mol3gqm7pI1eZXFZLyY5qR/kpIeboe24s/0HjMqkDpaSoLm8w1K4OBz/DkqEXLQIA e=found last=16 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAt/U/lE+Ye1eYBlUZwt4m5Eu6gmd9cUtA0Zxgj+nyDmYSse1Uhn+PtCrFrCtL4ozVP0wVe/N02tSA priv=MEcCAQAwBQYDK2VxBDsEORBuHqpq/HqHstR3fcAOp7S85iuy4hx2npo4W1QA3WeBxQLpvN1aol6qkEzT5JZyhLy+4RW6oCSjsQ== msg=W8Wt60AaLBc+UG6muIETmlUIrzoLbRFQ/pevQDEUCefAMcDDPrmrJQIHFpbyswGfbRlGv2oh1BIrPn6v7wWt3Q== sig=uXOjJZoAl7oSrS19jlE49/wtIhgaU1xICjcCbLv55CDrYYHgZ45GOTFkjV/QzYh139DhRvLDVj2ARSnr8z/1Hd/Vkj0bLcsMTkZ6lTBab8C88Fj333cVfWcJ78dePFEBABC1HjZM+VK5YezM/+f/EyoA e=found last=18 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAc2xR44B2YITt5U5oY/S+oLlhgf4i63h1pRvCtx+o84hgoSa4h7taMIheJI+c7h1mvOko9ApFxRYA priv=MEcCAQAwBQYDK2VxBDsEOQDYE5NDODEDyPG6rtNYCbFKLHOdG3cJ5mADBKwqdY8bND0aVugEeQc7P8kK4e1rdaebmA6x9WFqtw== msg=sJzNrs6zF+I+/9oXSLEtYgxitvUw4ztN4L2qs78MwlTzUPAzEZ/z7ksb2XMmVN9wTFNHrbPDrRMShJXW18NssA== sig=NJBIBQsK9cStUOlGgxWG3oZX0VGoKafyTAE08NMA3j2Zuj0Bv504CsMewpNWinWQ57t+VqaGUtGALpmrgy79I5yAuUa2HcL7Duc0W6qHWShYzXJPYVcbHzP7xBXU3L8K+CnNz1lhdFPUvem7Wa1kJz0A e=found last=17 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAkooTtoRFmwwsZr3gPfrd0N6SizHceNx704QbcV5fOyWSm0fSZl84TSXB6ib970lHf7umKUWlTr+A priv=MEcCAQAwBQYDK2VxBDsEOdhgbvLg/Rxi4YzZbSQVPPO+HhjgsqNUrt16dp6rcZEFID0dGPzVw18WYad8ZwQCAkyW607wBnPJ1g== msg=z4mgC1yaXemf8LLmEn/z1ORLeeRABGMYM0bQcWYtSsSOqtTZHfAEKaQn0R/4bDfKE0AYjYirVlZx/1rRhx2PLg== sig=1ECwyt1Ae8c+n1qW0ey8Xj6zpkoesrGCJjx9W2/Tf02Ol0FIQWdEZ4GdsrskAJacYE4yOuPV97eAQ3r2a/Tn7TixECNC8A+K1VBDca92Cpbpl3DIpBBje0pWqbvcGUjlWfETugYYoqpX6/6RQsmprQwA e=found last=26 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsB70sHFiRc4zX5b1Z2joO+Q5hpJFh2YID8lqrslZGy5RcPuX49u7Z8VPgXxmum8SHH9/ErG4DMcA priv=MEcCAQAwBQYDK2VxBDsEOfx+tXN0Y0ZNLFdXGIyxFP74ZAxOkfbqKQPx/ti3NffB7rSldpwh+1bnfpBjiIm7qvuTv/LVZXjslw== msg=eUWwPOr5jelb2LnQE3CTyw8yisqqEoMRBRgE1H9KGxb4/Bd4ddhi42qg87uXlb3G/Fgx9fideflxRv6HkMA5Pw== sig=VEXclZ1iaew2MKEf8dWdes/4QenUtYLdQ9afLZmmkb7R9guaddU5QwZGf6uE0CGfVDoN0hp4wvmAAIxUZmAnEsa5c1/X5hBVXYXdYyfh0fkA41dTu7sW+qv1xj1LpBjWAp71xyVCaJwI5YtFEZCiZTQA e=found last=21 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwMMcLKqNfL9r5JuHQ39FsqCVCzWzFITcfHdPCQOmzxpR9olLJNMOtrpNfCnPTGt1RKgMyfjRtVgA priv=MEcCAQAwBQYDK2VxBDsEORrBLO5NlczxQ6308W1PJRSd/Gai3Noksrukc7nXztutuhqirdbEdfjh5bTZuc+HRo7JfpKxuo1uTw== msg=41Y5rA49YTlnRs/hvQogCrZ091I7ZTx9wR7DTdASdsv1Psf1ywf2cXUAquoNGEtRnni0gQqDTUiKz++6x0ZztQ== sig=AHR886H+zV/UrXCW93XhxkoRiyzylEBrEaVgpYvW39/6R17UWJW96zeWQou//hCf5DSUbxV14VEAkeUdtPCTjdIxG1Ptnu72AaWNBO4gxYSVIZnYOmkJuNRcpiqlCqtp+43ebFyeNg60JGAAOc+azg0A e=found last=22 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAbpxSIg3Sr5YQVIGAEJRxjrlhZjiPWgmSk9mTcvP5ix6NDeaHzPsmokmilIN61BkHfPGGjol5C/gA priv=MEcCAQAwBQYDK2VxBDsEOdbyUwsrRzMsvXo5ULaR1tE/YL6XQfaqRIPwcT7YuwSoQWOpekLfSj75G6sL5eCzkvrdc4tmcNdi+g== msg=EG6kjm9k8QKWzzKItUyzYUid5Itr+CjK0L64LnXUkyezL5RQTg11Aff+cdr+9yBAaoVG+5+oWxpc5TZTa82/Lg== sig=VlpgEn87VdU/p3enS0IT98RnRZlKWWRaGK4d/1tJ1YEhkHM21Cb35zLWcyJLPlHB1jXpJckF+6UA4qTOCbYhE+Ox3VkbXmFHTUEfYVaQCqMm/pjda2lS6QrbMdkN/ruNz+b/gFWmkesOpRhbSO7r7A0A e=found last=27 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAsyyiWaAYZ6E0hwLpoDylPTjIAZPQIMZ/wx76sSFeNGiJSdtICT7dCX3+e2wMN6mE9iXqg2BjxZKA priv=MEcCAQAwBQYDK2VxBDsEOWep33Wf8XFncMbsV3miHekV44RAFCDYpTCHQX9SMICXHc7lDE7UEW95/t2ITbDH912dHYBF4unS3Q== msg=rL+YkHKrtrwpzqG17PoGahrcmjnFr4nj5ecHOKcdtpj+J6liluTIVO8VRgT9x37A3Cl6PpmPu151Sf4pD72tCA== sig=l/K0P+rOeUcGxNyUDFc3bVzf2txTYFjoATKXVjNWvqQqiQfAauCU9wMjSfTxqIyITZUlc524pZoA4AxO/gr4g+J96ynTReuD+m75ZYw4mTI024IzsRzEYPMxeEUbQPCQObzyoAJtL9mVTO+iyMrZIRcA e=found last=18 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA8j/9W36My4BYTxRJQtSg4yEhTiKAzKCkq8BXqr8lDMPyQJ3jymJyDUCq6KspzI5GVjO39yYIYjKA priv=MEcCAQAwBQYDK2VxBDsEOblhxuzVzlPOJQcQZg2nOJI0Y1sS57Bg7oq0FzSzh7rEdumoa/iWdTyZTrnHqvJ30vDN2hSNkerE9A== msg=TbFwE0yvpowxg77Cz08FW3eD8Nt4HHn17pbq+1RZDAwIFnsNQGk2wlKBpcfIAk3BE/zx3EHZR7pTiAe349b2IQ== sig=zJEGp+Gk+n6S0EL0ktg6ZpDONbO/TCk0/pionbnVv5wBaqI1179m04Zp2FMIxVqKuDPYiSSvat4AqzDGlqnQWfr+CYTUgkVE12F4/Bd6kAVYi2mKVK+9/MrInT329xiAc81BGWgOPf59sZE4dE2OCDAA e=found last=18 s=27 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoALP1t5iprbiA5Ldxe1iLdratUz0iS+OkrnybTTqDnGnEmQZGmgaMslL/16eP6EJk4yNQdvLukpLSA priv=MEcCAQAwBQYDK2VxBDsEOamziuKFMxy/IyI5Pkpm2Btkmjql1l3fKp95VkBKKpyagfSgDTfI7ujRXw/Key1DFncOmjQy7zxnag== msg=SP7E6wakjrquY+N+rD0jPBtZekgzzP5vTUtIRR3iyKY8fTOhiaQMA/1ErIEVprXzuMHL80pB2AJISGKWKhm7jw== sig=Y+17vS9xO1ZmHy2DLUwBQ5ezD/eKUJZfubg2sNLp7wL4icAFSBuFcR9YmS8IkHQNBeEqbNPzb/WAFGUYUY150YuYWCxV2VIMq0x5FCZ69axifL1VFq81nqquZztOZFN2qfXbjqwM4KqtMZLrvLELswkA e=found last=27 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAPDtUJLc+WGodOXmRtUkTJJsquVI1fxkbbw/i1/bV7nbfx0anSS/IOJBqbwkjbDFfkaZj28UCODCA priv=MEcCAQAwBQYDK2VxBDsEObjfZV+plxbhba3kJT9AEDU8YeF9VHlZxn9cp/Vm5OqA7Gs/fd40VFOt0TcU73AQ2kGmf+Fqh23cbw== msg=6dyJ3ak2iBstLvl9Vf3JQXwzB1KqUe1LcF/wN5WNvNnRR7TAqWrYwft9Y3gUlExRTwp/cf6rDjXCi+aHuD+KBQ== sig=TOGko0FxQJ5+kmsmURdr9+PAC8jbGmcvzHPhGHdJ6VJ5l6RgaDSAomKNtpx4ZmeAuIKugghcQTgAHNQzJfYtuCPtM8Jnz2F5Iup2i1CPhVE9zbgshNFKgULopL8trD8SeP2q/0GEK972rnUk3A3tKQ8A e=found last=27 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoADN63UYfbhbRkNT91J0N4cMCrAPwLN45q6/grjwEB0FLKS2LFHMPTb1lBDZFBSpm593HqWLCOQ8aA priv=MEcCAQAwBQYDK2VxBDsEORdF0ofl9MyU94hkcUkbyeUc5tUR76sN9MbA3dxa5XKB1TH6KpOMKNnC3/Vnv+gkAGpP2Lp/ZhRV0g== msg=rX26hls4EVcI7fQD8g9LbWIgj6M2sBu2SZCpHHnfZOOFiLn0/YaKu9Kq+FIfgtj/VUhrOBC7wEcjaUjeKwWgig== sig=y2xMZn1g0jFjL8Y6Wd6eWm42cgprUP+Qz1RK1VO/VPO2fYTdnJFVtzPiRtFAeKdu75MisOuAojcAQhHJsFovtM1dzM7DDi0CoiK1b42YkURgAzx4ty+vjiAfgtF95mvvW30D66yJk8lA77TIXiMf0joA e=found 124 iterations",
+ "pub=MEMwBQYDK2VxAzoAHSl1o+zfGRRSQ1cQ7khAyCv6DI1N/S2im+salqCCTvBEM1grC1MUzBr3Gx0qd0Iykj6HihXjXbOA priv=MEcCAQAwBQYDK2VxBDsEOX+eX0n7fFoRlfQKmclJWd3gFcmGQyZmfWGZ2UZZn08Bt7V9G3fFzDJrUa4z2SKdWlydliv4C4eJNw== msg=JVm3gGHogwAMyn3m+7hOETOv+iXGRdNklAd0ot/110O6XtY7LLHqiMLfIzjZQqHoz65Y4W2ajp0Mr0qHfzbuDQ== sig=5zGX4m+hpyfhvL4kH4erwp7iRnzZNsuCHE7oQI+mIU2WMhB8gLQFthhrrgRCMEZAZ5BJQzdcXquAjam1V36cVqZzB+ZvsdfvkkUUmFYp+DDwfz5JOykvIaPq0tnif1otekxpfFJJCZVXvyYyMOEY3BQA e=found last=26 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAw+DkXnbpB/ZccEc3Q1u7kZNGa50zFfWm46gXrS3fiXU42I2jL4uN5zMPC3eZ3XqLhMgFH3Of7s4A priv=MEcCAQAwBQYDK2VxBDsEOa605SAfczAk1ggtT8VlrRM7bv2jPDdp9xeizWtL7P06egwnigX7I9v9F9TtQYs1cno9BeviArvLTA== msg=ZF2i2V/anX/NOBg6L5x3vTdQESfk3xuLjg2XHJklQHcjGpPHyufsI+0zYF4im8jr9EJ4E2J50L7TeOKAsUH7lw== sig=rOEbjB8D9aOx+t+TaDbTZNGdoiuaecUvutDeV8z4ySr5Oksm7mE4mpKhgFyT/27i6O1EfgRpTOiAGUny0OjXYhuilGRjebCb9TiWZNBJ8rNBoxtj12Emly71+S/bRbNL3l4bCvG/ntXpqPTKpOO95CsA e=found last=24 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2qIfIgYjUGwrm3j9JpfnKZ5KiT+S7K9CJu6H5FcBdsfc3fx/+/VR+yzSlJnU0jLYsAzHsrQzFEOA priv=MEcCAQAwBQYDK2VxBDsEOXZdolUBW+rJPRP8u+/IyHAUnzwyPAS4D8JnJXwhDSnUau1UgeDHt1HtTYjfjk8AMrRRhg0aaTiWLQ== msg=gTjXAP4UzG56oPd+pIoc/3rL91pNc81ECGzwLuIT1zmC3bs0HyHW0eiPiFAaH2wqCrb1w0YsTj3WVMEH9Sjw0g== sig=DNbaonwA9+xq6LglnjVgif2nfVd6TSe27X3xahaDI3pnG2bcW3vC3WAaK7C3rEtQx9MKT3bCHVkAMpxIFv4YzlnI3MQsTE5T8Y1HLPQb58O0QQBbUby35pBD069ZZn9otg9HVXOfvZrgezjk8b6q5SUA e=found last=22 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVc7owYropYikjDSsaB4szN7T4x+oRimfPlSVDW3NWQcFnw5TXSM2E11wYdQ783T6jZ1YlISRV+6A priv=MEcCAQAwBQYDK2VxBDsEObi99BvIbxISTyiwQBJ94Iq7zzme/V18aKQcGj8jaYzyAkzQK8pszXIbamEghlXTMDrrAAEu3PmgjA== msg=qT59YFa5OdvUBRS5GydDLYO2dnWlvvukBEffydZQXEzDf5OSHA+BWO1yl0EdQmyDJvo/h+nYQsS4aGiPjlCyLA== sig=bSc6Cu/0s3LQkQbLtR3s9uxAy1N21kguUFJYrnr4PEPHuMvMOUJEs73XMjN5xsoOSGNAES7Y1TeAGtP1owlHIMeDveTJdTrs5b4srnoVWkm6cHna1BNiBEdJACZ0w5kQJtgZHqAN10tWJEjjPz+KJgEA e=found last=20 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUQILKF0f8rL93PWgRLLygibCUrcUKmO2WfrOeRMKKsXKDl2EjA11mAkyMAxDUrxVvmezHtJj8SaA priv=MEcCAQAwBQYDK2VxBDsEOSNag5Uiv3m9Yp46+nUOh8Qn2PBQa7JVBBXl46EcDrgha1nWA5/1XopMgzJIKkr6MiTf6Ka7SVTmXQ== msg=pcLEyjZyqMNDONm85afOk/bHkgvrnfaBv4Ja5BxbLCbSeM2lyj0Ivb7TNJqmHKAJlf4UhRBu2JudU73uNhbvcw== sig=jRy8kWRW89h2jJ//lDVm3P6B23URMBKIYOo0KOSTn0NltoBAM2LNcmlp9hf7oUFMMMvFoHuG4G2AyVl+4MVkgtFqEyuQEFDrg9uv4rHaAyKS+tq0B4TPEWS0gt972wq30xym46iSGylISJtaDON8PycA e=found last=24 s=33 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAA3wIBJV+jCYx8i48+f/WeefmKWmm4GY5nfIW4uWmKm2U532YscVnKE+KANRTtk/iVjHqfLz72lYA priv=MEcCAQAwBQYDK2VxBDsEObKlJFq2WvJFv6YKRVhYdcoDybbbNLflYAtVP1Hvvtm3vcnvCOP1oZ6pmDiVZkVaKDTEUkwbAXDL6g== msg=TeNZv+1wyaAzYt5j87qOPJH9gpWzzdvqCwTEO8NS/k84XjtuwT0T93rMQhUmcw4TeK48an7UZmIam7CvEnfxRQ== sig=vC4mcQT3Ff9xzYXgANW+Ob0wqE+5PagwxQHGWZRsN4EICPcie3ZiPaxD4ZpukeEHdMhw14Gj4m4AtSUY/i1+dNXu6mKoATYyPWB1yJhcIF2NcmjKkGatl2gGyoXV9PEmKUZW4mqnY8xqVazyNb1JBTsA e=found last=16 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoATJ4A1Cz0dkbpw+nN6owzWmLxc2FUycM6JApXxCuQgooySMUXXyjiMJfvP6d3vQOXize5J35OIiGA priv=MEcCAQAwBQYDK2VxBDsEOZc2MrlEZe37YDCDHf6LslSxBq83yM3prprViqjinqANRPVyWz1dxXpvhyTQUBKoSs3N5ayliE2pDg== msg=08wUGMkQ/eP15+fYWvByEXufMSFga0RJcTlIzwtktAE4iz6ObcVGeidcXWPgLj0g6JT+RoEpY0SFiSXvYlsxXA== sig=eWN+EaBzGHN3aVqxKbsK4IQ60TDxRwCp0c874PqKPbKoQnRAKi/khXnRWJVkgx77Fwmo7YIQWCUACaCLdzX8T1Ecyfcotq1fiCOv8+moTUM+u3nN7Em+070gVwb4Hv3ISKvU9nJhl9626pdJ41cQVygA e=found last=18 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA2+ukUgf2wZO4Uv3LmuHnRULyC6SkTPre5OTYpUyrAiu1zgHLXOBv6isR+x9UP15ZQinV63UEHUIA priv=MEcCAQAwBQYDK2VxBDsEOa2utg9l4ulrOfD/p4vY9D3cRISHyrochzg6s+cEVBvGewnN9tHjvG1THUTtRe3CK8VIfYOEE8tIEw== msg=SIBJePHokinNbs7Dtbuccbk9JnDR6b5Qx/2qolsT3k3/BcNKiXlkpaD+EhBj9yZ6AVxebWCiEhR/ra/eOq/arA== sig=mR3Ees8NjSxbbqB0V2t8hpVRmhsn7Z7ktQh3IwDmdI+ffwBJdNy5sTKXGz2aAvqHBwEgt2P+RYAAW59G7iFH7zPy9tHfFC2KBr1/4zVPMjJ+FCphmpP3Mg6l/7PNsPmoMJgaQoZEcX0e3K6Tmm55JxAA e=found last=16 s=33 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGE/PGAKzyQw5QF0ktLOV/WUyjoXLE1DlfkF2Bp136FmRcGOtYDJZeSekETyF+7U3LjK/14LfI/AA priv=MEcCAQAwBQYDK2VxBDsEObsMsVGzC5ndTmSqD8CI634lzh3eeFhkwadwEJ9MfjJltvCwZ3OHWX/xXSUYeE/jFn5taXfTBDZBYw== msg=v5YGQPPgOE4J7B3GErhK9gPUsz4CgQHkvmCpO4kgBM675y0CGDCNxUNlbujPRQPFQtdYwO5+gwGxFbwrLxVMkw== sig=Bc+gxF8RfsF7M9XrOvYgEHkKqFTJexbbzp4YxonKIfkW8yG129dAihtfCKkLUEFi6WDQaBKKzfoAqGEnjk+Ck8+m+GbC8Q4X+C8RmSr2feecYY9YPHvZqYldlY6hn57AAhEzn+FhkT/PRyV6eNQiUDkA e=found last=19 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA7WECMg6rRohfDMWcY17BfKaHVlCyFpoeTcJUlknMxTiQIrdhgwSeEpkDlITY7FhiRMREer05cE+A priv=MEcCAQAwBQYDK2VxBDsEOez88B2EUU8NaNBqmr+mD8+XBJCx22OXw69Fcm7CKpTEgQOUuQCnKTAUj73Uz/8DZ4dlxl68nIwKag== msg=0CPg/+LEdwZpORap8mhiu2PC84CWaof6l60X1iY8VjReWCeeD48kYDnDVpnEsUtTlScMGTCklE0xjlaWFwxf8w== sig=jhN7mM4RPSACI1jExSuOnz9bojcCj9qquJ/kfffnsZiNXqa0sIAGkHU2wgnzpvm03GI/oK8xZxMA4Hf2+oGp14JxKZwb9svfzRsC/DYNYUgMu174C8eyC5JHub+91J55o8XjlTe7Fvo5DEUHYcq1Nj4A e=found last=24 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAa/rQtU4lzMyrv7b2n97kY6lJXZcbFvVoPvcdhQjgcxVCsOp371U6ruvpqgkm61jLebuCKg5zgA0A priv=MEcCAQAwBQYDK2VxBDsEOfJlLW69SeqCxWCNLbtU2ugGRuQNNWCZTmTokMVS/waC5dYIpdz42tGC/sCAi1spSmsYdRtUWckolA== msg=iEsTPTqu+nMg/ejxEl+5cPTTDVZIKHTzWx9Cg5V1Yw/k5h9zWOPmrG3YJCl3ZeOrfWndeAg8+zKac/EpNopKVA== sig=m2U4uj9HOqtwmbrbsCFQekPpqkU+v8BzgBanwbsODfCOAr7yhBZRo7I96cG+NYFfViMFS769wbAA8uJg/9FnXPpo5m1VAGIIB1aY/1oos5vB6knbsPHSK5yDqvDZ9Cvf1iOl6wc8+4NhpAgMlXg1EjUA e=found last=20 s=34 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoABIO6bwKMAIURj1zmQFwCQ99s/S+kCAEwpC4kDcB3/oqBHehpbr7LoeX9Rqn/oSZvgm0SU1GVxJGA priv=MEcCAQAwBQYDK2VxBDsEOQnQkBQuV6JAORECAtWigj0p7sDY6kYTAq4NG8WWA/iGXCZKj8N5pmUjC0Ttmi1lQg+JkMPxw388UA== msg=DWr5+8fmCuAcgI12VYJiMksl8SsURVql4HckcR5aW9uQn45pcOlRlPp0pO7G6eu3WT/btKluAwcEun2PytTVLA== sig=lpzyb55kvZVPmeJq9L0sKcX1BWAaxtviysNlnX1z0X9ZmdSCo7sFiFHqdJkzxsIyu6Yd46iTZTQA9Fp9ALCb4TXHO9usQpigAshlb8RFnNcPabFe7xYPeNcOtxgBmGWfeWWD+6oV+NH7XvglslyfpA8A e=found last=23 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUsrURx+JkSY5Tkxo7OgpPJC1lcMCiALuxFgVSXWKgLs6GyZNMUc/pbAgbSqN6a8RpHwN3xhR/YIA priv=MEcCAQAwBQYDK2VxBDsEOeP+Qjg98PVat//eve8ssttMWqq6FcKohV1Iq4116Kqi8bKedHZIioJUoxzYmsLlbbULzKMQJveIVQ== msg=bgLZJeohd7t5UQ243uwyOo8ycSrPt99oAnG2/Rr1SxrJTzU/DSk3YhtJNKhaMxt6IAGommr2WEmbvc+7Mz3Rpw== sig=q1pDdC2Aqg6vPQy2uzx8m7NysYJ9U81tXGP2zOHGLyNAiBlQ1cXfVkuiP1CA1JUDyS42eOjrbE+AE1AFKrD04jZd0VCaqQQzNZK9onE0R65SCCpXHWr0mZsb9vDG8XJPkpwkBzi2kB81gMZqQxzoOTYA e=found last=17 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAAdSv0vBskPPFMx2B2btSwSiPA7CJdfD+P9inIotUsjlQ/1FCjdLUANoXYVf1iga4+sufspaQB7wA priv=MEcCAQAwBQYDK2VxBDsEOawOE1TAqPcYIB6MJ9oHmnB6ege8/J14FxhoR7QJOZ1zjvkofLDC9tSjA5B1Ks52x16DlSFqGylDVw== msg=++M0pNYqS5PuOyFjayiLmnxmhYbenkmsqW7no1bqcrgKDwL7UFIA6T8N71OwTPGLKw5WHu6HCrrd2bxsGobzIA== sig=xOZn6/swFWYIfNLRvH/e96N1Oi0fZ5v/dJWO5fke3q3go+2sePMP6cATTo+AgBEq1P9ot08kBiuA23YmEn6R4giXp86JfY9FRAbkQA2mk8OBJcR9/6pdJqJpKTdKyLZ1hZA5pUDZn+q7lJa4yGEe1RIA e=found last=22 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA8JXlCDbPOZCh3HWxQw2HGK4VeTV7gOKcQYI6pwwEM/9RBadjqcNuRbDc4aj0PS/dihAxQ2nwjC0A priv=MEcCAQAwBQYDK2VxBDsEOZYQUiydeouf7fUP+cuJjky7kUT9lrMo69Zh+IYYy/Eh5oLP7WQmB9BvwI5ruOnJT9vhkPSgSIU7LA== msg=xJnwFHDFPOk0DhA1awomHsuD7s02yG14EshaK87yZoROejXw+ait+E7lGZqgeTpN3VCpcouMjvTHxa6eZrh9Eg== sig=r3EtMQAwxRxbuNldngXcqqQDiS/V5KJrehX4j0xbyUwQhwOhAUM8nIiL4mD8GcDDqO2QsAfNrpMADdR1LfGR+sz0yUb6r+kPHfoaKusb5BHVCQ/B4SpMOgnuN5sJY/Xv4OIzCm5KJcOZd2R1UOIZiD4A e=found last=16 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA5goEoei4VmPmP7+XchK/xHF+8oXNk0RKW695MGhSzkmRlDmN0tAFm+SUw1MYlCuYIRAdNgVphRQA priv=MEcCAQAwBQYDK2VxBDsEOV29Nc3hg/DmMMllZ5necwYawGRtvMNPd+T8lhyHgNHhVHaginCwz1Zp3613FimPkcAoaNaRcr13lg== msg=NP15VRvFqZ1jklUYnQPviBwtbnvUyH8UI8RwOn0cLm/V06I2f+UmJG9i1UVBijWrSoqGIxfqazBSCIEwyVhNAg== sig=JV9KyPPHI7OWkf3f6u/+oJh5RjK97Eddj/GWtU1LqIZMQCthkEpBgZL0IZ9UtvcUIMu4/jUyzU8AY5xkfSip611Fr85hxXNGov1eB+vL66ZKNn+2ReunFHSa+nQFQ/UADDvVXK18q3OjufA8daCl2wkA e=found last=26 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA+6UZKzeyDym2XU9DIZF1CG0uKHJuaKpw+mJ0FDv/PM8xb7/lYkJmr/4gwp03l/ItRhvXf/P45GaA priv=MEcCAQAwBQYDK2VxBDsEObj2IptnQUTCLWyRHli9VgqTk14U5y5DCJkHY5kS/pvNbNiUymfDiutkCX8UKHip2dKwbE07EQ/wRw== msg=4JV2qTbTze4vC1F3XatdFf2d6UiOVrvfl5dZ+v2UMQF828UqTeQkiwQBFdymQKxef64h5DFUdCynnuAh7mvRNQ== sig=OjRFO1LZUrikO72s5xwcMnZ66dH4ib2XXDDz7SSdDcnwb+kVwxe+ePfkX1/zgGAPj/tv5jxhOrAA8Fy7pjhkRXhwny5tjF1wOwicbsPdUbT4rtB8YpFxSAooHf/VWfcnFjyp8z7xECbiGHmKKdju0RgA e=found last=27 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJTy6Zz3TPhwfuwA0LsPlKUyajxT5dIdeHurLidS7fPjzbANjrmSr5A8rL5NZWiIkj8C2k40R0iiA priv=MEcCAQAwBQYDK2VxBDsEOXk+Wv/IZk08Bf/yWy+/OjtK6UelKFHu4DKM5recpw3DLF67eBYzA4SkwR4WTblVN5VlbkrKWyy2RA== msg=nGfs0OdeLWKCcqBSPsjOLHpIFhSXTLIFmz6VK5GQrmxfK7GvE0U1nsq9l8PamfRiOj6mB6hrRl4TB502/Q/tVA== sig=gkv39hq+8BxbPpYxTeHx0atFZBKLgmY5JnXJAKzAxQgVsjrwYlTX23IkrDPFVdXunWFmtsLATyQAhuAAoaE5LdsPwimQEv7wrdRJvMVCRz8QSTBvWy5oTfV4EPwvv3w938o4OadOFxAAkS3uXOcIWjEA e=found last=19 s=39 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUcTxQAhnSpt55b3kAU6wiFx8wFM0Kycnm25Qzxo8HTTXrsqBpuUs5MEJoviBtzpG/qSjsAdVs9GA priv=MEcCAQAwBQYDK2VxBDsEOb/b5Un+KBGZftPX03tsxi6rpVmvKIfUkqFqhFBjy7iXcrBRF2ArWeSx7Kqv/VdebSeXUHh/PpHWbA== msg=EiyPGaMd4z8DbbLksxopAd3uLo6dsstjx7a8qP7yOFnWs23OmOK6c63dLqOeDtzfXQBBjTbrriu+7+eRnTUq3w== sig=QQhjJXgqAfocim/IJzXGdOolg5qnL5gD6L57rvvfFMtyK6+WIkub8Id7nKbBLnJolAYNanutssUAsUAcpXiiu81hvoc7xrp3KjsdVlObleTTmVQtHlRHa8pn+XXY01eMwSlEdlyYHGHq0TWh34inHjYA e=found last=20 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoArjlIXkdseoKDzoBrAHpUCWjJF6KbvO7oD5ZBtrKLId/xsNyeJllGFBj82HGHyfSOnru/XEalCKyA priv=MEcCAQAwBQYDK2VxBDsEOYUfr/NXvDkopB1Z/xwEmi5+6PzdG+0EVwtjQlniCwDb8sSFlFXsEfFJ7CNBXpljcU7fIW7YsIkKgQ== msg=DZoKA0DY2yLaANppl12u/oLGDUqHoXsGMMV4UV885WPYJKEa2XnvVzjCFRA00MXoRInQCn4VOIr13B9mQI6ihw== sig=4Mhc1Z8uXrg9XAdzYIApFf3kbULScaXiTkbvchBBcYKC+2iDzzD8fLK4vd5XYY0wPR9r/cNrNdQAIXJTnyan5f7zPaHGUuUG9TJlFIUMPIELkKNdSxi5rWL7OL62a5QgiKsvMgro++K0thyyJGpEEAEA e=found last=20 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAae+v3gXugfdYnbmCy661xDJU0hmd25/sshIaXT59kndK3sUw9Vl1yNhPP1YNB44a48qCV3bfoPCA priv=MEcCAQAwBQYDK2VxBDsEOYoYrHKFY6SMltZG0dE512SMB+3SrPVVJ/LDmZ8qWm/02KmBrD1sYv/C5rE+b6ZfuxCpndmw3MCzEA== msg=/paBof8rx2RQG9WlVdsTgmtPNHvc6KHBjCiphGUZG9Vp8Mo48kT96mZ+rOcOlbacIl4mzXuwKtw9xGVx57p7KQ== sig=EgrAC+dvpPUMcbbIK2hP6XQj0FuxAcopgZdDuwGWAUfuWBTEUoD1ZzvVE0MKOk3LeWpi/g6ZpvEA52qTmFcSL6+mTmnmlJextIGPk2uI99R9llzQqMkkLprZNWmoz8SNexzeYLw/M7BcLZHcHORxsDYA e=found last=22 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAu8m0RnCXaNgy9R3fJ9VsRyc2FpvU3XjQ2/B3Fu48ymMkfci10bQprmnPJ8msYDGI4w1VkAz9zkEA priv=MEcCAQAwBQYDK2VxBDsEOdUf/jyIGvO6f1N9tW7YISL2yOfDNPPdJxEak2hi/olXsy3PzhCJKSDyL73tiUXfxaS5uUQFZ31m9g== msg=V8UebbDS5kGefNTiixtACKEj/YsDjvsyV09cmqCP/Lrf/7YnBdhsrtEGJkwg4Qohw9WWkbo6ixnrROF5NIFIKA== sig=8+KRqvq5y11fZlT0n+iLsdh2wsmwXcLofYMUS91qVwU8ygBifoH+dQNUOOD8BwE9WoZ+SKORNpmA3KMYWKF3jUR0NXTz/LFo5TbkdF5Glsy47+k+y1TMGVY5s0n8Mn5AoQv2HmvWHXyKvkoAqi/sWQUA e=found last=25 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAt2WF190tB5PjnP4yDz3QhyOKbfDzcaz+Ju528CkqaPRZP0GN1ISqmQKLCV1IK8hVaYwmQF0Y9quA priv=MEcCAQAwBQYDK2VxBDsEOZ6UdFmMUZ6z4iVD9q9MZny59nypHDd5e/gZKKb9hSjZfGT6r/CyRVb/hJVPDLXOZ1AwVBghJgJsLA== msg=oYUpwe+76v9xVrnBvIqLXmPJCJkfHY7wfjq5H8t2SbRltyviwlC2EHvN8/tNvUoW4nOdMxB73PDsh1pcFJuJPg== sig=aLAHef1qjFfa3BvmG7Rm26tfBtN+P0ukUBPX9rvLLrGgSl8OvXDpocIiqI4WQV+nqk5A75qOopiAg+bFxP1vIFiGQ1gygpfTapNeepq11hXYFrvndixl3ib7eo64YHSUuvPmZHZyrkOM8FDVpTILeBwA e=found last=19 s=33 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAobMuck2WcR4/5Hu+d553b8xk+wV1N/rnoDA0h+EEJGJX5YVZ6MGmJFneS4uajd0Z/nia8Bv0J9cA priv=MEcCAQAwBQYDK2VxBDsEOfz8TvLDfO7LVnAAHYRFPqmXNxPcHVMhoV6a+8989G3sLMoxT4NCkGCwhr1w9La5ESVDcftFYzuxOQ== msg=wPPAseEtOf+Y5rqPrEjX1qLJP4a2fcQZnGnUI+Md7USXlRIWKdiJaljws+NCHyEpTwea8XJaEJfpCC7rKdToAw== sig=0sgO1ArmVAHRovu28e933i4/ohBsGnqjuXdGOZOFaTkGOEHJV/HK2m1th+JUMrTW01cezqZ6YQqAqmRc+kXrb3l9h6oRxp2mSvxOgqekYliq6dvUv6NyNh3sClKFs7V24bkoeJTvFo8Z0mnmpS4/8hQA e=found last=17 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEgN+AcaJA7F3981BNxNLFc582tVduZPIzyXZJUffC3DSy7aJ2PwMkWTeeks+8r4SZnwc60+cN6qA priv=MEcCAQAwBQYDK2VxBDsEOSIa6SvJR8r6elxvl41hqdXqlE2UcDT0DT/HpV9BGUdlw4ge/nD7Ix/x9YSRbpwzwREEOf49yP+NeQ== msg=NIC++8XfLuyfd1irB0kV//ttm+TyZULgqLX9bM/5DFUryOSJEXePhwCilgvLbXuvqT4lchTyg+AwVHvZ0XC0uQ== sig=EPTT94T0ksq8y+mMqDMyYe+oH53weDHJLwr3aJSMtqSTDbZEXZo5IX11gLIrnhNAWtnnpctIBOSAluNhnQbDsRlh3/qgiNtvIIDQoC0x2334vDumPnxjqRBYV5s0pLkNdFGy4tulbpauP0eiUM0tvhQA e=found last=20 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAKUem7fxaPwsBTYa6WcdX9gs1soko1IcOXr3aDl3Qzm+HctfRC1hLxmvvOSslDoTp87ajbsl1J9UA priv=MEcCAQAwBQYDK2VxBDsEOeAyLyDpVC+mW+8HcQpo6y2d8JXYYzNhrc/ZqfcbUbZV23mrGo2AJyx2Cdxn5ro038piaM9OFQG1BQ== msg=44IM52dDFN1wQrqtwxojCnxHEqwkyL4vEG+PU+xGL7IjhMp0Z5UTrXXZMMW/8Tj0qlkoixs4K/m3Xz4Up3vz0w== sig=iYaJWuTOMjPOiZwg0lOMgI28aJcJwOFqSMbJqbF2jTnDqIyhxup0AU//LAsQeQSHx2dFKhTewdeA/02cITeYQWdDMltxgztBz9ZCECYeFuJYgx/tAf68/dssCmIpceRwUOo8a1SVDg+rJ9xnno6vQjoA e=found last=27 s=36 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAKXdS1/a9mm2CY7fCH+vJiatWAhCf/oOJIs1KT95OAW03v7dMYyhfQZw8V1wIeRuIN8eoONDJPaEA priv=MEcCAQAwBQYDK2VxBDsEOZ7CKSy0mLFsVlz0j0uEWOnls0hC409U0avWkVjG6L3xfk5zwfeM8EJzzNR3iym7vsyhImdp3khovQ== msg=dZzxIn8dkBqdgXAPPvg0a+Nurf9QybFRM5gX4q7NfQnEshTUdau9WmH1JHdZfEiDFppGoJO7LgKQ4fidtJs9wA== sig=lc9pQCqWEph8bkvXYwkIFvJrKqkGAnEiWGj1HdSEDKaRbRm5uaJSwpxbf7US4l9YO6PGjnuL3FeAfNp8YIapVt7CukWJZzqiPPsikKeKD82+9IZZ+X49oi49UpKudObg8JjVLfVoSR/GejhRuUrtcTMA e=found last=23 s=33 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAeoUk8jhRd9RrjYRpSHDc4NlvyYU/gJmQQU5qcvmzl5IF/ExNP6Uu98uaPNeXjHVqRS0ns3Kpj/8A priv=MEcCAQAwBQYDK2VxBDsEOTsioO5SZQtTDOiXhkaN2b/03bPOrpvdwO8sdF6xBwaZhwSqD4CmZ/AjQ+ykPbi8rp1LUL1MkCQQwQ== msg=HwrLGrsgkk3a8tJBBRPs8jYuBzb/xAKHtnvvmiofCrqu3B3vlPwJYoW5h+aOvOn97xpegFQ8SM3QlWmLvV8t4A== sig=6TiQjBGZprOPPkSk5EgrJn5UzHKx3FZH3iqEksc5cda8kTNXuAV5haKsEE5J8z5kMBMO2jNTcGOA7s5dPkStLNcG0jz3uJ41vdsAuRvXakJfii3MHpXcmslJmLmrlh++YG0R458xLBRTmie+L8jH/jUA e=found last=16 s=34 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA1boWIazvwR9+g0rV/2DcNxs0fKYMDLChjKdhq+cNwWXjkyPPDbJsWYXojHSJ7K3vMbUiY7H9LreA priv=MEcCAQAwBQYDK2VxBDsEOfzx74t9pqFJEfACptDdQtxuJSCEi9qCVD3p/lnXi3gB7lmBCrW/UsMBQNd8WugVloua5OCtyagbLg== msg=/ijPvZ8Uez3LiPdGJcyGVdkrVG1BNcl1rt6c4E40FX9LzoUX11yF1n2Sxnhg1PE63ZP8XMcxZZ+ACSgaCZ68EQ== sig=ZUxhKY0oc0CSGzRfDxgsVXiLhbWgZzb3V3IR2QxLyTVQbVb44yKphT+ZIGc38tQl94RKOEoP+pqAZa2fWRfYFL01d9my/AufdDD4EaEiRTNt7Yb4NfeHtmNN1AymD2SELSRsp28wXDzqVK0QuSpsPB8A e=found last=18 s=34 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoACMSCvfAn+B4ZO9XpJ7PKGV2ubj8orxveCap0iEONyYD6NafrrV3zn0jxaKuXa4CuFR6VFMdzcncA priv=MEcCAQAwBQYDK2VxBDsEOSN8gjbZA+ZTyREfjuTGuO0ug/iW09lvmWwsPIufGIeUMGcPHZIthGi60XZPW40lRmk3SVEDhAT+Tg== msg=usYim8w+np0aKoghUuTI3Y4dJQ48r/TvkOe0d7K7DUuU4qA6NDotrVRrGuDXFZ/MqNkTPKzWQvlWcbyrIyveWA== sig=6EoKrvHnL2Bo8lK5M7WX0RWURWBb0lzYoEaoalDL8PM56rgiSVDPb8ycHl3/2r1kNxZH5SQcPxUAkXyefVaC0u8Sej8rpp8kJt6IkcAGfUZCN1Y5X8sFbb+cPHa8eswVZuktKfJdQwzMziLkmOubtBgA e=found last=17 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuDYI64c+G8ra+or+1T5kaVaJoeB8FGr9zrM6P+rSMGiw1czhSW3OeuxFpAG8a9e+n09RS9sW4xsA priv=MEcCAQAwBQYDK2VxBDsEOV79c7La75d58wm1GVFzf8Ftmhoz1jA8H9OJL+mT57suv+Q6cMXlhyVrnLHUDVIU8qpLfZC8Gjza+Q== msg=faEIlc3hf9nEIuSQj40s4gOhUyidmNfu48N4fsGryIpDOn1Gy3VhfS0V3XewxRzVjAb5HBvBH0g1AIQhuNvFTA== sig=Wbzxs9JNhVaqt1Ktdp9jPQfTbT/+Rfe+jtzVQUmhIzEsAS9nyff/16Y6F441IoY+AsRqowHxPp6AdyHPhMJ4qAOIofBXAfpce8Dy7ODjien1BHSTmQihy1z/bdRgdx91Ukn/ps8/zYfOq0at0pk18SEA e=found last=23 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAnW/riA6Ac2+uFfMsYJ99/wh8c/UNexdQC27Af+r1hX3zX5VW6HqBuB6o7JgGTl9Vgq+vgqXZBOOA priv=MEcCAQAwBQYDK2VxBDsEOQ2jqyN7bHlT3o6nmN9J4LYzDgmcjIb4pf+Hyeswnf4aph3j37t9gYj0k0CDn4zM0s5tYa7izoFW6w== msg=PUfWe7I0XGVethir7SFn8EtZSGxUjtfw2tM6kyn72F8P2YCZDEdX/smPCGFYuPXY4G/aCvSzXTVPDooalSGu5Q== sig=t18545jXtWnGDAJmQr3hyE9OChphy6iOKcGxq/n26zxqI+WTgbAuToBV00q6sMRd42RAQHiEL5uAbrKv74QrlMkBTC2c9MMRqP3RsY5QAcUVI095bJQgMVMMd6XfYmffDoW/nd4sxI3i8ncnviRU3gEA e=found 218 iterations",
+ "pub=MEMwBQYDK2VxAzoA0tFMeYtJRV9bycPfOknEej+fMeDdqyLhNv6R4Ga7cqNjnAUtgYCPDEx99L3dXeYGkIKL5IclWGCA priv=MEcCAQAwBQYDK2VxBDsEOeDCTLhncn/xk5mwEKodtnnYeNZvVdLMImAmP/5KUtCra0CoReq18jgIRshDX+KEj4sShTaxrMpMzQ== msg=iJADT8+WAp6IBOzOShtFt9yGKmQDhhoSz5fnqA8sJKQgFCaC2ebnk14XuqZHd3t3mcPU0E1TA3o/oUERStozBQ== sig=aNYXgH3OFXBn0a4J6e4hlYKjsHeGEjIq+UHqyveSz27VG+bwlnxV9fqId9jE0VFadhXbyj8ozyeAhpmVgcRYMa3rWmS0BFXfqm3LbwRkwXYYAhYQ1nKDnuvz8yy9U2GRPggRevTdw44teycHAdhvMDAA e=found last=19 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAfjfVKWRiZI6WMfFPFzqZbmkkPYiNHhBkoN4feeTIzlFu9ba6gXXKPHQ/95eHBibvc5O9j/ncLTGA priv=MEcCAQAwBQYDK2VxBDsEOSsoWOvliMPktQxsZ3Wp4JPDMIlbIaX3fDWQ7J3bPwWorWnMyIywr2NcLImszbQYvbGVjAt3Tb2P7w== msg=pJfDnwyoYF1qYmQTEQlUzd3qIelMbMw6os4AV6K6sZNiwh84D+/GcgsI1uaq8TG6cYTgNUCxDOufqyg6fjVydw== sig=BSy43sjZQQ/kdWVAx+UBGMaRM6/K8/Ree295hc3fHt9jBfDA9uVCkearlWBZ9lRP0ODDP5+3kCMAtCWXV1kSi4I7T7BTHhDl3OGowoixuLhiMU4KkYeCoQaR2MYb+72i2nc7dM2zLj59luBPdMignwQA e=found last=20 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdKL3X07Fhvfua1Eyum7B7JPM6R1u1dEr2xnYFqfkV1tDrZRx5fC6bcJgBu4LAbwJA8vCq2xLP70A priv=MEcCAQAwBQYDK2VxBDsEOTRaoCCmqNxjGRmEKajrvQV3Yi5v7aHDxClWzd/ZTmgbbeeDbYCdt40Bg56oXG8n/hUOZdrQePmapw== msg=S08Iedj49xrabOyT2MiU+CZXQq7I6Dh9Om5j2UhUAdOYjeGufNBJeWtgJ9qs2zk8rQVsLPyCQ4+mhjsdCWl10w== sig=ww8asU3horElc30ApSb32BF/eXM8pRHkQk31PPk6rJxWUSx4yUciIRARwFqQsUmM4o0fsN4nTTcAX+ij2uTom//ztDmtJZnBDGkmOnBK95zkaDBWX1C1QhEa051gnRY77Ec0zgXltEA7h2EtgYjGHzsA e=found 223 iterations",
+ "pub=MEMwBQYDK2VxAzoAtbdidYl+f8CyKgKKAoLYMWR/tIZ9WFxHmNuw91Vc289vr8FInEXb2jixUkJXLz5BUbbry4u5KO4A priv=MEcCAQAwBQYDK2VxBDsEOVt5/zURh2jN3YX+RtP0giulGWgrFX0Iq18Du1VEzK8j+5aBTtCnawXADgMsu6CevUsh1Yu9n3G+Eg== msg=vKRzj9XTkU3XNFEV0JDyKnnNvR9XNV7ZB9V7Zl7/ijLC8A24MVKhlgjhbw32WCfUj4lmzmkW98bBcuSSKtODog== sig=Zy29uKA3lrV+j1OQxGRvw6/0DzSrVHMu/NC74wG0nDJY83UmxlFZlc7YYQrpQbs1hfAkiMReqIUAOWZeIP8nOOqfmfgSpg8/dfNN2Pb40PHu58cP9CFhKxn2MSVGlJ+2Jte4qLqv+raZZ4+Mi5osIzgA e=found last=27 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAChsUhuwhqvh+ZHVtGmYuzvzLQpnkIre/sGacMrdJh9ba6aHWEQzc904yEXXkT4XHRgqEbBYEGiAA priv=MEcCAQAwBQYDK2VxBDsEOWR+XQG4yR8mK+HH0ZMa+FX0/0t9NmZxD4tvPuRlrSTzwLcUSZ8cIxRKCys6OBw/ZKewrkDpCqfCMQ== msg=Oq0LGiyihIk82mMQ4lcsrcn8AfmILUYD2vPWFd3uzhWzgKwo1KxodWKk4Jb2qt/XHWw7uXqVLe9DYNrPhbx4CQ== sig=R452JniCLItjvwAmcSdWSLO0nSdqo6971anDlG/7EI78kMGDsvAWdj4DSu+gJm8UnRmLISJiE2UAWkKRPkr9iHjbeQKIZAcnIIfJ4Xqoi4E7E41G3wuS7alotzKW9unuqzX4LaMuBi9XXY7/gG10YzAA e=found last=15 s=31 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAEtMeaMAhbZHT4hQF3xpsuJ1Qj3FdHkXm84bxAUAKqdH/CYCGlgQ3nltAds5zxY2fa3ubmZpYN9YA priv=MEcCAQAwBQYDK2VxBDsEOcwJSEoGu4xwvsAEUE6kUaM3o/cE963g/FkpR5nCcP1udVBEs3vlguufNHCw2iQO+X9C2cKPmMh+wg== msg=oJiQNUBmJMmh8kAzaCcm3p0Nw+Q6n3al4M5l3743EEjaJnyiD7rvKDg4Tc5dGBwMEIUAZ+54IAthPdZL5Jn5kw== sig=EuzCOcMcHpc2nXqdkjOnQl9wp0UhE226W+K3cld5fHbQtxNrVg1F7kf4GTLxq4cV56cvbphJmf6AtA4ePEbSivZljPzfxkh1+WfckPnLN2MD000ncQAQW78VJUtm7x4TxJJtiqe4d23II+/PWsq8bg0A e=found last=22 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9ixKg3BGCL1Txr2BkYATjcXCFUKyg0U53Q+fHjG78T3yssKHuxBJ26MPB+yDK//rcK3Y3Dh8+oEA priv=MEcCAQAwBQYDK2VxBDsEOWtQxNjoRpfSbSuc3z6I1/QwT7js7fi/1ZesFfZNAYVyC+QNPQsNMLl/Zkf7kQX7uAezpHNd+J8Fkw== msg=UkGXnLc+IUX670e31Cn53WHh8CbB7hoHciX2/SkNvY2WiA+cYf9smEPjEew0Ox8UtdnRVR0tKqlPqlSMQlBsiA== sig=73wzxhhMQiUBU0pkhL1m9X3wWMyqJmnLWlN19/HxIDLinbfKfnSFfTSVptV1P5tZ/v7OUNrIkPQA94RRbjkPdcRVSFcyq/YIywQLhqbuADfS++8K57h1MHl2JzKhlpqZfEdCPSOdY5eEfCwwd5Y7HwEA e=found last=27 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwrZfrsYW7khNng+cqZKGgVumT15L24dwYPICVD/aOiU12OB4afWXR3lo49pgb/ACuGNv0+EHDMgA priv=MEcCAQAwBQYDK2VxBDsEObqClbYv+jh0UEY1jPx0ag832HA0qGD2YHHc8XnsIhI1HSt4Fo7+ISCpPABIfDlMhjARJYxi5OM8HA== msg=wjS6P9+a1uqgFDrRAyALJg4fIK/QR5hnbVgqP/1umrz+2mWYHnruv1sXFpTtvAxbw5aa1/FwexAF4FwK1w5lIw== sig=ICT1H+i9byx9JFhyaIpweYDA+1MsXFjKKk8eHiVan+7F5pRoGoV8ITgcEe+FbOQxbzWmTAFih+gApJiBBvfYQt0O9+N7yyb4fZiVQh2N7fH8MYPDQWe/bYYroKF2qmLdTx9A1lCFVg+PuA/kw7fgBAoA e=found 219 iterations",
+ "pub=MEMwBQYDK2VxAzoAjWsDFLPrw0pk+knAfm+wxa95OPNMbAuMS2HAUXAJ/dtPUkykn3XsY6SMUTDQzfsSTZD4e1f7Hl0A priv=MEcCAQAwBQYDK2VxBDsEOT2Hl84P4X83D8RR3Q30p5zEQAOTdp7N0wBoLBVkFspU+PpSaVXN7/pEIdQIjvjWyixokLEtRBd4JQ== msg=3tSDwknKkRfEVLQIhxXLE2pmm8RhZkQBg/3MlUWqCZm3+rVIwD/B5d4WFzIH5WNM7nPjS6eeAzRnOV6apWGdxw== sig=rkvvqpCv9SKpa1oJqkv1c9B5uZ+5fRcY2TGDOkaA/4341uA374H+fKedtVRIFQzDIrrn2lBoxysAwDkLfPuA8bYyn9wkl3Pbit5l0ryezmC08FjQYvwcSPKEdT7fSaoAWYZM0A6S7772vHl4ElZc1wkA e=found last=16 s=33 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA6IkkrpH0eDbW3ALyDbU98JN1AYg4HiyywM03I1+UwVuXxkdnHuVGfdGNCmvL23ANm0Pcb/OA4LWA priv=MEcCAQAwBQYDK2VxBDsEOagEHY/KFkhx/HeMA//i3eAzfNGQRRnpOfw2IqEMWlZ5/Sd1RRPAtmHvb4pWIiM+JdV1Z/86fgLa6g== msg=oWwtaAe23QLUFlsYiFRz5Y4I9g8WW1FtA8V0KU0gN18Oh3CuZnVKbEajKGFoUyC+1VVm+YrmfpDOIOq/bpOCRQ== sig=MQi28BnFCjQpUV9w/hl8yfdHd9kT/epz5WqktLdiLQNB/WmndXRZpaQZrFNl+oVgi+D/ByS+x+MAJUM/hav5eiPmpl0ErhMgwquiQeowuJzGULZdk2onZ+2GqjNUrrcBqt9X7KKbQhS+UUEx58kfKSMA e=found last=18 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdqRkZj/otKxzqfd5kbDSFIGAX82c4ltuD8LlWLwDhzLiPUBmeDFLP1Ykod9JqeYLRPztLsCBu20A priv=MEcCAQAwBQYDK2VxBDsEOSCwA8FJAA2lo3iaCgSXIU6EtWbj321Lp4G4hlngI9lvD5z7egF+S7CMkVHHcNFuhEtMAWuwhksFSg== msg=kfZIV5Pu7BLu+ebHHzz7QK1fLYq2uiOk5n2wV4d9Bz5Zttbqh0zyCa0dGNVkfmf2DiYZtIPasEmhjQy7Ej/J9Q== sig=vmeAVPoQWtOk/rfD0IcfdDRGAujVqEbQCuENhkHGU+htFZxFUHX7LEbNBuG/UTsqCjC665xrHF2AtmS5ZZOOU1kcpkA5oSd65xXIZ4wnLBI6FWqW2jzuIiHwXCnVvicUl4JViDDquiKz4faNw9Mf4wwA e=found last=26 s=40 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAxt5HY9UGwew3+0zJk33xPSR1ybD9+8M6RBCUBEjB0lGj2Yq/eHvGexvDZb84KGI8xsLkCLOGS+OA priv=MEcCAQAwBQYDK2VxBDsEOctq6dTR7f4RPpcdSzYztmkXac4en0nvQiJSA8koMm/adBruuSfH2lyj6J+wYbtc42m/3PmKLEY3oA== msg=n2ae+UHDZWWXR/8+4bV2z0CoFfJxpkOH6eYyK4Ey+tDqlAwGrza3mXmdHtdIPN855hDXAb06izcwpJU5N39pJQ== sig=Szv6xK5C1v4U7XJ6b2FAkKnlsbBVBR6KXL2IuJj6/cWwKgD9wbAwdr7h9IERlfhGVtk7wnRYEK2AfITblN7oEXL5OwofyAdaVA6h3jftkdbaBLqVOcB1E94PWM3P54RdFyGMv8vEmftQL4QmyCYvxSgA e=found last=25 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAdtPNyDqvphpWorXqJ2eIKSp9vBaw13odzgODodmMuilueW8I2OGCvbWF2VQObSSCMbDja7UtjmkA priv=MEcCAQAwBQYDK2VxBDsEOeqRPGmPxvMnHGqcMt5W/In9KDolV3QzSztjulVZdSyXY2O/iCH4ananB0CFJOK0Sm/CrOQ3hlwrVA== msg=joYMRLff1//2DBbS/dzP51Grzj3Al841P1SU+muwY/zrotD6sFifTSZgrTjiYzZo0nWIIS0jXEsHInfj+PGLPQ== sig=5hMyp9S11OpcI4oLqua08ec7+4UlQRxY1InDBw+1Vh7YZvfXu63PUg+Phv+9Q6YMsJ1ZFfWwsL0AUDMkYxcsLw67JeBe++fn1EIu1WUYjPNg4M7XWrgKa1mak/vVINEk5f8ojDXDvMMmJixb46NCLh0A e=found last=25 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAg4yzYGyGkfEa8uPPwibaRFRqJpzLkGgMc2Z4W7IQVr+jFD/ocOj1/83dEGtkRXcIsEO7XzSCAJOA priv=MEcCAQAwBQYDK2VxBDsEOXbVRi+023NyM36oWEm5aZZO5yI78XSdDls0taLdNmN5oIS2g8UPVo7/pmhiCbPuTJtqr1g41ODUXA== msg=RTD2C6uOozkPMqgIT9vHv2Xg/POWcenH/vfvsj339wvRYEUIXmEQjfEZ8Hm8CfMPBuVSpcwJVIh857C9C1SOXw== sig=us3MAwci+WI6t2sGjODsc23hJUiQsT/RmO8oQXDu1JFpMU6i6pQ5ELwPShZr8SeMOL9dpFtALLwAoeGYEVtByx2Z4ehsgwlbjQggj6tuqwKrsgWNRJU1GRB+U/S/nzHfbZGuw13EPlzdGDObZdR7fBAA e=found last=21 s=34 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAhuYQPHJ1zfVmv4Uq8Z/GD6n0q4lIQ4mc7WXPtqKRVArTM24czqE3q09VZ7SKHYp6bvXaIfMHf+yA priv=MEcCAQAwBQYDK2VxBDsEOZDDtxMWtwE4+bxA00rx//wLGNHpz3PoATmTTjz7xdXzPWCu0eUwccTvdQMiQLX9eUDeOfLgt1m20w== msg=Wqruv5A+e6JVXrhwllZIBRAllEH1DNj76g/QN/HgzHg048nnU+/CUCG3RJzsdLMKGu1yWgzVKlaWlsdnrALw5Q== sig=vvvv64SDCkbh3BSnPZTm/SnbX3GOljLzzsTA5K0bfplGo7DYNKpPZWGLCTr/s5ApQWzHYXmbBIEAh+9XUqSGLqFf0XFwz+rjFv/qZL3A36L+g4ZDMWKegn0wIEJUQU9K3Uu++Ulsj/rD+7aFz0mwuDkA e=found last=23 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGkE6uM8dqjBGkbq9SFsQiMGQ9palJfkPMTRmOamfYp0RcXtv19+fIzhBjOJjClhFrPHlKuVdSDAA priv=MEcCAQAwBQYDK2VxBDsEORLz8uQk6g/oV2NaBn4whJGXqdXsebnhff76ntH0NVbCMCBfWpzRTSG6bpt80+0qe4SF55e8nLXPuA== msg=tp5QFMfyLWT6MYewgzcViKO7ABKIf2SJ8OJ02vdmJ/7sBORe0ASohIIGkUn228D3XhC3l6YjRXFI6/USnaJLJw== sig=P9fg4W7D38VVs6oCDYKwE2pZdGH1UX9ETtx4rwytt6s+VyjBi4DU6UIe0HWx95+vWjHXez3igWcAVvDIndrtnMrCKAAHAGXT6j9Szz/+HO0Pg4CQd3RlzWuOXNQ+YTVdl3DvgLNMcQ/qPAn0osfyBzkA e=found last=24 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAmm/hNL98IVpLLeG9Ixej5OnaDp4NFQGM5xBYEHzIy9DJcXia1I+73gnkUa75VV33qPe+0ZEt5LiA priv=MEcCAQAwBQYDK2VxBDsEOZZxtMkukFA8FZkUNlCWm6rE8Mm/LwE8NBySys/v0O46rprnuKwkQAJsjZukAtUAdTCruidVKosuUw== msg=qn2Foo/OPnf/15armYepqLg4O8UsaZCHsIIzS9U8J+ZxLrNECY8B8HnjUd26iD+bgobMp1CVj3V9zCjavRSeNg== sig=QhxRZvp+DhsjlTJS7C6w22dpZajrej/wh9RmnekHIpol1Vlgrnsrx/u3nfGEKWujm/lGZnkoZQyA0PTIJIQfIhLm/1F12uIKTdeWfPjkrR/jk4g/cepl4J84Zn5FAruTRfLavmQUORDaCvtjuiXjOA4A e=found last=15 s=30 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAtXtqxWgaRpShYXzoXo+A3djYDFu+hyZUfyl13ydulEfm83fY0MQjQkl8DqPZWnFtcLz/TBfkxcMA priv=MEcCAQAwBQYDK2VxBDsEOfW7Bec9UrllksKwlFylLMCBk9W2zDYDimN4Sp8HE/WSVxRVeZROaLXw4IYls7sxdslInkzRu9dowA== msg=mU69oLJkYrJiN0WB4WvQMgSND0RdC3iLsz93DcZJ+9/51le23ZP37/iWI4mcasJz8Fa+t3kp5XA7rpsv2gswAQ== sig=IGTaXi9paWqtDGpYpdRBFwP16vi0eBjOC4GS1rt8kmXj0ECyM3/Y6Hr+TyzJ+kyBYLZ3Z/k08TyArwbpEerYX9f0eMImPwXnbg6s+WnHw+Ni623kEO09Wc/UB23hyRsB+Z1QPLHrMNKmfX1j3ThijD0A e=found last=25 s=35 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA4m9VA71e/Kwz10BQPy7tmTvWjfFeJ3hvVmdeltx1V+T9snUGn9XXV0alKd1HdlmOOf38rCeAH2iA priv=MEcCAQAwBQYDK2VxBDsEOT86w7llyLNRNKroJFCXfKS6PDPQ8MVnSGqOGw9sxrkBNemYVCyz+JqRib0RsbU5b5aDJ/KasaOLiQ== msg=/5Tgvatz3Y6ABVaqz9GGxqMjcgQCZw1i7CZ5fywPE2qL+4oXPegK3Q+rOAdrDWHzalKnT03FG3EcyCqQC5siqA== sig=oNjpl8PvZ/QkGvzb4CFqhrknc6UqL8c/Un72CM/0D0mgQj6zL9Dm9jwvkvfnmEYTfLku9biVG40AZvUwLaRg+K4xFhnGZD+S6YlVA/9wHE2cncjG0eiYkJcsSLBQ03PQJhBtZN1668sBIxto2SKsiAAA e=found last=26 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAWJ7aMjgvigONWzj9iPwZWmxmj0WUjxLowTXbtu4AFIzg2AndbNqThZQBQAxNmcvIdwUSEB5KhVyA priv=MEcCAQAwBQYDK2VxBDsEOZR8Vnczc4t/aG7YGLW0yRiA8QreKZ9FWB+DK5d1e5CIPdSdeHoKEN4+9KL9IBMT/38xSXUGwCaWCg== msg=bnwzIYL4L9PH4BY2D7DiuE1XRJlf8RmRfTiKiS/cpr75E2/E8RaVz7Qw4Qp3aaBb3Fa8+yn+MqSJ90jZaOVQBg== sig=4mbiOaAhk7VQkysQ+vxSVi2kOHjnP1OO7+Dha8O7s/8h2RTVIA7MK4aPg/bVldQO4oUm2f36srwAmj/oELX58iJx2+C1Jny9kdwCyBBBXvyIrIsBAiMKjywnOYfBcLN6oSGKNzUNR+HtN1PnCfoCLAMA e=found last=15 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAKFw+Jp1/lVnX0V8CXnOs+wTl0hbg7Psi5jrsers5TXZsjX0hAUz2qQHHoWsH7jLxz0Z6N3iciNYA priv=MEcCAQAwBQYDK2VxBDsEOTQj7i9Xx4B1QP/2nCh2sMtUxxytjwbSBvxuFYP9W1lVHp1thtYXk/1mbWoLe9yPqT2ac3AxqX+mHg== msg=aAk0U6XMxB1ENA4VL8traR9uGTtiVzTo6zpLTSqcAUoloUeUerQWSicxNmiHe2N8+yU+3TY/w86SNx0OVtHgrg== sig=QI8frdGaDDrWSP9s5dQmvPJkWKvAD69132bcVK6NR7r0RNtQ7r8fLTc5jCumyzdzfrORICFRF10AbayzEOp1VV5lJ8/Y/slJU250u4gnrlcOEtQ2F/HxxYvUXeDoLi8FpMdoa5CBN54VMeCAJ6wzlBYA e=found last=23 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAABQoOOUG5zd2dLpTCzzQF6S5anfUzOgPEGsIE8fBag6HMNhM8RlkPa/4WHPP4rEW5O6AVLGSkSyA priv=MEcCAQAwBQYDK2VxBDsEOXu80FzkZK2weCayA44/KTJ1um1HQ+NIuK73XGd3lJFtIJXjmms2RcWxbTpA9FY2ahZ9SlZYE4iZOg== msg=uC0+GwbgZFxCXlOVGEkWysXz/HFbZ2viiSQAuEshbMEogc/zuY2+XA/Gz0WhvTan58cXPoqcZnKPnE3QwhjIgA== sig=c42abL1TmMDykiEuhUHbxmmbKN8tmmfmdxgN2M3HOSK707zXy1x5xtC9tPcoiEmMz2PDJfpb/XIA2Nz1Y5hck4xvJ+1Cl1kMfshC0YaUkTvtPo5GgLQffu9EP2BVmFNxp+LdNPeTeEWeQxdn3Nt35iAA e=found last=16 s=38 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAajrI1Jyca5IDojHFG+i42w897kZ8hr7MnCIoq4R5wDiDIGaPWMHErNhrY97q6V/RtKbcXVyxd0GA priv=MEcCAQAwBQYDK2VxBDsEOUgLIuS0YkJbN6EyUiSVaAhQHYFLm/EvJpPI0JhVzYPzToT32ah2bYg0uZ1PBIPRk6fcCl7dy0Z3jw== msg=8W5eWe7spgpgr7bxzC60cDfrBdkXX++vYhUtFG8nTTjzdDf0rSjr31GaT7rlYumzdyrPqUMvUZ77HeBvyrbVqQ== sig=82RCoR69OIR2I0tsYSdn2IFktBHbpCspMEjJJK+WZoGC+nBj6XVRY0XzwS12iF9y4hlhk975MiGA9EJtAbNKt/SIkRAwBYa0y3oAAMJhP4gfMQVMc/IaHobwgl7hpGlXHbEXuZKshNg1v4VqRrtTGAsA e=found last=18 s=36 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAIIBQcfsPo0jEm6YhpxUiguw1tI7DIJxSmzqaCUkXd3htUIYq+h+MzkgHlNL2UzEzrKKHpPWJRWKA priv=MEcCAQAwBQYDK2VxBDsEOSphCjqH9KIbhDIOZi1vGftasEFkXsD+pTCZjOybp5KspLQ9smV2MmmA+a5jdO/ZbW7PkoB1fCcw1A== msg=SYrmwRG1BBAiZlBjF+jWjb/h5sJFF5q+gZY6EV+U79QIyDP5+jVcf1uRLIbMWCtKUJwEz2ymATc0zduyh7ExjQ== sig=vBMaX42RzXhtdHuH57RHl+y3Gr/StK9o3wcW4VOpkxozGGA/8v0UtS9Ogv8cSRSHXsoZ5Z6uivSAfWwGCPaV5RL0FBQL8885nwUkKzDADLybCKeggCy8Nh9jOo8dy9qZ34RE5qRz+8+lEsRaLt1yyz0A e=found last=26 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAD3g26G8SomfWErF2UbYFiA1jBI7PoALuMblIgwVyl2nX5THC5qtFaZWIT8ZI6JwEr1FUzYCgI8oA priv=MEcCAQAwBQYDK2VxBDsEOfatUla2PCCtYN9rGwr5IC492VFxjSdFqQhaMg6wS9PuB3zN/+NJPE+NwnEfTh1jkz3KUiS6E3KT5g== msg=HTrwOmgaAisdl/75WDLS0oAB9p0iX+HJu/HLxJZqQn1GthD1v2skl+PFCg2Z19pIrhhrz3CA9lrWvTX+I8tqBQ== sig=zMU0SYJQr93ltpQ38vf/NizTfHFtMLfPAQ8qO2Uk9AhHHO1jlASRlQ7G2pyNOqPXkH66ZXS9hhiA7fbYB4r9Mo504zZJYzbKp5KA5BNVidzy8+Mb7NxHCopznD4uIqv8UG9GKjeeUPBCr3kiEHm0ITwA e=found last=21 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAr5baI8/+iANSdofiCvYZmbQU7M0yOtjIPKf/GZkqv0LLkSXEjwDfIQ3Z/s0qUTsUZ2R1ujIXbO4A priv=MEcCAQAwBQYDK2VxBDsEOVk5OVZQKorsqjGXEQoJJ1kdjQMlEMWawVp8yqqwYQv9L9l8VQtrO64FKk0bRBYA6yIWi/auOPGLkw== msg=xmSEwpC/UQG1ytHnX+ko2tmPX4hQwjBTT+s2WU5hDME6HhLeBQmcwGHTc+4lg/+XquRCHmjH4alXRZ2gCnqihw== sig=530fJ0yzCsuVUseTf00fuKS6y52LoGEGKY15AfOo0AjG40SkEPaM4wupXSRFqdQtXufgUcvy2bcADG4yBRd6u4FV8QmtrfxIaiHn6shzwoxU7dqFV/LmZ7S95Kk2FWo/x7ITfYnv4+H5r9CNGO9gHCEA e=found 217 iterations",
+ "pub=MEMwBQYDK2VxAzoAhjsz1GlBB9sgthmMXR0FHPhf69PxDA8Tlth+sgVevINfN1UN0Jwc1DWqA4a9O0B2UzQk65VePNaA priv=MEcCAQAwBQYDK2VxBDsEOXJwTstltDy7fwPUp/fONTLFNi9vkccNx0WUPSO3xDgp/mKbE0CRm+Lhk/Wa5tRcDGk2DyHW6RcV0A== msg=DvmotGB2Rq2BCq0Zecm81UZwwDEAtCToMlCWZjyTMzaKmgBZl+YbArKVWoSdEUStMKVb67tuEMblo1GHNiq4Ng== sig=EADNkiQ/wqh/dLsVrC/Fd45sdXJ9lVMp5mJbnV+wn6AzdKAgZzK+JM6OTx6vrMVWO7+rm6zecp+Aif6aKVz0lLPlAJuicgUwk3O4zSnTDbEqEx2dD2jtm8+CWvlB5nDMp5Tm+x6F4VoNiRGwP2f36zUA e=found last=15 s=29 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAt+k2sSlFzkMzt4/YQH92hCY3WWcnc7rQxyG7HGVFzTkLyMgfHWCLS/Zz5bFD92iYVshPMkxPVAKA priv=MEcCAQAwBQYDK2VxBDsEOQnQHr2nVTlksT7gxNWVfThPlgs4rXjCKhI3XG31uACVq73o8zY9r9cvZU5RWRkImX1dY5cOT5+o9g== msg=ebNJ8O0XPruILIhY8SEYGNTe3mZuYhwoFw3YadhAon5iF6M2vpdaky8dsRCEwc+MfdBbELFqVpw8MQKqwFy//w== sig=V6N4MiKHUXdnaFOAjHGhZDwZqszIYHKUOYtb8eLFwkvQWK0WJlrHIhG+NONEYjeha9Jry/xo1GOAGXUqrzqfGQBrboYOsTcYTTlIVjFf6IU8sNEtBPvoiIynaJPeGv1FnCISRq7a9aQeuiuhBZjYrzUA e=found last=20 s=32 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAVILcBaSDWon86wqvVFQiyeC0fF/CExdklcIV2nL/aRzkPBTHhLpgsD41KgFeu3A+avnSwRs4IWyA priv=MEcCAQAwBQYDK2VxBDsEOe3Ba2YJffX6y6MjV3CxgfjjZWAVP7FUUodw87j+G7c9LKKLHeuTOjBO1kk/eyp9SfCpIY+8MxIWiA== msg=KwJKEayYCXy9oEkHtDK58DmZ0wzlbx+5wzBdLYX+lFcBUB8F1zAHHxZOIu/gd5k971aOl+cAzRiP5sJ2w6KKGw== sig=NEWgYgMY0P/zPp9KV2CcGpD4P109Qvr7yW+yAq6/8Ciz3LzGaw2ybqc4GXKvYz2aymcwF0imCtmALxMnh2XbUV+1gD8u0aOnEUdUKmqP0ZobalZQGvTmavr1GsBHa6Z5WEFmjitzUGoBZvipldmMMSIA e=found last=21 s=35 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAulAa7/mFzUkjMqwKicvOZ5HF6iYI5Tbi3R2oceBYhvieX9uO/BFPixIB7uEnoct3YCnb7cxErIKA priv=MEcCAQAwBQYDK2VxBDsEOZGidl4/00yWhG7CAjp7iIws9kr7T7D/NvOZOKtGYvyoh7EbEaUlTlc2IRBUT1peFLpCl1vOkZRuXA== msg=KbM67DnjAaxQ9/SOILzGPpaSCKH83pCsdCtE2MTvOGPlk69uByucDpMLQIKhPEBnJCkfFgDiksIQPCT/yTHjcQ== sig=kKhG/we4N7ZHBepliSV6WjNuXL19ueqUptuHoSA5GfUnWjKLkTOwKTcIEpKSjh0iEpZO4izuZA6AsUqPXJzSvc9uEtFvK9jiMVk5BhrCGpiz1cP56O8OOi+mBgqTRsmhn/vygeOEt1Fka2Lo5XQ2BAEA e=found last=18 s=33 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAwodHrjBMXoztmniYb4g1yJ3+dVRsMILaN9L25VOmiBDMoP4VJLG/s48y65g15zeIlnvnI/FzdhWA priv=MEcCAQAwBQYDK2VxBDsEOUUhMmhUUqPGThfIaP4Y8uQr++pbJG0nH+wJQp2fRMYYvzZol3kPbMP96UqkUKHtZNg91CSMZRQ+Og== msg=FpwEpGkLTuCK4qXZBv35LLJFXnCTwjIye2vIINtxhqyBQyl9Cs1gV/Q8HgoXhNCplX4hBRrEXv9k9xGm1tWaLw== sig=jO2NpCgRN52/kp3YvajSYkSEPlRHDOhPl0F6eKAcYmYeyIjFwRo32tR4v9V79E3OznPW0UtExRuAk9kPKu6prStM6+ftapO+Y5dJWmXLrewtps8RPzAoiz9DiiSKlUVHfTYf+Gj4tF4iykDcoX3w/y4A e=found last=27 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGVF+pM4kdFF5ZBqkKp9O/c2De+kMDH4y8wv973VRRc1cFKpIYeIXQt0LCM46KoTD8i6xcJ6IseUA priv=MEcCAQAwBQYDK2VxBDsEOVNavFia97xqag7r1ibi/y3drFmP+mTF5CaQo3OILdGOcW1aR5+z0O37JBfefpBG0KafDnacds43Bw== msg=7gQZcOPFK6kLicp6dru5mvY/w+JdGtULYciti3Ob9n04kEbtiH0KdEH4/XtulavkkveSn90BWBPRIypdKOmg6A== sig=4rx9J3zw32S1DHMhba508i/bJXIWNcc+5JBP3zDU+Ya9N5qxAhDE1aKbTx9yZNsPWPNGALJTKggATBGObM+ZDgU9Sp5dc0h15OcIccyAaQhOSil8s3JuijinBPa5/s3Muw7NWozUnziocVtD8k5YCzAA e=found last=17 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUq5IRTWOTcdVekcdVrHn0dDvfDbutOCTYeXqd6lR8EJGT9QXuoTFLDcF5okRg22nrEqJqGXC4PwA priv=MEcCAQAwBQYDK2VxBDsEOZdA1/F2wdRtF/aCeMduLYuazOFpTBwmdzeUT63p9EItMDWEHwfOaX1kPwmP59LxyAFaltuU6vO5RQ== msg=0s2CayaR/IyLU+xFvk4ZZVH0yPGXpTasDHOU9oQV6+oEEZHyhjnY4u1MZU36xNNJ9t+pgtajBlnlMvqlVHR6NQ== sig=rglY9PssRPcNsvaft34HLOSzG3vQFI4ABAVZ/mXJ61f4jqd12PMAlh7cgzUBtOcjpcfR6+Rv7wUAw7OUzy5NKCmx11P2nd0Qbxx+wr6XX2eHrqU0H6xVrqPJyRPOKtLN9QuA/8XK0PxVxOB9hojWbiUA e=found last=15 s=28 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoApLOx16z61YS0x/OtwR4JoDm3pml4bKXp7/uK4AYNc0ArfUA1xa5iDYJmZHRTPQyhiDtCeuVVyZ6A priv=MEcCAQAwBQYDK2VxBDsEOazl5jYlESX14C36rjCva2bKGSrP1N4YB99MiEmKdO2V/y10fwUyi1jCXrYkHO+QTF0Ac0WrsT6SRA== msg=wGw9KMeMXIHawe4anWYv5p5uTKCejx23rqnCfZrGvQxCju34BWKAm2duC84X/wpx/LtppgNaiToaHUcfSmyTuA== sig=ck0vfxQ0R8snLbSyIXtKJoL1mP5OEmUPcQUkroomUYzxw/fFxrKB6Rlf0QWmfNZEp/baiObKmI6AbJJhbgahilzZSq/RY+T5hFrfYdPnXl53Q00zmN0Nr/UfcxfOEJNJav42Sq3D9oDnazjxekAUyx4A e=found last=20 s=34 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAqJ/g4QNf8P3w0Xg87hBUhSJ69MkmHwgJk3jxYtiLAJhlf4HBc5KMuPNZsob8r6tCTrKPA/Wnl0+A priv=MEcCAQAwBQYDK2VxBDsEOX6RvhjveBxw/5fzLtgWUo7gF7gmXmIa7ew1zsZ7zRs6oAntQY1NYDuY5D7oAwcKxM9Y7ARux5b2UQ== msg=r8C4uxbRpikuVUjK2YaIcEbnNrBQxDHEUebgc4NofhgAZ+VKcNG8ocPDAtDAyi6AjDVbugqJlpZB30O4u6zwXw== sig=1G4HMz+RjI+LCTkifCy6nCLb8sPTw+FCaPSpqDB3FSIkUPe7mo/HuZD8MiG7oJRN4dTWaqlDIjqAtkxevR9C5ZIW/LYRe989pQU1ds7F4PAkY+WHsoUnEKWgbEGIGGdyX9ty6A9sJA4g+eG9Rsa4XQgA e=found last=17 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUKVuy8V5JA7Ql0Fo93HxSNQQKUtnl1nnqdTHgUe6CTAKIborLwEhN7cXMrePVZrppeh08TIxphoA priv=MEcCAQAwBQYDK2VxBDsEOSeYWs+QnMlxXSI/escK0iM6NHx63JifDAD3DLGZhhkzwpvsbHbcXUUttZ1Pmd3VTMBqu7IchOFS4A== msg=pcK9TiWpzcpJwn2zeI2BAshKqw0TCHVn+MHXcw9zpan5K2E4Mr6W+NhXBr/bM6o8jAdukcR0z2bb2ARCk56AxA== sig=pYAEeLaWD07knIk8kGMWshKj5NiSMl00vhJ/5uSlSMTttEAkmDNdSiPNplHMtJ/joce4ynSIaXwAUgyuRVcrpE5o0o4q+4/RTi6AvYdQkbFZMpamR7jSIv90SQWdbs43PuXoIbhRBTuTrWzd8sdEYiIA e=found last=27 s=35 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAc4J4meeIGm5teqolxTotQ/kjvknKGoyVXDd/lR3pH5cH6B7A+Z45Xzw0usClnCZyFtQSdIDDlU8A priv=MEcCAQAwBQYDK2VxBDsEOSR0HJou5hpooWIn0t60/GKasMx9tFSf3RoyQtFn6LQxYvc0JWcCuNuwJPVwXuo9wnki4eqPFCA8Zw== msg=PPrrsQFbPEufUKCsSv76/ExFTYF/eTAjTaXgcuGGCjlY90F4beU8aW97zV4yq/sz5YGfPnjm0v82DJC15Z8xxQ== sig=JSfWUc4B8n8Kvj6AWroWd8ZeKPrwwIpPmRoib+/vZWESKDpdulK8vW9nkHT6qoF81hW72M/uBZwAn1Vm28iGmcdJb0WuJJy+5vP02W7DmFuDoSOmslIrLBU5w7mxXj9cUn0Cf9xCBn7+NYq79g1MejcA e=found last=15 s=29 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAG4gTAhHS5uod05LCNcOwGqX1ikolIqWu4HnTj7EZokWFVWwB0pkAbd/+ZcD4yr3Q2HZOClf8hY+A priv=MEcCAQAwBQYDK2VxBDsEOewdHwYLiN7Q3wE49wOBNJRsytK6Mq7thlcfxi2tPwXqK6TRSr4dnthd2Uhvm9lAcdNwSpQqhR6b2g== msg=ZZG9umyOIDj1roTGkwoVKhi9moWkxam5SyeQTXUgTMvhCpaz+l403Rd/PG9r6m62MlOmp1T/L909cVMJO26vvg== sig=9y3EZmWkWpzPFYWLRR1sc3Fs7741BiPTNipttD1ikDnnlp/gneQO5USqbADGeSyG5TW9KwFNZbqAP7lVPMQMCB8oofr1goGzEt+LwiTv9b0TUDogmSHwYVJs9a538WC6dKn7fBq9PeTUCyW4opHPUS4A e=found last=16 s=31 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA9pnRBuFAnWamWPPdypRhvvQcc4sNxmr9c3n/2r6EuNcUINJo+UX8o1zPb8zLZlH1TJzB8BIUFP2A priv=MEcCAQAwBQYDK2VxBDsEOZcit8eS7vh1WQHWFaBdQ2UtUQDU57yTkifc3qXNDokwNg3vOQqPXUagktvORknBCJKc60ASrFGwHA== msg=Qg47VfmaDzqlIxoZ+2usEqBXVbNLXIR3awnRaPmpWTTwEJmiqiyid++Y6NmOIY8VtQOC0ALd2CVbxjQ0uUUDmg== sig=SsI+Sdzu2EQtRMejz2JuAASg0PlINtac5GTcJYHLuQKQBm31TX6q7HrOZKVddmPZQE+sVFKoni2ApYWdNJYkWYqMnw3Fu1f+Ya2osKSStT9xIejr29TH9UVxHZ0Pjm0iV3vQieWMs60Tx3YH64CeXwgA e=found last=19 s=30 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA21ixR8pqT0CSNjXO1WxKLAlkLss3XoswS6lBRcoELZItvYOXYlmwG8Marli8EwdlUj1y/e4wDeQA priv=MEcCAQAwBQYDK2VxBDsEOe1zi+dV1my5ujZ3vRuRI273SLcjBHGDzJLpISzBed4RDW1PN4Pdrv2jk1GKl99NMk3c0wLFKlGTzA== msg=PP5xAyZMvXnLMTTYNPKefo3pE9l6R2IHzscBa4H9yK11RJZW/JySvbjOa1fT0jEBtGcXp7NCmVvUpwtKY3FTzA== sig=/2a58hmWCSIOXjP7unHLE2iA13hQ5u+0DwOQYjE+qMUJEUeef6IgryijubVQTiQ4thBTgRdi51MADUPAW4nrtxt6NvkXvlmjkKtfjDLmj4Pwvq2aX/ztN3WKHO/ZZF1Px0/tiMd+I8OvPKTkDxZKKg0A e=found last=19 s=33 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGeH/+sLVVjTr4wiwWZWFmuJjr1O+gKSnCqk2Sz0zwqXSpvM7HXLoZKbTmESdonoeePDRe4dc5ooA priv=MEcCAQAwBQYDK2VxBDsEOWnGFfKZNPI3dLhkSyy6jpwrddRjzyVW0nPQjeY/heJJz4Ig6nvn+bHF9YFgW5FE/pwvhAN2HbGm9g== msg=7cFi/gQH7xWnu1Ap7BmPwu7MpW1myu/0Iw42xW7wiZLNnEl6ETTSys3gcpY19q8AyPbS50CAzRkILfOwcBk8ZA== sig=QzcaCEFYM2mNU1MkM2GWoApAMpUodzQRXMLAWv7/+7AflOX9yJnGMgPYim1i6c+nFPH+XUwSyPoAfLcmpQzOfTYGBB3YfgLMsRX/o7zuOg044MnUihVAhXknhKXatsFjSDAKiIwFeeVVZqi9pR7NZisA e=found last=21 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAJ1x4GRPK0s3VF/Kpd/q0ho2nyX/1QHhW6z6hDEEjbvGt9v4uZWsu61BB7UOIfJC7lveyuGJljVgA priv=MEcCAQAwBQYDK2VxBDsEOaJCHWdCPodkapjEEC3vpBxpskX4JCq0HbIEG3PIEquZIwHrk6dA+IUCvnhqfa+bwoBsS1yVr7rutQ== msg=lnarK/d90dQw4EdvsiXRRecB5/3O12SvSw7oAzjbIXvN8G9SuYNPG+siz5wy5yc6zUMd4ivSErPxEi53viGrug== sig=d58T2Xai2mj53ysF2sveZEzjmga04JRBHoM52Uxoe9xE43IjDk67Bv40WtX+D9vhZepWB8giw2QA26ApoZBeCBgiZThkxnCa4RQxI/JkSbh1/Ka9W6GNJ860dZS+FfZsJhI3zL6K5RwCa+OPAl6flwwA e=found 121 iterations",
+ "pub=MEMwBQYDK2VxAzoA0TvA49qAAuGMYbGVDcm7zV7bObh3KmzmqKu+pnDTxqsZHELLDPbHWZ2Mt3NiQkzo8snN0VoAC6+A priv=MEcCAQAwBQYDK2VxBDsEOYocE4KALBjx383x8it677YwNG6ULwPoZsy9Dyb2V5c6a9ecLKGaR2/P3ikzQ1BJSTWCjxuBYChdcA== msg=C6uGSc4my5sc1b5KD0yzf8pvAugs9TX1zAn/UoaGBtQ+PbTERPZo0gUkFaJpzi7pAylYWEPbypATSCu9VzZ1bA== sig=5R8zBpHcMTrjxKPKQHfmOMX/0pLI6ikVtPNDAnnMN95Arep+AUrOvTD/AdhCqFbYQ2HfSLyj1HyA1/uCkOuxLIWB6Q/PEknObXSSGos/OW2VOPZwzS2wnsDl9Df6Pe1CQoywOdW2bWeyKjtyeOffjSYA e=found last=26 s=33 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAuENBggn7f3u0IyjKLoWBgNcyW9k7/SF0HbdimUKQJExJV7F7HQOyCCNVsPdVEQBBbQzznB4bPeaA priv=MEcCAQAwBQYDK2VxBDsEOc9xVr0rIxIyOpon/KwfGdAOMlshcr41rNZjphlVaCSB1iIrHQ4wrjsZ+h9REaSWpJ5s9Ksf9WKL0w== msg=kDQGWVXNvahPn3Rd3V+C1yTosn7TS/jCq4mcsXCXwcqLOye95FXLYWh6+8koMFrpy3QC+t6btoy+2zm41JToOw== sig=8fd5Vuk+z3hDe6oyuPcxMks0Q9ylutXLVkHXkYdKo3oroNCGGddLfJfUguKb+6Iz+CuZxWzifAEAmOr48bu/YgB+hnL4pGkUZugyo/CyVSkmpX5Eb7O2dyOEXqucftefutrCHP4C1+je45N6DqZtkyAA e=found last=24 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAMl450MCopDKQsEXd4b1U88znZzWc6UjNYBJJ5sDLQsufLY/gYhNEpIlWgpIahwaTEdH0fjinWTQA priv=MEcCAQAwBQYDK2VxBDsEOUEYV/45lZUrFGk+hjnbeiDPQL/83rXcjLtKBRuAqpRIVLTt/uzXDPAzUstBwGGFlHttEAc078L8qw== msg=8KLaRHr+9luLuGq0K3sgfn1+79E66+HrHsnPu/B6nUpIu8JKXLwR1AgiKIrYrKSqZc1cuhQJZMI9N9SW+V/6TA== sig=eL4YPCVzDIUM0fx+N7MqDZaPY7OZN2lU04NZAdmpRQDX9WkXokuwBrEuFvTOwuJM/Ydh+rQmH7qAvqjO29CZI1R7Zv4ltEfviKlNISiAaO0qZdeMADQWKYPX/B/QDAC852JbIIEtEAemRrQwkduXCwYA e=found last=22 s=33 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA573btSSbaybdztah73t5LrfjEORPNbgsOu0/ZeO0HsqlXHYlQruWoAtoa8/N/x9xQsBX1HjzxncA priv=MEcCAQAwBQYDK2VxBDsEOS6E7Vfi734RWXf6Xz4Yrhmm/Nr8o+eh7G+rRCm7xQt8Ecd2B8XDItDRnbEo7bUB6qiT9vM88yRJdA== msg=tS7X22+OgLy/G4J3F8mqBg8OBvna5Vg1aN3uUKEFvm0VhSbD4rlJCkgIXy+ONaQdyq/4oUCtVhD5LpS2tf6ndA== sig=t0pS+98EaOXQCwwl7NAVnD939GkxireAZhXYvlUsGzw4G3ZbPxBemAtqaXZX6XcXlKBYvjeicnuADfWm4lA2tL7SjSABfb8VfMhu3ieBnSRG4gp/gHz+t7ksgxpe4yQrGqB2alfRX9n56gKZDc6rsi0A e=found 120 iterations",
+ "pub=MEMwBQYDK2VxAzoAQ9NflEtCllQdc+A3xSh+iHvi2zLM2ycSMWU4PZCjKtZ0fB0JYchkkXENpEh+Kl30bk8w7HrP1l6A priv=MEcCAQAwBQYDK2VxBDsEOQ2mSo7cDmgMZCuzYFBwEAxjQvQM4cl6COo7EU5Ld7BSANEKaC/7A5pzoPMJ/tO+mrwEnX24y+xPbQ== msg=Zd+GFlhel1ymFG+iUZgV4mjTZXLVFdAaiz68MtJ446zDHJfwScEAG2Av28+xh4Ox/IEaZnx4XnZ4NJ8Yzl1TBQ== sig=AZ93IuKRI/qr/XyL92HT2HwwD7GTrx8RTXTgwYFytcPIMlYByvNm9ZM029b6pepOwF33DFkM2o4AyikPzOMv/hFOAo9XT+YBHzk33BRMioS4sytzCYdZG1H8bDKukAxR39XwCM3Bx1b98FwiBqF2HjMA e=found last=25 s=36 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAf62n94Rpz+QXA9y0N2Wm0DyS5JkCCLZtfXzTDHa9NunS4tTIZQaPSuQ6V0uYSsw9zMyyzjHhUUOA priv=MEcCAQAwBQYDK2VxBDsEOZ+KhNkw8/7696bx1pnp1rVCPqdiarUVIYfSZVhq1fUlYNL414RCuhdUbt32l9NaexDjjOYXx2Wixg== msg=IJ64czHpTUo5Y5hJJ8KUF6EXQGOUqHt2pipaSd1YGtI1K+dy2Il8RLFx96lrEMQl+ioIVQvvxTB/RZ75a9lYXw== sig=Vxb9Q4IzAMHA0scCG8hRZLTOAPWQyOkN1/lY3M7YDbGcS0W2EG/UlR86PfNrW9bNzGD+y1w6layAy1YOrZ6sfyZoofn/x+U0jwYMpbw/LMGV0XuXshCu9hd3Np+8RGpR5l/bGcP8pxhG6z3UE6RJhwQA e=found last=19 s=34 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoA3yITBoCG/wtDJDNLiRvNPpeKWGjracmeKrwtb1SXOLgk2AibF2JzazjX5QAlg3++a2AArbMHpSAA priv=MEcCAQAwBQYDK2VxBDsEOdR64c1XQ47KP7IcIDkjprQQeRKIWzj5gfYDcoExw+aIQmxJk5NcPkh2rUsfgbDNq67/ICeKQqNU3w== msg=oirK/UXccmACP1hCe3tIm1mob4uweNwscS4PywZ950UlX/29JRXwoTAyqpROO/FeiHqe1l06Lk/glW64B/1lag== sig=/3CYxD6WVJaugYZvP0iP+Fgsst7xZHY+hgHbPRxn5AeezC5uc10GhVwo+TouGDOsdMYFQHjBiD6ApOWaJOjERWffLg6FCZyEe8fOgNbnumYp1aMO46/NJei1HqNIZufg3W2ym+T4SLcdn7dxAbVf8QcA e=found last=25 s=36 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAYwhB5Vg9eU+kcqNkXCnN+MWurbNsp6mSRzOyoQMOIwMskEJJruUhCzbnBmIXRkl3sYkiNVEcxv8A priv=MEcCAQAwBQYDK2VxBDsEOT50tAUTvflML4JnKvHBWG3PAX/y/Ld9N0pBzZuYRZtEFXP/Pp3m9zSPacXxo/gwutny9p9DHDUZSA== msg=qhwh7bSWZp3HFZODTNUR+ptNSR4mySYiYEByw+pln1NM3fAtr1Zqgpyv/JNg6vX+Ze0xZiqy4WO6pTWIZMOaLw== sig=kwcT35Tnum7Px20ZPIq5Rj9A+d8oEVK5CDc0yuPDVxubKV1tF89LN4Ffa8SVXe14kPBKsur+apSAsa1XBDJdhxLAQm43E4bnCWKgXZfFGdRVY53EQ6KxpJEpr1geG4CNWDm54jaX4rbnRHXcmbRpnRMA e=found last=27 s=33 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAii4Pnugi6fdrvCg0v0Tr4O4cpvsejrpxrUgbFA9C0qFfIzReArEho4Lj5PBP2RGta4aQ59wfRx+A priv=MEcCAQAwBQYDK2VxBDsEOf7xCFwbgaPBG99Ie6Hv+7c+c+nDLPhtudSgTB2XH1p18TncC+06ng3gQx/prc4Sc8xqdxOlivXk7A== msg=hIJRPz26zBKGOUNyGqaCXvsxFUwvCE+LjvXBV8kVh1qgW2Zf/32VwhNNodFXqnTsZ8GPFp405ur/XJjUq/jN9g== sig=MDVK4VfP8YTzTsCsjvu3Hb4gLT2dP5usQPyEOdwRzvbAZop+lBUKJWtiUt4Dgt4MMwTkkHpA+L8APjjb0AofdMSS8xmYq4EmW4s1/4XLNd08ytvItvExG1FGoG4g4Cyh5nmavzTyeuZDFaRapFqFFSQA e=found last=23 s=32 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAclJpk2GIlQgu/cTr5Ydt7oboJFRDZTXtRI1+Z3ziPTl9N8Krsp991a0u9CVaRUa9KlGwVEaimWAA priv=MEcCAQAwBQYDK2VxBDsEOaXj2iO0tgr+r0NGAQjVeM9D4UtO0opzTDrB07phdrG/iOf5ewU3f2UIAf0KvcJubdiy9CL/Ko2v8A== msg=V9hz/ZC763KgvL6g+HJLawEcpjVrpe1W+WU4j+7kDBF1yOCkwm+q8VVmZg6uVjdN/1YPcAlT1V/wpiENEZY+5A== sig=d0h+mhTrsksYkwg3wGLx/9tMwEkIRVcVU1D+GuIQXV22q4kJcBbR1MqejEx5aNhX0x0SZAcFNuYAp1GOgA83EtWVOsdXGKNlqBgC2dS6q91aFWkx6BWfliMgtwHFNaQ2LAw2IAtpgQFPqFILBKIWyAMA e=found last=18 s=35 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAUUN8YLlaMRvSh5No5lhzZEWWXenj5s/xYahQ36Wi7h6WA9fftEh1Dzqg/Ahp3dJ4JK1jK0U1RKgA priv=MEcCAQAwBQYDK2VxBDsEOdH8ajmonAv3c/ttJN+dzOsCOyOkegEv+nxyMj4Smi0M+GMg70OR8xYRxD6tAa/2a+zDAQYEWu9fNg== msg=kPcDcqX5HKxYMr4Ib0IwDY7YmfqLLxScWe8uVelCEFrBbkTGcU0MMR+GLJ/KX+UjV12cw0piV0jeVpywuRef7g== sig=GYAjudVq7b3amLCblFF547qphAT1+79DHgAGA5odg1RYxOOsKgjN7Mpk8vmPnzEnOGrPaBSWebEAdLjNbPmUYhfUxFwqrdF8mWFaNyRy9etONkkZ34NKOd4/VJbqJ7KgWXkcdHNG5Xe+8E+M73ATmTAA e=found last=20 s=33 in subShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAHDFVC+LSl0eBbc2R8U7XERNn2IghiFvVuowduSSHsASZBXBiVMujpsSBI5CkYLMw8wA5e8Of+ioA priv=MEcCAQAwBQYDK2VxBDsEOX4x/IJAwLMkZbs0gRwKy9hzZYqpslcA5RGCooEHXFZPY1Ct7cvmARbH+W0+o4Rk1MY/ffT4QK3Tog== msg=kmM34GXThQA/skDKDXetReU28jnAFvSW6zTXJiXR1VL0D+Gllog6KjUjej8/Xtdh1tbq7h6jOIa87rVRImRH1w== sig=dLYgl8cicjOpNPvbDxxa5N+WQmrQ+WGFVudWH15jVNzdYei2NWrfpRCf0+8H3FUtcXQh02fAUCEAXir8V8Q1oHlK32saXFdLs0vSFKLCY9na0luVEPuMdNW0NVlJPJxHV75jKwyWO58rI6JHL6Gx1AcA e=found last=23 s=35 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAGRn/O5NyCFjzKog9IPRh7G7mD5tejb4XOnBnseg1W7H5hcT8AyIAV2U9z8ekJfu9kdyrmlGf4KUA priv=MEcCAQAwBQYDK2VxBDsEOfrAdWFSKVghyArZjuG/sJnR+oYyO9kzxYu3pbqQQqCRHe37XRRCosY23HAsL9JvQMW11xAy4h9Enw== msg=/JrIENe1/CNVlfDMWBaUjCv9WT/6A8op8syjB/AtezRno6I4HqlagZAnIHnUCoz3cQgfOm5lIrp3B/5gCOi1Dw== sig=Rtr8jfKYNfFY3h9DeusHycfJKpIw0Ob4OYy3zSk2u0dNTv6kK0X7j6H+nvps5SNsbxkdcmb5JaKAPvqCwlDHtzSkGlNLMqCbrA3zn7ap/sVJz0KriZgN2LkZmSjNQLzIY6xHXodlyta2JE2iGuCbgy0A e=found last=21 s=33 in addShifted_NP",
+ "pub=MEMwBQYDK2VxAzoAk6TbBisa2S0/rC6zKE3mKFC4If2yJZ3P9V/LNPhh8R1ch5Ugn13v8vDjqotXSmxwBHDIGtu1wRiA priv=MEcCAQAwBQYDK2VxBDsEOZV5u73XH2owfeYVPY9p9usxM2HKPMT3fRIaxq+WB601FGy/z6Q4ByRnrNahAbjt5C02xqH0uWF0yA== msg=vkkXHvYZOYAo8psXZDjY/uTXYpe7RiuhhaLo8VGPhHmcg0akrJfUAyLyuGVWpgeR7dkiN58qFL6Arw8CLyEU8A== sig=h4UndzbUyfve20M8qaX+e0vCwEVXaNeDxLRe1izwA3Zn6kWYJkaXWnihxwifXg9JP0PFWGzZOjaAF6MSnkVUM8m2AuXt4iRgTTi3D9y3yjHfDwwPzW4iuQj521plOBgLWQ73AY7K+ARFY0WEyLo3fQcA e=found last=20 s=36 in subShifted_NP",
+ };
+
+ for (String test : testCases)
+ {
+ String[] parts = test.split(" ", 5);
+ if (!parts[0].startsWith("pub=") || !parts[1].startsWith("priv=") || !parts[2].startsWith("msg=") || !parts[3].startsWith("sig=") || !parts[4].startsWith("e="))
+ {
+ fail("invalid test case format; expected five parts (pub=, priv=, msg=, sig=, e=), but got " + test);
+ }
+
+ byte[] x509PubBytes = Base64.decode(parts[0].substring("pub=".length()));
+ byte[] x509PrivBytes = Base64.decode(parts[1].substring("priv=".length()));
+ byte[] msg = Base64.decode(parts[2].substring("msg=".length()));
+ byte[] sig = Base64.decode(parts[3].substring("sig=".length()));
+ String error = parts[4].substring("e=".length());
+
+ byte[] pubBytes = Arrays.copyOfRange(x509PubBytes, 12, x509PubBytes.length);
+ byte[] privBytes = Arrays.copyOfRange(x509PrivBytes, 16, x509PrivBytes.length);
+
+ Ed448PublicKeyParameters pub = new Ed448PublicKeyParameters(pubBytes);
+ Ed448PrivateKeyParameters priv = new Ed448PrivateKeyParameters(privBytes);
+ Ed448PublicKeyParameters pubDerived = priv.generatePublicKey();
+
+ if (!Arrays.areEqual(pubDerived.getEncoded(), pub.getEncoded())) {
+ fail("different derived public keys; expected=" + Hex.toHexString(pub.getEncoded()) + " derived=" + Hex.toHexString(pubDerived.getEncoded()));
+ }
+
+ Signer signer = new Ed448Signer(new byte[0]);
+ signer.init(true, priv);
+ signer.update(msg, 0, msg.length);
+ byte[] sigDerived = signer.generateSignature();
+
+ if (!Arrays.areEqual(sigDerived, sig)) {
+ fail("different signatures of message; expected=" + Hex.toHexString(sig) + " actual=" + Hex.toHexString(sigDerived));
+ }
+
+ signer.init(false, pub);
+ signer.update(msg, 0, msg.length);
+ if (!signer.verifySignature(sig)) {
+ fail("signature verification failed for test vector: " + error);
+ }
+ }
+ }
}
From 61514fb2ba0fe735f04db6d76e8f55897d63c28e Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Fri, 29 Mar 2024 12:21:36 +0700
Subject: [PATCH 0207/1846] Update EdDSA tests
---
.../java/org/bouncycastle/crypto/test/Ed25519Test.java | 9 +++++----
.../java/org/bouncycastle/crypto/test/Ed448Test.java | 8 +++++---
2 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java b/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java
index 87bdd0467e..a3debc6b89 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Ed25519Test.java
@@ -34,6 +34,8 @@ public static void main(String[] args)
public void performTest() throws Exception
{
+ basicSigTest();
+
for (int i = 0; i < 10; ++i)
{
testConsistency(Ed25519.Algorithm.Ed25519, null);
@@ -43,7 +45,6 @@ public void performTest() throws Exception
testConsistency(Ed25519.Algorithm.Ed25519ph, context);
}
- basicSigTest();
testRegressionInfiniteLoop();
}
@@ -837,9 +838,9 @@ private void testRegressionInfiniteLoop() throws Exception
signer.init(false, pub);
signer.update(msg, 0, msg.length);
- if (!signer.verifySignature(sig)) {
- fail("signature verification failed for test vector: " + error);
- }
+ boolean shouldVerify = signer.verifySignature(sig);
+
+ isTrue("signature verification failed for test vector: " + error, shouldVerify);
}
}
}
diff --git a/core/src/test/java/org/bouncycastle/crypto/test/Ed448Test.java b/core/src/test/java/org/bouncycastle/crypto/test/Ed448Test.java
index 07e0295406..baae4e7b0d 100644
--- a/core/src/test/java/org/bouncycastle/crypto/test/Ed448Test.java
+++ b/core/src/test/java/org/bouncycastle/crypto/test/Ed448Test.java
@@ -41,6 +41,8 @@ public void performTest() throws Exception
testConsistency(Ed448.Algorithm.Ed448, context);
testConsistency(Ed448.Algorithm.Ed448ph, context);
}
+
+ testRegressionInfiniteLoop();
}
private void basicSigTest()
@@ -1234,9 +1236,9 @@ private void testRegressionInfiniteLoop() throws Exception
signer.init(false, pub);
signer.update(msg, 0, msg.length);
- if (!signer.verifySignature(sig)) {
- fail("signature verification failed for test vector: " + error);
- }
+ boolean shouldVerify = signer.verifySignature(sig);
+
+ isTrue("signature verification failed for test vector: " + error, shouldVerify);
}
}
}
From 5eaa2903c417b5e670493355ce99f215048994c2 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Sat, 30 Mar 2024 03:33:29 +1100
Subject: [PATCH 0208/1846] corrected test to avoid failure where last byte was
already zero.
---
.../jce/provider/test/ChaCha20Poly1305Test.java | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/ChaCha20Poly1305Test.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/ChaCha20Poly1305Test.java
index b3cf3b5c46..5b8b6084dc 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/ChaCha20Poly1305Test.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/ChaCha20Poly1305Test.java
@@ -18,6 +18,7 @@
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;
+import org.bouncycastle.util.test.TestFailedException;
public class ChaCha20Poly1305Test
extends SimpleTest
@@ -91,13 +92,19 @@ public void performTest() throws Exception
// check mac failure
byte[] faulty = new byte[enc.length];
- System.arraycopy(enc, 0, faulty, 0, enc.length - 1);
+ System.arraycopy(enc, 0, faulty, 0, enc.length);
+ faulty[faulty.length - 1] ^= 0xff;
+
try
{
decCipher.doFinal(faulty);
fail("no exception");
}
+ catch (TestFailedException e)
+ {
+ throw e;
+ }
catch (Exception e)
{
if (aeadAvailable)
From 9aa5b506ad20aa86408c58419537440d828f5ac2 Mon Sep 17 00:00:00 2001
From: royb
Date: Tue, 2 Apr 2024 11:02:20 -0400
Subject: [PATCH 0209/1846] Added Mock Tls Tests
---
.../tls/test/MockTlsKEMClient.java | 232 +++++++++++++++++
.../tls/test/MockTlsKEMServer.java | 242 ++++++++++++++++++
.../tls/test/TlsProtocolKEMTest.java | 78 ++++++
3 files changed, 552 insertions(+)
create mode 100644 tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMClient.java
create mode 100644 tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMServer.java
create mode 100644 tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java
diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMClient.java
new file mode 100644
index 0000000000..26a9bb28a8
--- /dev/null
+++ b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMClient.java
@@ -0,0 +1,232 @@
+package org.bouncycastle.tls.test;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.x509.Certificate;
+import org.bouncycastle.tls.AlertDescription;
+import org.bouncycastle.tls.AlertLevel;
+import org.bouncycastle.tls.CertificateRequest;
+import org.bouncycastle.tls.ChannelBinding;
+import org.bouncycastle.tls.ClientCertificateType;
+import org.bouncycastle.tls.DefaultTlsClient;
+import org.bouncycastle.tls.MaxFragmentLength;
+import org.bouncycastle.tls.NamedGroup;
+import org.bouncycastle.tls.NamedGroupRole;
+import org.bouncycastle.tls.ProtocolName;
+import org.bouncycastle.tls.ProtocolVersion;
+import org.bouncycastle.tls.SignatureAlgorithm;
+import org.bouncycastle.tls.TlsAuthentication;
+import org.bouncycastle.tls.TlsCredentials;
+import org.bouncycastle.tls.TlsExtensionsUtils;
+import org.bouncycastle.tls.TlsFatalAlert;
+import org.bouncycastle.tls.TlsServerCertificate;
+import org.bouncycastle.tls.TlsSession;
+import org.bouncycastle.tls.TlsUtils;
+import org.bouncycastle.tls.crypto.TlsCertificate;
+import org.bouncycastle.tls.crypto.TlsCrypto;
+import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.Integers;
+import org.bouncycastle.util.encoders.Hex;
+
+class MockTlsKEMClient
+ extends DefaultTlsClient
+{
+ TlsSession session;
+
+ MockTlsKEMClient(TlsSession session)
+ {
+ super(new BcTlsCrypto());
+
+ this.session = session;
+ }
+
+ protected Vector getProtocolNames()
+ {
+ Vector protocolNames = new Vector();
+ protocolNames.addElement(ProtocolName.HTTP_1_1);
+ protocolNames.addElement(ProtocolName.HTTP_2_TLS);
+ return protocolNames;
+ }
+
+ protected Vector getSupportedGroups(Vector namedGroupRoles) {
+ TlsCrypto crypto = getCrypto();
+ Vector supportedGroups = new Vector();
+
+ if (namedGroupRoles.contains(Integers.valueOf(NamedGroupRole.kem))) {
+ TlsUtils.addIfSupported(supportedGroups, crypto,
+ new int[]{ NamedGroup.kyber512, NamedGroup.kyber768, NamedGroup.kyber1024 });
+ };
+ return supportedGroups;
+ }
+
+ public TlsSession getSessionToResume()
+ {
+ return this.session;
+ }
+
+ public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause)
+ {
+ PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out;
+ out.println("TLS client raised alert: " + AlertLevel.getText(alertLevel)
+ + ", " + AlertDescription.getText(alertDescription));
+ if (message != null)
+ {
+ out.println("> " + message);
+ }
+ if (cause != null)
+ {
+ cause.printStackTrace(out);
+ }
+ }
+
+ public void notifyAlertReceived(short alertLevel, short alertDescription)
+ {
+ PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out;
+ out.println("TLS PQC client received alert: " + AlertLevel.getText(alertLevel)
+ + ", " + AlertDescription.getText(alertDescription));
+ }
+
+ public Hashtable getClientExtensions() throws IOException
+ {
+ if (context.getSecurityParametersHandshake().getClientRandom() == null)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions());
+ {
+ /*
+ * NOTE: If you are copying test code, do not blindly set these extensions in your own client.
+ */
+ TlsExtensionsUtils.addMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9);
+ TlsExtensionsUtils.addPaddingExtension(clientExtensions, context.getCrypto().getSecureRandom().nextInt(16));
+ TlsExtensionsUtils.addTruncatedHMacExtension(clientExtensions);
+ }
+ return clientExtensions;
+ }
+
+ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException
+ {
+ super.notifyServerVersion(serverVersion);
+
+ System.out.println("TLS PQC client negotiated " + serverVersion);
+ }
+
+ public TlsAuthentication getAuthentication() throws IOException
+ {
+ return new TlsAuthentication()
+ {
+ public void notifyServerCertificate(TlsServerCertificate serverCertificate) throws IOException
+ {
+ TlsCertificate[] chain = serverCertificate.getCertificate().getCertificateList();
+
+ System.out.println("TLS PQC client received server certificate chain of length " + chain.length);
+ for (int i = 0; i != chain.length; i++)
+ {
+ Certificate entry = Certificate.getInstance(chain[i].getEncoded());
+ // TODO Create fingerprint based on certificate signature algorithm digest
+ System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " ("
+ + entry.getSubject() + ")");
+ }
+
+ boolean isEmpty = serverCertificate == null || serverCertificate.getCertificate() == null
+ || serverCertificate.getCertificate().isEmpty();
+
+ if (isEmpty)
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+ }
+
+ String[] trustedCertResources = new String[]{ "x509-server-dsa.pem", "x509-server-ecdh.pem",
+ "x509-server-ecdsa.pem", "x509-server-ed25519.pem", "x509-server-ed448.pem",
+ "x509-server-rsa_pss_256.pem", "x509-server-rsa_pss_384.pem", "x509-server-rsa_pss_512.pem",
+ "x509-server-rsa-enc.pem", "x509-server-rsa-sign.pem" };
+
+ TlsCertificate[] certPath = TlsTestUtils.getTrustedCertPath(context.getCrypto(), chain[0],
+ trustedCertResources);
+
+ if (null == certPath)
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+ }
+
+ TlsUtils.checkPeerSigAlgs(context, certPath);
+ }
+
+ public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) throws IOException
+ {
+ short[] certificateTypes = certificateRequest.getCertificateTypes();
+ if (certificateTypes == null || !Arrays.contains(certificateTypes, ClientCertificateType.rsa_sign))
+ {
+ return null;
+ }
+
+ return TlsTestUtils.loadSignerCredentials(context, certificateRequest.getSupportedSignatureAlgorithms(),
+ SignatureAlgorithm.rsa, "x509-client-rsa.pem", "x509-client-key-rsa.pem");
+ }
+ };
+ }
+
+ public void notifyHandshakeComplete() throws IOException
+ {
+ super.notifyHandshakeComplete();
+
+ ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol();
+ if (protocolName != null)
+ {
+ System.out.println("PQC Client ALPN: " + protocolName.getUtf8Decoding());
+ }
+
+ TlsSession newSession = context.getSession();
+ if (newSession != null)
+ {
+ if (newSession.isResumable())
+ {
+ byte[] newSessionID = newSession.getSessionID();
+ String hex = hex(newSessionID);
+
+ if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID))
+ {
+ System.out.println("PQC Client resumed session: " + hex);
+ }
+ else
+ {
+ System.out.println("PQC Client established session: " + hex);
+ }
+
+ this.session = newSession;
+ }
+
+ byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point);
+ if (null != tlsServerEndPoint)
+ {
+ System.out.println("PQC Client 'tls-server-end-point': " + hex(tlsServerEndPoint));
+ }
+
+ byte[] tlsUnique = context.exportChannelBinding(ChannelBinding.tls_unique);
+ System.out.println("PQC Client 'tls-unique': " + hex(tlsUnique));
+
+ byte[] tlsExporter = context.exportChannelBinding(ChannelBinding.tls_exporter);
+ System.out.println("PQC Client 'tls-exporter': " + hex(tlsExporter));
+ }
+ }
+
+ public void processServerExtensions(Hashtable serverExtensions) throws IOException
+ {
+ if (context.getSecurityParametersHandshake().getServerRandom() == null)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ super.processServerExtensions(serverExtensions);
+ }
+
+ protected String hex(byte[] data)
+ {
+ return data == null ? "(null)" : Hex.toHexString(data);
+ }
+}
\ No newline at end of file
diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMServer.java
new file mode 100644
index 0000000000..a5530a1839
--- /dev/null
+++ b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMServer.java
@@ -0,0 +1,242 @@
+package org.bouncycastle.tls.test;
+
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Hashtable;
+import java.util.Vector;
+
+import org.bouncycastle.asn1.x500.X500Name;
+import org.bouncycastle.asn1.x509.Certificate;
+import org.bouncycastle.tls.AlertDescription;
+import org.bouncycastle.tls.AlertLevel;
+import org.bouncycastle.tls.CertificateRequest;
+import org.bouncycastle.tls.ChannelBinding;
+import org.bouncycastle.tls.ClientCertificateType;
+import org.bouncycastle.tls.DefaultTlsServer;
+import org.bouncycastle.tls.NamedGroup;
+import org.bouncycastle.tls.ProtocolName;
+import org.bouncycastle.tls.ProtocolVersion;
+import org.bouncycastle.tls.SignatureAlgorithm;
+import org.bouncycastle.tls.TlsCredentialedDecryptor;
+import org.bouncycastle.tls.TlsCredentialedSigner;
+import org.bouncycastle.tls.TlsCredentials;
+import org.bouncycastle.tls.TlsFatalAlert;
+import org.bouncycastle.tls.TlsUtils;
+import org.bouncycastle.tls.crypto.TlsCertificate;
+import org.bouncycastle.tls.crypto.impl.bc.BcTlsCrypto;
+import org.bouncycastle.util.encoders.Hex;
+
+class MockTlsKEMServer
+ extends DefaultTlsServer
+{
+ MockTlsKEMServer()
+ {
+ super(new BcTlsCrypto());
+ }
+
+ protected Vector getProtocolNames()
+ {
+ Vector protocolNames = new Vector();
+ protocolNames.addElement(ProtocolName.HTTP_2_TLS);
+ protocolNames.addElement(ProtocolName.HTTP_1_1);
+ return protocolNames;
+ }
+
+ public int[] getSupportedGroups() throws IOException {
+ return new int[] {
+ NamedGroup.kyber512,
+ NamedGroup.kyber768,
+ NamedGroup.kyber1024,
+// NamedGroup.secp256Kyber512,
+// NamedGroup.secp384Kyber768,
+// NamedGroup.secp521Kyber1024,
+// NamedGroup.x25519Kyber512,
+// NamedGroup.x25519Kyber768,
+// NamedGroup.x448Kyber768,
+ NamedGroup.x25519
+ };
+ }
+
+ public TlsCredentials getCredentials() throws IOException
+ {
+ /*
+ * TODO[tls13] Should really be finding the first client-supported signature scheme that the
+ * server also supports and has credentials for.
+ */
+ if (TlsUtils.isTLSv13(context))
+ {
+ return getRSASignerCredentials();
+ }
+
+ return super.getCredentials();
+ }
+
+ public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause)
+ {
+ PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out;
+ out.println("TLS PQC server raised alert: " + AlertLevel.getText(alertLevel)
+ + ", " + AlertDescription.getText(alertDescription));
+ if (message != null)
+ {
+ out.println("> " + message);
+ }
+ if (cause != null)
+ {
+ cause.printStackTrace(out);
+ }
+ }
+
+ public void notifyAlertReceived(short alertLevel, short alertDescription)
+ {
+ PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out;
+ out.println("TLS PQC server received alert: " + AlertLevel.getText(alertLevel)
+ + ", " + AlertDescription.getText(alertDescription));
+ }
+
+ public ProtocolVersion getServerVersion() throws IOException
+ {
+ ProtocolVersion serverVersion = super.getServerVersion();
+
+ System.out.println("TLS PQC server negotiated " + serverVersion);
+
+ return serverVersion;
+ }
+
+ public CertificateRequest getCertificateRequest() throws IOException
+ {
+ Vector serverSigAlgs = null;
+ if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(context.getServerVersion()))
+ {
+ serverSigAlgs = TlsUtils.getDefaultSupportedSignatureAlgorithms(context);
+ }
+
+ Vector certificateAuthorities = new Vector();
+// certificateAuthorities.addElement(TlsTestUtils.loadBcCertificateResource("x509-ca-dsa.pem").getSubject());
+// certificateAuthorities.addElement(TlsTestUtils.loadBcCertificateResource("x509-ca-ecdsa.pem").getSubject());
+// certificateAuthorities.addElement(TlsTestUtils.loadBcCertificateResource("x509-ca-rsa.pem").getSubject());
+
+ // All the CA certificates are currently configured with this subject
+ certificateAuthorities.addElement(new X500Name("CN=BouncyCastle TLS Test CA"));
+
+ if (TlsUtils.isTLSv13(context))
+ {
+ // TODO[tls13] Support for non-empty request context
+ byte[] certificateRequestContext = TlsUtils.EMPTY_BYTES;
+
+ // TODO[tls13] Add TlsTestConfig.serverCertReqSigAlgsCert
+ Vector serverSigAlgsCert = null;
+
+ return new CertificateRequest(certificateRequestContext, serverSigAlgs, serverSigAlgsCert,
+ certificateAuthorities);
+ }
+ else
+ {
+ short[] certificateTypes = new short[]{ ClientCertificateType.rsa_sign,
+ ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign };
+
+ return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities);
+ }
+ }
+
+ public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCertificate) throws IOException
+ {
+ TlsCertificate[] chain = clientCertificate.getCertificateList();
+
+ System.out.println("TLS PQC server received client certificate chain of length " + chain.length);
+ for (int i = 0; i != chain.length; i++)
+ {
+ Certificate entry = Certificate.getInstance(chain[i].getEncoded());
+ // TODO Create fingerprint based on certificate signature algorithm digest
+ System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " ("
+ + entry.getSubject() + ")");
+ }
+
+ boolean isEmpty = (clientCertificate == null || clientCertificate.isEmpty());
+
+ if (isEmpty)
+ {
+ return;
+ }
+
+ String[] trustedCertResources = new String[]{ "x509-client-dsa.pem", "x509-client-ecdh.pem",
+ "x509-client-ecdsa.pem", "x509-client-ed25519.pem", "x509-client-ed448.pem", "x509-client-rsa_pss_256.pem",
+ "x509-client-rsa_pss_384.pem", "x509-client-rsa_pss_512.pem", "x509-client-rsa.pem" };
+
+ TlsCertificate[] certPath = TlsTestUtils.getTrustedCertPath(context.getCrypto(), chain[0],
+ trustedCertResources);
+
+ if (null == certPath)
+ {
+ throw new TlsFatalAlert(AlertDescription.bad_certificate);
+ }
+
+ TlsUtils.checkPeerSigAlgs(context, certPath);
+ }
+
+ public void notifyHandshakeComplete() throws IOException
+ {
+ super.notifyHandshakeComplete();
+
+ ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol();
+ if (protocolName != null)
+ {
+ System.out.println("PQC Server ALPN: " + protocolName.getUtf8Decoding());
+ }
+
+ byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point);
+ System.out.println("PQC Server 'tls-server-end-point': " + hex(tlsServerEndPoint));
+
+ byte[] tlsUnique = context.exportChannelBinding(ChannelBinding.tls_unique);
+ System.out.println("PQC Server 'tls-unique': " + hex(tlsUnique));
+
+ byte[] tlsExporter = context.exportChannelBinding(ChannelBinding.tls_exporter);
+ System.out.println("PQC Server 'tls-exporter': " + hex(tlsExporter));
+ }
+
+ public void processClientExtensions(Hashtable clientExtensions) throws IOException
+ {
+ if (context.getSecurityParametersHandshake().getClientRandom() == null)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ super.processClientExtensions(clientExtensions);
+ }
+
+ public Hashtable getServerExtensions() throws IOException
+ {
+ if (context.getSecurityParametersHandshake().getServerRandom() == null)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ return super.getServerExtensions();
+ }
+
+ public void getServerExtensionsForConnection(Hashtable serverExtensions) throws IOException
+ {
+ if (context.getSecurityParametersHandshake().getServerRandom() == null)
+ {
+ throw new TlsFatalAlert(AlertDescription.internal_error);
+ }
+
+ super.getServerExtensionsForConnection(serverExtensions);
+ }
+
+ protected TlsCredentialedDecryptor getRSAEncryptionCredentials() throws IOException
+ {
+ return TlsTestUtils.loadEncryptionCredentials(context, new String[]{ "x509-server-rsa-enc.pem", "x509-ca-rsa.pem" },
+ "x509-server-key-rsa-enc.pem");
+ }
+
+ protected TlsCredentialedSigner getRSASignerCredentials() throws IOException
+ {
+ Vector clientSigAlgs = context.getSecurityParametersHandshake().getClientSigAlgs();
+ return TlsTestUtils.loadSignerCredentialsServer(context, clientSigAlgs, SignatureAlgorithm.rsa);
+ }
+
+ protected String hex(byte[] data)
+ {
+ return data == null ? "(null)" : Hex.toHexString(data);
+ }
+}
\ No newline at end of file
diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java
new file mode 100644
index 0000000000..d895308b0c
--- /dev/null
+++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java
@@ -0,0 +1,78 @@
+package org.bouncycastle.tls.test;
+
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+
+import org.bouncycastle.tls.TlsClientProtocol;
+import org.bouncycastle.tls.TlsServerProtocol;
+import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.io.Streams;
+
+import junit.framework.TestCase;
+
+public class TlsProtocolKEMTest
+ extends TestCase
+{
+ public void testClientServer() throws Exception
+ {
+ PipedInputStream clientRead = TlsTestUtils.createPipedInputStream();
+ PipedInputStream serverRead = TlsTestUtils.createPipedInputStream();
+ PipedOutputStream clientWrite = new PipedOutputStream(serverRead);
+ PipedOutputStream serverWrite = new PipedOutputStream(clientRead);
+
+ TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite);
+ TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite);
+
+ ServerThread serverThread = new ServerThread(serverProtocol);
+ serverThread.start();
+
+ MockTlsKEMClient client = new MockTlsKEMClient(null);
+ clientProtocol.connect(client);
+
+ // NOTE: Because we write-all before we read-any, this length can't be more than the pipe capacity
+ int length = 1000;
+
+ byte[] data = new byte[length];
+ client.getCrypto().getSecureRandom().nextBytes(data);
+
+ OutputStream output = clientProtocol.getOutputStream();
+ output.write(data);
+
+ byte[] echo = new byte[data.length];
+ int count = Streams.readFully(clientProtocol.getInputStream(), echo);
+
+ assertEquals(count, data.length);
+ assertTrue(Arrays.areEqual(data, echo));
+
+ output.close();
+
+ serverThread.join();
+ }
+
+ static class ServerThread
+ extends Thread
+ {
+ private final TlsServerProtocol serverProtocol;
+
+ ServerThread(TlsServerProtocol serverProtocol)
+ {
+ this.serverProtocol = serverProtocol;
+ }
+
+ public void run()
+ {
+ try
+ {
+ MockTlsKEMServer server = new MockTlsKEMServer();
+ serverProtocol.accept(server);
+ Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream());
+ serverProtocol.close();
+ }
+ catch (Exception e)
+ {
+// throw new RuntimeException(e);
+ }
+ }
+ }
+}
\ No newline at end of file
From 373d02ef28be06d3b21a6d660558d2353b391254 Mon Sep 17 00:00:00 2001
From: royb
Date: Tue, 2 Apr 2024 13:11:13 -0400
Subject: [PATCH 0210/1846] Renamed kyber to mlkem
---
.../jsse/provider/NamedGroupInfo.java | 6 ++---
.../java/org/bouncycastle/tls/NamedGroup.java | 22 +++++++++----------
.../bouncycastle/tls/crypto/TlsKEMConfig.java | 17 --------------
.../tls/crypto/impl/bc/BcTlsCrypto.java | 2 +-
.../bc/{BcTlsKyber.java => BcTlsMlKem.java} | 10 ++++-----
...KyberDomain.java => BcTlsMlKemDomain.java} | 16 +++++++-------
.../tls/crypto/impl/jcajce/JcaTlsCrypto.java | 8 +++----
.../{JceTlsKyber.java => JceTlsMlKem.java} | 10 ++++-----
...yberDomain.java => JceTlsMlKemDomain.java} | 16 +++++++-------
9 files changed, 45 insertions(+), 62 deletions(-)
rename tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/{BcTlsKyber.java => BcTlsMlKem.java} (86%)
rename tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/{BcTlsKyberDomain.java => BcTlsMlKemDomain.java} (87%)
rename tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/{JceTlsKyber.java => JceTlsMlKem.java} (86%)
rename tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/{JceTlsKyberDomain.java => JceTlsMlKemDomain.java} (87%)
diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java b/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java
index 384f203795..f3ea03cc24 100644
--- a/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java
+++ b/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java
@@ -75,9 +75,9 @@ private enum All
ffdhe6144(NamedGroup.ffdhe6144, "DiffieHellman"),
ffdhe8192(NamedGroup.ffdhe8192, "DiffieHellman"),
- kyber512(NamedGroup.kyber512, "KEM"),
- kyber768(NamedGroup.kyber768, "KEM"),
- kyber1024(NamedGroup.kyber1024, "KEM");
+ kyber512(NamedGroup.mlkem512, "KEM"),
+ kyber768(NamedGroup.mlkem768, "KEM"),
+ kyber1024(NamedGroup.mlkem1024, "KEM");
private final int namedGroup;
private final String name;
diff --git a/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java b/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java
index a3f24ffcc5..e63223f306 100644
--- a/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java
+++ b/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java
@@ -102,9 +102,9 @@ public class NamedGroup
public static final int arbitrary_explicit_prime_curves = 0xFF01;
public static final int arbitrary_explicit_char2_curves = 0xFF02;
- public static final int kyber512 = 0x023A;
- public static final int kyber768 = 0x023C;
- public static final int kyber1024 = 0x023D;
+ public static final int mlkem512 = 0x0247;
+ public static final int mlkem768 = 0x0248;
+ public static final int mlkem1024 = 0x0249;
/* Names of the actual underlying elliptic curves (not necessarily matching the NamedGroup names). */
private static final String[] CURVE_NAMES = new String[] { "sect163k1", "sect163r1", "sect163r2", "sect193r1",
@@ -135,7 +135,7 @@ public static boolean canBeNegotiated(int namedGroup, ProtocolVersion version)
{
if ((namedGroup >= brainpoolP256r1tls13 && namedGroup <= brainpoolP512r1tls13)
|| (namedGroup == curveSM2)
- || (namedGroup == kyber512 || namedGroup == kyber768 || namedGroup == kyber1024))
+ || (namedGroup == mlkem512 || namedGroup == mlkem768 || namedGroup == mlkem1024))
{
return false;
}
@@ -269,12 +269,12 @@ public static String getKEMName(int namedGroup)
{
switch (namedGroup)
{
- case kyber512:
- return "kyber512";
- case kyber768:
- return "kyber768";
- case kyber1024:
- return "kyber1024";
+ case mlkem512:
+ return "mlkem512";
+ case mlkem768:
+ return "mlkem768";
+ case mlkem1024:
+ return "mlkem1024";
default:
return null;
}
@@ -440,7 +440,7 @@ public static boolean refersToASpecificFiniteField(int namedGroup)
public static boolean refersToASpecificKEM(int namedGroup)
{
- return namedGroup == kyber512 || namedGroup == kyber768 || namedGroup == kyber1024;
+ return namedGroup == mlkem512 || namedGroup == mlkem768 || namedGroup == mlkem1024;
}
public static boolean refersToASpecificGroup(int namedGroup)
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMConfig.java b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMConfig.java
index e10cefe467..730ef2c487 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMConfig.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMConfig.java
@@ -31,22 +31,5 @@ public int getKEMNamedGroup()
private int getKEMNamedGroup(int namedGroup)
{
return namedGroup;
- // switch (namedGroup)
- // {
- // case NamedGroup.kyber512:
- // case NamedGroup.secp256Kyber512:
- // case NamedGroup.x25519Kyber512:
- // return NamedGroup.kyber512;
- // case NamedGroup.kyber768:
- // case NamedGroup.secp384Kyber768:
- // case NamedGroup.x25519Kyber768:
- // case NamedGroup.x448Kyber768:
- // return NamedGroup.kyber768;
- // case NamedGroup.kyber1024:
- // case NamedGroup.secp521Kyber1024:
- // return NamedGroup.kyber1024;
- // default:
- // return namedGroup;
- // }
}
}
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java
index 4f5a3262c4..da2f0dd6af 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java
@@ -215,7 +215,7 @@ public TlsECDomain createECDomain(TlsECConfig ecConfig)
public TlsKEMDomain createKEMDomain(TlsKEMConfig kemConfig)
{
- return new BcTlsKyberDomain(this, kemConfig);
+ return new BcTlsMlKemDomain(this, kemConfig);
}
public TlsNonceGenerator createNonceGenerator(byte[] additionalSeedMaterial)
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyber.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMlKem.java
similarity index 86%
rename from tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyber.java
rename to tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMlKem.java
index 1d65e6726b..414e2641f3 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyber.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMlKem.java
@@ -9,16 +9,16 @@
import org.bouncycastle.tls.crypto.TlsSecret;
import org.bouncycastle.util.Arrays;
-public class BcTlsKyber implements TlsAgreement
+public class BcTlsMlKem implements TlsAgreement
{
- protected final BcTlsKyberDomain domain;
+ protected final BcTlsMlKemDomain domain;
protected AsymmetricCipherKeyPair localKeyPair;
protected KyberPublicKeyParameters peerPublicKey;
protected byte[] ciphertext;
protected byte[] secret;
- public BcTlsKyber(BcTlsKyberDomain domain)
+ public BcTlsMlKem(BcTlsMlKemDomain domain)
{
this.domain = domain;
}
@@ -41,7 +41,7 @@ public void receivePeerValue(byte[] peerValue) throws IOException
if (domain.getTlsKEMConfig().isServer())
{
this.peerPublicKey = domain.decodePublicKey(peerValue);
- SecretWithEncapsulation encap = domain.enCap(peerPublicKey);
+ SecretWithEncapsulation encap = domain.encap(peerPublicKey);
ciphertext = encap.getEncapsulation();
secret = encap.getSecret();
}
@@ -59,7 +59,7 @@ public TlsSecret calculateSecret() throws IOException
}
else
{
- return domain.adoptLocalSecret(domain.deCap((KyberPrivateKeyParameters)localKeyPair.getPrivate(), ciphertext));
+ return domain.adoptLocalSecret(domain.decap((KyberPrivateKeyParameters)localKeyPair.getPrivate(), ciphertext));
}
}
}
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyberDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMlKemDomain.java
similarity index 87%
rename from tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyberDomain.java
rename to tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMlKemDomain.java
index e6e8396082..c886c15fd0 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyberDomain.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsMlKemDomain.java
@@ -15,17 +15,17 @@
import org.bouncycastle.tls.crypto.TlsKEMDomain;
import org.bouncycastle.tls.crypto.TlsSecret;
-public class BcTlsKyberDomain implements TlsKEMDomain
+public class BcTlsMlKemDomain implements TlsKEMDomain
{
public static KyberParameters getKyberParameters(TlsKEMConfig kemConfig)
{
switch (kemConfig.getKEMNamedGroup())
{
- case NamedGroup.kyber512:
+ case NamedGroup.mlkem512:
return KyberParameters.kyber512;
- case NamedGroup.kyber768:
+ case NamedGroup.mlkem768:
return KyberParameters.kyber768;
- case NamedGroup.kyber1024:
+ case NamedGroup.mlkem1024:
return KyberParameters.kyber1024;
default:
return null;
@@ -41,7 +41,7 @@ public TlsKEMConfig getTlsKEMConfig()
return kemConfig;
}
- public BcTlsKyberDomain(BcTlsCrypto crypto, TlsKEMConfig kemConfig)
+ public BcTlsMlKemDomain(BcTlsCrypto crypto, TlsKEMConfig kemConfig)
{
this.crypto = crypto;
this.kemConfig = kemConfig;
@@ -50,7 +50,7 @@ public BcTlsKyberDomain(BcTlsCrypto crypto, TlsKEMConfig kemConfig)
public TlsAgreement createKEM()
{
- return new BcTlsKyber(this);
+ return new BcTlsMlKem(this);
}
public KyberPublicKeyParameters decodePublicKey(byte[] encoding)
@@ -75,13 +75,13 @@ public TlsSecret adoptLocalSecret(byte[] secret)
return crypto.adoptLocalSecret(secret);
}
- public SecretWithEncapsulation enCap(KyberPublicKeyParameters peerPublicKey)
+ public SecretWithEncapsulation encap(KyberPublicKeyParameters peerPublicKey)
{
KyberKEMGenerator kemGen = new KyberKEMGenerator(crypto.getSecureRandom());
return kemGen.generateEncapsulated(peerPublicKey);
}
- public byte[] deCap(KyberPrivateKeyParameters kyberPrivateKeyParameters, byte[] cipherText)
+ public byte[] decap(KyberPrivateKeyParameters kyberPrivateKeyParameters, byte[] cipherText)
{
KyberKEMExtractor kemExtract = new KyberKEMExtractor(kyberPrivateKeyParameters);
byte[] secret = kemExtract.extractSecret(cipherText);
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java
index b6fcc0331b..a793678dbd 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java
@@ -442,9 +442,9 @@ else if (NamedGroup.refersToASpecificKEM(namedGroup))
{
switch (namedGroup)
{
- case NamedGroup.kyber512:
- case NamedGroup.kyber768:
- case NamedGroup.kyber1024:
+ case NamedGroup.mlkem512:
+ case NamedGroup.mlkem768:
+ case NamedGroup.mlkem1024:
return null;
}
}
@@ -843,7 +843,7 @@ public TlsECDomain createECDomain(TlsECConfig ecConfig)
public TlsKEMDomain createKEMDomain(TlsKEMConfig kemConfig)
{
- return new JceTlsKyberDomain(this, kemConfig);
+ return new JceTlsMlKemDomain(this, kemConfig);
}
public TlsSecret hkdfInit(int cryptoHashAlgorithm)
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyber.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMlKem.java
similarity index 86%
rename from tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyber.java
rename to tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMlKem.java
index 0d5e4768eb..fc5e82d6cd 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyber.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMlKem.java
@@ -8,16 +8,16 @@
import org.bouncycastle.tls.crypto.TlsAgreement;
import org.bouncycastle.util.Arrays;
-public class JceTlsKyber implements TlsAgreement
+public class JceTlsMlKem implements TlsAgreement
{
- protected final JceTlsKyberDomain domain;
+ protected final JceTlsMlKemDomain domain;
protected AsymmetricCipherKeyPair localKeyPair;
protected KyberPublicKeyParameters peerPublicKey;
protected byte[] ciphertext;
protected byte[] secret;
- public JceTlsKyber(JceTlsKyberDomain domain)
+ public JceTlsMlKem(JceTlsMlKemDomain domain)
{
this.domain = domain;
}
@@ -40,7 +40,7 @@ public void receivePeerValue(byte[] peerValue) throws IOException
if (domain.getTlsKEMConfig().isServer())
{
this.peerPublicKey = domain.decodePublicKey(peerValue);
- SecretWithEncapsulation encap = domain.enCap(peerPublicKey);
+ SecretWithEncapsulation encap = domain.encap(peerPublicKey);
ciphertext = encap.getEncapsulation();
secret = encap.getSecret();
}
@@ -58,7 +58,7 @@ public JceTlsSecret calculateSecret() throws IOException
}
else
{
- return domain.adoptLocalSecret(domain.deCap((KyberPrivateKeyParameters)localKeyPair.getPrivate(), ciphertext));
+ return domain.adoptLocalSecret(domain.decap((KyberPrivateKeyParameters)localKeyPair.getPrivate(), ciphertext));
}
}
}
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyberDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMlKemDomain.java
similarity index 87%
rename from tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyberDomain.java
rename to tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMlKemDomain.java
index 6f52c7c8e9..c6bf27711b 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyberDomain.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsMlKemDomain.java
@@ -14,17 +14,17 @@
import org.bouncycastle.tls.crypto.TlsKEMConfig;
import org.bouncycastle.tls.crypto.TlsKEMDomain;
-public class JceTlsKyberDomain implements TlsKEMDomain
+public class JceTlsMlKemDomain implements TlsKEMDomain
{
public static KyberParameters getKyberParameters(TlsKEMConfig kemConfig)
{
switch (kemConfig.getKEMNamedGroup())
{
- case NamedGroup.kyber512:
+ case NamedGroup.mlkem512:
return KyberParameters.kyber512;
- case NamedGroup.kyber768:
+ case NamedGroup.mlkem768:
return KyberParameters.kyber768;
- case NamedGroup.kyber1024:
+ case NamedGroup.mlkem1024:
return KyberParameters.kyber1024;
default:
return null;
@@ -40,7 +40,7 @@ public TlsKEMConfig getTlsKEMConfig()
return kemConfig;
}
- public JceTlsKyberDomain(JcaTlsCrypto crypto, TlsKEMConfig kemConfig)
+ public JceTlsMlKemDomain(JcaTlsCrypto crypto, TlsKEMConfig kemConfig)
{
this.crypto = crypto;
this.kemConfig = kemConfig;
@@ -49,7 +49,7 @@ public JceTlsKyberDomain(JcaTlsCrypto crypto, TlsKEMConfig kemConfig)
public TlsAgreement createKEM()
{
- return new JceTlsKyber(this);
+ return new JceTlsMlKem(this);
}
public KyberPublicKeyParameters decodePublicKey(byte[] encoding)
@@ -74,13 +74,13 @@ public JceTlsSecret adoptLocalSecret(byte[] secret)
return crypto.adoptLocalSecret(secret);
}
- public SecretWithEncapsulation enCap(KyberPublicKeyParameters peerPublicKey)
+ public SecretWithEncapsulation encap(KyberPublicKeyParameters peerPublicKey)
{
KyberKEMGenerator kemGen = new KyberKEMGenerator(crypto.getSecureRandom());
return kemGen.generateEncapsulated(peerPublicKey);
}
- public byte[] deCap(KyberPrivateKeyParameters kyberPrivateKeyParameters, byte[] cipherText)
+ public byte[] decap(KyberPrivateKeyParameters kyberPrivateKeyParameters, byte[] cipherText)
{
KyberKEMExtractor kemExtract = new KyberKEMExtractor(kyberPrivateKeyParameters);
byte[] secret = kemExtract.extractSecret(cipherText);
From d33131e762fbfd1f7d71ec280f886a1cd6966666 Mon Sep 17 00:00:00 2001
From: royb
Date: Tue, 2 Apr 2024 16:01:02 -0400
Subject: [PATCH 0211/1846] Added mismatch test for different version of mlkem
---
.../tls/test/MockTlsKEMClient.java | 31 +++++---
.../tls/test/MockTlsKEMServer.java | 41 +++++------
.../tls/test/TlsProtocolKEMTest.java | 70 +++++++++++++++++--
3 files changed, 108 insertions(+), 34 deletions(-)
diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMClient.java b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMClient.java
index 26a9bb28a8..0d338f67d1 100644
--- a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMClient.java
+++ b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMClient.java
@@ -52,13 +52,24 @@ protected Vector getProtocolNames()
return protocolNames;
}
+ public int[] supportedGroups = new int[] {
+ NamedGroup.mlkem512,
+ NamedGroup.mlkem768,
+ NamedGroup.mlkem1024
+ };
+
+ public void setSupportedGroups(int[] supportedGroups)
+ {
+ this.supportedGroups = supportedGroups;
+ }
+
protected Vector getSupportedGroups(Vector namedGroupRoles) {
TlsCrypto crypto = getCrypto();
Vector supportedGroups = new Vector();
if (namedGroupRoles.contains(Integers.valueOf(NamedGroupRole.kem))) {
TlsUtils.addIfSupported(supportedGroups, crypto,
- new int[]{ NamedGroup.kyber512, NamedGroup.kyber768, NamedGroup.kyber1024 });
+ this.supportedGroups);
};
return supportedGroups;
}
@@ -86,7 +97,7 @@ public void notifyAlertRaised(short alertLevel, short alertDescription, String m
public void notifyAlertReceived(short alertLevel, short alertDescription)
{
PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out;
- out.println("TLS PQC client received alert: " + AlertLevel.getText(alertLevel)
+ out.println("TLS KEM client received alert: " + AlertLevel.getText(alertLevel)
+ ", " + AlertDescription.getText(alertDescription));
}
@@ -113,7 +124,7 @@ public void notifyServerVersion(ProtocolVersion serverVersion) throws IOExceptio
{
super.notifyServerVersion(serverVersion);
- System.out.println("TLS PQC client negotiated " + serverVersion);
+ System.out.println("TLS KEM client negotiated " + serverVersion);
}
public TlsAuthentication getAuthentication() throws IOException
@@ -124,7 +135,7 @@ public void notifyServerCertificate(TlsServerCertificate serverCertificate) thro
{
TlsCertificate[] chain = serverCertificate.getCertificate().getCertificateList();
- System.out.println("TLS PQC client received server certificate chain of length " + chain.length);
+ System.out.println("TLS KEM client received server certificate chain of length " + chain.length);
for (int i = 0; i != chain.length; i++)
{
Certificate entry = Certificate.getInstance(chain[i].getEncoded());
@@ -178,7 +189,7 @@ public void notifyHandshakeComplete() throws IOException
ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol();
if (protocolName != null)
{
- System.out.println("PQC Client ALPN: " + protocolName.getUtf8Decoding());
+ System.out.println("KEM Client ALPN: " + protocolName.getUtf8Decoding());
}
TlsSession newSession = context.getSession();
@@ -191,11 +202,11 @@ public void notifyHandshakeComplete() throws IOException
if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID))
{
- System.out.println("PQC Client resumed session: " + hex);
+ System.out.println("KEM Client resumed session: " + hex);
}
else
{
- System.out.println("PQC Client established session: " + hex);
+ System.out.println("KEM Client established session: " + hex);
}
this.session = newSession;
@@ -204,14 +215,14 @@ public void notifyHandshakeComplete() throws IOException
byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point);
if (null != tlsServerEndPoint)
{
- System.out.println("PQC Client 'tls-server-end-point': " + hex(tlsServerEndPoint));
+ System.out.println("KEM Client 'tls-server-end-point': " + hex(tlsServerEndPoint));
}
byte[] tlsUnique = context.exportChannelBinding(ChannelBinding.tls_unique);
- System.out.println("PQC Client 'tls-unique': " + hex(tlsUnique));
+ System.out.println("KEM Client 'tls-unique': " + hex(tlsUnique));
byte[] tlsExporter = context.exportChannelBinding(ChannelBinding.tls_exporter);
- System.out.println("PQC Client 'tls-exporter': " + hex(tlsExporter));
+ System.out.println("KEM Client 'tls-exporter': " + hex(tlsExporter));
}
}
diff --git a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMServer.java b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMServer.java
index a5530a1839..188c0dbe4b 100644
--- a/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMServer.java
+++ b/tls/src/test/java/org/bouncycastle/tls/test/MockTlsKEMServer.java
@@ -42,19 +42,20 @@ protected Vector getProtocolNames()
return protocolNames;
}
+ public int[] supportedGroups = new int[] {
+ NamedGroup.mlkem512,
+ NamedGroup.mlkem768,
+ NamedGroup.mlkem1024,
+ NamedGroup.x25519
+ };
+
+ public void setSupportedGroups(int[] supportedGroups)
+ {
+ this.supportedGroups = supportedGroups;
+ }
+
public int[] getSupportedGroups() throws IOException {
- return new int[] {
- NamedGroup.kyber512,
- NamedGroup.kyber768,
- NamedGroup.kyber1024,
-// NamedGroup.secp256Kyber512,
-// NamedGroup.secp384Kyber768,
-// NamedGroup.secp521Kyber1024,
-// NamedGroup.x25519Kyber512,
-// NamedGroup.x25519Kyber768,
-// NamedGroup.x448Kyber768,
- NamedGroup.x25519
- };
+ return supportedGroups;
}
public TlsCredentials getCredentials() throws IOException
@@ -74,7 +75,7 @@ public TlsCredentials getCredentials() throws IOException
public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause)
{
PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out;
- out.println("TLS PQC server raised alert: " + AlertLevel.getText(alertLevel)
+ out.println("TLS KEM server raised alert: " + AlertLevel.getText(alertLevel)
+ ", " + AlertDescription.getText(alertDescription));
if (message != null)
{
@@ -89,7 +90,7 @@ public void notifyAlertRaised(short alertLevel, short alertDescription, String m
public void notifyAlertReceived(short alertLevel, short alertDescription)
{
PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out;
- out.println("TLS PQC server received alert: " + AlertLevel.getText(alertLevel)
+ out.println("TLS KEM server received alert: " + AlertLevel.getText(alertLevel)
+ ", " + AlertDescription.getText(alertDescription));
}
@@ -97,7 +98,7 @@ public ProtocolVersion getServerVersion() throws IOException
{
ProtocolVersion serverVersion = super.getServerVersion();
- System.out.println("TLS PQC server negotiated " + serverVersion);
+ System.out.println("TLS KEM server negotiated " + serverVersion);
return serverVersion;
}
@@ -142,7 +143,7 @@ public void notifyClientCertificate(org.bouncycastle.tls.Certificate clientCerti
{
TlsCertificate[] chain = clientCertificate.getCertificateList();
- System.out.println("TLS PQC server received client certificate chain of length " + chain.length);
+ System.out.println("TLS KEM server received client certificate chain of length " + chain.length);
for (int i = 0; i != chain.length; i++)
{
Certificate entry = Certificate.getInstance(chain[i].getEncoded());
@@ -180,17 +181,17 @@ public void notifyHandshakeComplete() throws IOException
ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol();
if (protocolName != null)
{
- System.out.println("PQC Server ALPN: " + protocolName.getUtf8Decoding());
+ System.out.println("KEM Server ALPN: " + protocolName.getUtf8Decoding());
}
byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point);
- System.out.println("PQC Server 'tls-server-end-point': " + hex(tlsServerEndPoint));
+ System.out.println("KEM Server 'tls-server-end-point': " + hex(tlsServerEndPoint));
byte[] tlsUnique = context.exportChannelBinding(ChannelBinding.tls_unique);
- System.out.println("PQC Server 'tls-unique': " + hex(tlsUnique));
+ System.out.println("KEM Server 'tls-unique': " + hex(tlsUnique));
byte[] tlsExporter = context.exportChannelBinding(ChannelBinding.tls_exporter);
- System.out.println("PQC Server 'tls-exporter': " + hex(tlsExporter));
+ System.out.println("KEM Server 'tls-exporter': " + hex(tlsExporter));
}
public void processClientExtensions(Hashtable clientExtensions) throws IOException
diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java
index d895308b0c..924a0abebb 100644
--- a/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java
+++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java
@@ -1,9 +1,11 @@
package org.bouncycastle.tls.test;
+import java.io.IOException;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
+import org.bouncycastle.tls.NamedGroup;
import org.bouncycastle.tls.TlsClientProtocol;
import org.bouncycastle.tls.TlsServerProtocol;
import org.bouncycastle.util.Arrays;
@@ -14,6 +16,40 @@
public class TlsProtocolKEMTest
extends TestCase
{
+
+ // mismatched ML-KEM strengths w/o classical crypto
+ public void testMismatchStrength() throws Exception
+ {
+ PipedInputStream clientRead = TlsTestUtils.createPipedInputStream();
+ PipedInputStream serverRead = TlsTestUtils.createPipedInputStream();
+ PipedOutputStream clientWrite = new PipedOutputStream(serverRead);
+ PipedOutputStream serverWrite = new PipedOutputStream(clientRead);
+
+ TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite);
+ TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite);
+
+ ServerThread serverThread = new ServerThread(serverProtocol, new int[] {NamedGroup.mlkem768}, true);
+ try
+ {
+ serverThread.start();
+ }
+ catch (Exception ignored)
+ {
+ }
+ MockTlsKEMClient client = new MockTlsKEMClient(null);
+ client.setSupportedGroups(new int[] {NamedGroup.mlkem512});
+ try
+ {
+ clientProtocol.connect(client);
+ fail();
+ }
+ catch (Exception ex)
+ {
+ }
+
+ serverThread.join();
+ }
+
public void testClientServer() throws Exception
{
PipedInputStream clientRead = TlsTestUtils.createPipedInputStream();
@@ -24,7 +60,7 @@ public void testClientServer() throws Exception
TlsClientProtocol clientProtocol = new TlsClientProtocol(clientRead, clientWrite);
TlsServerProtocol serverProtocol = new TlsServerProtocol(serverRead, serverWrite);
- ServerThread serverThread = new ServerThread(serverProtocol);
+ ServerThread serverThread = new ServerThread(serverProtocol, false);
serverThread.start();
MockTlsKEMClient client = new MockTlsKEMClient(null);
@@ -54,10 +90,21 @@ static class ServerThread
extends Thread
{
private final TlsServerProtocol serverProtocol;
+ private final int[] supportedGroups;
- ServerThread(TlsServerProtocol serverProtocol)
+ private boolean shouldFail = false;
+
+ ServerThread(TlsServerProtocol serverProtocol, int[] supportedGroups, boolean fail)
{
this.serverProtocol = serverProtocol;
+ this.supportedGroups = supportedGroups;
+ this.shouldFail = fail;
+ }
+ ServerThread(TlsServerProtocol serverProtocol, boolean fail)
+ {
+ this.serverProtocol = serverProtocol;
+ this.supportedGroups = null;
+ this.shouldFail = fail;
}
public void run()
@@ -65,13 +112,28 @@ public void run()
try
{
MockTlsKEMServer server = new MockTlsKEMServer();
- serverProtocol.accept(server);
+ if (supportedGroups != null)
+ {
+ server.setSupportedGroups(supportedGroups);
+ }
+
+ try
+ {
+ serverProtocol.accept(server);
+ if (shouldFail)
+ {
+ fail();
+ }
+ }
+ catch (IOException ignored)
+ {
+ }
+
Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream());
serverProtocol.close();
}
catch (Exception e)
{
-// throw new RuntimeException(e);
}
}
}
From 8adb393bb9bc353851f765be8e5bd23cb95d65f5 Mon Sep 17 00:00:00 2001
From: royb
Date: Tue, 2 Apr 2024 16:58:54 -0400
Subject: [PATCH 0212/1846] Added missing input validation for ML-KEM
Encapsulation (fips 203 6.2)
---
.../crypto/crystals/kyber/KyberEngine.java | 17 ++++++
.../pqc/crypto/test/CrystalsKyberTest.java | 52 +++++++++++++++++++
2 files changed, 69 insertions(+)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/kyber/KyberEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/kyber/KyberEngine.java
index f9bed21031..ab44f40b96 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/kyber/KyberEngine.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/kyber/KyberEngine.java
@@ -1,6 +1,7 @@
package org.bouncycastle.pqc.crypto.crystals.kyber;
import org.bouncycastle.util.Arrays;
+import org.bouncycastle.util.encoders.Hex;
import java.security.SecureRandom;
@@ -217,6 +218,22 @@ public byte[][] generateKemKeyPair()
public byte[][] kemEncrypt(byte[] publicKeyInput)
{
+ // Input validation (6.2 ML-KEM Encaps)
+ // Type Check
+ if (publicKeyInput.length != KyberIndCpaPublicKeyBytes)
+ {
+ throw new RuntimeException("Input validation Error: Type check failed for ml-kem encapsulation");
+ }
+ // Modulus Check
+ PolyVec polyVec = new PolyVec(this);
+ byte[] seed = indCpa.unpackPublicKey(polyVec, publicKeyInput);
+ byte[] ek = indCpa.packPublicKey(polyVec, seed);
+ if (!Arrays.areEqual(ek, publicKeyInput))
+ {
+ throw new RuntimeException("Input validation: Modulus check failed for ml-kem encapsulation");
+ }
+
+
byte[] outputCipherText;
byte[] buf = new byte[2 * KyberSymBytes];
diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsKyberTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsKyberTest.java
index e085dca826..11316a1172 100644
--- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsKyberTest.java
+++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/CrystalsKyberTest.java
@@ -1,6 +1,7 @@
package org.bouncycastle.pqc.crypto.test;
import java.io.BufferedReader;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -34,6 +35,57 @@
public class CrystalsKyberTest
extends TestCase
{
+
+ public void testModulus() throws IOException
+ {
+ KyberParameters[] params = new KyberParameters[]{
+ KyberParameters.kyber512,
+ KyberParameters.kyber768,
+ KyberParameters.kyber1024,
+ };
+
+ String[] files = new String[]{
+ "ML-KEM-512.txt",
+ "ML-KEM-768.txt",
+ "ML-KEM-1024.txt",
+ };
+
+ TestSampler sampler = new TestSampler();
+ for (int fileIndex = 0; fileIndex != files.length; fileIndex++)
+ {
+ String name = files[fileIndex];
+ // System.out.println("testing: " + name);
+ InputStream src = TestResourceFinder.findTestResource("pqc/crypto/kyber/modulus", name);
+ BufferedReader bin = new BufferedReader(new InputStreamReader(src));
+
+ String line = null;
+ while ((line = bin.readLine()) != null)
+ {
+ line = line.trim();
+ line = line.trim();
+ byte[] key = Hex.decode(line);
+ KyberParameters parameters = params[fileIndex];
+
+
+ KyberPublicKeyParameters pubParams = (KyberPublicKeyParameters) PublicKeyFactory.createKey(
+ SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(new KyberPublicKeyParameters(parameters, key)));
+
+ // KEM Enc
+ SecureRandom random = new SecureRandom();
+ KyberKEMGenerator KyberEncCipher = new KyberKEMGenerator(random);
+ try
+ {
+ SecretWithEncapsulation secWenc = KyberEncCipher.generateEncapsulated(pubParams);
+ byte[] generated_cipher_text = secWenc.getEncapsulation();
+ fail();
+ }
+ catch (Exception ignored)
+ {
+ }
+ }
+ }
+ }
+
public void testPrivInfoGeneration()
throws IOException
{
From ff11107dc4365114dbf950283d683313769834cb Mon Sep 17 00:00:00 2001
From: royb
Date: Tue, 2 Apr 2024 17:07:01 -0400
Subject: [PATCH 0213/1846] Replaced RuntimeException with
IllegalArgumentException
---
.../bouncycastle/pqc/crypto/crystals/kyber/KyberEngine.java | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/kyber/KyberEngine.java b/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/kyber/KyberEngine.java
index ab44f40b96..2bd3802d47 100644
--- a/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/kyber/KyberEngine.java
+++ b/core/src/main/java/org/bouncycastle/pqc/crypto/crystals/kyber/KyberEngine.java
@@ -222,7 +222,7 @@ public byte[][] kemEncrypt(byte[] publicKeyInput)
// Type Check
if (publicKeyInput.length != KyberIndCpaPublicKeyBytes)
{
- throw new RuntimeException("Input validation Error: Type check failed for ml-kem encapsulation");
+ throw new IllegalArgumentException("Input validation Error: Type check failed for ml-kem encapsulation");
}
// Modulus Check
PolyVec polyVec = new PolyVec(this);
@@ -230,7 +230,7 @@ public byte[][] kemEncrypt(byte[] publicKeyInput)
byte[] ek = indCpa.packPublicKey(polyVec, seed);
if (!Arrays.areEqual(ek, publicKeyInput))
{
- throw new RuntimeException("Input validation: Modulus check failed for ml-kem encapsulation");
+ throw new IllegalArgumentException("Input validation: Modulus check failed for ml-kem encapsulation");
}
From 8e58f1afb6d66a22ea68be025da57c1050aa26a2 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 3 Apr 2024 13:21:53 +1100
Subject: [PATCH 0214/1846] minor changes for compatibility
---
.../CompositeSignaturesConstants.java | 6 +++---
.../compositesignatures/KeyFactorySpi.java | 14 ++++++++------
.../compositesignatures/KeyPairGeneratorSpi.java | 5 +++--
.../compositesignatures/SignatureSpi.java | 14 ++++++++++----
4 files changed, 24 insertions(+), 15 deletions(-)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java
index 430a0d145f..53b1095fdf 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/CompositeSignaturesConstants.java
@@ -77,7 +77,7 @@ public String getId()
static
{
- compositeNameASN1IdentifierMap = new HashMap<>();
+ compositeNameASN1IdentifierMap = new HashMap();
compositeNameASN1IdentifierMap.put(CompositeName.MLDSA44_RSA2048_PSS_SHA256, MiscObjectIdentifiers.id_MLDSA44_RSA2048_PSS_SHA256);
compositeNameASN1IdentifierMap.put(CompositeName.MLDSA44_RSA2048_PKCS15_SHA256, MiscObjectIdentifiers.id_MLDSA44_RSA2048_PKCS15_SHA256);
compositeNameASN1IdentifierMap.put(CompositeName.MLDSA44_ECDSA_P256_SHA256, MiscObjectIdentifiers.id_MLDSA44_ECDSA_P256_SHA256);
@@ -103,7 +103,7 @@ public String getId()
static
{
- ASN1IdentifierCompositeNameMap = new HashMap<>();
+ ASN1IdentifierCompositeNameMap = new HashMap();
for (Entry entry : compositeNameASN1IdentifierMap.entrySet())
{
ASN1IdentifierCompositeNameMap.put(entry.getValue(), entry.getKey());
@@ -117,7 +117,7 @@ public String getId()
static
{
- ASN1IdentifierAlgorithmNameMap = new HashMap<>();
+ ASN1IdentifierAlgorithmNameMap = new HashMap();
for (ASN1ObjectIdentifier oid : supportedIdentifiers)
{
CompositeName algName = ASN1IdentifierCompositeNameMap.get(oid); //Get enum so we can get name() value.
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java
index 6c8bab5e26..8f1976fa67 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyFactorySpi.java
@@ -1,6 +1,7 @@
package org.bouncycastle.jcajce.provider.asymmetric.compositesignatures;
import java.io.IOException;
+import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
@@ -34,6 +35,7 @@
import org.bouncycastle.jcajce.CompositePrivateKey;
import org.bouncycastle.jcajce.CompositePublicKey;
import org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi;
+import org.bouncycastle.util.Exceptions;
/**
* KeyFactory for composite signatures. List of supported combinations is in CompositeSignaturesConstants
@@ -105,9 +107,9 @@ public PrivateKey generatePrivate(PrivateKeyInfo keyInfo)
}
return new CompositePrivateKey(keyIdentifier, privateKeys);
}
- catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException e)
+ catch (GeneralSecurityException e)
{
- throw new RuntimeException(e);
+ throw Exceptions.ioException(e.getMessage(), e);
}
}
@@ -156,9 +158,9 @@ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
return new CompositePublicKey(keyIdentifier, publicKeys);
}
- catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidKeySpecException e)
+ catch (GeneralSecurityException e)
{
- throw new RuntimeException(e);
+ throw Exceptions.ioException(e.getMessage(), e);
}
}
@@ -173,8 +175,8 @@ public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo)
private List getKeyFactoriesFromIdentifier(ASN1ObjectIdentifier algorithmIdentifier)
throws NoSuchAlgorithmException, NoSuchProviderException
{
- List factories = new ArrayList<>();
- List algorithmNames = new ArrayList<>();
+ List factories = new ArrayList();
+ List algorithmNames = new ArrayList();
switch (CompositeSignaturesConstants.ASN1IdentifierCompositeNameMap.get(algorithmIdentifier))
{
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
index 56f646bc92..f74da56a5a 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/KeyPairGeneratorSpi.java
@@ -1,5 +1,6 @@
package org.bouncycastle.jcajce.provider.asymmetric.compositesignatures;
+import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
@@ -57,7 +58,7 @@ private void initializeParameters()
this.secureRandom = new SecureRandom();
}
- List generators = new ArrayList<>();
+ List generators = new ArrayList();
try
{
switch (this.algorithmIdentifier)
@@ -152,7 +153,7 @@ private void initializeParameters()
throw new IllegalStateException("Generators not correctly initialized. Unsupported composite algorithm.");
}
}
- catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchProviderException e)
+ catch (GeneralSecurityException e)
{
throw new RuntimeException(e);
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
index 29d9f3970c..29d0680c7c 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/compositesignatures/SignatureSpi.java
@@ -2,6 +2,7 @@
import java.io.IOException;
import java.security.AlgorithmParameters;
+import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.InvalidParameterException;
import java.security.NoSuchAlgorithmException;
@@ -25,6 +26,7 @@
import org.bouncycastle.crypto.util.DigestFactory;
import org.bouncycastle.jcajce.CompositePrivateKey;
import org.bouncycastle.jcajce.CompositePublicKey;
+import org.bouncycastle.util.Exceptions;
/**
* Signature class for composite signatures. Selected algorithm is set by the "subclasses" at the end of this file.
@@ -50,7 +52,7 @@ public class SignatureSpi
{
this.algorithmIdentifier = algorithmIdentifier;
this.algorithmIdentifierASN1 = CompositeSignaturesConstants.compositeNameASN1IdentifierMap.get(this.algorithmIdentifier);
- List componentSignatures = new ArrayList<>();
+ List componentSignatures = new ArrayList();
try
{
switch (this.algorithmIdentifier)
@@ -112,16 +114,20 @@ public class SignatureSpi
this.digest = DigestFactory.createSHA512();
break;
default:
- throw new RuntimeException("Unknown composite algorithm.");
+ throw new IllegalArgumentException("unknown composite algorithm");
}
//get bytes of composite signature algorithm OID in DER
//these bytes are used a prefix to the message digest https://www.ietf.org/archive/id/draft-ounsworth-pq-composite-sigs-13.html#name-composite-sign
OIDBytes = this.algorithmIdentifierASN1.getEncoded(ASN1Encoding.DER);
}
- catch (NoSuchAlgorithmException | NoSuchProviderException | IOException e)
+ catch (GeneralSecurityException e)
{
- throw new RuntimeException(e);
+ throw Exceptions.illegalStateException(e.getMessage(), e);
+ }
+ catch (IOException e)
+ {
+ throw Exceptions.illegalStateException(e.getMessage(), e);
}
this.componentSignatures = Collections.unmodifiableList(componentSignatures);
}
From a795ca3e94a5df251324e06d15c2f2cd4d2b51b1 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 3 Apr 2024 13:22:35 +1100
Subject: [PATCH 0215/1846] minor changes for compatibility
---
.../org/bouncycastle/jcajce/CompositePrivateKey.java | 9 +++++----
.../java/org/bouncycastle/jcajce/CompositePublicKey.java | 8 ++++----
.../jcajce/provider/asymmetric/CompositeSignatures.java | 2 +-
3 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
index 65788feb76..e0831e7b59 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePrivateKey.java
@@ -17,6 +17,7 @@
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.CompositeSignaturesConstants;
import org.bouncycastle.jcajce.provider.asymmetric.compositesignatures.KeyFactorySpi;
import org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter;
+import org.bouncycastle.util.Exceptions;
/**
* A composite private key class.
@@ -52,10 +53,10 @@ public CompositePrivateKey(ASN1ObjectIdentifier algorithmIdentifier, PrivateKey.
if (keys == null || keys.length == 0)
{
- throw new IllegalArgumentException("At least one private key must be provided for the composite private key.");
+ throw new IllegalArgumentException("at least one private key must be provided for the composite private key");
}
- List keyList = new ArrayList<>(keys.length);
+ List keyList = new ArrayList(keys.length);
for (int i = 0; i < keys.length; i++)
{
keyList.add(keys[i]);
@@ -88,7 +89,7 @@ public CompositePrivateKey(PrivateKeyInfo keyInfo)
}
catch (IOException e)
{
- throw new RuntimeException(e);
+ throw Exceptions.illegalStateException(e.getMessage(), e);
}
this.keys = privateKeyFromFactory.getPrivateKeys();
@@ -142,7 +143,7 @@ public byte[] getEncoded()
}
catch (IOException e)
{
- throw new IllegalStateException("Unable to encode composite private key: " + e.getMessage());
+ throw new IllegalStateException("unable to encode composite private key: " + e.getMessage());
}
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
index c55cb83dc5..1bc8a6e634 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/CompositePublicKey.java
@@ -55,7 +55,7 @@ public CompositePublicKey(ASN1ObjectIdentifier algorithmIdentifier, PublicKey...
throw new IllegalArgumentException("at least one public key must be provided for the composite public key");
}
- List keyList = new ArrayList<>(keys.length);
+ List keyList = new ArrayList(keys.length);
for (int i = 0; i < keys.length; i++)
{
keyList.add(keys[i]);
@@ -77,19 +77,19 @@ public CompositePublicKey(SubjectPublicKeyInfo keyInfo)
//Check if the public key algorithm specified in SubjectPublicKeyInfo is one of the supported composite signatures.
if (!Arrays.asList(CompositeSignaturesConstants.supportedIdentifiers).contains(keyInfoIdentifier))
{
- throw new IllegalStateException("Unable to create CompositePublicKey from SubjectPublicKeyInfo");
+ throw new IllegalStateException("unable to create CompositePublicKey from SubjectPublicKeyInfo");
}
AsymmetricKeyInfoConverter keyInfoConverter = new KeyFactorySpi();
publicKeyFromFactory = (CompositePublicKey) keyInfoConverter.generatePublic(keyInfo);
if (publicKeyFromFactory == null)
{
- throw new IllegalStateException("Unable to create CompositePublicKey from SubjectPublicKeyInfo");
+ throw new IllegalStateException("unable to create CompositePublicKey from SubjectPublicKeyInfo");
}
}
catch (IOException e)
{
- throw new RuntimeException(e);
+ throw new IllegalStateException(e.getMessage(), e);
}
this.keys = publicKeyFromFactory.getPublicKeys();
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java
index 93c635901c..11c24acf3f 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/CompositeSignatures.java
@@ -16,7 +16,7 @@ public class CompositeSignatures
{
private static final String PREFIX = "org.bouncycastle.jcajce.provider.asymmetric" + ".compositesignatures.";
- private static final Map compositesAttributes = new HashMap<>();
+ private static final Map compositesAttributes = new HashMap();
static
{
From cc6e9962aa00815f6d455a20b5a8f7956cd4b8ca Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 3 Apr 2024 13:23:56 +1100
Subject: [PATCH 0216/1846] added AES CBC based PKCS12 store and AES GCM based
PKCS12 store
---
.../jcajce/provider/keystore/PKCS12.java | 24 +-
.../keystore/pkcs12/PKCS12KeyStoreSpi.java | 229 ++++++++++++++++--
.../jce/provider/test/PKCS12StoreTest.java | 56 +++++
3 files changed, 281 insertions(+), 28 deletions(-)
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/PKCS12.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/PKCS12.java
index 73abd17468..91dea52e5e 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/PKCS12.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/PKCS12.java
@@ -2,6 +2,7 @@
import org.bouncycastle.jcajce.provider.config.ConfigurableProvider;
import org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider;
+import org.bouncycastle.util.Properties;
public class PKCS12
{
@@ -16,15 +17,30 @@ public Mappings()
public void configure(ConfigurableProvider provider)
{
- provider.addAlgorithm("KeyStore.PKCS12", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
- provider.addAlgorithm("KeyStore.BCPKCS12", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
- provider.addAlgorithm("KeyStore.PKCS12-DEF", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStore");
+ String defType = Properties.getPropertyValue("org.bouncycastle.pkcs12.default");
+
+ if (defType != null)
+ {
+ provider.addAlgorithm("Alg.Alias.KeyStore.PKCS12", defType);
+ provider.addAlgorithm("Alg.Alias.KeyStore.BCPKCS12", defType);
+ provider.addAlgorithm("Alg.Alias.KeyStore.PKCS12-DEF", defType.substring(0, 5) + "-DEF" + defType.substring(6));
+ }
+ else
+ {
+ provider.addAlgorithm("KeyStore.PKCS12", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
+ provider.addAlgorithm("KeyStore.BCPKCS12", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
+ provider.addAlgorithm("KeyStore.PKCS12-DEF", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStore");
+ }
provider.addAlgorithm("KeyStore.PKCS12-3DES-40RC2", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore");
provider.addAlgorithm("KeyStore.PKCS12-3DES-3DES", PREFIX + "PKCS12KeyStoreSpi$BCPKCS12KeyStore3DES");
-
+ provider.addAlgorithm("KeyStore.PKCS12-AES256-AES128", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStoreAES256");
+ provider.addAlgorithm("KeyStore.PKCS12-AES256-AES128-GCM", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStoreAES256GCM");
+
provider.addAlgorithm("KeyStore.PKCS12-DEF-3DES-40RC2", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStore");
provider.addAlgorithm("KeyStore.PKCS12-DEF-3DES-3DES", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStore3DES");
+ provider.addAlgorithm("KeyStore.PKCS12-DEF-AES256-AES128", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStoreAES256");
+ provider.addAlgorithm("KeyStore.PKCS12-DEF-AES256-AES128-GCM", PREFIX + "PKCS12KeyStoreSpi$DefPKCS12KeyStoreAES256GCM");
}
}
}
diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
index be99ffcd9a..3f40889bee 100644
--- a/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java
@@ -7,6 +7,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
+import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
@@ -71,6 +72,8 @@
import org.bouncycastle.asn1.pkcs.CertBag;
import org.bouncycastle.asn1.pkcs.ContentInfo;
import org.bouncycastle.asn1.pkcs.EncryptedData;
+import org.bouncycastle.asn1.pkcs.EncryptionScheme;
+import org.bouncycastle.asn1.pkcs.KeyDerivationFunc;
import org.bouncycastle.asn1.pkcs.MacData;
import org.bouncycastle.asn1.pkcs.PBES2Parameters;
import org.bouncycastle.asn1.pkcs.PBKDF2Params;
@@ -93,6 +96,7 @@
import org.bouncycastle.crypto.CryptoServicesRegistrar;
import org.bouncycastle.crypto.Digest;
import org.bouncycastle.crypto.util.DigestFactory;
+import org.bouncycastle.internal.asn1.cms.GCMParameters;
import org.bouncycastle.internal.asn1.misc.MiscObjectIdentifiers;
import org.bouncycastle.internal.asn1.ntt.NTTObjectIdentifiers;
import org.bouncycastle.internal.asn1.oiw.OIWObjectIdentifiers;
@@ -135,6 +139,8 @@ public class PKCS12KeyStoreSpi
private Hashtable chainCerts = new Hashtable();
private Hashtable keyCerts = new Hashtable();
+
+
//
// generic object types
//
@@ -202,6 +208,26 @@ public boolean equals(
}
}
+ private static boolean isPBKDF2(ASN1ObjectIdentifier oid)
+ {
+ return oid.equals(NISTObjectIdentifiers.id_aes256_CBC)
+ || oid.equals(NISTObjectIdentifiers.id_aes256_GCM)
+ || oid.equals(NISTObjectIdentifiers.id_aes128_CBC)
+ || oid.equals(NISTObjectIdentifiers.id_aes128_GCM);
+ }
+
+ private static int getKeyLength(ASN1ObjectIdentifier oid)
+ {
+ if (oid.equals(NISTObjectIdentifiers.id_aes256_CBC) || oid.equals(NISTObjectIdentifiers.id_aes256_GCM))
+ {
+ return 32;
+ }
+ else
+ {
+ return 16;
+ }
+ }
+
public PKCS12KeyStoreSpi(
JcaJceHelper helper,
ASN1ObjectIdentifier keyAlgorithm,
@@ -676,6 +702,38 @@ protected byte[] wrapKey(
return out;
}
+ protected byte[] wrapKey(
+ EncryptionScheme encAlgId,
+ Key key,
+ PBKDF2Params pbeParams,
+ char[] password)
+ throws IOException
+ {
+ PBEKeySpec pbeSpec = new PBEKeySpec(password, pbeParams.getSalt(),
+ pbeParams.getIterationCount().intValueExact(), pbeParams.getKeyLength().intValueExact() * 8);
+ byte[] out;
+
+ try
+ {
+ SecretKeyFactory keyFact = helper.createSecretKeyFactory("PBKDF2withHMacSHA256");
+
+ Cipher cipher = helper.createCipher(encAlgId.getAlgorithm().getId());
+
+ AlgorithmParameters algParams = AlgorithmParameters.getInstance(encAlgId.getAlgorithm().getId());
+ algParams.init(encAlgId.getParameters().toASN1Primitive().getEncoded());
+
+ cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), algParams);
+
+ out = cipher.wrap(key);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("exception encrypting data - " + e.toString());
+ }
+
+ return out;
+ }
+
protected byte[] cryptData(
boolean forEncryption,
AlgorithmIdentifier algId,
@@ -746,7 +804,6 @@ private Cipher createCipher(int mode, char[] password, AlgorithmIdentifier algId
}
Cipher cipher = helper.createCipher(alg.getEncryptionScheme().getAlgorithm().getId());
-
ASN1Encodable encParams = alg.getEncryptionScheme().getParameters();
if (encParams instanceof ASN1OctetString)
{
@@ -754,10 +811,30 @@ private Cipher createCipher(int mode, char[] password, AlgorithmIdentifier algId
}
else
{
- // TODO: at the moment it's just GOST, but...
- GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams);
+ ASN1Sequence params = ASN1Sequence.getInstance(encParams);
+
+ if (params.getObjectAt(1) instanceof ASN1ObjectIdentifier)
+ {
+ // TODO: at the moment it's just GOST, but...
+ GOST28147Parameters gParams = GOST28147Parameters.getInstance(encParams);
+
+ cipher.init(mode, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV()));
+ }
+ else
+ {
+ AlgorithmParameters algParams = AlgorithmParameters.getInstance(encScheme.getAlgorithm().getId(), "BC");
- cipher.init(mode, key, new GOST28147ParameterSpec(gParams.getEncryptionParamSet(), gParams.getIV()));
+ try
+ {
+ algParams.init(params.getEncoded());
+ }
+ catch (IOException e)
+ {
+ throw new InvalidKeySpecException(e.getMessage());
+ }
+
+ cipher.init(mode, key, algParams);
+ }
}
return cipher;
}
@@ -792,6 +869,9 @@ public void engineLoad(
return;
}
+ boolean noMac = true;
+ boolean noEnc = true;
+
BufferedInputStream bufIn = new BufferedInputStream(stream);
bufIn.mark(10);
@@ -832,6 +912,7 @@ public void engineLoad(
throw new NullPointerException("no password supplied when one expected");
}
+ noMac = false;
MacData mData = bag.getMacData();
DigestInfo dInfo = mData.getMac();
macAlgorithm = dInfo.getAlgorithmId();
@@ -873,13 +954,6 @@ public void engineLoad(
throw new IOException("error constructing MAC: " + e.toString());
}
}
- else if (password != null && password.length != 0)
- {
- if (!Properties.isOverrideSet("org.bouncycastle.pkcs12.ignore_useless_passwd"))
- {
- throw new IOException("password supplied for keystore that does not require one");
- }
- }
keys = new IgnoresCaseHashtable();
localIds = new IgnoresCaseHashtable();
@@ -903,6 +977,7 @@ else if (password != null && password.length != 0)
if (b.getBagId().equals(pkcs8ShroudedKeyBag))
{
unmarkedKey = processShroudedKeyBag(b, password, wrongPKCS12Zero);
+ noEnc = false;
}
else if (b.getBagId().equals(certBag))
{
@@ -927,6 +1002,7 @@ else if (c[i].getContentType().equals(encryptedData))
password, wrongPKCS12Zero, d.getContent().getOctets());
ASN1Sequence seq = ASN1Sequence.getInstance(octets);
+ noEnc = false;
for (int j = 0; j != seq.size(); j++)
{
SafeBag b = SafeBag.getInstance(seq.getObjectAt(j));
@@ -1085,6 +1161,17 @@ else if (oid.equals(pkcs_9_at_localKeyId))
}
}
}
+
+ if (noMac && noEnc)
+ {
+ if (password != null && password.length != 0)
+ {
+ if (!Properties.isOverrideSet("org.bouncycastle.pkcs12.ignore_useless_passwd"))
+ {
+ throw new IOException("password supplied for keystore that does not require one");
+ }
+ }
+ }
}
private boolean processShroudedKeyBag(SafeBag b, char[] password, boolean wrongPKCS12Zero)
@@ -1251,6 +1338,30 @@ private int validateIterationCount(BigInteger i)
return count;
}
+ private ASN1Primitive getAlgParams(ASN1ObjectIdentifier algorithm)
+ {
+ if (algorithm.equals(NISTObjectIdentifiers.id_aes128_CBC)
+ || algorithm.equals(NISTObjectIdentifiers.id_aes256_CBC))
+ {
+ byte[] iv = new byte[16];
+
+ random.nextBytes(iv);
+
+ return new DEROctetString(iv);
+ }
+ else if (algorithm.equals(NISTObjectIdentifiers.id_aes128_GCM)
+ || algorithm.equals(NISTObjectIdentifiers.id_aes256_GCM))
+ {
+ byte[] nonce = new byte[12];
+
+ random.nextBytes(nonce);
+
+ return new GCMParameters(nonce, 16).toASN1Primitive();
+ }
+
+ throw new IllegalStateException("unknown encryption OID in getAlgParams()");
+ }
+
public void engineStore(LoadStoreParameter param)
throws IOException,
NoSuchAlgorithmException, CertificateException
@@ -1374,9 +1485,23 @@ private void doStore(OutputStream stream, char[] password, boolean useDEREncodin
String name = (String)ks.nextElement();
PrivateKey privKey = (PrivateKey)keys.get(name);
- PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
- byte[] kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
- AlgorithmIdentifier kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
+ AlgorithmIdentifier kAlgId;
+ byte[] kBytes;
+ if (isPBKDF2(keyAlgorithm))
+ {
+ // TODO: keySize hard coded to 256 bits
+ PBKDF2Params kParams = new PBKDF2Params(kSalt, MIN_ITERATIONS, getKeyLength(keyAlgorithm), new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA256, DERNull.INSTANCE));
+ EncryptionScheme encScheme = new EncryptionScheme(keyAlgorithm, getAlgParams(keyAlgorithm));
+ kAlgId = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, new PBES2Parameters(
+ new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, kParams), encScheme));
+ kBytes = wrapKey(encScheme, privKey, kParams, password);
+ }
+ else
+ {
+ PKCS12PBEParams kParams = new PKCS12PBEParams(kSalt, MIN_ITERATIONS);
+ kBytes = wrapKey(keyAlgorithm.getId(), privKey, kParams, password);
+ kAlgId = new AlgorithmIdentifier(keyAlgorithm, kParams.toASN1Primitive());
+ }
org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo kInfo = new org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo(kAlgId, kBytes);
boolean attrSet = false;
ASN1EncodableVector kName = new ASN1EncodableVector();
@@ -1455,8 +1580,18 @@ private void doStore(OutputStream stream, char[] password, boolean useDEREncodin
random.nextBytes(cSalt);
ASN1EncodableVector certSeq = new ASN1EncodableVector();
- PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
- AlgorithmIdentifier cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
+ AlgorithmIdentifier cAlgId;
+ if (isPBKDF2(certAlgorithm))
+ {
+ PBKDF2Params cParams = new PBKDF2Params(cSalt, MIN_ITERATIONS, getKeyLength(certAlgorithm), new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA256, DERNull.INSTANCE));
+ cAlgId = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, new PBES2Parameters(
+ new KeyDerivationFunc(PKCSObjectIdentifiers.id_PBKDF2, cParams), new EncryptionScheme(certAlgorithm, getAlgParams(certAlgorithm))));
+ }
+ else
+ {
+ PKCS12PBEParams cParams = new PKCS12PBEParams(cSalt, MIN_ITERATIONS);
+ cAlgId = new AlgorithmIdentifier(certAlgorithm, cParams.toASN1Primitive());
+ }
Hashtable doneCerts = new Hashtable();
Enumeration cs = keys.keys();
@@ -1649,17 +1784,24 @@ private void doStore(OutputStream stream, char[] password, boolean useDEREncodin
MacData mData;
- try
+ if (keyAlgorithm.equals(NISTObjectIdentifiers.id_aes256_GCM))
{
- byte[] res = calculatePbeMac(macAlgorithm.getAlgorithm(), mSalt, itCount, password, false, data);
-
- DigestInfo dInfo = new DigestInfo(macAlgorithm, res);
-
- mData = new MacData(dInfo, mSalt, itCount);
+ mData = null;
}
- catch (Exception e)
+ else
{
- throw new IOException("error constructing MAC: " + e.toString());
+ try
+ {
+ byte[] res = calculatePbeMac(macAlgorithm.getAlgorithm(), mSalt, itCount, password, false, data);
+
+ DigestInfo dInfo = new DigestInfo(macAlgorithm, res);
+
+ mData = new MacData(dInfo, mSalt, itCount);
+ }
+ catch (Exception e)
+ {
+ throw new IOException("error constructing MAC: " + e.toString());
+ }
}
//
@@ -1832,6 +1974,24 @@ public BCPKCS12KeyStore3DES()
}
}
+ public static class BCPKCS12KeyStoreAES256
+ extends AdaptingKeyStoreSpi
+ {
+ public BCPKCS12KeyStoreAES256()
+ {
+ super(new BCJcaJceHelper(), new PKCS12KeyStoreSpi(new BCJcaJceHelper(), NISTObjectIdentifiers.id_aes256_CBC, NISTObjectIdentifiers.id_aes128_CBC));
+ }
+ }
+
+ public static class BCPKCS12KeyStoreAES256GCM
+ extends AdaptingKeyStoreSpi
+ {
+ public BCPKCS12KeyStoreAES256GCM()
+ {
+ super(new BCJcaJceHelper(), new PKCS12KeyStoreSpi(new BCJcaJceHelper(), NISTObjectIdentifiers.id_aes256_GCM, NISTObjectIdentifiers.id_aes128_GCM));
+ }
+ }
+
public static class DefPKCS12KeyStore
extends AdaptingKeyStoreSpi
{
@@ -1850,6 +2010,24 @@ public DefPKCS12KeyStore3DES()
}
}
+ public static class DefPKCS12KeyStoreAES256
+ extends AdaptingKeyStoreSpi
+ {
+ public DefPKCS12KeyStoreAES256()
+ {
+ super(new BCJcaJceHelper(), new PKCS12KeyStoreSpi(new BCJcaJceHelper(), NISTObjectIdentifiers.id_aes256_CBC, NISTObjectIdentifiers.id_aes128_CBC));
+ }
+ }
+
+ public static class DefPKCS12KeyStoreAES256GCM
+ extends AdaptingKeyStoreSpi
+ {
+ public DefPKCS12KeyStoreAES256GCM()
+ {
+ super(new BCJcaJceHelper(), new PKCS12KeyStoreSpi(new BCJcaJceHelper(), NISTObjectIdentifiers.id_aes256_GCM, NISTObjectIdentifiers.id_aes128_GCM));
+ }
+ }
+
private static class IgnoresCaseHashtable
{
private Hashtable orig = new Hashtable();
@@ -1922,6 +2100,9 @@ private static class DefaultSecretKeyProvider
keySizes.put(NISTObjectIdentifiers.id_aes192_CBC, Integers.valueOf(192));
keySizes.put(NISTObjectIdentifiers.id_aes256_CBC, Integers.valueOf(256));
+ keySizes.put(NISTObjectIdentifiers.id_aes128_GCM, Integers.valueOf(128));
+ keySizes.put(NISTObjectIdentifiers.id_aes256_GCM, Integers.valueOf(256));
+
keySizes.put(NTTObjectIdentifiers.id_camellia128_cbc, Integers.valueOf(128));
keySizes.put(NTTObjectIdentifiers.id_camellia192_cbc, Integers.valueOf(192));
keySizes.put(NTTObjectIdentifiers.id_camellia256_cbc, Integers.valueOf(256));
diff --git a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
index 9ab48d1177..05d2ff588e 100644
--- a/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
+++ b/prov/src/test/java/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java
@@ -2,6 +2,7 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.Key;
@@ -20,6 +21,8 @@
import java.security.spec.RSAPublicKeySpec;
import java.util.Enumeration;
+import javax.swing.KeyStroke;
+
import org.bouncycastle.asn1.ASN1BMPString;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1InputStream;
@@ -2132,6 +2135,56 @@ private void testJKS()
isTrue(ks.isCertificateEntry("cert0"));
}
+ private void testStoreType(String storeType, boolean isMacExpected)
+ throws Exception
+ {
+ KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC");
+ KeyPair kp = kpGen.generateKeyPair();
+ X509Certificate cert = TestUtils.createSelfSignedCert(new X500Name("CN=PKCS12 Test"), "SHA256withECDSA", kp);
+
+ KeyStore keyStore = KeyStore.getInstance(storeType, "BC");
+ keyStore.load(null, null);
+
+ keyStore.setKeyEntry("key", kp.getPrivate(), null, new Certificate[] { cert });
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ keyStore.store(bOut, passwd);
+
+ KeyStore inStore = KeyStore.getInstance("PKCS12", "BC");
+
+ inStore.load(new ByteArrayInputStream(bOut.toByteArray()), passwd);
+
+ FileOutputStream fOut = new FileOutputStream("/tmp/" + storeType + ".p12");
+ fOut.write(bOut.toByteArray());
+ fOut.close();
+ Key k = inStore.getKey("key", null);
+
+ Pfx pfx = Pfx.getInstance(bOut.toByteArray());
+
+ if (isMacExpected)
+ {
+ isTrue(pfx.getMacData() != null);
+ }
+ else
+ {
+ isTrue(pfx.getMacData() == null);
+ }
+
+ }
+
+ private void testAES256_AES128()
+ throws Exception
+ {
+ testStoreType("PKCS12-AES256-AES128", true);
+ }
+
+ private void testAES256GCM_AES128_GCM()
+ throws Exception
+ {
+ testStoreType("PKCS12-AES256-AES128-GCM", false);
+ }
+
public void performTest()
throws Exception
{
@@ -2148,6 +2201,9 @@ public void performTest()
testNTRUStore();
testSphincsPlusStore();
testRawKeyBagStore();
+ testAES256_AES128();
+ testAES256GCM_AES128_GCM();
+
// converter tests
KeyStore kS = KeyStore.getInstance("PKCS12", BC);
From f36c59f53da8336119aa7a003d1e67504eeb0b6a Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 3 Apr 2024 13:24:09 +1100
Subject: [PATCH 0217/1846] minor changes for compatibility
---
.../jcajce/provider/test/CompositeSignaturesTest.java | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java
index 8ca3699913..89941d343e 100644
--- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java
+++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/CompositeSignaturesTest.java
@@ -19,6 +19,7 @@
import org.bouncycastle.jcajce.provider.asymmetric.rsa.BCRSAPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.test.TestResourceFinder;
+import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Base64;
public class CompositeSignaturesTest
@@ -62,10 +63,10 @@ public void testKeyPairGeneration()
CompositePublicKey compositePublicKey = (CompositePublicKey)keyPair.getPublic();
CompositePrivateKey compositePrivateKey = (CompositePrivateKey)keyPair.getPrivate();
- String firstPublicKeyAlgorithm = compositePublicKey.getPublicKeys().get(0).getAlgorithm().toUpperCase();
- String secondPublicKeyAlgorithm = compositePublicKey.getPublicKeys().get(1).getAlgorithm().toUpperCase();
- String firstPrivateKeyAlgorithm = compositePrivateKey.getPrivateKeys().get(0).getAlgorithm().toUpperCase();
- String secondPrivateKeyAlgorithm = compositePrivateKey.getPrivateKeys().get(1).getAlgorithm().toUpperCase();
+ String firstPublicKeyAlgorithm = Strings.toUpperCase(compositePublicKey.getPublicKeys().get(0).getAlgorithm());
+ String secondPublicKeyAlgorithm = Strings.toUpperCase(compositePublicKey.getPublicKeys().get(1).getAlgorithm());
+ String firstPrivateKeyAlgorithm = Strings.toUpperCase(compositePrivateKey.getPrivateKeys().get(0).getAlgorithm());
+ String secondPrivateKeyAlgorithm = Strings.toUpperCase(compositePrivateKey.getPrivateKeys().get(1).getAlgorithm());
BCRSAPublicKey rsaPublicKey = null;
BCRSAPublicKey rsaPrivateKey = null;
From e21587a0af22fb380c7476ade5b1f654efe5c196 Mon Sep 17 00:00:00 2001
From: David Hook
Date: Wed, 3 Apr 2024 13:24:59 +1100
Subject: [PATCH 0218/1846] added use of Strings.toLowerCase()
---
.../org/bouncycastle/jce/provider/X509LDAPCertStoreSpi.java | 4 ++--
.../java/org/bouncycastle/x509/util/LDAPStoreHelper.java | 5 +++--
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/prov/src/main/java/org/bouncycastle/jce/provider/X509LDAPCertStoreSpi.java b/prov/src/main/java/org/bouncycastle/jce/provider/X509LDAPCertStoreSpi.java
index be96ba3a72..5789fd1714 100644
--- a/prov/src/main/java/org/bouncycastle/jce/provider/X509LDAPCertStoreSpi.java
+++ b/prov/src/main/java/org/bouncycastle/jce/provider/X509LDAPCertStoreSpi.java
@@ -34,6 +34,7 @@
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.x509.CertificatePair;
import org.bouncycastle.jce.X509LDAPCertStoreParameters;
+import org.bouncycastle.util.Strings;
/**
* This is a general purpose implementation to get X.509 certificates and CRLs
@@ -126,8 +127,7 @@ private DirContext connectLDAP()
private String parseDN(String subject, String subjectAttributeName)
{
String temp = subject;
- int begin = temp.toLowerCase().indexOf(
- subjectAttributeName.toLowerCase());
+ int begin = Strings.toLowerCase(temp).indexOf(Strings.toLowerCase(subjectAttributeName));
temp = temp.substring(begin + subjectAttributeName.length());
int end = temp.indexOf(',');
if (end == -1)
diff --git a/prov/src/main/java/org/bouncycastle/x509/util/LDAPStoreHelper.java b/prov/src/main/java/org/bouncycastle/x509/util/LDAPStoreHelper.java
index 9392bd2eb7..8121a498ed 100644
--- a/prov/src/main/java/org/bouncycastle/x509/util/LDAPStoreHelper.java
+++ b/prov/src/main/java/org/bouncycastle/x509/util/LDAPStoreHelper.java
@@ -36,6 +36,7 @@
import org.bouncycastle.jce.provider.X509CertPairParser;
import org.bouncycastle.jce.provider.X509CertParser;
import org.bouncycastle.util.StoreException;
+import org.bouncycastle.util.Strings;
import org.bouncycastle.x509.X509AttributeCertStoreSelector;
import org.bouncycastle.x509.X509AttributeCertificate;
import org.bouncycastle.x509.X509CRLStoreSelector;
@@ -113,8 +114,8 @@ private DirContext connectLDAP() throws NamingException
private String parseDN(String subject, String dNAttributeName)
{
String temp = subject;
- int begin = temp.toLowerCase().indexOf(
- dNAttributeName.toLowerCase() + "=");
+ int begin = Strings.toLowerCase(temp).indexOf(
+ Strings.toLowerCase(dNAttributeName) + "=");
if (begin == -1)
{
return "";
From 65c98320be9fca91384710e16f7cf3c178de4f3b Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 3 Apr 2024 16:08:30 +0700
Subject: [PATCH 0219/1846] BCJSSE: Private key may not support encoding
---
.../org/bouncycastle/jsse/provider/JsseUtils.java | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java b/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java
index 134dfb5945..b552d997b3 100644
--- a/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java
+++ b/tls/src/main/java/org/bouncycastle/jsse/provider/JsseUtils.java
@@ -691,10 +691,15 @@ static String getPrivateKeyAlgorithm(PrivateKey privateKey)
*/
if ("RSA".equalsIgnoreCase(algorithm))
{
- PrivateKeyInfo pki = PrivateKeyInfo.getInstance(privateKey.getEncoded());
- if (PKCSObjectIdentifiers.id_RSASSA_PSS.equals(pki.getPrivateKeyAlgorithm().getAlgorithm()))
+ // NOTE: Private keys might not support encoding (e.g. for an HSM).
+ byte[] encoding = privateKey.getEncoded();
+ if (encoding != null)
{
- return "RSASSA-PSS";
+ PrivateKeyInfo pki = PrivateKeyInfo.getInstance(encoding);
+ if (PKCSObjectIdentifiers.id_RSASSA_PSS.equals(pki.getPrivateKeyAlgorithm().getAlgorithm()))
+ {
+ return "RSASSA-PSS";
+ }
}
}
From c47f6444a744396135322784b5fea1d35d46a8a7 Mon Sep 17 00:00:00 2001
From: Peter Dettman
Date: Wed, 3 Apr 2024 21:24:27 +0700
Subject: [PATCH 0220/1846] BCJSSE: Improved workaround for InetAddress
limitation
- URLConnectionUtil now calls BCSSLSocket.setHost instead of direct SNI config
---
.../jsse/provider/ProvSSLSocketDirect.java | 14 ++--
.../jsse/provider/ProvSSLSocketWrap.java | 14 ++--
.../jsse/util/SetHostSocketFactory.java | 80 +++++++++++++++++++
.../jsse/util/URLConnectionUtil.java | 2 +-
4 files changed, 99 insertions(+), 11 deletions(-)
create mode 100644 tls/src/main/java/org/bouncycastle/jsse/util/SetHostSocketFactory.java
diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java
index fe2d7138c1..245b1eb461 100644
--- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java
+++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java
@@ -345,7 +345,6 @@ public synchronized void setEnableSessionCreation(boolean flag)
public synchronized void setHost(String host)
{
this.peerHost = host;
- this.peerHostSNI = host;
}
@Override
@@ -531,6 +530,7 @@ synchronized void notifyConnected()
InetAddress peerAddress = getInetAddress();
if (null == peerAddress)
{
+ this.peerHostSNI = null;
return;
}
@@ -538,8 +538,8 @@ synchronized void notifyConnected()
* TODO[jsse] If we could somehow access the 'originalHostName' of peerAddress, it would be
* usable as a default SNI host_name.
*/
-// String originalHostName = null;
-// if (null != originalHostName)
+// String originalHostName = peerAddress.holder().getOriginalHostName();
+// if (JsseUtils.isNameSpecified(originalHostName))
// {
// this.peerHost = originalHostName;
// this.peerHostSNI = originalHostName;
@@ -555,13 +555,17 @@ synchronized void notifyConnected()
return;
}
- if (useClientMode && provJdkTlsTrustNameService)
+ if (!useClientMode)
+ {
+ this.peerHost = peerAddress.getHostAddress();
+ }
+ else if (provJdkTlsTrustNameService)
{
this.peerHost = peerAddress.getHostName();
}
else
{
- this.peerHost = peerAddress.getHostAddress();
+ this.peerHost = null;
}
this.peerHostSNI = null;
diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketWrap.java b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketWrap.java
index b31f215289..59fabd7bb4 100644
--- a/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketWrap.java
+++ b/tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketWrap.java
@@ -470,7 +470,6 @@ public synchronized void setEnableSessionCreation(boolean flag)
public synchronized void setHost(String host)
{
this.peerHost = host;
- this.peerHostSNI = host;
}
@Override
@@ -720,6 +719,7 @@ synchronized void notifyConnected()
InetAddress peerAddress = getInetAddress();
if (null == peerAddress)
{
+ this.peerHostSNI = null;
return;
}
@@ -727,8 +727,8 @@ synchronized void notifyConnected()
* TODO[jsse] If we could somehow access the 'originalHostName' of peerAddress, it would be
* usable as a default SNI host_name.
*/
-// String originalHostName = null;
-// if (null != originalHostName)
+// String originalHostName = peerAddress.holder().getOriginalHostName();
+// if (JsseUtils.isNameSpecified(originalHostName))
// {
// this.peerHost = originalHostName;
// this.peerHostSNI = originalHostName;
@@ -744,13 +744,17 @@ synchronized void notifyConnected()
return;
}
- if (useClientMode && provJdkTlsTrustNameService)
+ if (!useClientMode)
+ {
+ this.peerHost = peerAddress.getHostAddress();
+ }
+ else if (provJdkTlsTrustNameService)
{
this.peerHost = peerAddress.getHostName();
}
else
{
- this.peerHost = peerAddress.getHostAddress();
+ this.peerHost = null;
}
this.peerHostSNI = null;
diff --git a/tls/src/main/java/org/bouncycastle/jsse/util/SetHostSocketFactory.java b/tls/src/main/java/org/bouncycastle/jsse/util/SetHostSocketFactory.java
new file mode 100644
index 0000000000..0eeccaf367
--- /dev/null
+++ b/tls/src/main/java/org/bouncycastle/jsse/util/SetHostSocketFactory.java
@@ -0,0 +1,80 @@
+package org.bouncycastle.jsse.util;
+
+import java.net.Socket;
+import java.net.URL;
+import java.util.concurrent.Callable;
+import java.util.logging.Logger;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLSocketFactory;
+
+import org.bouncycastle.jsse.BCSSLSocket;
+
+public class SetHostSocketFactory extends CustomSSLSocketFactory
+{
+ private static final Logger LOG = Logger.getLogger(SetHostSocketFactory.class.getName());
+
+ protected static final ThreadLocal threadLocal = new ThreadLocal();
+
+ /**
+ * Signature matches {@link SSLSocketFactory#getDefault()} so that it can be
+ * used with e.g. the "java.naming.ldap.factory.socket" property or similar.
+ *
+ * @see #call(Callable)
+ */
+ public static SocketFactory getDefault()
+ {
+ SSLSocketFactory sslSocketFactory = threadLocal.get();
+ if (null != sslSocketFactory)
+ {
+ return sslSocketFactory;
+ }
+
+ return SSLSocketFactory.getDefault();
+ }
+
+ protected final URL url;
+
+ public SetHostSocketFactory(SSLSocketFactory delegate, URL url)
+ {
+ super(delegate);
+
+ this.url = url;
+ }
+
+ /**
+ * Calls a {@link Callable} in a context where this class's static
+ * {@link #getDefault()} method will return this {@link SetHostSocketFactory}.
+ */
+ public V call(Callable callable) throws Exception
+ {
+ try
+ {
+ threadLocal.set(this);
+
+ return callable.call();
+ }
+ finally
+ {
+ threadLocal.remove();
+ }
+ }
+
+ @Override
+ protected Socket configureSocket(Socket s)
+ {
+ if (url != null && s instanceof BCSSLSocket)
+ {
+ BCSSLSocket ssl = (BCSSLSocket)s;
+
+ String host = url.getHost();
+ if (host != null)
+ {
+ LOG.fine("Setting host on socket: " + host);
+
+ ssl.setHost(host);
+ }
+ }
+ return s;
+ }
+}
diff --git a/tls/src/main/java/org/bouncycastle/jsse/util/URLConnectionUtil.java b/tls/src/main/java/org/bouncycastle/jsse/util/URLConnectionUtil.java
index 63a7db5a0b..6eb4861f2d 100644
--- a/tls/src/main/java/org/bouncycastle/jsse/util/URLConnectionUtil.java
+++ b/tls/src/main/java/org/bouncycastle/jsse/util/URLConnectionUtil.java
@@ -66,6 +66,6 @@ protected URLConnection configureConnection(URL url, URLConnection connection)
protected SSLSocketFactory createSSLSocketFactory(SSLSocketFactory delegate, URL url)
{
- return new SNISocketFactory(delegate, url);
+ return new SetHostSocketFactory(delegate, url);
}
}
From 807df10779e319c5639986d8fcafdcfe4245cec4 Mon Sep 17 00:00:00 2001
From: yuhh0328
Date: Wed, 10 Jan 2024 06:02:25 +0000
Subject: [PATCH 0221/1846] Updates : add tls-kyber
---
.../jsse/provider/NamedGroupInfo.java | 6 +-
.../java/org/bouncycastle/tls/NamedGroup.java | 36 +++++++-
.../org/bouncycastle/tls/NamedGroupRole.java | 1 +
.../bouncycastle/tls/TlsServerProtocol.java | 9 +-
.../java/org/bouncycastle/tls/TlsUtils.java | 16 +++-
.../bouncycastle/tls/crypto/TlsCrypto.java | 15 ++++
.../bouncycastle/tls/crypto/TlsKEMConfig.java | 52 +++++++++++
.../bouncycastle/tls/crypto/TlsKEMDomain.java | 6 ++
.../tls/crypto/impl/bc/BcTlsCrypto.java | 12 +++
.../tls/crypto/impl/bc/BcTlsKyber.java | 65 ++++++++++++++
.../tls/crypto/impl/bc/BcTlsKyberDomain.java | 90 +++++++++++++++++++
.../tls/crypto/impl/jcajce/JcaTlsCrypto.java | 26 ++++++
.../tls/crypto/impl/jcajce/JceTlsKyber.java | 64 +++++++++++++
.../crypto/impl/jcajce/JceTlsKyberDomain.java | 89 ++++++++++++++++++
.../jsse/provider/test/BasicTlsTest.java | 1 +
15 files changed, 481 insertions(+), 7 deletions(-)
create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMConfig.java
create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMDomain.java
create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyber.java
create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyberDomain.java
create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyber.java
create mode 100644 tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyberDomain.java
diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java b/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java
index 15cca607d5..384f203795 100644
--- a/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java
+++ b/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java
@@ -73,7 +73,11 @@ private enum All
ffdhe3072(NamedGroup.ffdhe3072, "DiffieHellman"),
ffdhe4096(NamedGroup.ffdhe4096, "DiffieHellman"),
ffdhe6144(NamedGroup.ffdhe6144, "DiffieHellman"),
- ffdhe8192(NamedGroup.ffdhe8192, "DiffieHellman");
+ ffdhe8192(NamedGroup.ffdhe8192, "DiffieHellman"),
+
+ kyber512(NamedGroup.kyber512, "KEM"),
+ kyber768(NamedGroup.kyber768, "KEM"),
+ kyber1024(NamedGroup.kyber1024, "KEM");
private final int namedGroup;
private final String name;
diff --git a/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java b/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java
index 18721f2e1b..a3f24ffcc5 100644
--- a/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java
+++ b/tls/src/main/java/org/bouncycastle/tls/NamedGroup.java
@@ -102,6 +102,10 @@ public class NamedGroup
public static final int arbitrary_explicit_prime_curves = 0xFF01;
public static final int arbitrary_explicit_char2_curves = 0xFF02;
+ public static final int kyber512 = 0x023A;
+ public static final int kyber768 = 0x023C;
+ public static final int kyber1024 = 0x023D;
+
/* Names of the actual underlying elliptic curves (not necessarily matching the NamedGroup names). */
private static final String[] CURVE_NAMES = new String[] { "sect163k1", "sect163r1", "sect163r2", "sect193r1",
"sect193r2", "sect233k1", "sect233r1", "sect239k1", "sect283k1", "sect283r1", "sect409k1", "sect409r1",
@@ -130,7 +134,8 @@ public static boolean canBeNegotiated(int namedGroup, ProtocolVersion version)
else
{
if ((namedGroup >= brainpoolP256r1tls13 && namedGroup <= brainpoolP512r1tls13)
- || (namedGroup == curveSM2))
+ || (namedGroup == curveSM2)
+ || (namedGroup == kyber512 || namedGroup == kyber768 || namedGroup == kyber1024))
{
return false;
}
@@ -260,6 +265,21 @@ public static String getFiniteFieldName(int namedGroup)
return null;
}
+ public static String getKEMName(int namedGroup)
+ {
+ switch (namedGroup)
+ {
+ case kyber512:
+ return "kyber512";
+ case kyber768:
+ return "kyber768";
+ case kyber1024:
+ return "kyber1024";
+ default:
+ return null;
+ }
+ }
+
public static int getMaximumChar2CurveBits()
{
return 571;
@@ -344,6 +364,12 @@ public static String getStandardName(int namedGroup)
return finiteFieldName;
}
+ String kemName = getKEMName(namedGroup);
+ if (null != kemName)
+ {
+ return kemName;
+ }
+
return null;
}
@@ -412,9 +438,15 @@ public static boolean refersToASpecificFiniteField(int namedGroup)
return namedGroup >= ffdhe2048 && namedGroup <= ffdhe8192;
}
+ public static boolean refersToASpecificKEM(int namedGroup)
+ {
+ return namedGroup == kyber512 || namedGroup == kyber768 || namedGroup == kyber1024;
+ }
+
public static boolean refersToASpecificGroup(int namedGroup)
{
return refersToASpecificCurve(namedGroup)
- || refersToASpecificFiniteField(namedGroup);
+ || refersToASpecificFiniteField(namedGroup)
+ || refersToASpecificKEM(namedGroup);
}
}
diff --git a/tls/src/main/java/org/bouncycastle/tls/NamedGroupRole.java b/tls/src/main/java/org/bouncycastle/tls/NamedGroupRole.java
index 724cfcc167..eea7d9262c 100644
--- a/tls/src/main/java/org/bouncycastle/tls/NamedGroupRole.java
+++ b/tls/src/main/java/org/bouncycastle/tls/NamedGroupRole.java
@@ -9,4 +9,5 @@ public class NamedGroupRole
public static final int dh = 1;
public static final int ecdh = 2;
public static final int ecdsa = 3;
+ public static final int kem = 4;
}
diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java b/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java
index a788067b64..ff067d2dd5 100644
--- a/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java
+++ b/tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java
@@ -10,8 +10,10 @@
import org.bouncycastle.tls.crypto.TlsAgreement;
import org.bouncycastle.tls.crypto.TlsCrypto;
+import org.bouncycastle.tls.crypto.TlsCryptoParameters;
import org.bouncycastle.tls.crypto.TlsDHConfig;
import org.bouncycastle.tls.crypto.TlsECConfig;
+import org.bouncycastle.tls.crypto.TlsKEMConfig;
import org.bouncycastle.tls.crypto.TlsSecret;
import org.bouncycastle.util.Arrays;
@@ -405,16 +407,21 @@ else if (NamedGroup.refersToASpecificFiniteField(namedGroup))
{
agreement = crypto.createDHDomain(new TlsDHConfig(namedGroup, true)).createDH();
}
+ else if (NamedGroup.refersToASpecificKEM(namedGroup))
+ {
+ agreement = crypto.createKEMDomain(new TlsKEMConfig(namedGroup, new TlsCryptoParameters(tlsServerContext))).createKEM();
+ }
else
{
throw new TlsFatalAlert(AlertDescription.internal_error);
}
+ agreement.receivePeerValue(clientShare.getKeyExchange());
+
byte[] key_exchange = agreement.generateEphemeral();
KeyShareEntry serverShare = new KeyShareEntry(namedGroup, key_exchange);
TlsExtensionsUtils.addKeyShareServerHello(serverHelloExtensions, serverShare);
- agreement.receivePeerValue(clientShare.getKeyExchange());
sharedSecret = agreement.calculateSecret();
}
diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java
index 5a02e05e65..00f3305629 100644
--- a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java
+++ b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java
@@ -40,6 +40,7 @@
import org.bouncycastle.tls.crypto.TlsEncryptor;
import org.bouncycastle.tls.crypto.TlsHash;
import org.bouncycastle.tls.crypto.TlsHashOutputStream;
+import org.bouncycastle.tls.crypto.TlsKEMConfig;
import org.bouncycastle.tls.crypto.TlsSecret;
import org.bouncycastle.tls.crypto.TlsStreamSigner;
import org.bouncycastle.tls.crypto.TlsStreamVerifier;
@@ -4022,6 +4023,7 @@ public static Vector getNamedGroupRoles(Vector keyExchangeAlgorithms)
// TODO[tls13] We're conservatively adding both here, though maybe only one is needed
addToSet(result, NamedGroupRole.dh);
addToSet(result, NamedGroupRole.ecdh);
+ addToSet(result, NamedGroupRole.kem);
break;
}
}
@@ -5303,7 +5305,7 @@ static Hashtable addKeyShareToClientHello(TlsClientContext clientContext, TlsCli
Hashtable clientAgreements = new Hashtable(3);
Vector clientShares = new Vector(2);
- collectKeyShares(clientContext.getCrypto(), supportedGroups, keyShareGroups, clientAgreements, clientShares);
+ collectKeyShares(clientContext, supportedGroups, keyShareGroups, clientAgreements, clientShares);
// TODO[tls13-psk] When clientShares empty, consider not adding extension if pre_shared_key in use
TlsExtensionsUtils.addKeyShareClientHello(clientExtensions, clientShares);
@@ -5319,7 +5321,7 @@ static Hashtable addKeyShareToClientHelloRetry(TlsClientContext clientContext, H
Hashtable clientAgreements = new Hashtable(1, 1.0f);
Vector clientShares = new Vector(1);
- collectKeyShares(clientContext.getCrypto(), supportedGroups, keyShareGroups, clientAgreements, clientShares);
+ collectKeyShares(clientContext, supportedGroups, keyShareGroups, clientAgreements, clientShares);
TlsExtensionsUtils.addKeyShareClientHello(clientExtensions, clientShares);
@@ -5332,9 +5334,10 @@ static Hashtable addKeyShareToClientHelloRetry(TlsClientContext clientContext, H
return clientAgreements;
}
- private static void collectKeyShares(TlsCrypto crypto, int[] supportedGroups, Vector keyShareGroups,
+ private static void collectKeyShares(TlsClientContext clientContext, int[] supportedGroups, Vector keyShareGroups,
Hashtable clientAgreements, Vector clientShares) throws IOException
{
+ TlsCrypto crypto = clientContext.getCrypto();
if (isNullOrEmpty(supportedGroups))
{
return;
@@ -5371,6 +5374,13 @@ else if (NamedGroup.refersToASpecificFiniteField(supportedGroup))
agreement = crypto.createDHDomain(new TlsDHConfig(supportedGroup, true)).createDH();
}
}
+ else if (NamedGroup.refersToASpecificKEM(supportedGroup))
+ {
+ if (crypto.hasKEMAgreement())
+ {
+ agreement = crypto.createKEMDomain(new TlsKEMConfig(supportedGroup, new TlsCryptoParameters(clientContext))).createKEM();
+ }
+ }
if (null != agreement)
{
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java
index 2534d6aaee..0e1492ac5f 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsCrypto.java
@@ -69,6 +69,13 @@ public interface TlsCrypto
*/
boolean hasECDHAgreement();
+ /**
+ * Return true if this TlsCrypto can support KEM key agreement.
+ *
+ * @return true if this instance can support KEM key agreement, false otherwise.
+ */
+ boolean hasKEMAgreement();
+
/**
* Return true if this TlsCrypto can support the passed in block/stream encryption algorithm.
*
@@ -213,6 +220,14 @@ TlsCipher createCipher(TlsCryptoParameters cryptoParams, int encryptionAlgorithm
*/
TlsECDomain createECDomain(TlsECConfig ecConfig);
+ /**
+ * Create a domain object supporting the domain parameters described in kemConfig.
+ *
+ * @param kemConfig the config describing the KEM parameters to use.
+ * @return a TlsKEMDomain supporting the parameters in kemConfig.
+ */
+ TlsKEMDomain createKEMDomain(TlsKEMConfig kemConfig);
+
/**
* Adopt the passed in secret, creating a new copy of it.
*
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMConfig.java b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMConfig.java
new file mode 100644
index 0000000000..e10cefe467
--- /dev/null
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMConfig.java
@@ -0,0 +1,52 @@
+package org.bouncycastle.tls.crypto;
+
+public class TlsKEMConfig
+{
+ protected final int namedGroup;
+ protected final TlsCryptoParameters cryptoParams;
+ protected final int kemNamedGroup;
+
+ public TlsKEMConfig(int namedGroup, TlsCryptoParameters cryptoParams)
+ {
+ this.namedGroup = namedGroup;
+ this.cryptoParams = cryptoParams;
+ this.kemNamedGroup = getKEMNamedGroup(namedGroup);
+ }
+
+ public int getNamedGroup()
+ {
+ return namedGroup;
+ }
+
+ public boolean isServer()
+ {
+ return cryptoParams.isServer();
+ }
+
+ public int getKEMNamedGroup()
+ {
+ return kemNamedGroup;
+ }
+
+ private int getKEMNamedGroup(int namedGroup)
+ {
+ return namedGroup;
+ // switch (namedGroup)
+ // {
+ // case NamedGroup.kyber512:
+ // case NamedGroup.secp256Kyber512:
+ // case NamedGroup.x25519Kyber512:
+ // return NamedGroup.kyber512;
+ // case NamedGroup.kyber768:
+ // case NamedGroup.secp384Kyber768:
+ // case NamedGroup.x25519Kyber768:
+ // case NamedGroup.x448Kyber768:
+ // return NamedGroup.kyber768;
+ // case NamedGroup.kyber1024:
+ // case NamedGroup.secp521Kyber1024:
+ // return NamedGroup.kyber1024;
+ // default:
+ // return namedGroup;
+ // }
+ }
+}
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMDomain.java
new file mode 100644
index 0000000000..94a15b5cdf
--- /dev/null
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/TlsKEMDomain.java
@@ -0,0 +1,6 @@
+package org.bouncycastle.tls.crypto;
+
+public interface TlsKEMDomain
+{
+ TlsAgreement createKEM();
+}
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java
index 56b4c1fc83..4f5a3262c4 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsCrypto.java
@@ -54,6 +54,8 @@
import org.bouncycastle.tls.crypto.TlsECDomain;
import org.bouncycastle.tls.crypto.TlsHMAC;
import org.bouncycastle.tls.crypto.TlsHash;
+import org.bouncycastle.tls.crypto.TlsKEMConfig;
+import org.bouncycastle.tls.crypto.TlsKEMDomain;
import org.bouncycastle.tls.crypto.TlsNonceGenerator;
import org.bouncycastle.tls.crypto.TlsSRP6Client;
import org.bouncycastle.tls.crypto.TlsSRP6Server;
@@ -211,6 +213,11 @@ public TlsECDomain createECDomain(TlsECConfig ecConfig)
}
}
+ public TlsKEMDomain createKEMDomain(TlsKEMConfig kemConfig)
+ {
+ return new BcTlsKyberDomain(this, kemConfig);
+ }
+
public TlsNonceGenerator createNonceGenerator(byte[] additionalSeedMaterial)
{
int cryptoHashAlgorithm = CryptoHashAlgorithm.sha256;
@@ -304,6 +311,11 @@ public boolean hasECDHAgreement()
return true;
}
+ public boolean hasKEMAgreement()
+ {
+ return true;
+ }
+
public boolean hasEncryptionAlgorithm(int encryptionAlgorithm)
{
switch (encryptionAlgorithm)
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyber.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyber.java
new file mode 100644
index 0000000000..1d65e6726b
--- /dev/null
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyber.java
@@ -0,0 +1,65 @@
+package org.bouncycastle.tls.crypto.impl.bc;
+
+import java.io.IOException;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.SecretWithEncapsulation;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPublicKeyParameters;
+import org.bouncycastle.tls.crypto.TlsAgreement;
+import org.bouncycastle.tls.crypto.TlsSecret;
+import org.bouncycastle.util.Arrays;
+
+public class BcTlsKyber implements TlsAgreement
+{
+ protected final BcTlsKyberDomain domain;
+
+ protected AsymmetricCipherKeyPair localKeyPair;
+ protected KyberPublicKeyParameters peerPublicKey;
+ protected byte[] ciphertext;
+ protected byte[] secret;
+
+ public BcTlsKyber(BcTlsKyberDomain domain)
+ {
+ this.domain = domain;
+ }
+
+ public byte[] generateEphemeral() throws IOException
+ {
+ if (domain.getTlsKEMConfig().isServer())
+ {
+ return Arrays.clone(ciphertext);
+ }
+ else
+ {
+ this.localKeyPair = domain.generateKeyPair();
+ return domain.encodePublicKey((KyberPublicKeyParameters)localKeyPair.getPublic());
+ }
+ }
+
+ public void receivePeerValue(byte[] peerValue) throws IOException
+ {
+ if (domain.getTlsKEMConfig().isServer())
+ {
+ this.peerPublicKey = domain.decodePublicKey(peerValue);
+ SecretWithEncapsulation encap = domain.enCap(peerPublicKey);
+ ciphertext = encap.getEncapsulation();
+ secret = encap.getSecret();
+ }
+ else
+ {
+ this.ciphertext = Arrays.clone(peerValue);
+ }
+ }
+
+ public TlsSecret calculateSecret() throws IOException
+ {
+ if (domain.getTlsKEMConfig().isServer())
+ {
+ return domain.adoptLocalSecret(secret);
+ }
+ else
+ {
+ return domain.adoptLocalSecret(domain.deCap((KyberPrivateKeyParameters)localKeyPair.getPrivate(), ciphertext));
+ }
+ }
+}
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyberDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyberDomain.java
new file mode 100644
index 0000000000..e6e8396082
--- /dev/null
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/bc/BcTlsKyberDomain.java
@@ -0,0 +1,90 @@
+package org.bouncycastle.tls.crypto.impl.bc;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.SecretWithEncapsulation;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKEMExtractor;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKEMGenerator;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKeyGenerationParameters;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKeyPairGenerator;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberParameters;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPublicKeyParameters;
+import org.bouncycastle.tls.NamedGroup;
+import org.bouncycastle.tls.crypto.TlsAgreement;
+import org.bouncycastle.tls.crypto.TlsKEMConfig;
+import org.bouncycastle.tls.crypto.TlsKEMDomain;
+import org.bouncycastle.tls.crypto.TlsSecret;
+
+public class BcTlsKyberDomain implements TlsKEMDomain
+{
+ public static KyberParameters getKyberParameters(TlsKEMConfig kemConfig)
+ {
+ switch (kemConfig.getKEMNamedGroup())
+ {
+ case NamedGroup.kyber512:
+ return KyberParameters.kyber512;
+ case NamedGroup.kyber768:
+ return KyberParameters.kyber768;
+ case NamedGroup.kyber1024:
+ return KyberParameters.kyber1024;
+ default:
+ return null;
+ }
+ }
+
+ protected final BcTlsCrypto crypto;
+ protected final TlsKEMConfig kemConfig;
+ protected final KyberParameters kyberParameters;
+
+ public TlsKEMConfig getTlsKEMConfig()
+ {
+ return kemConfig;
+ }
+
+ public BcTlsKyberDomain(BcTlsCrypto crypto, TlsKEMConfig kemConfig)
+ {
+ this.crypto = crypto;
+ this.kemConfig = kemConfig;
+ this.kyberParameters = getKyberParameters(kemConfig);
+ }
+
+ public TlsAgreement createKEM()
+ {
+ return new BcTlsKyber(this);
+ }
+
+ public KyberPublicKeyParameters decodePublicKey(byte[] encoding)
+ {
+ return new KyberPublicKeyParameters(kyberParameters, encoding);
+ }
+
+ public byte[] encodePublicKey(KyberPublicKeyParameters kyberPublicKeyParameters)
+ {
+ return kyberPublicKeyParameters.getEncoded();
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ KyberKeyPairGenerator keyPairGenerator = new KyberKeyPairGenerator();
+ keyPairGenerator.init(new KyberKeyGenerationParameters(crypto.getSecureRandom(), kyberParameters));
+ return keyPairGenerator.generateKeyPair();
+ }
+
+ public TlsSecret adoptLocalSecret(byte[] secret)
+ {
+ return crypto.adoptLocalSecret(secret);
+ }
+
+ public SecretWithEncapsulation enCap(KyberPublicKeyParameters peerPublicKey)
+ {
+ KyberKEMGenerator kemGen = new KyberKEMGenerator(crypto.getSecureRandom());
+ return kemGen.generateEncapsulated(peerPublicKey);
+ }
+
+ public byte[] deCap(KyberPrivateKeyParameters kyberPrivateKeyParameters, byte[] cipherText)
+ {
+ KyberKEMExtractor kemExtract = new KyberKEMExtractor(kyberPrivateKeyParameters);
+ byte[] secret = kemExtract.extractSecret(cipherText);
+ return secret;
+ }
+}
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java
index 7c19caace0..b6fcc0331b 100644
--- a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JcaTlsCrypto.java
@@ -48,6 +48,8 @@
import org.bouncycastle.tls.crypto.TlsECDomain;
import org.bouncycastle.tls.crypto.TlsHMAC;
import org.bouncycastle.tls.crypto.TlsHash;
+import org.bouncycastle.tls.crypto.TlsKEMConfig;
+import org.bouncycastle.tls.crypto.TlsKEMDomain;
import org.bouncycastle.tls.crypto.TlsNonceGenerator;
import org.bouncycastle.tls.crypto.TlsSRP6Client;
import org.bouncycastle.tls.crypto.TlsSRP6Server;
@@ -436,6 +438,16 @@ else if (NamedGroup.refersToASpecificFiniteField(namedGroup))
{
return DHUtil.getAlgorithmParameters(this, TlsDHUtils.getNamedDHGroup(namedGroup));
}
+ else if (NamedGroup.refersToASpecificKEM(namedGroup))
+ {
+ switch (namedGroup)
+ {
+ case NamedGroup.kyber512:
+ case NamedGroup.kyber768:
+ case NamedGroup.kyber1024:
+ return null;
+ }
+ }
throw new IllegalArgumentException("NamedGroup not supported: " + NamedGroup.getText(namedGroup));
}
@@ -559,6 +571,11 @@ public boolean hasECDHAgreement()
{
return true;
}
+
+ public boolean hasKEMAgreement()
+ {
+ return true;
+ }
public boolean hasEncryptionAlgorithm(int encryptionAlgorithm)
{
@@ -823,6 +840,11 @@ public TlsECDomain createECDomain(TlsECConfig ecConfig)
return new JceTlsECDomain(this, ecConfig);
}
}
+
+ public TlsKEMDomain createKEMDomain(TlsKEMConfig kemConfig)
+ {
+ return new JceTlsKyberDomain(this, kemConfig);
+ }
public TlsSecret hkdfInit(int cryptoHashAlgorithm)
{
@@ -1148,6 +1170,10 @@ protected Boolean isSupportedNamedGroup(int namedGroup)
}
}
}
+ else if (NamedGroup.refersToASpecificKEM(namedGroup))
+ {
+ return Boolean.TRUE;
+ }
else if (NamedGroup.refersToAnECDSACurve(namedGroup))
{
return Boolean.valueOf(ECUtil.isCurveSupported(this, NamedGroup.getCurveName(namedGroup)));
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyber.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyber.java
new file mode 100644
index 0000000000..0d5e4768eb
--- /dev/null
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyber.java
@@ -0,0 +1,64 @@
+package org.bouncycastle.tls.crypto.impl.jcajce;
+
+import java.io.IOException;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.SecretWithEncapsulation;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPublicKeyParameters;
+import org.bouncycastle.tls.crypto.TlsAgreement;
+import org.bouncycastle.util.Arrays;
+
+public class JceTlsKyber implements TlsAgreement
+{
+ protected final JceTlsKyberDomain domain;
+
+ protected AsymmetricCipherKeyPair localKeyPair;
+ protected KyberPublicKeyParameters peerPublicKey;
+ protected byte[] ciphertext;
+ protected byte[] secret;
+
+ public JceTlsKyber(JceTlsKyberDomain domain)
+ {
+ this.domain = domain;
+ }
+
+ public byte[] generateEphemeral() throws IOException
+ {
+ if (domain.getTlsKEMConfig().isServer())
+ {
+ return Arrays.clone(ciphertext);
+ }
+ else
+ {
+ this.localKeyPair = domain.generateKeyPair();
+ return domain.encodePublicKey((KyberPublicKeyParameters)localKeyPair.getPublic());
+ }
+ }
+
+ public void receivePeerValue(byte[] peerValue) throws IOException
+ {
+ if (domain.getTlsKEMConfig().isServer())
+ {
+ this.peerPublicKey = domain.decodePublicKey(peerValue);
+ SecretWithEncapsulation encap = domain.enCap(peerPublicKey);
+ ciphertext = encap.getEncapsulation();
+ secret = encap.getSecret();
+ }
+ else
+ {
+ this.ciphertext = Arrays.clone(peerValue);
+ }
+ }
+
+ public JceTlsSecret calculateSecret() throws IOException
+ {
+ if (domain.getTlsKEMConfig().isServer())
+ {
+ return domain.adoptLocalSecret(secret);
+ }
+ else
+ {
+ return domain.adoptLocalSecret(domain.deCap((KyberPrivateKeyParameters)localKeyPair.getPrivate(), ciphertext));
+ }
+ }
+}
diff --git a/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyberDomain.java b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyberDomain.java
new file mode 100644
index 0000000000..6f52c7c8e9
--- /dev/null
+++ b/tls/src/main/java/org/bouncycastle/tls/crypto/impl/jcajce/JceTlsKyberDomain.java
@@ -0,0 +1,89 @@
+package org.bouncycastle.tls.crypto.impl.jcajce;
+
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.SecretWithEncapsulation;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKEMExtractor;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKEMGenerator;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKeyGenerationParameters;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberKeyPairGenerator;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberParameters;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPrivateKeyParameters;
+import org.bouncycastle.pqc.crypto.crystals.kyber.KyberPublicKeyParameters;
+import org.bouncycastle.tls.NamedGroup;
+import org.bouncycastle.tls.crypto.TlsAgreement;
+import org.bouncycastle.tls.crypto.TlsKEMConfig;
+import org.bouncycastle.tls.crypto.TlsKEMDomain;
+
+public class JceTlsKyberDomain implements TlsKEMDomain
+{
+ public static KyberParameters getKyberParameters(TlsKEMConfig kemConfig)
+ {
+ switch (kemConfig.getKEMNamedGroup())
+ {
+ case NamedGroup.kyber512:
+ return KyberParameters.kyber512;
+ case NamedGroup.kyber768:
+ return KyberParameters.kyber768;
+ case NamedGroup.kyber1024:
+ return KyberParameters.kyber1024;
+ default:
+ return null;
+ }
+ }
+
+ protected final JcaTlsCrypto crypto;
+ protected final TlsKEMConfig kemConfig;
+ protected final KyberParameters kyberParameters;
+
+ public TlsKEMConfig getTlsKEMConfig()
+ {
+ return kemConfig;
+ }
+
+ public JceTlsKyberDomain(JcaTlsCrypto crypto, TlsKEMConfig kemConfig)
+ {
+ this.crypto = crypto;
+ this.kemConfig = kemConfig;
+ this.kyberParameters = getKyberParameters(kemConfig);
+ }
+
+ public TlsAgreement createKEM()
+ {
+ return new JceTlsKyber(this);
+ }
+
+ public KyberPublicKeyParameters decodePublicKey(byte[] encoding)
+ {
+ return new KyberPublicKeyParameters(kyberParameters, encoding);
+ }
+
+ public byte[] encodePublicKey(KyberPublicKeyParameters kyberPublicKeyParameters)
+ {
+ return kyberPublicKeyParameters.getEncoded();
+ }
+
+ public AsymmetricCipherKeyPair generateKeyPair()
+ {
+ KyberKeyPairGenerator keyPairGenerator = new KyberKeyPairGenerator();
+ keyPairGenerator.init(new KyberKeyGenerationParameters(crypto.getSecureRandom(), kyberParameters));
+ return keyPairGenerator.generateKeyPair();
+ }
+
+ public JceTlsSecret adoptLocalSecret(byte[] secret)
+ {
+ return crypto.adoptLocalSecret(secret);
+ }
+
+ public SecretWithEncapsulation enCap(KyberPublicKeyParameters peerPublicKey)
+ {
+ KyberKEMGenerator kemGen = new KyberKEMGenerator(crypto.getSecureRandom());
+ return kemGen.generateEncapsulated(peerPublicKey);
+ }
+
+ public byte[] deCap(KyberPrivateKeyParameters kyberPrivateKeyParameters, byte[] cipherText)
+ {
+ KyberKEMExtractor kemExtract = new KyberKEMExtractor(kyberPrivateKeyParameters);
+ byte[] secret = kemExtract.extractSecret(cipherText);
+ return secret;
+ }
+}
diff --git a/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java b/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java
index de1cbcaee2..03f5bf58a7 100644
--- a/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java
+++ b/tls/src/test/java/org/bouncycastle/jsse/provider/test/BasicTlsTest.java
@@ -24,6 +24,7 @@ public class BasicTlsTest
protected void setUp()
{
ProviderUtils.setupLowPriority(false);
+// System.setProperty("jdk.tls.namedGroups", "kyber768");
}
private static final String HOST = "localhost";
From 35002d903e7e2ebaaf68f6c9a585d8cebfbbc454 Mon Sep 17 00:00:00 2001
From: royb
Date: Wed, 3 Apr 2024 11:24:40 -0400
Subject: [PATCH 0222/1846] Added KEM check in selectKeyShare/Group minor name
change
---
.../org/bouncycastle/jsse/provider/NamedGroupInfo.java | 6 +++---
tls/src/main/java/org/bouncycastle/tls/TlsUtils.java | 10 ++++++++++
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java b/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java
index f3ea03cc24..ea22016383 100644
--- a/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java
+++ b/tls/src/main/java/org/bouncycastle/jsse/provider/NamedGroupInfo.java
@@ -75,9 +75,9 @@ private enum All
ffdhe6144(NamedGroup.ffdhe6144, "DiffieHellman"),
ffdhe8192(NamedGroup.ffdhe8192, "DiffieHellman"),
- kyber512(NamedGroup.mlkem512, "KEM"),
- kyber768(NamedGroup.mlkem768, "KEM"),
- kyber1024(NamedGroup.mlkem1024, "KEM");
+ mlkem512(NamedGroup.mlkem512, "KEM"),
+ mlkem768(NamedGroup.mlkem768, "KEM"),
+ mlkem1024(NamedGroup.mlkem1024, "KEM");
private final int namedGroup;
private final String name;
diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java
index 00f3305629..91329c164f 100644
--- a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java
+++ b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java
@@ -5439,6 +5439,11 @@ static KeyShareEntry selectKeyShare(TlsCrypto crypto, ProtocolVersion negotiated
continue;
}
+ if (NamedGroup.refersToASpecificKEM(group) && !crypto.hasKEMAgreement())
+ {
+ continue;
+ }
+
return clientShare;
}
}
@@ -5475,6 +5480,11 @@ static int selectKeyShareGroup(TlsCrypto crypto, ProtocolVersion negotiatedVersi
continue;
}
+ if (NamedGroup.refersToASpecificKEM(group) && !crypto.hasKEMAgreement())
+ {
+ continue;
+ }
+
return group;
}
}
From 63fa26677b9caf30451d6a50db90d68508b22503 Mon Sep 17 00:00:00 2001
From: royb
Date: Wed, 3 Apr 2024 11:24:59 -0400
Subject: [PATCH 0223/1846] added fail in catch
---
.../java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java
index 924a0abebb..27f57f913a 100644
--- a/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java
+++ b/tls/src/test/java/org/bouncycastle/tls/test/TlsProtocolKEMTest.java
@@ -127,6 +127,10 @@ public void run()
}
catch (IOException ignored)
{
+ if (!shouldFail)
+ {
+ fail();
+ }
}
Streams.pipeAll(serverProtocol.getInputStream(), serverProtocol.getOutputStream());
From 58b5355c89dbafae66e70efea8ef9e6c0800bdc0 Mon Sep 17 00:00:00 2001
From: royb
Date: Wed, 3 Apr 2024 11:52:39 -0400
Subject: [PATCH 0224/1846] quick little arrangement
---
tls/src/main/java/org/bouncycastle/tls/TlsUtils.java | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java
index 91329c164f..db859d6b9f 100644
--- a/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java
+++ b/tls/src/main/java/org/bouncycastle/tls/TlsUtils.java
@@ -5434,15 +5434,12 @@ static KeyShareEntry selectKeyShare(TlsCrypto crypto, ProtocolVersion negotiated
}
if ((NamedGroup.refersToASpecificCurve(group) && !crypto.hasECDHAgreement()) ||
- (NamedGroup.refersToASpecificFiniteField(group) && !crypto.hasDHAgreement()))
+ (NamedGroup.refersToASpecificFiniteField(group) && !crypto.hasDHAgreement()) ||
+ (NamedGroup.refersToASpecificKEM(group) && !crypto.hasKEMAgreement()))
{
continue;
}
- if (NamedGroup.refersToASpecificKEM(group) && !crypto.hasKEMAgreement())
- {
- continue;
- }
return clientShare;
}
From b6ac3d4d114fb13a2a8ab9e8cbe8b9b8b507de06 Mon Sep 17 00:00:00 2001
From: Peter Dettman