1764 lines
79 KiB
Java
1764 lines
79 KiB
Java
/* RsaTest.java
|
|
*
|
|
* Copyright (C) 2006-2026 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
package com.wolfssl.wolfcrypt.test;
|
|
|
|
import static org.junit.Assert.*;
|
|
|
|
import java.nio.ByteBuffer;
|
|
|
|
import org.junit.Assume;
|
|
import org.junit.BeforeClass;
|
|
import org.junit.Test;
|
|
import org.junit.Rule;
|
|
import org.junit.rules.TestRule;
|
|
import org.junit.rules.TestWatcher;
|
|
import org.junit.runner.Description;
|
|
|
|
import java.util.Arrays;
|
|
import java.util.Iterator;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.CountDownLatch;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
import java.security.MessageDigest;
|
|
|
|
import com.wolfssl.wolfcrypt.Sha;
|
|
import com.wolfssl.wolfcrypt.Sha224;
|
|
import com.wolfssl.wolfcrypt.Sha256;
|
|
import com.wolfssl.wolfcrypt.Sha384;
|
|
import com.wolfssl.wolfcrypt.Sha512;
|
|
import com.wolfssl.wolfcrypt.Rsa;
|
|
import com.wolfssl.wolfcrypt.Rng;
|
|
import com.wolfssl.wolfcrypt.test.TimedTestWatcher;
|
|
import com.wolfssl.wolfcrypt.Fips;
|
|
import com.wolfssl.wolfcrypt.FeatureDetect;
|
|
import com.wolfssl.wolfcrypt.NativeStruct;
|
|
import com.wolfssl.wolfcrypt.WolfCrypt;
|
|
import com.wolfssl.wolfcrypt.WolfCryptError;
|
|
import com.wolfssl.wolfcrypt.WolfCryptException;
|
|
|
|
public class RsaTest {
|
|
private static Rng rng = new Rng();
|
|
|
|
@Rule(order = Integer.MIN_VALUE)
|
|
public TestRule testWatcher = TimedTestWatcher.create();
|
|
|
|
@BeforeClass
|
|
public static void setUpRng() {
|
|
rng.init();
|
|
}
|
|
|
|
@BeforeClass
|
|
public static void checkAvailability() {
|
|
try {
|
|
new Rsa();
|
|
System.out.println("JNI Rsa Class");
|
|
} catch (WolfCryptException e) {
|
|
if (e.getError() == WolfCryptError.NOT_COMPILED_IN)
|
|
System.out.println("Rsa test skipped: " + e.getError());
|
|
Assume.assumeNoException(e);
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void constructorShouldNotInitializeNativeStruct() {
|
|
assertEquals(NativeStruct.NULL, new Rsa().getNativeStruct());
|
|
}
|
|
|
|
@Test
|
|
@SuppressWarnings("deprecation")
|
|
public void deprecatedConstructorThrows() {
|
|
try {
|
|
new Rsa( new byte[] {0x00} );
|
|
fail("Failed to throw expected exception");
|
|
} catch (WolfCryptException e) {
|
|
/* expected */
|
|
}
|
|
|
|
try {
|
|
new Rsa( new byte[] {0x00}, new byte[] {0x00} );
|
|
fail("Failed to throw expected exception");
|
|
} catch (WolfCryptException e) {
|
|
/* expected */
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testGetMinRsaSize() {
|
|
|
|
int minRsaSize = Rsa.RSA_MIN_SIZE;
|
|
assertTrue(minRsaSize > 0);
|
|
}
|
|
|
|
/* RSA key generation can fail with PRIME_GEN_E. Prime generation uses a
|
|
* finite retry count (NIST FIPS 186-4 B.3.3 in FIPS mode) and the prime
|
|
* search occasionally misses. JCE-level classes retry internally, the
|
|
* JNI-level Rsa class does not. */
|
|
private static final int MAKE_KEY_MAX_ATTEMPTS = 3;
|
|
|
|
/**
|
|
* Helper to make an RSA key, retrying on transient PRIME_GEN_E up to
|
|
* {@link #MAKE_KEY_MAX_ATTEMPTS} times. Any other error, or a PRIME_GEN_E
|
|
* on the final attempt, is propagated. Each attempt uses a fresh key.
|
|
*
|
|
* @return new Rsa object holding the generated key, caller must
|
|
* release with releaseNativeStruct()
|
|
*/
|
|
private Rsa makeKeyWithRetry(int size, long e, Rng rng) {
|
|
|
|
for (int i = 0; i < MAKE_KEY_MAX_ATTEMPTS; i++) {
|
|
Rsa key = new Rsa();
|
|
try {
|
|
key.makeKey(size, e, rng);
|
|
return key;
|
|
} catch (WolfCryptException ex) {
|
|
key.releaseNativeStruct();
|
|
if (ex.getError() == WolfCryptError.PRIME_GEN_E &&
|
|
i < MAKE_KEY_MAX_ATTEMPTS - 1) {
|
|
/* transient prime-search miss, retry with a fresh key */
|
|
continue;
|
|
}
|
|
throw ex;
|
|
}
|
|
}
|
|
|
|
/* Not reachable, the loop always returns or throws */
|
|
throw new IllegalStateException("RSA makeKey retry loop exited");
|
|
}
|
|
|
|
@Test
|
|
public void testMakeKey() {
|
|
|
|
/* FIPS after 2425 doesn't allow 1024-bit RSA key gen */
|
|
if ((Fips.enabled && Fips.fipsVersion < 5) ||
|
|
(!Fips.enabled && Rsa.RSA_MIN_SIZE <= 1024)) {
|
|
makeKeyWithRetry(1024, 65537, rng).releaseNativeStruct();
|
|
}
|
|
|
|
makeKeyWithRetry(2048, 65537, rng).releaseNativeStruct();
|
|
makeKeyWithRetry(3072, 65537, rng).releaseNativeStruct();
|
|
makeKeyWithRetry(4096, 65537, rng).releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void testDerExportImportSignVerify() {
|
|
|
|
/* generate new 2048-bit key */
|
|
Rsa key = makeKeyWithRetry(2048, 65537, rng);
|
|
|
|
/* export key to DER */
|
|
byte[] rsaDer = key.exportPrivateDer();
|
|
assertNotNull(rsaDer);
|
|
assertTrue(rsaDer.length > 0);
|
|
key.releaseNativeStruct();
|
|
|
|
/* try to re-import DER into new Rsa object */
|
|
key = new Rsa();
|
|
key.decodePrivateKey(rsaDer);
|
|
|
|
/* sign data */
|
|
byte[] data = "Hello wolfSSL".getBytes();
|
|
byte[] signed = key.sign(data, rng);
|
|
|
|
/* verify data matches original */
|
|
byte[] verify = key.verify(signed);
|
|
assertNotNull(verify);
|
|
assertArrayEquals(data, verify);
|
|
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void rsaPrivateToPkcs8() {
|
|
Rsa key = new Rsa();
|
|
byte[] pkcs8;
|
|
byte[] prvKey = Util.h2b(
|
|
"308204a40201000282010100c303d12bfe39a432453b53c8842b2a7c"
|
|
+ "749abdaa2a520747d6a636b207328ed0ba697bc6c3449ed48148"
|
|
+ "fd2d68a28b67bba175c8362c4ad21bf78bbacf0df9efecf1811e"
|
|
+ "7b9b03479abf65cc7f652469a6e814895be434f7c5b01493f567"
|
|
+ "7b3a7a78e101565691a613428dd23c409c4cefd186df37511b0c"
|
|
+ "a13bf5f1a34a35e4e1ce96df1b7ebf4e97d010e8a8083081af20"
|
|
+ "0b4314c57467b432826f8d86c28840993683ba1e40722217d752"
|
|
+ "652473b0ceef19cdaeff786c7bc01203d44e720d506d3ba33ba3"
|
|
+ "995e9dc8d90c85b3d98ad95426db6dfaacbbff254cc4d179f471"
|
|
+ "d386401813b063b5724e30c49784862d562fd715f77fc0aef5fc"
|
|
+ "5be5fba1bad302030100010282010100a2e6d85f107164089e2e"
|
|
+ "6dd16d1e85d20ab18c47ce2c516aa0129e53de914c1d6dea597b"
|
|
+ "f277aad9c6d98aabd8e116e46326ffb56c1359b8e3a5c872172e"
|
|
+ "0c9f6fe5593f766f49b111c25a2e16290ddeb78edc40d5a2eee0"
|
|
+ "1ea1f4be97db86639614cd9809602d30769c3ccde688ee479279"
|
|
+ "0b5a00e25e5f117c7df908b72006892a5dfd00ab22e1f0b3bc24"
|
|
+ "a95e260e1f002dfe219a535b6dd32bab9482684336d8f62fc622"
|
|
+ "fcb5415d0d3360eaa47d7ee84b559156d35c578f1f94172faade"
|
|
+ "e99ea8f4cf8a4c8ea0e45673b2cf4f86c5693cf324208b5c960c"
|
|
+ "fa6b123b9a67c1dfc696b2a5d5920d9b094268241045d450e417"
|
|
+ "3948d0358b946d11de8fca5902818100ea24a7f96933e971dc52"
|
|
+ "7d8821282f49deba7216e9cc477a880d94578458163a81b03fa2"
|
|
+ "cfa66c1eb00629008fe77776acdbcac7d95e9b3f269052aefc38"
|
|
+ "900014bbb40f5894e72f6a7e1c4f4121d431591f4e8a1a8da757"
|
|
+ "6c22d8e5f47e32a610cb64a5550387a627058cc3d7b627b24dba"
|
|
+ "30da478f54d33d8b848d949858a502818100d5381bc38fc5930c"
|
|
+ "470b6f3592c5b08d46c892188ff5800af7efa1fe80b9b52abaca"
|
|
+ "18b05da507d0938dd89c041cd4628ea6268101ffce8a2a633435"
|
|
+ "40aa6d80de89236a574d9e6ead934e56900b6d9d738b0cae273d"
|
|
+ "de4ef0aac56c78676c94529c37676c2defbbafdfa6903cc447cf"
|
|
+ "8d969e98a9b49fc5a650dcb3f0fb74170281805e830962bdba7c"
|
|
+ "a2bf4274f57c1cd269c9040d857e3e3d2412c3187bf329f35f0e"
|
|
+ "766c5975e44184699d32f3cd22abb035ba4ab23ce5d958b6624f"
|
|
+ "5ddee59e0aca53b22cf79eb36b0a5b7965ec6e914e9220f6fcfc"
|
|
+ "16edd3760ce2ec7fb269136b780e5a4664b45eb725a05a753a4b"
|
|
+ "efc73c3ef7fd26b820c4990a9a73bec31902818100ba449314ac"
|
|
+ "34193b5f9160acf7b4d681053651533de865dcaf2edc613ec97d"
|
|
+ "b87f87f03b9b03822937ce724e11d5b1c10c07a099914a8d7fec"
|
|
+ "79cff139b5e985ec62f7da7dbc644d223c0ef2d651f587d899c0"
|
|
+ "11205d0f29fd5be2aed91cd921566dfc84d05fed10151c1821e7"
|
|
+ "c43d4bd7d09e6a95cf22c9037b9ee36001fc2f02818011d04bcf"
|
|
+ "1b67b99f1075478665ae31c2c630ac590650d90fb57006f7f0d3"
|
|
+ "c8627ca8da6ef6213fd37f5fea8aab3fd92a5ef351d2c23037e3"
|
|
+ "2da3750d1e4d2134d557705c89bf72ec4a6e68d5cd1874334e8c"
|
|
+ "3a458fe69640eb63f919863a51dd894bb0f3f99f5d289538be35"
|
|
+ "abca5ce7935334a1455d1339654246a19fcdf5bf");
|
|
|
|
byte[] expectedPkcs8 = Util.h2b(
|
|
"308204be020100300d06092a864886f70d0101010500048204a8"
|
|
+ "308204a40201000282010100c303d12bfe39a432453b53c8842b"
|
|
+ "2a7c749abdaa2a520747d6a636b207328ed0ba697bc6c3449ed4"
|
|
+ "8148fd2d68a28b67bba175c8362c4ad21bf78bbacf0df9efecf1"
|
|
+ "811e7b9b03479abf65cc7f652469a6e814895be434f7c5b01493"
|
|
+ "f5677b3a7a78e101565691a613428dd23c409c4cefd186df3751"
|
|
+ "1b0ca13bf5f1a34a35e4e1ce96df1b7ebf4e97d010e8a8083081"
|
|
+ "af200b4314c57467b432826f8d86c28840993683ba1e40722217"
|
|
+ "d752652473b0ceef19cdaeff786c7bc01203d44e720d506d3ba3"
|
|
+ "3ba3995e9dc8d90c85b3d98ad95426db6dfaacbbff254cc4d179"
|
|
+ "f471d386401813b063b5724e30c49784862d562fd715f77fc0ae"
|
|
+ "f5fc5be5fba1bad302030100010282010100a2e6d85f10716408"
|
|
+ "9e2e6dd16d1e85d20ab18c47ce2c516aa0129e53de914c1d6dea"
|
|
+ "597bf277aad9c6d98aabd8e116e46326ffb56c1359b8e3a5c872"
|
|
+ "172e0c9f6fe5593f766f49b111c25a2e16290ddeb78edc40d5a2"
|
|
+ "eee01ea1f4be97db86639614cd9809602d30769c3ccde688ee47"
|
|
+ "92790b5a00e25e5f117c7df908b72006892a5dfd00ab22e1f0b3"
|
|
+ "bc24a95e260e1f002dfe219a535b6dd32bab9482684336d8f62f"
|
|
+ "c622fcb5415d0d3360eaa47d7ee84b559156d35c578f1f94172f"
|
|
+ "aadee99ea8f4cf8a4c8ea0e45673b2cf4f86c5693cf324208b5c"
|
|
+ "960cfa6b123b9a67c1dfc696b2a5d5920d9b094268241045d450"
|
|
+ "e4173948d0358b946d11de8fca5902818100ea24a7f96933e971"
|
|
+ "dc527d8821282f49deba7216e9cc477a880d94578458163a81b0"
|
|
+ "3fa2cfa66c1eb00629008fe77776acdbcac7d95e9b3f269052ae"
|
|
+ "fc38900014bbb40f5894e72f6a7e1c4f4121d431591f4e8a1a8d"
|
|
+ "a7576c22d8e5f47e32a610cb64a5550387a627058cc3d7b627b2"
|
|
+ "4dba30da478f54d33d8b848d949858a502818100d5381bc38fc5"
|
|
+ "930c470b6f3592c5b08d46c892188ff5800af7efa1fe80b9b52a"
|
|
+ "baca18b05da507d0938dd89c041cd4628ea6268101ffce8a2a63"
|
|
+ "343540aa6d80de89236a574d9e6ead934e56900b6d9d738b0cae"
|
|
+ "273dde4ef0aac56c78676c94529c37676c2defbbafdfa6903cc4"
|
|
+ "47cf8d969e98a9b49fc5a650dcb3f0fb74170281805e830962bd"
|
|
+ "ba7ca2bf4274f57c1cd269c9040d857e3e3d2412c3187bf329f3"
|
|
+ "5f0e766c5975e44184699d32f3cd22abb035ba4ab23ce5d958b6"
|
|
+ "624f5ddee59e0aca53b22cf79eb36b0a5b7965ec6e914e9220f6"
|
|
+ "fcfc16edd3760ce2ec7fb269136b780e5a4664b45eb725a05a75"
|
|
+ "3a4befc73c3ef7fd26b820c4990a9a73bec31902818100ba4493"
|
|
+ "14ac34193b5f9160acf7b4d681053651533de865dcaf2edc613e"
|
|
+ "c97db87f87f03b9b03822937ce724e11d5b1c10c07a099914a8d"
|
|
+ "7fec79cff139b5e985ec62f7da7dbc644d223c0ef2d651f587d8"
|
|
+ "99c011205d0f29fd5be2aed91cd921566dfc84d05fed10151c18"
|
|
+ "21e7c43d4bd7d09e6a95cf22c9037b9ee36001fc2f02818011d0"
|
|
+ "4bcf1b67b99f1075478665ae31c2c630ac590650d90fb57006f7"
|
|
+ "f0d3c8627ca8da6ef6213fd37f5fea8aab3fd92a5ef351d2c230"
|
|
+ "37e32da3750d1e4d2134d557705c89bf72ec4a6e68d5cd187433"
|
|
+ "4e8c3a458fe69640eb63f919863a51dd894bb0f3f99f5d289538"
|
|
+ "be35abca5ce7935334a1455d1339654246a19fcdf5bf");
|
|
|
|
/* FIPS after 2425 doesn't allow 1024-bit RSA key gen */
|
|
if ((Fips.enabled && Fips.fipsVersion >= 5) ||
|
|
(Rsa.RSA_MIN_SIZE > 1024)) {
|
|
/* skip */
|
|
return;
|
|
}
|
|
|
|
/* Test that exception is thrown without private key available */
|
|
try {
|
|
pkcs8 = key.privateKeyEncodePKCS8();
|
|
fail("Rsa.privateKeyEncodePKCS8() should throw exception");
|
|
} catch (IllegalStateException e) {
|
|
/* expected */
|
|
}
|
|
|
|
/* Test that encoded PKCS#8 private key matches expected */
|
|
key.decodePrivateKey(prvKey);
|
|
pkcs8 = key.privateKeyEncodePKCS8();
|
|
assertArrayEquals(pkcs8, expectedPkcs8);
|
|
key.releaseNativeStruct();
|
|
|
|
/* Test that generated key encodes without error */
|
|
key = makeKeyWithRetry(1024, 65537, rng);
|
|
pkcs8 = key.privateKeyEncodePKCS8();
|
|
assertTrue(pkcs8 != null);
|
|
assertTrue(pkcs8.length != 0);
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void rsaPkcs8DecodeAndVerify() {
|
|
Rsa key = new Rsa();
|
|
|
|
byte[] prvKey = Util.h2b(
|
|
"308204a40201000282010100c303d12bfe39a432"
|
|
+ "453b53c8842b2a7c749abdaa2a520747d6a636b2"
|
|
+ "07328ed0ba697bc6c3449ed48148fd2d68a28b67"
|
|
+ "bba175c8362c4ad21bf78bbacf0df9efecf1811e"
|
|
+ "7b9b03479abf65cc7f652469a6e814895be434f7"
|
|
+ "c5b01493f5677b3a7a78e101565691a613428dd2"
|
|
+ "3c409c4cefd186df37511b0ca13bf5f1a34a35e4"
|
|
+ "e1ce96df1b7ebf4e97d010e8a8083081af200b43"
|
|
+ "14c57467b432826f8d86c28840993683ba1e4072"
|
|
+ "2217d752652473b0ceef19cdaeff786c7bc01203"
|
|
+ "d44e720d506d3ba33ba3995e9dc8d90c85b3d98a"
|
|
+ "d95426db6dfaacbbff254cc4d179f471d3864018"
|
|
+ "13b063b5724e30c49784862d562fd715f77fc0ae"
|
|
+ "f5fc5be5fba1bad302030100010282010100a2e6"
|
|
+ "d85f107164089e2e6dd16d1e85d20ab18c47ce2c"
|
|
+ "516aa0129e53de914c1d6dea597bf277aad9c6d9"
|
|
+ "8aabd8e116e46326ffb56c1359b8e3a5c872172e"
|
|
+ "0c9f6fe5593f766f49b111c25a2e16290ddeb78e"
|
|
+ "dc40d5a2eee01ea1f4be97db86639614cd980960"
|
|
+ "2d30769c3ccde688ee4792790b5a00e25e5f117c"
|
|
+ "7df908b72006892a5dfd00ab22e1f0b3bc24a95e"
|
|
+ "260e1f002dfe219a535b6dd32bab9482684336d8"
|
|
+ "f62fc622fcb5415d0d3360eaa47d7ee84b559156"
|
|
+ "d35c578f1f94172faadee99ea8f4cf8a4c8ea0e4"
|
|
+ "5673b2cf4f86c5693cf324208b5c960cfa6b123b"
|
|
+ "9a67c1dfc696b2a5d5920d9b094268241045d450"
|
|
+ "e4173948d0358b946d11de8fca5902818100ea24"
|
|
+ "a7f96933e971dc527d8821282f49deba7216e9cc"
|
|
+ "477a880d94578458163a81b03fa2cfa66c1eb006"
|
|
+ "29008fe77776acdbcac7d95e9b3f269052aefc38"
|
|
+ "900014bbb40f5894e72f6a7e1c4f4121d431591f"
|
|
+ "4e8a1a8da7576c22d8e5f47e32a610cb64a55503"
|
|
+ "87a627058cc3d7b627b24dba30da478f54d33d8b"
|
|
+ "848d949858a502818100d5381bc38fc5930c470b"
|
|
+ "6f3592c5b08d46c892188ff5800af7efa1fe80b9"
|
|
+ "b52abaca18b05da507d0938dd89c041cd4628ea6"
|
|
+ "268101ffce8a2a63343540aa6d80de89236a574d"
|
|
+ "9e6ead934e56900b6d9d738b0cae273dde4ef0aa"
|
|
+ "c56c78676c94529c37676c2defbbafdfa6903cc4"
|
|
+ "47cf8d969e98a9b49fc5a650dcb3f0fb74170281"
|
|
+ "805e830962bdba7ca2bf4274f57c1cd269c9040d"
|
|
+ "857e3e3d2412c3187bf329f35f0e766c5975e441"
|
|
+ "84699d32f3cd22abb035ba4ab23ce5d958b6624f"
|
|
+ "5ddee59e0aca53b22cf79eb36b0a5b7965ec6e91"
|
|
+ "4e9220f6fcfc16edd3760ce2ec7fb269136b780e"
|
|
+ "5a4664b45eb725a05a753a4befc73c3ef7fd26b8"
|
|
+ "20c4990a9a73bec31902818100ba449314ac3419"
|
|
+ "3b5f9160acf7b4d681053651533de865dcaf2edc"
|
|
+ "613ec97db87f87f03b9b03822937ce724e11d5b1"
|
|
+ "c10c07a099914a8d7fec79cff139b5e985ec62f7"
|
|
+ "da7dbc644d223c0ef2d651f587d899c011205d0f"
|
|
+ "29fd5be2aed91cd921566dfc84d05fed10151c18"
|
|
+ "21e7c43d4bd7d09e6a95cf22c9037b9ee36001fc"
|
|
+ "2f02818011d04bcf1b67b99f1075478665ae31c2"
|
|
+ "c630ac590650d90fb57006f7f0d3c8627ca8da6e"
|
|
+ "f6213fd37f5fea8aab3fd92a5ef351d2c23037e3"
|
|
+ "2da3750d1e4d2134d557705c89bf72ec4a6e68d5"
|
|
+ "cd1874334e8c3a458fe69640eb63f919863a51dd"
|
|
+ "894bb0f3f99f5d289538be35abca5ce7935334a1"
|
|
+ "455d1339654246a19fcdf5bf");
|
|
|
|
/* FIPS after 2425 doesn't allow 1024-bit RSA */
|
|
if ((Fips.enabled && Fips.fipsVersion >= 5) ||
|
|
(Rsa.RSA_MIN_SIZE > 1024)) {
|
|
key.releaseNativeStruct();
|
|
return;
|
|
}
|
|
|
|
/* Encode DER private key to PKCS8 */
|
|
key.decodePrivateKey(prvKey);
|
|
byte[] pkcs8 = key.privateKeyEncodePKCS8();
|
|
assertNotNull(pkcs8);
|
|
assertTrue(pkcs8.length > 0);
|
|
key.releaseNativeStruct();
|
|
|
|
/* Decode PKCS8 back into a new key */
|
|
Rsa pkcs8Key = new Rsa();
|
|
pkcs8Key.decodePrivateKeyPKCS8(pkcs8);
|
|
pkcs8Key.setRng(rng);
|
|
|
|
/* Extract public key for verification */
|
|
byte[] n_out = new byte[256];
|
|
byte[] e_out = new byte[3];
|
|
long[] n_len = { n_out.length };
|
|
long[] e_len = { e_out.length };
|
|
pkcs8Key.exportRawPublicKey(n_out, n_len, e_out, e_len);
|
|
|
|
Rsa pub = new Rsa();
|
|
pub.decodeRawPublicKey(Arrays.copyOf(n_out, (int)n_len[0]),
|
|
Arrays.copyOf(e_out, (int)e_len[0]));
|
|
|
|
/* Sign with PKCS8-decoded key, verify with public */
|
|
byte[] plaintext = "Hello PKCS8".getBytes();
|
|
byte[] signature = pkcs8Key.sign(plaintext, rng);
|
|
assertArrayEquals(plaintext, pub.verify(signature));
|
|
|
|
pkcs8Key.releaseNativeStruct();
|
|
pub.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void publicKeyDecodeAndEncodeWithByteBuffer() {
|
|
Rsa key = new Rsa();
|
|
|
|
ByteBuffer n_in = ByteBuffer.allocateDirect(256);
|
|
ByteBuffer e_in = ByteBuffer.allocateDirect(256);
|
|
ByteBuffer n_out = ByteBuffer.allocateDirect(256);
|
|
ByteBuffer e_out = ByteBuffer.allocateDirect(256);
|
|
|
|
n_in.put(Util
|
|
.h2b("aff5f9e2e2622320d44dbf54f2274a0f96fa7d70a63ddaa563f48811"
|
|
+ "43112bb3c36fe65ba0c9ad99d6fb6e53cb08e3938ee415b3a8cb"
|
|
+ "7f9602f2154fab83dd160fa6f509ba2c41295af9eea8787d333e"
|
|
+ "961461447fc60b3c61616ef5b94e822114e6fad44d1f2c476bc2"
|
|
+ "3bc03609e2e70a483d826409fdb7c50a91269a773976ef137e7f"
|
|
+ "a477c3951e8fbcb48f2378aa5e430e8c60b481beeb63df9abe10"
|
|
+ "c7ccf266e394fbd925e8725e4675fb6ad895caed4b31d751c871"
|
|
+ "2533e1c42ebefe9166e1aa20631521858c7548c61626ede105f2"
|
|
+ "812632bac96eb769c9be560beef4200b86409727a5a61d1cc583"
|
|
+ "1785ba4d42f02dd298a56bbbd6c479ce724d5bb5"))
|
|
.rewind();
|
|
e_in.put(Util.h2b("d0ee61")).rewind();
|
|
|
|
key.decodeRawPublicKey(n_in, e_in);
|
|
key.exportRawPublicKey(n_out, e_out);
|
|
|
|
assertEquals(n_in, n_out);
|
|
assertEquals(e_in, e_out);
|
|
}
|
|
|
|
@Test
|
|
public void publicKeyDecodeAndEncodeWithByteArray() {
|
|
Rsa key = new Rsa();
|
|
|
|
byte[] n_in = Util
|
|
.h2b("aff5f9e2e2622320d44dbf54f2274a0f96fa7d70a63ddaa563f48811"
|
|
+ "43112bb3c36fe65ba0c9ad99d6fb6e53cb08e3938ee415b3a8cb"
|
|
+ "7f9602f2154fab83dd160fa6f509ba2c41295af9eea8787d333e"
|
|
+ "961461447fc60b3c61616ef5b94e822114e6fad44d1f2c476bc2"
|
|
+ "3bc03609e2e70a483d826409fdb7c50a91269a773976ef137e7f"
|
|
+ "a477c3951e8fbcb48f2378aa5e430e8c60b481beeb63df9abe10"
|
|
+ "c7ccf266e394fbd925e8725e4675fb6ad895caed4b31d751c871"
|
|
+ "2533e1c42ebefe9166e1aa20631521858c7548c61626ede105f2"
|
|
+ "812632bac96eb769c9be560beef4200b86409727a5a61d1cc583"
|
|
+ "1785ba4d42f02dd298a56bbbd6c479ce724d5bb5");
|
|
byte[] e_in = Util.h2b("d0ee61");
|
|
byte[] n_out = new byte[n_in.length];
|
|
byte[] e_out = new byte[e_in.length];
|
|
long[] n_len = new long[1];
|
|
long[] e_len = new long[1];
|
|
|
|
n_len[0] = n_out.length;
|
|
e_len[0] = e_out.length;
|
|
|
|
key.decodeRawPublicKey(n_in, e_in);
|
|
key.exportRawPublicKey(n_out, n_len, e_out, e_len);
|
|
|
|
assertArrayEquals(n_in, n_out);
|
|
assertArrayEquals(e_in, e_out);
|
|
}
|
|
|
|
@Test
|
|
public void publicKeyDecodeRawOversizedSizesRejected() {
|
|
Rsa key = new Rsa();
|
|
|
|
byte[] n_in = new byte[8];
|
|
byte[] e_in = new byte[3];
|
|
|
|
/* nSize larger than n array length should throw exception */
|
|
try {
|
|
key.decodeRawPublicKey(n_in, n_in.length + 1, e_in, e_in.length);
|
|
fail("decodeRawPublicKey() with nSize > n.length should " +
|
|
"throw exception");
|
|
} catch (WolfCryptException e) {
|
|
/* expected */
|
|
}
|
|
|
|
/* eSize larger than e array length should throw exception */
|
|
try {
|
|
key.decodeRawPublicKey(n_in, n_in.length, e_in, e_in.length + 1);
|
|
fail("decodeRawPublicKey() with eSize > e.length should " +
|
|
"throw exception");
|
|
} catch (WolfCryptException e) {
|
|
/* expected */
|
|
}
|
|
|
|
ByteBuffer n_buf = ByteBuffer.allocateDirect(8);
|
|
ByteBuffer e_buf = ByteBuffer.allocateDirect(3);
|
|
|
|
/* nSize larger than n buffer limit should throw exception */
|
|
try {
|
|
key.decodeRawPublicKey(n_buf, n_buf.limit() + 1, e_buf,
|
|
e_buf.limit());
|
|
fail("decodeRawPublicKey() with nSize > n.limit() should " +
|
|
"throw exception");
|
|
} catch (WolfCryptException e) {
|
|
/* expected */
|
|
}
|
|
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void exportRawPublicKeyOversizedSizesRejected() {
|
|
Rsa key = new Rsa();
|
|
|
|
byte[] n_in = Util
|
|
.h2b("aff5f9e2e2622320d44dbf54f2274a0f96fa7d70a63ddaa563f48811"
|
|
+ "43112bb3c36fe65ba0c9ad99d6fb6e53cb08e3938ee415b3a8cb"
|
|
+ "7f9602f2154fab83dd160fa6f509ba2c41295af9eea8787d333e"
|
|
+ "961461447fc60b3c61616ef5b94e822114e6fad44d1f2c476bc2"
|
|
+ "3bc03609e2e70a483d826409fdb7c50a91269a773976ef137e7f"
|
|
+ "a477c3951e8fbcb48f2378aa5e430e8c60b481beeb63df9abe10"
|
|
+ "c7ccf266e394fbd925e8725e4675fb6ad895caed4b31d751c871"
|
|
+ "2533e1c42ebefe9166e1aa20631521858c7548c61626ede105f2"
|
|
+ "812632bac96eb769c9be560beef4200b86409727a5a61d1cc583"
|
|
+ "1785ba4d42f02dd298a56bbbd6c479ce724d5bb5");
|
|
byte[] e_in = Util.h2b("d0ee61");
|
|
|
|
key.decodeRawPublicKey(n_in, e_in);
|
|
|
|
/* Output arrays too small for key, with in/out sizes that lie
|
|
* about capacity. Native must not write past the Java arrays */
|
|
byte[] n_out = new byte[4];
|
|
byte[] e_out = new byte[4];
|
|
long[] n_len = new long[1];
|
|
long[] e_len = new long[1];
|
|
n_len[0] = 512;
|
|
e_len[0] = e_out.length;
|
|
|
|
try {
|
|
key.exportRawPublicKey(n_out, n_len, e_out, e_len);
|
|
fail("exportRawPublicKey() with nSz > n.length should " +
|
|
"throw exception");
|
|
} catch (WolfCryptException e) {
|
|
/* expected */
|
|
}
|
|
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void exportRawPublicKeySizesCorrect() {
|
|
Rsa key = new Rsa();
|
|
|
|
byte[] n_in = Util
|
|
.h2b("aff5f9e2e2622320d44dbf54f2274a0f"
|
|
+ "96fa7d70a63ddaa563f4881143112bb3"
|
|
+ "c36fe65ba0c9ad99d6fb6e53cb08e393"
|
|
+ "8ee415b3a8cb7f9602f2154fab83dd16"
|
|
+ "0fa6f509ba2c41295af9eea8787d333e"
|
|
+ "961461447fc60b3c61616ef5b94e8221"
|
|
+ "14e6fad44d1f2c476bc23bc03609e2e7"
|
|
+ "0a483d826409fdb7c50a91269a773976"
|
|
+ "ef137e7fa477c3951e8fbcb48f2378aa"
|
|
+ "5e430e8c60b481beeb63df9abe10c7cc"
|
|
+ "f266e394fbd925e8725e4675fb6ad895"
|
|
+ "caed4b31d751c8712533e1c42ebefe91"
|
|
+ "66e1aa20631521858c7548c61626ede1"
|
|
+ "05f2812632bac96eb769c9be560beef4"
|
|
+ "200b86409727a5a61d1cc5831785ba4d"
|
|
+ "42f02dd298a56bbbd6c479ce724d5bb5");
|
|
byte[] e_in = Util.h2b("d0ee61");
|
|
|
|
/*
|
|
* Use oversized output buffers and initial sizes to verify returned
|
|
* sizes are correct after call.
|
|
*/
|
|
byte[] n_out = new byte[512];
|
|
byte[] e_out = new byte[512];
|
|
long[] n_len = new long[1];
|
|
long[] e_len = new long[1];
|
|
n_len[0] = n_out.length;
|
|
e_len[0] = e_out.length;
|
|
|
|
key.decodeRawPublicKey(n_in, e_in);
|
|
key.exportRawPublicKey(n_out, n_len, e_out, e_len);
|
|
|
|
assertEquals(n_in.length, n_len[0]);
|
|
assertEquals(e_in.length, e_len[0]);
|
|
|
|
assertArrayEquals(n_in, Arrays.copyOf(n_out, (int)n_len[0]));
|
|
assertArrayEquals(e_in, Arrays.copyOf(e_out, (int)e_len[0]));
|
|
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void exportRawPrivateKeySizesCorrect() {
|
|
Rsa key = new Rsa();
|
|
|
|
key.decodePrivateKey(Util.h2b(
|
|
"308204a40201000282010100c303d12bfe39a432"
|
|
+ "453b53c8842b2a7c749abdaa2a520747d6a636b2"
|
|
+ "07328ed0ba697bc6c3449ed48148fd2d68a28b67"
|
|
+ "bba175c8362c4ad21bf78bbacf0df9efecf1811e"
|
|
+ "7b9b03479abf65cc7f652469a6e814895be434f7"
|
|
+ "c5b01493f5677b3a7a78e101565691a613428dd2"
|
|
+ "3c409c4cefd186df37511b0ca13bf5f1a34a35e4"
|
|
+ "e1ce96df1b7ebf4e97d010e8a8083081af200b43"
|
|
+ "14c57467b432826f8d86c28840993683ba1e4072"
|
|
+ "2217d752652473b0ceef19cdaeff786c7bc01203"
|
|
+ "d44e720d506d3ba33ba3995e9dc8d90c85b3d98a"
|
|
+ "d95426db6dfaacbbff254cc4d179f471d3864018"
|
|
+ "13b063b5724e30c49784862d562fd715f77fc0ae"
|
|
+ "f5fc5be5fba1bad302030100010282010100a2e6"
|
|
+ "d85f107164089e2e6dd16d1e85d20ab18c47ce2c"
|
|
+ "516aa0129e53de914c1d6dea597bf277aad9c6d9"
|
|
+ "8aabd8e116e46326ffb56c1359b8e3a5c872172e"
|
|
+ "0c9f6fe5593f766f49b111c25a2e16290ddeb78e"
|
|
+ "dc40d5a2eee01ea1f4be97db86639614cd980960"
|
|
+ "2d30769c3ccde688ee4792790b5a00e25e5f117c"
|
|
+ "7df908b72006892a5dfd00ab22e1f0b3bc24a95e"
|
|
+ "260e1f002dfe219a535b6dd32bab9482684336d8"
|
|
+ "f62fc622fcb5415d0d3360eaa47d7ee84b559156"
|
|
+ "d35c578f1f94172faadee99ea8f4cf8a4c8ea0e4"
|
|
+ "5673b2cf4f86c5693cf324208b5c960cfa6b123b"
|
|
+ "9a67c1dfc696b2a5d5920d9b094268241045d450"
|
|
+ "e4173948d0358b946d11de8fca5902818100ea24"
|
|
+ "a7f96933e971dc527d8821282f49deba7216e9cc"
|
|
+ "477a880d94578458163a81b03fa2cfa66c1eb006"
|
|
+ "29008fe77776acdbcac7d95e9b3f269052aefc38"
|
|
+ "900014bbb40f5894e72f6a7e1c4f4121d431591f"
|
|
+ "4e8a1a8da7576c22d8e5f47e32a610cb64a55503"
|
|
+ "87a627058cc3d7b627b24dba30da478f54d33d8b"
|
|
+ "848d949858a502818100d5381bc38fc5930c470b"
|
|
+ "6f3592c5b08d46c892188ff5800af7efa1fe80b9"
|
|
+ "b52abaca18b05da507d0938dd89c041cd4628ea6"
|
|
+ "268101ffce8a2a63343540aa6d80de89236a574d"
|
|
+ "9e6ead934e56900b6d9d738b0cae273dde4ef0aa"
|
|
+ "c56c78676c94529c37676c2defbbafdfa6903cc4"
|
|
+ "47cf8d969e98a9b49fc5a650dcb3f0fb74170281"
|
|
+ "805e830962bdba7ca2bf4274f57c1cd269c9040d"
|
|
+ "857e3e3d2412c3187bf329f35f0e766c5975e441"
|
|
+ "84699d32f3cd22abb035ba4ab23ce5d958b6624f"
|
|
+ "5ddee59e0aca53b22cf79eb36b0a5b7965ec6e91"
|
|
+ "4e9220f6fcfc16edd3760ce2ec7fb269136b780e"
|
|
+ "5a4664b45eb725a05a753a4befc73c3ef7fd26b8"
|
|
+ "20c4990a9a73bec31902818100ba449314ac3419"
|
|
+ "3b5f9160acf7b4d681053651533de865dcaf2edc"
|
|
+ "613ec97db87f87f03b9b03822937ce724e11d5b1"
|
|
+ "c10c07a099914a8d7fec79cff139b5e985ec62f7"
|
|
+ "da7dbc644d223c0ef2d651f587d899c011205d0f"
|
|
+ "29fd5be2aed91cd921566dfc84d05fed10151c18"
|
|
+ "21e7c43d4bd7d09e6a95cf22c9037b9ee36001fc"
|
|
+ "2f02818011d04bcf1b67b99f1075478665ae31c2"
|
|
+ "c630ac590650d90fb57006f7f0d3c8627ca8da6e"
|
|
+ "f6213fd37f5fea8aab3fd92a5ef351d2c23037e3"
|
|
+ "2da3750d1e4d2134d557705c89bf72ec4a6e68d5"
|
|
+ "cd1874334e8c3a458fe69640eb63f919863a51dd"
|
|
+ "894bb0f3f99f5d289538be35abca5ce7935334a1"
|
|
+ "455d1339654246a19fcdf5bf"));
|
|
|
|
/*
|
|
* Use oversized output buffers to verify returned sizes are correct
|
|
* after export.
|
|
*/
|
|
int bufSz = 512;
|
|
byte[] n = new byte[bufSz];
|
|
byte[] e = new byte[bufSz];
|
|
byte[] d = new byte[bufSz];
|
|
byte[] p = new byte[bufSz];
|
|
byte[] q = new byte[bufSz];
|
|
byte[] dP = new byte[bufSz];
|
|
byte[] dQ = new byte[bufSz];
|
|
byte[] u = new byte[bufSz];
|
|
long[] nSz = { bufSz };
|
|
long[] eSz = { bufSz };
|
|
long[] dSz = { bufSz };
|
|
long[] pSz = { bufSz };
|
|
long[] qSz = { bufSz };
|
|
long[] dPSz = { bufSz };
|
|
long[] dQSz = { bufSz };
|
|
long[] uSz = { bufSz };
|
|
|
|
try {
|
|
key.exportRawPrivateKey(n, nSz, e, eSz, d, dSz, p, pSz, q, qSz, dP,
|
|
dPSz, dQ, dQSz, u, uSz);
|
|
} catch (WolfCryptException ex) {
|
|
if (ex.getError() == WolfCryptError.NOT_COMPILED_IN) {
|
|
System.out.println("exportRawPrivateKey skipped: " +
|
|
ex.getError());
|
|
key.releaseNativeStruct();
|
|
Assume.assumeNoException(ex);
|
|
}
|
|
throw ex;
|
|
}
|
|
|
|
/* Returned sizes must be positive and fit in 32 bits */
|
|
assertTrue(nSz[0] > 0 && nSz[0] <= bufSz);
|
|
assertTrue(eSz[0] > 0 && eSz[0] <= bufSz);
|
|
assertTrue(dSz[0] > 0 && dSz[0] <= bufSz);
|
|
assertTrue(pSz[0] > 0 && pSz[0] <= bufSz);
|
|
assertTrue(qSz[0] > 0 && qSz[0] <= bufSz);
|
|
assertTrue(dPSz[0] > 0 && dPSz[0] <= bufSz);
|
|
assertTrue(dQSz[0] > 0 && dQSz[0] <= bufSz);
|
|
assertTrue(uSz[0] > 0 && uSz[0] <= bufSz);
|
|
|
|
/* RSA-2048: n,d = 256 bytes, e = 3 bytes,
|
|
* p,q,dP,dQ,u = ~128 bytes */
|
|
assertEquals(256, nSz[0]);
|
|
assertEquals(3, eSz[0]);
|
|
assertEquals(256, dSz[0]);
|
|
assertTrue(pSz[0] >= 127 && pSz[0] <= 129);
|
|
assertTrue(qSz[0] >= 127 && qSz[0] <= 129);
|
|
assertTrue(dPSz[0] >= 127 && dPSz[0] <= 129);
|
|
assertTrue(dQSz[0] >= 127 && dQSz[0] <= 129);
|
|
assertTrue(uSz[0] >= 127 && uSz[0] <= 129);
|
|
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void rsaOperations() {
|
|
Rsa priv = new Rsa();
|
|
byte[] n_out = new byte[256];
|
|
byte[] e_out = new byte[3];
|
|
long[] n_len = new long[1];
|
|
long[] e_len = new long[1];
|
|
n_len[0] = n_out.length;
|
|
e_len[0] = e_out.length;
|
|
|
|
priv.decodePrivateKey(Util
|
|
.h2b("308204a40201000282010100c303d12bfe39a432453b53c8842b2a7c"
|
|
+ "749abdaa2a520747d6a636b207328ed0ba697bc6c3449ed48148"
|
|
+ "fd2d68a28b67bba175c8362c4ad21bf78bbacf0df9efecf1811e"
|
|
+ "7b9b03479abf65cc7f652469a6e814895be434f7c5b01493f567"
|
|
+ "7b3a7a78e101565691a613428dd23c409c4cefd186df37511b0c"
|
|
+ "a13bf5f1a34a35e4e1ce96df1b7ebf4e97d010e8a8083081af20"
|
|
+ "0b4314c57467b432826f8d86c28840993683ba1e40722217d752"
|
|
+ "652473b0ceef19cdaeff786c7bc01203d44e720d506d3ba33ba3"
|
|
+ "995e9dc8d90c85b3d98ad95426db6dfaacbbff254cc4d179f471"
|
|
+ "d386401813b063b5724e30c49784862d562fd715f77fc0aef5fc"
|
|
+ "5be5fba1bad302030100010282010100a2e6d85f107164089e2e"
|
|
+ "6dd16d1e85d20ab18c47ce2c516aa0129e53de914c1d6dea597b"
|
|
+ "f277aad9c6d98aabd8e116e46326ffb56c1359b8e3a5c872172e"
|
|
+ "0c9f6fe5593f766f49b111c25a2e16290ddeb78edc40d5a2eee0"
|
|
+ "1ea1f4be97db86639614cd9809602d30769c3ccde688ee479279"
|
|
+ "0b5a00e25e5f117c7df908b72006892a5dfd00ab22e1f0b3bc24"
|
|
+ "a95e260e1f002dfe219a535b6dd32bab9482684336d8f62fc622"
|
|
+ "fcb5415d0d3360eaa47d7ee84b559156d35c578f1f94172faade"
|
|
+ "e99ea8f4cf8a4c8ea0e45673b2cf4f86c5693cf324208b5c960c"
|
|
+ "fa6b123b9a67c1dfc696b2a5d5920d9b094268241045d450e417"
|
|
+ "3948d0358b946d11de8fca5902818100ea24a7f96933e971dc52"
|
|
+ "7d8821282f49deba7216e9cc477a880d94578458163a81b03fa2"
|
|
+ "cfa66c1eb00629008fe77776acdbcac7d95e9b3f269052aefc38"
|
|
+ "900014bbb40f5894e72f6a7e1c4f4121d431591f4e8a1a8da757"
|
|
+ "6c22d8e5f47e32a610cb64a5550387a627058cc3d7b627b24dba"
|
|
+ "30da478f54d33d8b848d949858a502818100d5381bc38fc5930c"
|
|
+ "470b6f3592c5b08d46c892188ff5800af7efa1fe80b9b52abaca"
|
|
+ "18b05da507d0938dd89c041cd4628ea6268101ffce8a2a633435"
|
|
+ "40aa6d80de89236a574d9e6ead934e56900b6d9d738b0cae273d"
|
|
+ "de4ef0aac56c78676c94529c37676c2defbbafdfa6903cc447cf"
|
|
+ "8d969e98a9b49fc5a650dcb3f0fb74170281805e830962bdba7c"
|
|
+ "a2bf4274f57c1cd269c9040d857e3e3d2412c3187bf329f35f0e"
|
|
+ "766c5975e44184699d32f3cd22abb035ba4ab23ce5d958b6624f"
|
|
+ "5ddee59e0aca53b22cf79eb36b0a5b7965ec6e914e9220f6fcfc"
|
|
+ "16edd3760ce2ec7fb269136b780e5a4664b45eb725a05a753a4b"
|
|
+ "efc73c3ef7fd26b820c4990a9a73bec31902818100ba449314ac"
|
|
+ "34193b5f9160acf7b4d681053651533de865dcaf2edc613ec97d"
|
|
+ "b87f87f03b9b03822937ce724e11d5b1c10c07a099914a8d7fec"
|
|
+ "79cff139b5e985ec62f7da7dbc644d223c0ef2d651f587d899c0"
|
|
+ "11205d0f29fd5be2aed91cd921566dfc84d05fed10151c1821e7"
|
|
+ "c43d4bd7d09e6a95cf22c9037b9ee36001fc2f02818011d04bcf"
|
|
+ "1b67b99f1075478665ae31c2c630ac590650d90fb57006f7f0d3"
|
|
+ "c8627ca8da6ef6213fd37f5fea8aab3fd92a5ef351d2c23037e3"
|
|
+ "2da3750d1e4d2134d557705c89bf72ec4a6e68d5cd1874334e8c"
|
|
+ "3a458fe69640eb63f919863a51dd894bb0f3f99f5d289538be35"
|
|
+ "abca5ce7935334a1455d1339654246a19fcdf5bf"));
|
|
|
|
priv.exportRawPublicKey(n_out, n_len, e_out, e_len);
|
|
priv.setRng(rng);
|
|
|
|
Rsa pub = new Rsa();
|
|
pub.decodeRawPublicKey(n_out, e_out);
|
|
|
|
byte[] plaintext = "Now is the time for all".getBytes();
|
|
|
|
byte[] ciphertext = pub.encrypt(plaintext, rng);
|
|
|
|
assertArrayEquals(plaintext, priv.decrypt(ciphertext));
|
|
|
|
byte[] signature = priv.sign(plaintext, rng);
|
|
|
|
assertArrayEquals(plaintext, pub.verify(signature));
|
|
}
|
|
|
|
@Test
|
|
public void threadedRsaSignVerifyTest() throws InterruptedException {
|
|
|
|
int numThreads = 20;
|
|
ExecutorService service = Executors.newFixedThreadPool(numThreads);
|
|
final CountDownLatch latch = new CountDownLatch(numThreads);
|
|
final LinkedBlockingQueue<Integer> results =
|
|
new LinkedBlockingQueue<>();
|
|
|
|
final byte[] prvKey = Util
|
|
.h2b("308204a40201000282010100c303d12bfe39a432453b53c8842b2a7c"
|
|
+ "749abdaa2a520747d6a636b207328ed0ba697bc6c3449ed48148"
|
|
+ "fd2d68a28b67bba175c8362c4ad21bf78bbacf0df9efecf1811e"
|
|
+ "7b9b03479abf65cc7f652469a6e814895be434f7c5b01493f567"
|
|
+ "7b3a7a78e101565691a613428dd23c409c4cefd186df37511b0c"
|
|
+ "a13bf5f1a34a35e4e1ce96df1b7ebf4e97d010e8a8083081af20"
|
|
+ "0b4314c57467b432826f8d86c28840993683ba1e40722217d752"
|
|
+ "652473b0ceef19cdaeff786c7bc01203d44e720d506d3ba33ba3"
|
|
+ "995e9dc8d90c85b3d98ad95426db6dfaacbbff254cc4d179f471"
|
|
+ "d386401813b063b5724e30c49784862d562fd715f77fc0aef5fc"
|
|
+ "5be5fba1bad302030100010282010100a2e6d85f107164089e2e"
|
|
+ "6dd16d1e85d20ab18c47ce2c516aa0129e53de914c1d6dea597b"
|
|
+ "f277aad9c6d98aabd8e116e46326ffb56c1359b8e3a5c872172e"
|
|
+ "0c9f6fe5593f766f49b111c25a2e16290ddeb78edc40d5a2eee0"
|
|
+ "1ea1f4be97db86639614cd9809602d30769c3ccde688ee479279"
|
|
+ "0b5a00e25e5f117c7df908b72006892a5dfd00ab22e1f0b3bc24"
|
|
+ "a95e260e1f002dfe219a535b6dd32bab9482684336d8f62fc622"
|
|
+ "fcb5415d0d3360eaa47d7ee84b559156d35c578f1f94172faade"
|
|
+ "e99ea8f4cf8a4c8ea0e45673b2cf4f86c5693cf324208b5c960c"
|
|
+ "fa6b123b9a67c1dfc696b2a5d5920d9b094268241045d450e417"
|
|
+ "3948d0358b946d11de8fca5902818100ea24a7f96933e971dc52"
|
|
+ "7d8821282f49deba7216e9cc477a880d94578458163a81b03fa2"
|
|
+ "cfa66c1eb00629008fe77776acdbcac7d95e9b3f269052aefc38"
|
|
+ "900014bbb40f5894e72f6a7e1c4f4121d431591f4e8a1a8da757"
|
|
+ "6c22d8e5f47e32a610cb64a5550387a627058cc3d7b627b24dba"
|
|
+ "30da478f54d33d8b848d949858a502818100d5381bc38fc5930c"
|
|
+ "470b6f3592c5b08d46c892188ff5800af7efa1fe80b9b52abaca"
|
|
+ "18b05da507d0938dd89c041cd4628ea6268101ffce8a2a633435"
|
|
+ "40aa6d80de89236a574d9e6ead934e56900b6d9d738b0cae273d"
|
|
+ "de4ef0aac56c78676c94529c37676c2defbbafdfa6903cc447cf"
|
|
+ "8d969e98a9b49fc5a650dcb3f0fb74170281805e830962bdba7c"
|
|
+ "a2bf4274f57c1cd269c9040d857e3e3d2412c3187bf329f35f0e"
|
|
+ "766c5975e44184699d32f3cd22abb035ba4ab23ce5d958b6624f"
|
|
+ "5ddee59e0aca53b22cf79eb36b0a5b7965ec6e914e9220f6fcfc"
|
|
+ "16edd3760ce2ec7fb269136b780e5a4664b45eb725a05a753a4b"
|
|
+ "efc73c3ef7fd26b820c4990a9a73bec31902818100ba449314ac"
|
|
+ "34193b5f9160acf7b4d681053651533de865dcaf2edc613ec97d"
|
|
+ "b87f87f03b9b03822937ce724e11d5b1c10c07a099914a8d7fec"
|
|
+ "79cff139b5e985ec62f7da7dbc644d223c0ef2d651f587d899c0"
|
|
+ "11205d0f29fd5be2aed91cd921566dfc84d05fed10151c1821e7"
|
|
+ "c43d4bd7d09e6a95cf22c9037b9ee36001fc2f02818011d04bcf"
|
|
+ "1b67b99f1075478665ae31c2c630ac590650d90fb57006f7f0d3"
|
|
+ "c8627ca8da6ef6213fd37f5fea8aab3fd92a5ef351d2c23037e3"
|
|
+ "2da3750d1e4d2134d557705c89bf72ec4a6e68d5cd1874334e8c"
|
|
+ "3a458fe69640eb63f919863a51dd894bb0f3f99f5d289538be35"
|
|
+ "abca5ce7935334a1455d1339654246a19fcdf5bf");
|
|
|
|
final byte[] plaintext = "Now is the time for all".getBytes();
|
|
|
|
/* Do encrypt/decrypt and sign/verify in parallel across numThreads
|
|
* threads, all operations should pass */
|
|
for (int i = 0; i < numThreads; i++) {
|
|
service.submit(new Runnable() {
|
|
@Override public void run() {
|
|
|
|
int failed = 0;
|
|
|
|
Rsa priv = null;
|
|
Rsa pub = null;
|
|
Rng threadRng = null;
|
|
|
|
byte[] n_out = new byte[256];
|
|
byte[] e_out = new byte[3];
|
|
long[] n_len = new long[1];
|
|
long[] e_len = new long[1];
|
|
n_len[0] = n_out.length;
|
|
e_len[0] = e_out.length;
|
|
|
|
try {
|
|
/* Each thread needs its own RNG for FIPS */
|
|
threadRng = new Rng();
|
|
threadRng.init();
|
|
|
|
priv = new Rsa();
|
|
priv.decodePrivateKey(prvKey);
|
|
priv.exportRawPublicKey(n_out, n_len, e_out, e_len);
|
|
priv.setRng(threadRng);
|
|
|
|
pub = new Rsa();
|
|
pub.decodeRawPublicKey(n_out, e_out);
|
|
|
|
byte[] ciphertext = pub.encrypt(plaintext, threadRng);
|
|
|
|
if (!Arrays.equals(plaintext,
|
|
priv.decrypt(ciphertext))) {
|
|
failed = 1;
|
|
}
|
|
|
|
if (failed == 0) {
|
|
byte[] signature = priv.sign(plaintext, threadRng);
|
|
|
|
if (!Arrays.equals(plaintext,
|
|
pub.verify(signature))) {
|
|
failed = 1;
|
|
}
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
failed = 1;
|
|
|
|
} finally {
|
|
if (threadRng != null) {
|
|
threadRng.free();
|
|
threadRng.releaseNativeStruct();
|
|
}
|
|
priv.releaseNativeStruct();
|
|
pub.releaseNativeStruct();
|
|
results.add(failed);
|
|
latch.countDown();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/* wait for all threads to complete */
|
|
assertTrue("timed out waiting for threads to finish",
|
|
latch.await(120, TimeUnit.SECONDS));
|
|
service.shutdown();
|
|
|
|
/* Look for any failures that happened */
|
|
Iterator<Integer> listIterator = results.iterator();
|
|
while (listIterator.hasNext()) {
|
|
Integer cur = listIterator.next();
|
|
if (cur == 1) {
|
|
fail("Threading error in RSA sign/verify thread test");
|
|
}
|
|
}
|
|
}
|
|
|
|
@Test
|
|
public void testRsaPssSignVerify() {
|
|
|
|
if (!FeatureDetect.RsaPssEnabled()) {
|
|
/* Skip RSA-PSS tests if not supported */
|
|
return;
|
|
}
|
|
|
|
Rsa key = new Rsa();
|
|
Rng rng = new Rng();
|
|
rng.init();
|
|
|
|
/* Use the same test key as in other tests */
|
|
key.decodePrivateKey(Util
|
|
.h2b("308204a40201000282010100c303d12bfe39a432453b53c8842b2a7c"
|
|
+ "749abdaa2a520747d6a636b207328ed0ba697bc6c3449ed48148"
|
|
+ "fd2d68a28b67bba175c8362c4ad21bf78bbacf0df9efecf1811e"
|
|
+ "7b9b03479abf65cc7f652469a6e814895be434f7c5b01493f567"
|
|
+ "7b3a7a78e101565691a613428dd23c409c4cefd186df37511b0c"
|
|
+ "a13bf5f1a34a35e4e1ce96df1b7ebf4e97d010e8a8083081af20"
|
|
+ "0b4314c57467b432826f8d86c28840993683ba1e40722217d752"
|
|
+ "652473b0ceef19cdaeff786c7bc01203d44e720d506d3ba33ba3"
|
|
+ "995e9dc8d90c85b3d98ad95426db6dfaacbbff254cc4d179f471"
|
|
+ "d386401813b063b5724e30c49784862d562fd715f77fc0aef5fc"
|
|
+ "5be5fba1bad302030100010282010100a2e6d85f107164089e2e"
|
|
+ "6dd16d1e85d20ab18c47ce2c516aa0129e53de914c1d6dea597b"
|
|
+ "f277aad9c6d98aabd8e116e46326ffb56c1359b8e3a5c872172e"
|
|
+ "0c9f6fe5593f766f49b111c25a2e16290ddeb78edc40d5a2eee0"
|
|
+ "1ea1f4be97db86639614cd9809602d30769c3ccde688ee479279"
|
|
+ "0b5a00e25e5f117c7df908b72006892a5dfd00ab22e1f0b3bc24"
|
|
+ "a95e260e1f002dfe219a535b6dd32bab9482684336d8f62fc622"
|
|
+ "fcb5415d0d3360eaa47d7ee84b559156d35c578f1f94172faade"
|
|
+ "e99ea8f4cf8a4c8ea0e45673b2cf4f86c5693cf324208b5c960c"
|
|
+ "fa6b123b9a67c1dfc696b2a5d5920d9b094268241045d450e417"
|
|
+ "3948d0358b946d11de8fca5902818100ea24a7f96933e971dc52"
|
|
+ "7d8821282f49deba7216e9cc477a880d94578458163a81b03fa2"
|
|
+ "cfa66c1eb00629008fe77776acdbcac7d95e9b3f269052aefc38"
|
|
+ "900014bbb40f5894e72f6a7e1c4f4121d431591f4e8a1a8da757"
|
|
+ "6c22d8e5f47e32a610cb64a5550387a627058cc3d7b627b24dba"
|
|
+ "30da478f54d33d8b848d949858a502818100d5381bc38fc5930c"
|
|
+ "470b6f3592c5b08d46c892188ff5800af7efa1fe80b9b52abaca"
|
|
+ "18b05da507d0938dd89c041cd4628ea6268101ffce8a2a633435"
|
|
+ "40aa6d80de89236a574d9e6ead934e56900b6d9d738b0cae273d"
|
|
+ "de4ef0aac56c78676c94529c37676c2defbbafdfa6903cc447cf"
|
|
+ "8d969e98a9b49fc5a650dcb3f0fb74170281805e830962bdba7c"
|
|
+ "a2bf4274f57c1cd269c9040d857e3e3d2412c3187bf329f35f0e"
|
|
+ "766c5975e44184699d32f3cd22abb035ba4ab23ce5d958b6624f"
|
|
+ "5ddee59e0aca53b22cf79eb36b0a5b7965ec6e914e9220f6fcfc"
|
|
+ "16edd3760ce2ec7fb269136b780e5a4664b45eb725a05a753a4b"
|
|
+ "efc73c3ef7fd26b820c4990a9a73bec31902818100ba449314ac"
|
|
+ "34193b5f9160acf7b4d681053651533de865dcaf2edc613ec97d"
|
|
+ "b87f87f03b9b03822937ce724e11d5b1c10c07a099914a8d7fec"
|
|
+ "79cff139b5e985ec62f7da7dbc644d223c0ef2d651f587d899c0"
|
|
+ "11205d0f29fd5be2aed91cd921566dfc84d05fed10151c1821e7"
|
|
+ "c43d4bd7d09e6a95cf22c9037b9ee36001fc2f02818011d04bcf"
|
|
+ "1b67b99f1075478665ae31c2c630ac590650d90fb57006f7f0d3"
|
|
+ "c8627ca8da6ef6213fd37f5fea8aab3fd92a5ef351d2c23037e3"
|
|
+ "2da3750d1e4d2134d557705c89bf72ec4a6e68d5cd1874334e8c"
|
|
+ "3a458fe69640eb63f919863a51dd894bb0f3f99f5d289538be35"
|
|
+ "abca5ce7935334a1455d1339654246a19fcdf5bf"));
|
|
|
|
key.setRng(rng);
|
|
|
|
/* Test message */
|
|
byte[] message = "Everyone gets Friday off.".getBytes();
|
|
|
|
/* Hash the message first since RSA-PSS expects a digest */
|
|
Sha256 sha256 = new Sha256();
|
|
sha256.update(message, 0, message.length);
|
|
byte[] digest = sha256.digest();
|
|
|
|
/* Test RSA-PSS with SHA-256 (most common) */
|
|
try {
|
|
|
|
byte[] signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
/* Verify the signature */
|
|
boolean verified = key.rsaPssVerify(signature, digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32);
|
|
assertTrue("RSA-PSS signature verification failed", verified);
|
|
|
|
} catch (Exception e) {
|
|
fail("RSA-PSS sign/verify test failed: " + e.getMessage());
|
|
}
|
|
|
|
/* Test RSA-PSS with SHA-384 */
|
|
try {
|
|
/* Hash the message first since RSA-PSS expects a digest */
|
|
Sha384 sha384 = new Sha384();
|
|
sha384.update(message, 0, message.length);
|
|
byte[] digest384 = sha384.digest();
|
|
|
|
byte[] signature = key.rsaPssSign(digest384,
|
|
WolfCrypt.WC_HASH_TYPE_SHA384, Rsa.WC_MGF1SHA384, 48, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
/* Verify the signature */
|
|
boolean verified = key.rsaPssVerify(signature, digest384,
|
|
WolfCrypt.WC_HASH_TYPE_SHA384, Rsa.WC_MGF1SHA384, 48);
|
|
assertTrue("RSA-PSS SHA-384 signature verification failed",
|
|
verified);
|
|
|
|
} catch (Exception e) {
|
|
fail("RSA-PSS SHA-384 test failed: " + e.getMessage());
|
|
}
|
|
|
|
/* Test RSA-PSS with SHA-512 */
|
|
try {
|
|
/* Hash the message first since RSA-PSS expects a digest */
|
|
Sha512 sha512 = new Sha512();
|
|
sha512.update(message, 0, message.length);
|
|
byte[] digest512 = sha512.digest();
|
|
|
|
byte[] signature = key.rsaPssSign(digest512,
|
|
WolfCrypt.WC_HASH_TYPE_SHA512, Rsa.WC_MGF1SHA512, 64, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
/* Verify the signature */
|
|
boolean verified = key.rsaPssVerify(signature, digest512,
|
|
WolfCrypt.WC_HASH_TYPE_SHA512, Rsa.WC_MGF1SHA512, 64);
|
|
assertTrue("RSA-PSS SHA-512 signature verification failed",
|
|
verified);
|
|
|
|
} catch (Exception e) {
|
|
fail("RSA-PSS SHA-512 test failed: " + e.getMessage());
|
|
}
|
|
|
|
/* Test RSA-PSS with default salt length (-1) */
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256,
|
|
Rsa.RSA_PSS_SALT_LEN_DEFAULT, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
/* Verify the signature */
|
|
boolean verified = key.rsaPssVerify(signature, digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256,
|
|
Rsa.RSA_PSS_SALT_LEN_DEFAULT);
|
|
assertTrue("RSA-PSS default salt length verification failed",
|
|
verified);
|
|
|
|
} catch (Exception e) {
|
|
fail("RSA-PSS default salt length test failed: " + e.getMessage());
|
|
}
|
|
|
|
/* Test RSA-PSS with salt length discovery (-2) */
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
/* Verify with salt length discovery */
|
|
boolean verified = key.rsaPssVerify(signature, digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256,
|
|
Rsa.RSA_PSS_SALT_LEN_DISCOVER);
|
|
assertTrue("RSA-PSS salt length discovery verification failed",
|
|
verified);
|
|
|
|
} catch (WolfCryptException e) {
|
|
/* Salt length discovery may not be compiled in wolfSSL */
|
|
if (e.getMessage().contains("Bad function argument") ||
|
|
e.getMessage().contains("Not compiled in") ||
|
|
e.getMessage().contains("Length of salt is too big")) {
|
|
System.out.println(
|
|
"Salt length discovery not supported, skipping test");
|
|
} else {
|
|
fail("RSA-PSS salt length discovery test failed: " +
|
|
e.getMessage());
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
fail("RSA-PSS salt length discovery test failed: " +
|
|
e.getMessage());
|
|
}
|
|
|
|
/* Test cross-verification should fail */
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32, rng);
|
|
assertNotNull(signature);
|
|
|
|
/* Verify with different hash should fail */
|
|
boolean verified = key.rsaPssVerify(signature, digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA384, Rsa.WC_MGF1SHA384, 48);
|
|
assertFalse("RSA-PSS cross-verification should have failed",
|
|
verified);
|
|
|
|
} catch (Exception e) {
|
|
/* Expected to fail */
|
|
}
|
|
|
|
/* Test with zero salt length */
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 0, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
/* Verify the signature */
|
|
boolean verified = key.rsaPssVerify(signature, digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 0);
|
|
assertTrue("RSA-PSS zero salt length verification failed",
|
|
verified);
|
|
|
|
} catch (Exception e) {
|
|
fail("RSA-PSS zero salt length test failed: " + e.getMessage());
|
|
}
|
|
|
|
rng.free();
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void testRsaPssVerifyInline() {
|
|
if (Fips.enabled || !FeatureDetect.RsaPssEnabled()) {
|
|
/* Skip RSA-PSS tests in FIPS mode or if not supported */
|
|
return;
|
|
}
|
|
|
|
Rsa key = new Rsa();
|
|
Rng rng = new Rng();
|
|
rng.init();
|
|
|
|
/* Use the same test key */
|
|
key.decodePrivateKey(Util
|
|
.h2b("308204a40201000282010100c303d12bfe39a432453b53c8842b2a7c"
|
|
+ "749abdaa2a520747d6a636b207328ed0ba697bc6c3449ed48148"
|
|
+ "fd2d68a28b67bba175c8362c4ad21bf78bbacf0df9efecf1811e"
|
|
+ "7b9b03479abf65cc7f652469a6e814895be434f7c5b01493f567"
|
|
+ "7b3a7a78e101565691a613428dd23c409c4cefd186df37511b0c"
|
|
+ "a13bf5f1a34a35e4e1ce96df1b7ebf4e97d010e8a8083081af20"
|
|
+ "0b4314c57467b432826f8d86c28840993683ba1e40722217d752"
|
|
+ "652473b0ceef19cdaeff786c7bc01203d44e720d506d3ba33ba3"
|
|
+ "995e9dc8d90c85b3d98ad95426db6dfaacbbff254cc4d179f471"
|
|
+ "d386401813b063b5724e30c49784862d562fd715f77fc0aef5fc"
|
|
+ "5be5fba1bad302030100010282010100a2e6d85f107164089e2e"
|
|
+ "6dd16d1e85d20ab18c47ce2c516aa0129e53de914c1d6dea597b"
|
|
+ "f277aad9c6d98aabd8e116e46326ffb56c1359b8e3a5c872172e"
|
|
+ "0c9f6fe5593f766f49b111c25a2e16290ddeb78edc40d5a2eee0"
|
|
+ "1ea1f4be97db86639614cd9809602d30769c3ccde688ee479279"
|
|
+ "0b5a00e25e5f117c7df908b72006892a5dfd00ab22e1f0b3bc24"
|
|
+ "a95e260e1f002dfe219a535b6dd32bab9482684336d8f62fc622"
|
|
+ "fcb5415d0d3360eaa47d7ee84b559156d35c578f1f94172faade"
|
|
+ "e99ea8f4cf8a4c8ea0e45673b2cf4f86c5693cf324208b5c960c"
|
|
+ "fa6b123b9a67c1dfc696b2a5d5920d9b094268241045d450e417"
|
|
+ "3948d0358b946d11de8fca5902818100ea24a7f96933e971dc52"
|
|
+ "7d8821282f49deba7216e9cc477a880d94578458163a81b03fa2"
|
|
+ "cfa66c1eb00629008fe77776acdbcac7d95e9b3f269052aefc38"
|
|
+ "900014bbb40f5894e72f6a7e1c4f4121d431591f4e8a1a8da757"
|
|
+ "6c22d8e5f47e32a610cb64a5550387a627058cc3d7b627b24dba"
|
|
+ "30da478f54d33d8b848d949858a502818100d5381bc38fc5930c"
|
|
+ "470b6f3592c5b08d46c892188ff5800af7efa1fe80b9b52abaca"
|
|
+ "18b05da507d0938dd89c041cd4628ea6268101ffce8a2a633435"
|
|
+ "40aa6d80de89236a574d9e6ead934e56900b6d9d738b0cae273d"
|
|
+ "de4ef0aac56c78676c94529c37676c2defbbafdfa6903cc447cf"
|
|
+ "8d969e98a9b49fc5a650dcb3f0fb74170281805e830962bdba7c"
|
|
+ "a2bf4274f57c1cd269c9040d857e3e3d2412c3187bf329f35f0e"
|
|
+ "766c5975e44184699d32f3cd22abb035ba4ab23ce5d958b6624f"
|
|
+ "5ddee59e0aca53b22cf79eb36b0a5b7965ec6e914e9220f6fcfc"
|
|
+ "16edd3760ce2ec7fb269136b780e5a4664b45eb725a05a753a4b"
|
|
+ "efc73c3ef7fd26b820c4990a9a73bec31902818100ba449314ac"
|
|
+ "34193b5f9160acf7b4d681053651533de865dcaf2edc613ec97d"
|
|
+ "b87f87f03b9b03822937ce724e11d5b1c10c07a099914a8d7fec"
|
|
+ "79cff139b5e985ec62f7da7dbc644d223c0ef2d651f587d899c0"
|
|
+ "11205d0f29fd5be2aed91cd921566dfc84d05fed10151c1821e7"
|
|
+ "c43d4bd7d09e6a95cf22c9037b9ee36001fc2f02818011d04bcf"
|
|
+ "1b67b99f1075478665ae31c2c630ac590650d90fb57006f7f0d3"
|
|
+ "c8627ca8da6ef6213fd37f5fea8aab3fd92a5ef351d2c23037e3"
|
|
+ "2da3750d1e4d2134d557705c89bf72ec4a6e68d5cd1874334e8c"
|
|
+ "3a458fe69640eb63f919863a51dd894bb0f3f99f5d289538be35"
|
|
+ "abca5ce7935334a1455d1339654246a19fcdf5bf"));
|
|
|
|
key.setRng(rng);
|
|
|
|
/* Test message */
|
|
byte[] message = "Everyone gets Friday off.".getBytes();
|
|
|
|
/* Hash the message first since RSA-PSS expects a digest */
|
|
Sha256 sha256 = new Sha256();
|
|
sha256.update(message, 0, message.length);
|
|
byte[] digest = sha256.digest();
|
|
|
|
/* Test RSA-PSS VerifyInline method */
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
/* Test inline verification - use regular verify method */
|
|
boolean verified = key.rsaPssVerify(signature, digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32);
|
|
assertTrue("RSA-PSS inline verification failed", verified);
|
|
} catch (Exception e) {
|
|
fail("RSA-PSS inline verification test failed: " + e.getMessage());
|
|
}
|
|
|
|
rng.free();
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void testRsaPssVerifyCheck() {
|
|
if (Fips.enabled || !FeatureDetect.RsaPssEnabled()) {
|
|
/* Skip RSA-PSS tests in FIPS mode or if not supported */
|
|
return;
|
|
}
|
|
|
|
Rsa key = new Rsa();
|
|
Rng rng = new Rng();
|
|
rng.init();
|
|
|
|
/* Use the same test key */
|
|
key.decodePrivateKey(Util
|
|
.h2b("308204a40201000282010100c303d12bfe39a432453b53c8842b2a7c"
|
|
+ "749abdaa2a520747d6a636b207328ed0ba697bc6c3449ed48148"
|
|
+ "fd2d68a28b67bba175c8362c4ad21bf78bbacf0df9efecf1811e"
|
|
+ "7b9b03479abf65cc7f652469a6e814895be434f7c5b01493f567"
|
|
+ "7b3a7a78e101565691a613428dd23c409c4cefd186df37511b0c"
|
|
+ "a13bf5f1a34a35e4e1ce96df1b7ebf4e97d010e8a8083081af20"
|
|
+ "0b4314c57467b432826f8d86c28840993683ba1e40722217d752"
|
|
+ "652473b0ceef19cdaeff786c7bc01203d44e720d506d3ba33ba3"
|
|
+ "995e9dc8d90c85b3d98ad95426db6dfaacbbff254cc4d179f471"
|
|
+ "d386401813b063b5724e30c49784862d562fd715f77fc0aef5fc"
|
|
+ "5be5fba1bad302030100010282010100a2e6d85f107164089e2e"
|
|
+ "6dd16d1e85d20ab18c47ce2c516aa0129e53de914c1d6dea597b"
|
|
+ "f277aad9c6d98aabd8e116e46326ffb56c1359b8e3a5c872172e"
|
|
+ "0c9f6fe5593f766f49b111c25a2e16290ddeb78edc40d5a2eee0"
|
|
+ "1ea1f4be97db86639614cd9809602d30769c3ccde688ee479279"
|
|
+ "0b5a00e25e5f117c7df908b72006892a5dfd00ab22e1f0b3bc24"
|
|
+ "a95e260e1f002dfe219a535b6dd32bab9482684336d8f62fc622"
|
|
+ "fcb5415d0d3360eaa47d7ee84b559156d35c578f1f94172faade"
|
|
+ "e99ea8f4cf8a4c8ea0e45673b2cf4f86c5693cf324208b5c960c"
|
|
+ "fa6b123b9a67c1dfc696b2a5d5920d9b094268241045d450e417"
|
|
+ "3948d0358b946d11de8fca5902818100ea24a7f96933e971dc52"
|
|
+ "7d8821282f49deba7216e9cc477a880d94578458163a81b03fa2"
|
|
+ "cfa66c1eb00629008fe77776acdbcac7d95e9b3f269052aefc38"
|
|
+ "900014bbb40f5894e72f6a7e1c4f4121d431591f4e8a1a8da757"
|
|
+ "6c22d8e5f47e32a610cb64a5550387a627058cc3d7b627b24dba"
|
|
+ "30da478f54d33d8b848d949858a502818100d5381bc38fc5930c"
|
|
+ "470b6f3592c5b08d46c892188ff5800af7efa1fe80b9b52abaca"
|
|
+ "18b05da507d0938dd89c041cd4628ea6268101ffce8a2a633435"
|
|
+ "40aa6d80de89236a574d9e6ead934e56900b6d9d738b0cae273d"
|
|
+ "de4ef0aac56c78676c94529c37676c2defbbafdfa6903cc447cf"
|
|
+ "8d969e98a9b49fc5a650dcb3f0fb74170281805e830962bdba7c"
|
|
+ "a2bf4274f57c1cd269c9040d857e3e3d2412c3187bf329f35f0e"
|
|
+ "766c5975e44184699d32f3cd22abb035ba4ab23ce5d958b6624f"
|
|
+ "5ddee59e0aca53b22cf79eb36b0a5b7965ec6e914e9220f6fcfc"
|
|
+ "16edd3760ce2ec7fb269136b780e5a4664b45eb725a05a753a4b"
|
|
+ "efc73c3ef7fd26b820c4990a9a73bec31902818100ba449314ac"
|
|
+ "34193b5f9160acf7b4d681053651533de865dcaf2edc613ec97d"
|
|
+ "b87f87f03b9b03822937ce724e11d5b1c10c07a099914a8d7fec"
|
|
+ "79cff139b5e985ec62f7da7dbc644d223c0ef2d651f587d899c0"
|
|
+ "11205d0f29fd5be2aed91cd921566dfc84d05fed10151c1821e7"
|
|
+ "c43d4bd7d09e6a95cf22c9037b9ee36001fc2f02818011d04bcf"
|
|
+ "1b67b99f1075478665ae31c2c630ac590650d90fb57006f7f0d3"
|
|
+ "c8627ca8da6ef6213fd37f5fea8aab3fd92a5ef351d2c23037e3"
|
|
+ "2da3750d1e4d2134d557705c89bf72ec4a6e68d5cd1874334e8c"
|
|
+ "3a458fe69640eb63f919863a51dd894bb0f3f99f5d289538be35"
|
|
+ "abca5ce7935334a1455d1339654246a19fcdf5bf"));
|
|
|
|
key.setRng(rng);
|
|
|
|
/* Test message and its digest */
|
|
byte[] message = "Everyone gets Friday off.".getBytes();
|
|
|
|
/* Calculate SHA-256 digest manually for VerifyCheck */
|
|
Sha256 sha256 = new Sha256();
|
|
sha256.init();
|
|
sha256.update(message, 0, message.length);
|
|
byte[] digest = sha256.digest();
|
|
|
|
/* Test RSA-PSS VerifyCheck method */
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
/* Test check verification with explicit digest */
|
|
boolean verified = key.rsaPssVerifyWithDigest(signature, message,
|
|
digest, WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32);
|
|
assertTrue("RSA-PSS check verification failed", verified);
|
|
|
|
/* Test with non-default salt length,
|
|
* saltLen != digest length must be honored on verify */
|
|
signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 16, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
verified = key.rsaPssVerifyWithDigest(signature, message,
|
|
digest, WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 16);
|
|
assertTrue("RSA-PSS check verification failed with " +
|
|
"non-default salt length", verified);
|
|
|
|
/* Verification with wrong salt length should fail */
|
|
try {
|
|
verified = key.rsaPssVerifyWithDigest(signature, message,
|
|
digest, WolfCrypt.WC_HASH_TYPE_SHA256,
|
|
Rsa.WC_MGF1SHA256, 32);
|
|
} catch (WolfCryptException e) {
|
|
/* native error acceptable here, treat as not verified */
|
|
verified = false;
|
|
}
|
|
assertFalse("RSA-PSS check verification passed with " +
|
|
"mismatched salt length", verified);
|
|
|
|
/* Test special value RSA_PSS_SALT_LEN_DEFAULT, sign uses
|
|
* salt length equal to digest length */
|
|
signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256,
|
|
Rsa.RSA_PSS_SALT_LEN_DEFAULT, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
verified = key.rsaPssVerifyWithDigest(signature, message,
|
|
digest, WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256,
|
|
Rsa.RSA_PSS_SALT_LEN_DEFAULT);
|
|
assertTrue("RSA-PSS check verification failed with " +
|
|
"RSA_PSS_SALT_LEN_DEFAULT", verified);
|
|
|
|
/* Operational errors must throw, not report false */
|
|
try {
|
|
key.rsaPssVerifyWithDigest(null, message, digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32);
|
|
fail("rsaPssVerifyWithDigest should have thrown for " +
|
|
"null signature");
|
|
} catch (WolfCryptException e) {
|
|
/* expected */
|
|
}
|
|
|
|
/* Corrupted signatures must report false, not throw. PSS
|
|
* decode of garbage fails with position dependent error
|
|
* codes, exercise first, middle and last bytes */
|
|
signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32, rng);
|
|
int[] flipPos = new int[] { 0, signature.length / 2,
|
|
signature.length - 1 };
|
|
for (int pos : flipPos) {
|
|
byte[] badSig = signature.clone();
|
|
badSig[pos] ^= (byte)0x80;
|
|
verified = key.rsaPssVerifyWithDigest(badSig, message,
|
|
digest, WolfCrypt.WC_HASH_TYPE_SHA256,
|
|
Rsa.WC_MGF1SHA256, 32);
|
|
assertFalse("corrupted RSA-PSS signature verified, " +
|
|
"flipped byte " + pos, verified);
|
|
}
|
|
|
|
/* Mismatched digest must report false, not throw */
|
|
signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32, rng);
|
|
byte[] wrongDigest = digest.clone();
|
|
wrongDigest[0] ^= 1;
|
|
verified = key.rsaPssVerifyWithDigest(signature, message,
|
|
wrongDigest, WolfCrypt.WC_HASH_TYPE_SHA256,
|
|
Rsa.WC_MGF1SHA256, 32);
|
|
assertFalse("RSA-PSS signature verified with wrong digest",
|
|
verified);
|
|
|
|
} catch (Exception e) {
|
|
fail("RSA-PSS check verification test failed: " + e.getMessage());
|
|
}
|
|
|
|
sha256.releaseNativeStruct();
|
|
rng.free();
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void testRsaPssCheckPadding() {
|
|
if (Fips.enabled || !FeatureDetect.RsaPssEnabled()) {
|
|
/* Skip RSA-PSS tests in FIPS mode or if not supported */
|
|
return;
|
|
}
|
|
|
|
Rsa key = new Rsa();
|
|
Rng rng = new Rng();
|
|
rng.init();
|
|
|
|
/* Use the same test key */
|
|
key.decodePrivateKey(Util
|
|
.h2b("308204a40201000282010100c303d12bfe39a432453b53c8842b2a7c"
|
|
+ "749abdaa2a520747d6a636b207328ed0ba697bc6c3449ed48148"
|
|
+ "fd2d68a28b67bba175c8362c4ad21bf78bbacf0df9efecf1811e"
|
|
+ "7b9b03479abf65cc7f652469a6e814895be434f7c5b01493f567"
|
|
+ "7b3a7a78e101565691a613428dd23c409c4cefd186df37511b0c"
|
|
+ "a13bf5f1a34a35e4e1ce96df1b7ebf4e97d010e8a8083081af20"
|
|
+ "0b4314c57467b432826f8d86c28840993683ba1e40722217d752"
|
|
+ "652473b0ceef19cdaeff786c7bc01203d44e720d506d3ba33ba3"
|
|
+ "995e9dc8d90c85b3d98ad95426db6dfaacbbff254cc4d179f471"
|
|
+ "d386401813b063b5724e30c49784862d562fd715f77fc0aef5fc"
|
|
+ "5be5fba1bad302030100010282010100a2e6d85f107164089e2e"
|
|
+ "6dd16d1e85d20ab18c47ce2c516aa0129e53de914c1d6dea597b"
|
|
+ "f277aad9c6d98aabd8e116e46326ffb56c1359b8e3a5c872172e"
|
|
+ "0c9f6fe5593f766f49b111c25a2e16290ddeb78edc40d5a2eee0"
|
|
+ "1ea1f4be97db86639614cd9809602d30769c3ccde688ee479279"
|
|
+ "0b5a00e25e5f117c7df908b72006892a5dfd00ab22e1f0b3bc24"
|
|
+ "a95e260e1f002dfe219a535b6dd32bab9482684336d8f62fc622"
|
|
+ "fcb5415d0d3360eaa47d7ee84b559156d35c578f1f94172faade"
|
|
+ "e99ea8f4cf8a4c8ea0e45673b2cf4f86c5693cf324208b5c960c"
|
|
+ "fa6b123b9a67c1dfc696b2a5d5920d9b094268241045d450e417"
|
|
+ "3948d0358b946d11de8fca5902818100ea24a7f96933e971dc52"
|
|
+ "7d8821282f49deba7216e9cc477a880d94578458163a81b03fa2"
|
|
+ "cfa66c1eb00629008fe77776acdbcac7d95e9b3f269052aefc38"
|
|
+ "900014bbb40f5894e72f6a7e1c4f4121d431591f4e8a1a8da757"
|
|
+ "6c22d8e5f47e32a610cb64a5550387a627058cc3d7b627b24dba"
|
|
+ "30da478f54d33d8b848d949858a502818100d5381bc38fc5930c"
|
|
+ "470b6f3592c5b08d46c892188ff5800af7efa1fe80b9b52abaca"
|
|
+ "18b05da507d0938dd89c041cd4628ea6268101ffce8a2a633435"
|
|
+ "40aa6d80de89236a574d9e6ead934e56900b6d9d738b0cae273d"
|
|
+ "de4ef0aac56c78676c94529c37676c2defbbafdfa6903cc447cf"
|
|
+ "8d969e98a9b49fc5a650dcb3f0fb74170281805e830962bdba7c"
|
|
+ "a2bf4274f57c1cd269c9040d857e3e3d2412c3187bf329f35f0e"
|
|
+ "766c5975e44184699d32f3cd22abb035ba4ab23ce5d958b6624f"
|
|
+ "5ddee59e0aca53b22cf79eb36b0a5b7965ec6e914e9220f6fcfc"
|
|
+ "16edd3760ce2ec7fb269136b780e5a4664b45eb725a05a753a4b"
|
|
+ "efc73c3ef7fd26b820c4990a9a73bec31902818100ba449314ac"
|
|
+ "34193b5f9160acf7b4d681053651533de865dcaf2edc613ec97d"
|
|
+ "b87f87f03b9b03822937ce724e11d5b1c10c07a099914a8d7fec"
|
|
+ "79cff139b5e985ec62f7da7dbc644d223c0ef2d651f587d899c0"
|
|
+ "11205d0f29fd5be2aed91cd921566dfc84d05fed10151c1821e7"
|
|
+ "c43d4bd7d09e6a95cf22c9037b9ee36001fc2f02818011d04bcf"
|
|
+ "1b67b99f1075478665ae31c2c630ac590650d90fb57006f7f0d3"
|
|
+ "c8627ca8da6ef6213fd37f5fea8aab3fd92a5ef351d2c23037e3"
|
|
+ "2da3750d1e4d2134d557705c89bf72ec4a6e68d5cd1874334e8c"
|
|
+ "3a458fe69640eb63f919863a51dd894bb0f3f99f5d289538be35"
|
|
+ "abca5ce7935334a1455d1339654246a19fcdf5bf"));
|
|
|
|
key.setRng(rng);
|
|
|
|
/* Test message and its digest */
|
|
byte[] message = "Everyone gets Friday off.".getBytes();
|
|
|
|
/* Calculate SHA-256 digest manually for CheckPadding */
|
|
Sha256 sha256 = new Sha256();
|
|
sha256.init();
|
|
sha256.update(message, 0, message.length);
|
|
byte[] digest = sha256.digest();
|
|
|
|
/* Test RSA-PSS CheckPadding method */
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32, rng);
|
|
assertNotNull(signature);
|
|
assertTrue(signature.length > 0);
|
|
|
|
/* Test check padding verification */
|
|
boolean verified = key.rsaPssCheckPadding(signature, digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 32);
|
|
assertTrue("RSA-PSS check padding failed", verified);
|
|
|
|
} catch (Exception e) {
|
|
fail("RSA-PSS check padding test failed: " + e.getMessage());
|
|
}
|
|
|
|
sha256.releaseNativeStruct();
|
|
rng.free();
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void testRsaPssComprehensiveMgfTesting() {
|
|
if (Fips.enabled || !FeatureDetect.RsaPssEnabled()) {
|
|
/* Skip RSA-PSS tests in FIPS mode or if not supported */
|
|
return;
|
|
}
|
|
|
|
Rng rng = new Rng();
|
|
rng.init();
|
|
|
|
Rsa key = makeKeyWithRetry(2048, 65537, rng);
|
|
|
|
String message = "Comprehensive MGF testing";
|
|
|
|
/* Test MGF algorithms with their correct corresponding hash types.
|
|
* Each MGF algorithm must be paired with matching hash algorithm. */
|
|
int[][] mgfHashPairs = {
|
|
{Rsa.WC_MGF1SHA1, WolfCrypt.WC_HASH_TYPE_SHA},
|
|
{Rsa.WC_MGF1SHA224, WolfCrypt.WC_HASH_TYPE_SHA224},
|
|
{Rsa.WC_MGF1SHA256, WolfCrypt.WC_HASH_TYPE_SHA256},
|
|
{Rsa.WC_MGF1SHA384, WolfCrypt.WC_HASH_TYPE_SHA384},
|
|
{Rsa.WC_MGF1SHA512, WolfCrypt.WC_HASH_TYPE_SHA512}
|
|
};
|
|
|
|
for (int i = 0; i < mgfHashPairs.length; i++) {
|
|
int mgfType = mgfHashPairs[i][0];
|
|
int hashType = mgfHashPairs[i][1];
|
|
|
|
/* Create the appropriate digest for each hash type */
|
|
byte[] digest;
|
|
if (hashType == WolfCrypt.WC_HASH_TYPE_SHA) {
|
|
digest = sha1(message.getBytes());
|
|
} else if (hashType == WolfCrypt.WC_HASH_TYPE_SHA224) {
|
|
digest = sha224(message.getBytes());
|
|
} else if (hashType == WolfCrypt.WC_HASH_TYPE_SHA256) {
|
|
digest = sha256(message.getBytes());
|
|
} else if (hashType == WolfCrypt.WC_HASH_TYPE_SHA384) {
|
|
digest = sha384(message.getBytes());
|
|
} else if (hashType == WolfCrypt.WC_HASH_TYPE_SHA512) {
|
|
digest = sha512(message.getBytes());
|
|
} else {
|
|
throw new RuntimeException("Unsupported hash type: " +
|
|
hashType);
|
|
}
|
|
|
|
try {
|
|
/* Test each MGF algorithm with its corresponding
|
|
* hash type and digest */
|
|
byte[] signature = key.rsaPssSign(digest, hashType,
|
|
mgfType, Rsa.RSA_PSS_SALT_LEN_DEFAULT, rng);
|
|
assertNotNull("Signature should not be null for MGF type " +
|
|
mgfType, signature);
|
|
assertTrue("Signature should have non-zero length for " +
|
|
"MGF type " + mgfType, signature.length > 0);
|
|
|
|
/* Verify the signature */
|
|
boolean verified = key.rsaPssVerify(signature, digest, hashType,
|
|
mgfType, Rsa.RSA_PSS_SALT_LEN_DEFAULT);
|
|
assertTrue("RSA-PSS verification failed for MGF type " +
|
|
mgfType, verified);
|
|
|
|
} catch (WolfCryptException e) {
|
|
/* wolfSSL build may not support all hash types for RSA-PSS */
|
|
if (e.getMessage().contains("Bad function argument") ||
|
|
e.getMessage().contains("Not compiled in")) {
|
|
System.out.println("MGF type " + mgfType +
|
|
" with hash type " + hashType +
|
|
" not supported in this build, skipping. Error: " +
|
|
e.getMessage());
|
|
} else {
|
|
fail("RSA-PSS MGF test failed for MGF type " + mgfType +
|
|
" with hash type " + hashType + ": " + e.getMessage());
|
|
}
|
|
} catch (Exception e) {
|
|
fail("RSA-PSS MGF test failed for MGF type " + mgfType +
|
|
" with hash type " + hashType + ": " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
rng.free();
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void testRsaPssErrorConditions() {
|
|
if (Fips.enabled || !FeatureDetect.RsaPssEnabled()) {
|
|
/* Skip RSA-PSS tests in FIPS mode or if not supported */
|
|
return;
|
|
}
|
|
|
|
Rng rng = new Rng();
|
|
rng.init();
|
|
|
|
Rsa key = makeKeyWithRetry(2048, 65537, rng);
|
|
|
|
String message = "Error condition testing";
|
|
byte[] digest = sha256(message.getBytes());
|
|
|
|
/* Test with invalid hash type */
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest, 999,
|
|
Rsa.WC_MGF1SHA256, 32, rng);
|
|
fail("Should have thrown exception for invalid hash type");
|
|
} catch (WolfCryptException e) {
|
|
/* Expected exception */
|
|
} catch (Exception e) {
|
|
/* Expected exception */
|
|
}
|
|
|
|
/* Test with invalid MGF type */
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, 999, 32, rng);
|
|
fail("Should have thrown exception for invalid MGF type");
|
|
} catch (WolfCryptException e) {
|
|
/* Expected exception */
|
|
} catch (Exception e) {
|
|
/* Expected exception */
|
|
}
|
|
|
|
/* Test with salt length too large */
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest,
|
|
WolfCrypt.WC_HASH_TYPE_SHA256, Rsa.WC_MGF1SHA256, 1000, rng);
|
|
fail("Should have thrown exception for salt length too large");
|
|
} catch (WolfCryptException e) {
|
|
/* Expected exception */
|
|
} catch (Exception e) {
|
|
/* Expected exception */
|
|
}
|
|
|
|
rng.free();
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
@Test
|
|
public void testRsaPssIndividualMgfTypes() {
|
|
if (Fips.enabled || !FeatureDetect.RsaPssEnabled()) {
|
|
/* Skip RSA-PSS tests in FIPS mode or if not supported */
|
|
return;
|
|
}
|
|
|
|
Rng rng = new Rng();
|
|
rng.init();
|
|
|
|
Rsa key = makeKeyWithRetry(2048, 65537, rng);
|
|
|
|
String message = "Individual MGF testing";
|
|
|
|
/* Test each MGF type individually with matching hash type */
|
|
int[][] mgfHashPairs = {
|
|
{Rsa.WC_MGF1SHA1, WolfCrypt.WC_HASH_TYPE_SHA},
|
|
{Rsa.WC_MGF1SHA224, WolfCrypt.WC_HASH_TYPE_SHA224},
|
|
{Rsa.WC_MGF1SHA256, WolfCrypt.WC_HASH_TYPE_SHA256},
|
|
{Rsa.WC_MGF1SHA384, WolfCrypt.WC_HASH_TYPE_SHA384},
|
|
{Rsa.WC_MGF1SHA512, WolfCrypt.WC_HASH_TYPE_SHA512}
|
|
};
|
|
|
|
for (int[] pair : mgfHashPairs) {
|
|
int mgfType = pair[0];
|
|
int hashType = pair[1];
|
|
|
|
/* Create appropriate digest for this hash type */
|
|
byte[] digest;
|
|
if (hashType == WolfCrypt.WC_HASH_TYPE_SHA) {
|
|
digest = sha1(message.getBytes());
|
|
} else if (hashType == WolfCrypt.WC_HASH_TYPE_SHA224) {
|
|
digest = sha224(message.getBytes());
|
|
} else if (hashType == WolfCrypt.WC_HASH_TYPE_SHA256) {
|
|
digest = sha256(message.getBytes());
|
|
} else if (hashType == WolfCrypt.WC_HASH_TYPE_SHA384) {
|
|
digest = sha384(message.getBytes());
|
|
} else if (hashType == WolfCrypt.WC_HASH_TYPE_SHA512) {
|
|
digest = sha512(message.getBytes());
|
|
} else {
|
|
fail("Unknown hash type: " + hashType);
|
|
return;
|
|
}
|
|
|
|
try {
|
|
byte[] signature = key.rsaPssSign(digest, hashType, mgfType,
|
|
digest.length, rng);
|
|
} catch (WolfCryptException e) {
|
|
fail("MGF type " + mgfType + " with hash type " +
|
|
hashType + " failed: " + e.getMessage());
|
|
}
|
|
}
|
|
|
|
rng.free();
|
|
key.releaseNativeStruct();
|
|
}
|
|
|
|
private byte[] sha1(byte[] input) {
|
|
try {
|
|
MessageDigest md = MessageDigest.getInstance("SHA-1");
|
|
return md.digest(input);
|
|
} catch (Exception e) {
|
|
fail("SHA-1 digest failed: " + e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private byte[] sha224(byte[] input) {
|
|
try {
|
|
MessageDigest md = MessageDigest.getInstance("SHA-224");
|
|
return md.digest(input);
|
|
} catch (Exception e) {
|
|
fail("SHA-224 digest failed: " + e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private byte[] sha256(byte[] input) {
|
|
try {
|
|
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
return md.digest(input);
|
|
} catch (Exception e) {
|
|
fail("SHA-256 digest failed: " + e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private byte[] sha384(byte[] input) {
|
|
try {
|
|
MessageDigest md = MessageDigest.getInstance("SHA-384");
|
|
return md.digest(input);
|
|
} catch (Exception e) {
|
|
fail("SHA-384 digest failed: " + e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private byte[] sha512(byte[] input) {
|
|
try {
|
|
MessageDigest md = MessageDigest.getInstance("SHA-512");
|
|
return md.digest(input);
|
|
} catch (Exception e) {
|
|
fail("SHA-512 digest failed: " + e.getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|