| package org.bouncycastle.pqc.jcajce.provider.test; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.ObjectInputStream; |
| import java.io.ObjectOutputStream; |
| import java.security.KeyFactory; |
| import java.security.KeyPair; |
| import java.security.KeyPairGenerator; |
| import java.security.PrivateKey; |
| import java.security.PublicKey; |
| import java.security.SecureRandom; |
| import java.security.Security; |
| import java.security.Signature; |
| import java.security.SignatureException; |
| import java.security.spec.PKCS8EncodedKeySpec; |
| import java.security.spec.X509EncodedKeySpec; |
| |
| import junit.framework.TestCase; |
| import org.bouncycastle.asn1.ASN1Encodable; |
| import org.bouncycastle.asn1.ASN1ObjectIdentifier; |
| import org.bouncycastle.asn1.ASN1Sequence; |
| import org.bouncycastle.asn1.DERSequence; |
| import org.bouncycastle.asn1.bc.BCObjectIdentifiers; |
| import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; |
| import org.bouncycastle.crypto.Digest; |
| import org.bouncycastle.crypto.Xof; |
| import org.bouncycastle.crypto.digests.SHA256Digest; |
| import org.bouncycastle.crypto.digests.SHA512Digest; |
| import org.bouncycastle.crypto.digests.SHAKEDigest; |
| import org.bouncycastle.pqc.jcajce.interfaces.StateAwareSignature; |
| import org.bouncycastle.pqc.jcajce.interfaces.XMSSMTKey; |
| import org.bouncycastle.pqc.jcajce.interfaces.XMSSMTPrivateKey; |
| import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider; |
| import org.bouncycastle.pqc.jcajce.spec.XMSSMTParameterSpec; |
| import org.bouncycastle.pqc.jcajce.spec.XMSSParameterSpec; |
| import org.bouncycastle.util.Arrays; |
| import org.bouncycastle.util.Strings; |
| import org.bouncycastle.util.encoders.Base64; |
| |
| /** |
| * Test cases for the use of XMSS^MT with the BCPQC provider. |
| */ |
| public class XMSSMTTest |
| extends TestCase |
| { |
| private static final byte[] msg = Strings.toByteArray("Cthulhu Fthagn --What a wonderful phrase!Cthulhu Fthagn --Say it and you're crazed!"); |
| |
| private static byte[] testPrivKey = Base64.decode( |
| "MIIHuAIBADAkBgorBgEEAYGwGgIDMBYCAQACAQoCAQIwCwYJYIZIAWUDBAIBBIIHizCCB4cCAQAwgYsCAQAEILF57l4FB6N/vvGoIQ" + |
| "TjZ5gaZRgFQUPBjH7y6mfZgdvaBCBvDUjbkmb9GoHYbyKHxGlJ/dmHAkXahPNNfRR9AZCOlwQgBfd9vy9CNN4k4NIYjRvtz7QgMjjb" + |
| "kt5WAdQej5KzNM0EIPTPrmKVwjXe4F8QlmZOUZP28jDG/ZJpxR5712m2e4ywoIIG8gSCBu6s7QAFc3IALG9yZy5ib3VuY3ljYXN0bG" + |
| "UucHFjLmNyeXB0by54bXNzLkJEU1N0YXRlTWFwz+vLa6D+CbwCAAFMAAhiZHNTdGF0ZXQAD0xqYXZhL3V0aWwvTWFwO3hwc3IAEWph" + |
| "dmEudXRpbC5UcmVlTWFwDMH2Pi0lauYDAAFMAApjb21wYXJhdG9ydAAWTGphdmEvdXRpbC9Db21wYXJhdG9yO3hwcHcEAAAAAXNyAB" + |
| "FqYXZhLmxhbmcuSW50ZWdlchLioKT3gYc4AgABSQAFdmFsdWV4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHAAAAABc3IA" + |
| "JG9yZy5ib3VuY3ljYXN0bGUucHFjLmNyeXB0by54bXNzLkJEUwAAAAAAAAABAgAKSQAFaW5kZXhJAAFrSQAKdHJlZUhlaWdodFoABH" + |
| "VzZWRMABJhdXRoZW50aWNhdGlvblBhdGh0ABBMamF2YS91dGlsL0xpc3Q7TAAEa2VlcHEAfgABTAAGcmV0YWlucQB+AAFMAARyb290" + |
| "dAArTG9yZy9ib3VuY3ljYXN0bGUvcHFjL2NyeXB0by94bXNzL1hNU1NOb2RlO0wABXN0YWNrdAARTGphdmEvdXRpbC9TdGFjaztMAB" + |
| "F0cmVlSGFzaEluc3RhbmNlc3EAfgAKeHAAAAAAAAAAAwAAAAUAc3IAE2phdmEudXRpbC5BcnJheUxpc3R4gdIdmcdhnQMAAUkABHNp" + |
| "emV4cAAAAAV3BAAAAAVzcgApb3JnLmJvdW5jeWNhc3RsZS5wcWMuY3J5cHRvLnhtc3MuWE1TU05vZGUAAAAAAAAAAQIAAkkABmhlaW" + |
| "dodFsABXZhbHVldAACW0J4cAAAAAB1cgACW0Ks8xf4BghU4AIAAHhwAAAAIKblKPny5XBcLTom61U/VvUCJ+/xEX/qJaRXitEAu89F" + |
| "c3EAfgAQAAAAAXVxAH4AEwAAACDLWNO9lh3R8LdD5dVoQ5r85BH+XbLY3a/Bbf2ABa7AEXNxAH4AEAAAAAJ1cQB+ABMAAAAgv7gBYE" + |
| "q+h3U9GsU5dqmQp/p2ap7tr5wv6X8mYVgNJPhzcQB+ABAAAAADdXEAfgATAAAAIDLtl68/OsguE7QTZ2UzFfcjGv3fGoiBomQNlyEs" + |
| "VWT1c3EAfgAQAAAABHVxAH4AEwAAACC2CKhUAp92/hJwuyEIJXxBcHsTg/vgBg3FfHaFJh85cXhzcQB+AANwdwQAAAAAeHNxAH4AA3" + |
| "B3BAAAAAJzcQB+AAYAAAACc3IAFGphdmEudXRpbC5MaW5rZWRMaXN0DClTXUpgiCIDAAB4cHcEAAAAA3NxAH4AEAAAAAJ1cQB+ABMA" + |
| "AAAgl/DnFFIHZ6u8yNQSOIh47zRoRZLfkj8/CzUHM54wKQtzcQB+ABAAAAACdXEAfgATAAAAIPx12RSLQNhXo5DWenzn18i5c11MQ8" + |
| "E21a3fKBI1c1xTc3EAfgAQAAAAAnVxAH4AEwAAACAUw9Wnqw/IS+TLVVj5zAOe0lMvf+x3x61nHfjYAXY5BnhzcQB+AAYAAAADc3EA" + |
| "fgAgdwQAAAABc3EAfgAQAAAAA3VxAH4AEwAAACC4x1ONSAJrJ0+2gqZxhi6MJ7jY69JS2b425N3ZUAwiKnh4c3EAfgAQAAAABXVxAH" + |
| "4AEwAAACD0z65ilcI13uBfEJZmTlGT9vIwxv2SacUee9dptnuMsHNyAA9qYXZhLnV0aWwuU3RhY2sQ/irCuwmGHQIAAHhyABBqYXZh" + |
| "LnV0aWwuVmVjdG9y2Zd9W4A7rwEDAANJABFjYXBhY2l0eUluY3JlbWVudEkADGVsZW1lbnRDb3VudFsAC2VsZW1lbnREYXRhdAATW0" + |
| "xqYXZhL2xhbmcvT2JqZWN0O3hwAAAAAAAAAAB1cgATW0xqYXZhLmxhbmcuT2JqZWN0O5DOWJ8QcylsAgAAeHAAAAAKcHBwcHBwcHBw" + |
| "cHhzcQB+AA4AAAACdwQAAAACc3IALG9yZy5ib3VuY3ljYXN0bGUucHFjLmNyeXB0by54bXNzLkJEU1RyZWVIYXNoAAAAAAAAAAECAA" + |
| "ZaAAhmaW5pc2hlZEkABmhlaWdodEkADWluaXRpYWxIZWlnaHRaAAtpbml0aWFsaXplZEkACW5leHRJbmRleEwACHRhaWxOb2RlcQB+" + |
| "AAt4cAEAAAAAAAAAAAAAAAAAc3EAfgAQAAAAAHVxAH4AEwAAACBIFJAzhXYHQfeDbwNePGtSxwbQECJRTd1ut5zN8RA3yXNxAH4ANQ" + |
| "EAAAABAAAAAQAAAAAAc3EAfgAQAAAAAXVxAH4AEwAAACCugtHVqJDME59RRNQ0b2Podg5KdFxCIEOqJbBvwDzxCXh4"); |
| |
| private static byte[] testPublicKey = Base64.decode( |
| "MHIwJAYKKwYBBAGBsBoCAzAWAgEAAgEEAgECMAsGCWCGSAFlAwQCCwNKADBHAgEABCDIZh5Q96JIc0h+AmYHd3UP1ldE5buCIeHXsN" + |
| "xBgGEtbAQgxENVtn9cR2bPbe3IZcmy6JmI6fvHt5yMkJ1lgQZFw6A="); |
| |
| public void setUp() |
| { |
| if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) |
| { |
| Security.addProvider(new BouncyCastlePQCProvider()); |
| } |
| } |
| |
| public void testPrivateKeyRecovery() |
| throws Exception |
| { |
| KeyFactory kFact = KeyFactory.getInstance("XMSSMT", "BCPQC"); |
| |
| XMSSMTKey privKey = (XMSSMTKey)kFact.generatePrivate(new PKCS8EncodedKeySpec(testPrivKey)); |
| |
| ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
| ObjectOutputStream oOut = new ObjectOutputStream(bOut); |
| |
| oOut.writeObject(privKey); |
| |
| oOut.close(); |
| |
| ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); |
| |
| XMSSMTKey privKey2 = (XMSSMTKey)oIn.readObject(); |
| |
| assertEquals(privKey, privKey2); |
| } |
| |
| public void testPublicKeyRecovery() |
| throws Exception |
| { |
| KeyFactory kFact = KeyFactory.getInstance("XMSSMT", "BCPQC"); |
| |
| XMSSMTKey pubKey = (XMSSMTKey)kFact.generatePublic(new X509EncodedKeySpec(testPublicKey)); |
| |
| ByteArrayOutputStream bOut = new ByteArrayOutputStream(); |
| ObjectOutputStream oOut = new ObjectOutputStream(bOut); |
| |
| oOut.writeObject(pubKey); |
| |
| oOut.close(); |
| |
| ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); |
| |
| XMSSMTKey pubKey2 = (XMSSMTKey)oIn.readObject(); |
| |
| assertEquals(pubKey, pubKey2); |
| } |
| |
| public void testKeyExtraction() |
| throws Exception |
| { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(20, 10, XMSSMTParameterSpec.SHA256), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| Signature sig = Signature.getInstance("SHA256withXMSSMT-SHA256", "BCPQC"); |
| |
| assertTrue(sig instanceof StateAwareSignature); |
| |
| StateAwareSignature xmssSig = (StateAwareSignature)sig; |
| |
| xmssSig.initSign(kp.getPrivate()); |
| |
| assertTrue(xmssSig.isSigningCapable()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| byte[] s = sig.sign(); |
| |
| PrivateKey nKey = xmssSig.getUpdatedPrivateKey(); |
| |
| assertFalse(kp.getPrivate().equals(nKey)); |
| assertFalse(xmssSig.isSigningCapable()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| try |
| { |
| sig.sign(); |
| fail("no exception after key extraction"); |
| } |
| catch (SignatureException e) |
| { |
| assertEquals("signing key no longer usable", e.getMessage()); |
| } |
| |
| try |
| { |
| xmssSig.getUpdatedPrivateKey(); |
| fail("no exception after key extraction"); |
| } |
| catch (IllegalStateException e) |
| { |
| assertEquals("signature object not in a signing state", e.getMessage()); |
| } |
| |
| xmssSig.initSign(nKey); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| s = sig.sign(); |
| |
| xmssSig.initVerify(kp.getPublic()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| assertTrue(xmssSig.verify(s)); |
| } |
| |
| public void testXMSSMTSha256SignatureMultiple() |
| throws Exception |
| { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(20, 10, XMSSMTParameterSpec.SHA256), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| StateAwareSignature sig1 = (StateAwareSignature)Signature.getInstance("SHA256withXMSSMT-SHA256", "BCPQC"); |
| |
| StateAwareSignature sig2 = (StateAwareSignature)Signature.getInstance("SHA256withXMSSMT-SHA256", "BCPQC"); |
| |
| StateAwareSignature sig3 = (StateAwareSignature)Signature.getInstance("SHA256withXMSSMT-SHA256", "BCPQC"); |
| |
| sig1.initSign(kp.getPrivate()); |
| |
| sig2.initSign(sig1.getUpdatedPrivateKey()); |
| |
| sig3.initSign(sig2.getUpdatedPrivateKey()); |
| |
| sig1.update(msg, 0, msg.length); |
| |
| byte[] s1 = sig1.sign(); |
| |
| sig2.update(msg, 0, msg.length); |
| |
| byte[] s2 = sig2.sign(); |
| |
| sig3.update(msg, 0, msg.length); |
| |
| byte[] s3 = sig3.sign(); |
| |
| sig1.initVerify(kp.getPublic()); |
| |
| sig1.update(msg, 0, msg.length); |
| |
| assertTrue(sig1.verify(s1)); |
| |
| sig1.update(msg, 0, msg.length); |
| |
| assertTrue(sig1.verify(s2)); |
| |
| sig1.update(msg, 0, msg.length); |
| |
| assertTrue(sig1.verify(s3)); |
| } |
| |
| public void testXMSSMTSha512KeyFactory() |
| throws Exception |
| { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(20, 10, XMSSMTParameterSpec.SHA512), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| KeyFactory keyFactory = KeyFactory.getInstance("XMSSMT", "BCPQC"); |
| |
| XMSSMTKey privKey = (XMSSMTKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); |
| |
| assertEquals(kp.getPrivate(), privKey); |
| |
| XMSSMTKey pubKey = (XMSSMTKey)keyFactory.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded())); |
| |
| assertEquals(kp.getPublic(), pubKey); |
| |
| assertEquals(20, privKey.getHeight()); |
| assertEquals(10, privKey.getLayers()); |
| assertEquals(XMSSParameterSpec.SHA512, privKey.getTreeDigest()); |
| |
| assertEquals(20, pubKey.getHeight()); |
| assertEquals(10, pubKey.getLayers()); |
| assertEquals(XMSSParameterSpec.SHA512, pubKey.getTreeDigest()); |
| } |
| |
| public void testXMSSMTSha256Signature() |
| throws Exception |
| { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(10, 5, XMSSMTParameterSpec.SHA256), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| Signature sig = Signature.getInstance("SHA256withXMSSMT", "BCPQC"); |
| |
| assertTrue(sig instanceof StateAwareSignature); |
| |
| StateAwareSignature xmssSig = (StateAwareSignature)sig; |
| |
| xmssSig.initSign(kp.getPrivate()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| byte[] s = sig.sign(); |
| |
| xmssSig.initVerify(kp.getPublic()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| assertTrue(xmssSig.verify(s)); |
| } |
| |
| public void testXMSSMTSha512Signature() |
| throws Exception |
| { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(10, 5, XMSSMTParameterSpec.SHA512), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| Signature sig = Signature.getInstance("SHA256withXMSSMT", "BCPQC"); |
| |
| assertTrue(sig instanceof StateAwareSignature); |
| |
| StateAwareSignature xmssSig = (StateAwareSignature)sig; |
| |
| xmssSig.initSign(kp.getPrivate()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| byte[] s = sig.sign(); |
| |
| xmssSig.initVerify(kp.getPublic()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| assertTrue(xmssSig.verify(s)); |
| } |
| |
| public void testXMSSMTShake128Signature() |
| throws Exception |
| { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(4, 2, XMSSMTParameterSpec.SHAKE128), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| Signature sig = Signature.getInstance("SHAKE128withXMSSMT-SHAKE128", "BCPQC"); |
| |
| assertTrue(sig instanceof StateAwareSignature); |
| |
| StateAwareSignature xmssSig = (StateAwareSignature)sig; |
| |
| xmssSig.initSign(kp.getPrivate()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| byte[] s = sig.sign(); |
| |
| xmssSig.initVerify(kp.getPublic()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| assertTrue(xmssSig.verify(s)); |
| } |
| |
| public void testXMSSMTShake256Signature() |
| throws Exception |
| { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(4, 2, XMSSMTParameterSpec.SHAKE256), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| Signature sig = Signature.getInstance("SHAKE256withXMSSMT-SHAKE256", "BCPQC"); |
| |
| assertTrue(sig instanceof StateAwareSignature); |
| |
| StateAwareSignature xmssSig = (StateAwareSignature)sig; |
| |
| xmssSig.initSign(kp.getPrivate()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| byte[] s = sig.sign(); |
| |
| xmssSig.initVerify(kp.getPublic()); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| assertTrue(xmssSig.verify(s)); |
| } |
| |
| public void testKeyRebuild() |
| throws Exception |
| { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(6, 3, XMSSMTParameterSpec.SHA256), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| Signature sig = Signature.getInstance("SHA256withXMSSMT", "BCPQC"); |
| |
| assertTrue(sig instanceof StateAwareSignature); |
| |
| StateAwareSignature xmssSig = (StateAwareSignature)sig; |
| |
| xmssSig.initSign(kp.getPrivate()); |
| |
| for (int i = 0; i != 5; i++) |
| { |
| xmssSig.update(msg, 0, msg.length); |
| |
| xmssSig.sign(); |
| } |
| |
| PrivateKey pKey = xmssSig.getUpdatedPrivateKey(); |
| |
| PrivateKeyInfo pKeyInfo = PrivateKeyInfo.getInstance(pKey.getEncoded()); |
| |
| KeyFactory keyFactory = KeyFactory.getInstance("XMSSMT", "BCPQC"); |
| |
| ASN1Sequence seq = ASN1Sequence.getInstance(pKeyInfo.parsePrivateKey()); |
| |
| // create a new PrivateKeyInfo containing a key with no BDS state. |
| pKeyInfo = new PrivateKeyInfo(pKeyInfo.getPrivateKeyAlgorithm(), |
| new DERSequence(new ASN1Encodable[] { seq.getObjectAt(0), seq.getObjectAt(1) })); |
| |
| XMSSMTKey privKey = (XMSSMTKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(pKeyInfo.getEncoded())); |
| |
| xmssSig.initSign(pKey); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| byte[] sig1 = xmssSig.sign(); |
| |
| xmssSig.initSign((PrivateKey)privKey); |
| |
| xmssSig.update(msg, 0, msg.length); |
| |
| byte[] sig2 = xmssSig.sign(); |
| |
| // make sure we get the same signature as the two keys should now |
| // be in the same state. |
| assertTrue(Arrays.areEqual(sig1, sig2)); |
| } |
| |
| public void testXMSSMTSha256KeyFactory() |
| throws Exception |
| { |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(10, 2, XMSSParameterSpec.SHA256), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| KeyFactory keyFactory = KeyFactory.getInstance("XMSSMT", "BCPQC"); |
| |
| XMSSMTKey privKey = (XMSSMTKey)keyFactory.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); |
| |
| assertEquals(kp.getPrivate(), privKey); |
| |
| PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded())); |
| |
| assertEquals(kp.getPublic(), pubKey); |
| |
| assertEquals(10, privKey.getHeight()); |
| assertEquals(XMSSParameterSpec.SHA256, privKey.getTreeDigest()); |
| |
| testSig("SHA256withXMSSMT", pubKey, (PrivateKey)privKey); |
| } |
| |
| private void testSig(String algorithm, PublicKey pubKey, PrivateKey privKey) |
| throws Exception |
| { |
| byte[] message = Strings.toByteArray("hello, world!"); |
| |
| Signature s1 = Signature.getInstance(algorithm, "BCPQC"); |
| Signature s2 = Signature.getInstance(algorithm, "BCPQC"); |
| |
| s1.initSign(privKey); |
| |
| for (int i = 0; i != 100; i++) |
| { |
| s1.update(message, 0, message.length); |
| |
| byte[] sig = s1.sign(); |
| |
| s2.initVerify(pubKey); |
| |
| s2.update(message, 0, message.length); |
| |
| assertTrue(s2.verify(sig)); |
| } |
| } |
| |
| public void testPrehashWithWithout() |
| throws Exception |
| { |
| testPrehashAndWithoutPrehash("XMSSMT-SHA256", "SHA256", new SHA256Digest()); |
| testPrehashAndWithoutPrehash("XMSSMT-SHAKE128", "SHAKE128", new SHAKEDigest(128)); |
| testPrehashAndWithoutPrehash("XMSSMT-SHA512", "SHA512", new SHA512Digest()); |
| testPrehashAndWithoutPrehash("XMSSMT-SHAKE256", "SHAKE256", new SHAKEDigest(256)); |
| |
| testPrehashAndWithoutPrehash(BCObjectIdentifiers.xmss_mt_SHA256ph, BCObjectIdentifiers.xmss_mt_SHA256, "SHA256", new SHA256Digest()); |
| testPrehashAndWithoutPrehash(BCObjectIdentifiers.xmss_mt_SHAKE128ph, BCObjectIdentifiers.xmss_mt_SHAKE128, "SHAKE128", new SHAKEDigest(128)); |
| testPrehashAndWithoutPrehash(BCObjectIdentifiers.xmss_mt_SHA512ph, BCObjectIdentifiers.xmss_mt_SHA512, "SHA512", new SHA512Digest()); |
| testPrehashAndWithoutPrehash(BCObjectIdentifiers.xmss_mt_SHAKE256ph, BCObjectIdentifiers.xmss_mt_SHAKE256, "SHAKE256", new SHAKEDigest(256)); |
| } |
| |
| public void testExhaustion() |
| throws Exception |
| { |
| StateAwareSignature s1 = (StateAwareSignature)Signature.getInstance(BCObjectIdentifiers.xmss_mt_SHA256.getId(), "BCPQC"); |
| Signature s2 = Signature.getInstance(BCObjectIdentifiers.xmss_mt_SHA256.getId(), "BCPQC"); |
| |
| byte[] message = Strings.toByteArray("hello, world!"); |
| |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(4, 2,"SHA256"), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| XMSSMTPrivateKey privKey = (XMSSMTPrivateKey)kp.getPrivate(); |
| |
| assertEquals(16, privKey.getUsagesRemaining()); |
| |
| s1.initSign(privKey); |
| |
| do |
| { |
| s1.update(message, 0, message.length); |
| |
| byte[] sig = s1.sign(); |
| |
| s2.initVerify(kp.getPublic()); |
| |
| s2.update(message, 0, message.length); |
| |
| assertTrue(s2.verify(sig)); |
| |
| privKey = (XMSSMTPrivateKey)s1.getUpdatedPrivateKey(); |
| |
| s1.initSign(privKey); |
| } |
| while (s1.isSigningCapable()); |
| |
| assertEquals(0, privKey.getUsagesRemaining()); |
| } |
| |
| private void testPrehashAndWithoutPrehash(String baseAlgorithm, String digestName, Digest digest) |
| throws Exception |
| { |
| Signature s1 = Signature.getInstance(digestName + "with" + baseAlgorithm, "BCPQC"); |
| Signature s2 = Signature.getInstance(baseAlgorithm, "BCPQC"); |
| |
| doTestPrehashAndWithoutPrehash(digestName, digest, s1, s2); |
| } |
| |
| private void testPrehashAndWithoutPrehash(ASN1ObjectIdentifier oid1, ASN1ObjectIdentifier oid2, String digestName, Digest digest) |
| throws Exception |
| { |
| Signature s1 = Signature.getInstance(oid1.getId(), "BCPQC"); |
| Signature s2 = Signature.getInstance(oid2.getId(), "BCPQC"); |
| |
| doTestPrehashAndWithoutPrehash(digestName, digest, s1, s2); |
| } |
| |
| private void doTestPrehashAndWithoutPrehash(String digestName, Digest digest, Signature s1, Signature s2) |
| throws Exception |
| { |
| byte[] message = Strings.toByteArray("hello, world!"); |
| |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| |
| kpg.initialize(new XMSSMTParameterSpec(4, 2, digestName), new SecureRandom()); |
| |
| KeyPair kp = kpg.generateKeyPair(); |
| |
| s1.initSign(kp.getPrivate()); |
| |
| s1.update(message, 0, message.length); |
| |
| byte[] sig = s1.sign(); |
| |
| s2.initVerify(kp.getPublic()); |
| |
| digest.update(message, 0, message.length); |
| |
| byte[] dig = new byte[(digest instanceof Xof) ? digest.getDigestSize() * 2 : digest.getDigestSize()]; |
| |
| if (digest instanceof Xof) |
| { |
| ((Xof)digest).doFinal(dig, 0, dig.length); |
| } |
| else |
| { |
| digest.doFinal(dig, 0); |
| } |
| s2.update(dig); |
| |
| assertTrue(s2.verify(sig)); |
| } |
| |
| public void testReserialization() |
| throws Exception |
| { |
| String digest = "SHA512"; |
| String sigAlg = digest+"withXMSSMT"; |
| byte[] payload = Strings.toByteArray("Hello, world!"); |
| |
| KeyPairGenerator kpg = KeyPairGenerator.getInstance("XMSSMT", "BCPQC"); |
| kpg.initialize(new XMSSMTParameterSpec(4, 2, digest)); |
| KeyPair keyPair = kpg.generateKeyPair(); |
| |
| PrivateKey privateKey = keyPair.getPrivate(); |
| PublicKey publicKey = keyPair.getPublic(); |
| |
| for (int i = 0; i != 10; i++) |
| { |
| StateAwareSignature signer = (StateAwareSignature)Signature.getInstance(sigAlg, "BCPQC"); |
| signer.initSign(privateKey); |
| signer.update(payload); |
| |
| byte[] signature = signer.sign(); |
| |
| // serialise private key |
| byte[] enc = signer.getUpdatedPrivateKey().getEncoded(); |
| privateKey = KeyFactory.getInstance("XMSSMT").generatePrivate(new PKCS8EncodedKeySpec(enc)); |
| |
| Signature verifier = Signature.getInstance(sigAlg, "BCPQC"); |
| verifier.initVerify(publicKey); |
| verifier.update(payload); |
| assertTrue(verifier.verify(signature)); |
| } |
| } |
| } |