diff --git a/core/src/main/java/org/bouncycastle/pqc/crypto/aimer/AIMerSigner.java b/core/src/main/java/org/bouncycastle/pqc/crypto/aimer/AIMerSigner.java index 0227815ee3..ac070f23ee 100644 --- a/core/src/main/java/org/bouncycastle/pqc/crypto/aimer/AIMerSigner.java +++ b/core/src/main/java/org/bouncycastle/pqc/crypto/aimer/AIMerSigner.java @@ -77,6 +77,17 @@ public byte[] generateSignature(byte[] message) @Override public boolean verifySignature(byte[] message, byte[] signature) { + // generateSignature returns the message followed by the signature (the + // signed-message envelope), so the signature proper starts at + // message.length. Reject anything but exactly that envelope before + // slicing it: a shorter buffer would throw + // ArrayIndexOutOfBoundsException, and a longer one would have its + // trailing bytes ignored, so a valid signature with data appended + // would still verify. + if (signature.length != message.length + params.getSignatureBytes()) + { + return false; + } byte[] sig = new byte[params.getSignatureBytes()]; AIMerEngine engine = new AIMerEngine(params); System.arraycopy(signature, message.length, sig, 0, params.getSignatureBytes()); diff --git a/core/src/test/java/org/bouncycastle/pqc/crypto/test/AIMerTest.java b/core/src/test/java/org/bouncycastle/pqc/crypto/test/AIMerTest.java index a0bcf2fa79..f284ee3a40 100644 --- a/core/src/test/java/org/bouncycastle/pqc/crypto/test/AIMerTest.java +++ b/core/src/test/java/org/bouncycastle/pqc/crypto/test/AIMerTest.java @@ -3,6 +3,7 @@ import java.security.SecureRandom; import junit.framework.TestCase; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; import org.bouncycastle.crypto.CipherParameters; import org.bouncycastle.crypto.Signer; @@ -14,6 +15,8 @@ import org.bouncycastle.pqc.crypto.aimer.AIMerPrivateKeyParameters; import org.bouncycastle.pqc.crypto.aimer.AIMerPublicKeyParameters; import org.bouncycastle.pqc.crypto.aimer.AIMerSigner; +import org.bouncycastle.util.Arrays; +import org.bouncycastle.util.Strings; public class AIMerTest extends TestCase @@ -23,6 +26,7 @@ public static void main(String[] args) { AIMerTest test = new AIMerTest(); test.testTestVectors(); + test.testWrongLengthSignatureRejected(); } private static final AIMerParameters[] PARAMETER_SETS = new AIMerParameters[] @@ -94,4 +98,38 @@ public MessageSigner getMessageSigner() long end = System.currentTimeMillis(); System.out.println("time cost: " + (end - start) + "\n"); } + + public void testWrongLengthSignatureRejected() + { + SecureRandom random = new SecureRandom(); + byte[] message = Strings.toByteArray("AIMer wrong length signature"); + + for (int i = 0; i != PARAMETER_SETS.length; i++) + { + AIMerParameters parameters = PARAMETER_SETS[i]; + + AIMerKeyPairGenerator kpGen = new AIMerKeyPairGenerator(); + kpGen.init(new AIMerKeyGenerationParameters(random, parameters)); + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + AIMerSigner signer = new AIMerSigner(); + signer.init(true, kp.getPrivate()); + byte[] signature = signer.generateSignature(message); + + AIMerSigner verifier = new AIMerSigner(); + verifier.init(false, kp.getPublic()); + + assertEquals(parameters.getName(), message.length + parameters.getSignatureBytes(), signature.length); + assertTrue(parameters.getName(), verifier.verifySignature(message, signature)); + + // a short buffer must be rejected rather than indexed past its end + assertFalse(parameters.getName(), verifier.verifySignature(message, new byte[0])); + assertFalse(parameters.getName(), verifier.verifySignature(message, Arrays.copyOf(signature, signature.length - 1))); + assertFalse(parameters.getName(), verifier.verifySignature(message, Arrays.copyOf(signature, message.length))); + + // trailing data must not be silently ignored + assertFalse(parameters.getName(), verifier.verifySignature(message, Arrays.append(signature, (byte)0))); + assertFalse(parameters.getName(), verifier.verifySignature(message, Arrays.concatenate(signature, new byte[16]))); + } + } } diff --git a/docs/releasenotes.html b/docs/releasenotes.html index 918bc90105..779013672a 100644 --- a/docs/releasenotes.html +++ b/docs/releasenotes.html @@ -135,6 +135,7 @@