From b2730fb8c3c2b704f80a0bb06ca65cb17d5ddf27 Mon Sep 17 00:00:00 2001 From: Adrian Damian Date: Tue, 12 Dec 2023 13:42:42 -0800 Subject: [PATCH 1/3] Instantiate RSASignatureGenerator and RSASignatureValidator with in memory keys (byte arrays) --- cadc-util/build.gradle | 2 +- .../nrc/cadc/util/RsaSignatureGenerator.java | 98 ++++++++++--------- .../nrc/cadc/util/RsaSignatureVerifier.java | 81 ++++++++------- .../RSASignatureGeneratorValidatorTest.java | 27 +++++ 4 files changed, 126 insertions(+), 82 deletions(-) diff --git a/cadc-util/build.gradle b/cadc-util/build.gradle index 41826180..3dc38d87 100644 --- a/cadc-util/build.gradle +++ b/cadc-util/build.gradle @@ -16,7 +16,7 @@ sourceCompatibility = 1.8 group = 'org.opencadc' -version = '1.10.2' +version = '1.10.3' description = 'OpenCADC core utility library' def git_url = 'https://github.com/opencadc/core' diff --git a/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureGenerator.java b/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureGenerator.java index 95746f90..9acae6c2 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureGenerator.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureGenerator.java @@ -96,12 +96,10 @@ * This class is used to sign and/or verify signed messages. The class requires * and RSA private key to sign a message. * - *

The key is passed to the class via the MessageRSA.keys file in the - * classpath. This class cannot be instantiated without this file containing - * a private RSA key. + *

The key is passed to the class via a file or as a binary array. * *

Format of the key: - * The private key in the MessageRSA.keys file must be in PEM TKCS#8 to work + * The private key in the MessageRSA.keys file must be in PEM TKCS#8 to work * with basic Java. These keys are in text format delimited by the following * rows: * "-----BEGIN PRIVATE KEY-----" and "-----END PRIVATE KEY-----". @@ -150,86 +148,94 @@ public RsaSignatureGenerator(File keyFile) { super(keyFile, true); initPrivateKey(keyFile); } + + public RsaSignatureGenerator(byte[] keyContent) { + super(keyContent, true); + initPrivateKey(keyContent); + } private void initPrivateKey(File keysFile) { - KeyFactory keyFactory = null; - try { - keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - } catch (NoSuchAlgorithmException e1) { - throw new RuntimeException("BUG: Wrong algorithm " + KEY_ALGORITHM, - e1); - } // try to load the keys try { - BufferedReader br = new BufferedReader(new FileReader(keysFile)); - try { + try (BufferedReader br = new BufferedReader(new FileReader(keysFile))) { StringBuilder sb = null; boolean read = false; String line = null; while ((line = br.readLine()) != null) { if (line.equalsIgnoreCase(PRIV_KEY_START)) { if (read) { - throw new - IllegalArgumentException("Corrupted keys file"); + throw new + IllegalArgumentException("Corrupted keys file"); } - + if (privKey != null) { throw new - IllegalStateException("Found two private keys"); + IllegalStateException("Found two private keys"); } - + read = true; sb = new StringBuilder(); continue; } - + if (line.equalsIgnoreCase(PRIV_KEY_END)) { if (!read) { - throw new - IllegalArgumentException("Corrupted keys file"); + throw new + IllegalArgumentException("Corrupted keys file"); } - + read = false; String payload = sb.toString(); byte[] bytes = Base64.decode(payload); - PKCS8EncodedKeySpec privateKeySpec = new - PKCS8EncodedKeySpec(bytes); - try { - privKey = - keyFactory.generatePrivate(privateKeySpec); - // get corresponding public key - RSAPrivateCrtKey privk = - (RSAPrivateCrtKey)privKey; - RSAPublicKeySpec publicKeySpec = - new java.security.spec.RSAPublicKeySpec( - privk.getModulus(), - privk.getPublicExponent()); - - PublicKey publicKey = - keyFactory.generatePublic(publicKeySpec); - pubKeys.add(publicKey); - } catch (InvalidKeySpecException e) { - log.warn("Could not parse private key", e); - } + initPrivateKey(bytes); } - + if (read) { sb.append(line); } } - } finally { - br.close(); } } catch (IOException e) { String msg = "Could not read keys"; throw new RuntimeException(msg, e); } - + if (privKey == null) { String msg = "No valid private key found"; throw new IllegalStateException(msg); - } + } + } + + private void initPrivateKey(byte[] keysContent) { + + KeyFactory keyFactory = null; + try { + keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + } catch (NoSuchAlgorithmException e1) { + throw new RuntimeException("BUG: Wrong algorithm " + KEY_ALGORITHM, + e1); + } + + PKCS8EncodedKeySpec privateKeySpec = new + PKCS8EncodedKeySpec(keysContent); + try { + privKey = + keyFactory.generatePrivate(privateKeySpec); + // get corresponding public key + RSAPrivateCrtKey privk = + (RSAPrivateCrtKey)privKey; + RSAPublicKeySpec publicKeySpec = + new java.security.spec.RSAPublicKeySpec( + privk.getModulus(), + privk.getPublicExponent()); + + PublicKey publicKey = + keyFactory.generatePublic(publicKeySpec); + pubKeys.add(publicKey); + } catch (InvalidKeySpecException e) { + log.warn("Could not parse private key", e); + } } /** diff --git a/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java b/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java index ff1b6eae..5b6d11dd 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java @@ -92,9 +92,7 @@ * This class is used to verify signed messages. The class requires * an RSA public key to verify a message. * - *

The keys are passed to the class via the RsaSignaturePub.key file in the - * classpath. This class cannot be instantiated without this file containing - * public RSA keys. + *

The keys are passed to the class via a file or as a binary array. * *

Format of the keys: * Public keys in the keys file must be in PEM TKCS#1These keys are @@ -135,18 +133,18 @@ public class RsaSignatureVerifier { public static final String PUB_KEY_START = "-----BEGIN PUBLIC KEY-----"; public static final String PUB_KEY_END = "-----END PUBLIC KEY-----"; - + /** * Default constructor. This will look for a key file named RsaSignaturePub.key * and use it to verify. - * + * * @deprecated use RsaSignatureVerifier(File keyFile) */ @Deprecated public RsaSignatureVerifier() { this(PUB_KEY_FILE_NAME); } - + /** * Constructor. * @@ -165,6 +163,15 @@ public RsaSignatureVerifier(File keyFile) { } init(keyFile); } + + public RsaSignatureVerifier(byte[] keyContent) { + init(keyContent); + } + + public RsaSignatureVerifier(byte[] keyContent, boolean isPrivateKey) { + if(!isPrivateKey) + init(keyContent); + } // ctors for use by RsaSignatureGenerator subclass @Deprecated @@ -183,7 +190,7 @@ protected RsaSignatureVerifier(File keyFile, boolean isPrivateKeyFile) { init(keyFile); } } - + protected final File findFile(String fname) throws MissingResourceException { File ret = new File(DEFAULT_CONFIG_DIR, fname); if (!ret.exists()) { @@ -198,68 +205,72 @@ protected final File findFile(String fname) throws MissingResourceException { * @param keysFile */ protected void init(File keysFile) { - KeyFactory keyFactory = null; - try { - keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); - } catch (NoSuchAlgorithmException e1) { - throw new RuntimeException("BUG: Wrong algorithm " + KEY_ALGORITHM, e1); - } // try to load the keys try { log.debug("read pub keys: " + keysFile); - BufferedReader br = new BufferedReader(new - FileReader(keysFile)); - try { + try (BufferedReader br = new BufferedReader(new + FileReader(keysFile))) { StringBuilder sb = null; boolean readPub = false; - String line = null; + String line; while ((line = br.readLine()) != null) { if (line.equalsIgnoreCase(PUB_KEY_START)) { if (readPub) { - throw new - IllegalArgumentException("Corrupted keys file"); + throw new + IllegalArgumentException("Corrupted keys file"); } - + readPub = true; sb = new StringBuilder(); continue; } - + if (line.equalsIgnoreCase(PUB_KEY_END)) { if (!readPub) { - throw new - IllegalArgumentException("Corrupted keys file"); + throw new + IllegalArgumentException("Corrupted keys file"); } - + readPub = false; String payload = sb.toString(); byte[] bytes = Base64.decode(payload); - X509EncodedKeySpec publicKeySpec = - new X509EncodedKeySpec(bytes); - try { - pubKeys.add(keyFactory.generatePublic(publicKeySpec)); - } catch (InvalidKeySpecException e) { - log.warn("Could not parse public key", e); - } + init(bytes); } if (readPub) { sb.append(line); } } - } finally { - br.close(); } } catch (IOException e) { String msg = "Could not read keys"; throw new RuntimeException(msg, e); } - if (pubKeys.isEmpty()) { String msg = "No valid public keys found"; throw new IllegalStateException(msg); - } + } } + /** + * Init public keys from binary content. + * + * @param keysContent + */ + protected void init(byte[] keysContent) { + KeyFactory keyFactory = null; + try { + keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); + } catch (NoSuchAlgorithmException e1) { + throw new RuntimeException("BUG: Wrong algorithm " + KEY_ALGORITHM, e1); + } + + X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(keysContent); + try { + pubKeys.add(keyFactory.generatePublic(publicKeySpec)); + } catch (InvalidKeySpecException e) { + log.warn("Could not parse public key", e); + } + } /** * Method use to verify a stream diff --git a/cadc-util/src/test/java/ca/nrc/cadc/util/RSASignatureGeneratorValidatorTest.java b/cadc-util/src/test/java/ca/nrc/cadc/util/RSASignatureGeneratorValidatorTest.java index 2e323140..51a82a25 100644 --- a/cadc-util/src/test/java/ca/nrc/cadc/util/RSASignatureGeneratorValidatorTest.java +++ b/cadc-util/src/test/java/ca/nrc/cadc/util/RSASignatureGeneratorValidatorTest.java @@ -38,6 +38,9 @@ import java.io.File; import java.io.FileOutputStream; import java.io.PrintWriter; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; import java.util.Date; import java.util.MissingResourceException; import org.apache.log4j.Level; @@ -77,6 +80,30 @@ public void testSignVerify() throws Exception { } } + @Test + public void testSignVerifyBytes() throws Exception { + final String testString = "cadcauthtest1-" + new Date(); + KeyPairGenerator kpg; + try { + kpg = KeyPairGenerator.getInstance(RsaSignatureVerifier.KEY_ALGORITHM); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException( + "BUG: illegal key algorithm - " + RsaSignatureVerifier.KEY_ALGORITHM, e); + } + int[] keyLengths = { 512, 1024, 2048, 4096 }; + for (int len : keyLengths) { + log.info("testSignVerifyBytes: " + len); + + kpg.initialize(len); + KeyPair keyPair = kpg.genKeyPair(); + RsaSignatureGenerator sg = new RsaSignatureGenerator(keyPair.getPrivate().getEncoded()); + RsaSignatureVerifier sv = new RsaSignatureVerifier(keyPair.getPublic().getEncoded()); + assertTrue("Signature does not work!!!!", + sv.verify(new ByteArrayInputStream(testString.getBytes()), + sg.sign(new ByteArrayInputStream(testString.getBytes())))); + } + } + @Test public void testKeyFileNotFound() throws Exception { final String testString = "cadcauthtest1-" + new Date(); From 4bc9e722511b9ea1de5ca1257f9da75071c0e7a8 Mon Sep 17 00:00:00 2001 From: Adrian Damian Date: Tue, 12 Dec 2023 16:31:27 -0800 Subject: [PATCH 2/3] Rework after code review --- .../nrc/cadc/util/RsaSignatureGenerator.java | 27 +++++++++++-------- .../nrc/cadc/util/RsaSignatureVerifier.java | 3 ++- .../RSASignatureGeneratorValidatorTest.java | 10 +------ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureGenerator.java b/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureGenerator.java index 9acae6c2..ede57642 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureGenerator.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureGenerator.java @@ -294,17 +294,7 @@ public static void genKeyPair(File directory) } public static void genKeyPair(File pubKey, File privKey, int keyLength) throws FileNotFoundException { - // generate the certs - KeyPairGenerator kpg; - try { - kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException( - "BUG: illegal key algorithm - " + KEY_ALGORITHM, e); - } - - kpg.initialize(keyLength); - KeyPair keyPair = kpg.genKeyPair(); + KeyPair keyPair = getKeyPair(keyLength); String base64PrivKey = Base64.encodeLines(keyPair.getPrivate().getEncoded()); @@ -329,4 +319,19 @@ public static void genKeyPair(File pubKey, File privKey, int keyLength) throws F outPriv.close(); } } + + public static KeyPair getKeyPair(int keyLength) { + // generate the certs + KeyPairGenerator kpg; + try { + kpg = KeyPairGenerator.getInstance(KEY_ALGORITHM); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException( + "BUG: illegal key algorithm - " + KEY_ALGORITHM, e); + } + + kpg.initialize(keyLength); + KeyPair keyPair = kpg.genKeyPair(); + return keyPair; + } } diff --git a/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java b/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java index 5b6d11dd..c55376c9 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java @@ -169,8 +169,9 @@ public RsaSignatureVerifier(byte[] keyContent) { } public RsaSignatureVerifier(byte[] keyContent, boolean isPrivateKey) { - if(!isPrivateKey) + if (!isPrivateKey) { init(keyContent); + } } // ctors for use by RsaSignatureGenerator subclass diff --git a/cadc-util/src/test/java/ca/nrc/cadc/util/RSASignatureGeneratorValidatorTest.java b/cadc-util/src/test/java/ca/nrc/cadc/util/RSASignatureGeneratorValidatorTest.java index 51a82a25..eb3ad148 100644 --- a/cadc-util/src/test/java/ca/nrc/cadc/util/RSASignatureGeneratorValidatorTest.java +++ b/cadc-util/src/test/java/ca/nrc/cadc/util/RSASignatureGeneratorValidatorTest.java @@ -83,19 +83,11 @@ public void testSignVerify() throws Exception { @Test public void testSignVerifyBytes() throws Exception { final String testString = "cadcauthtest1-" + new Date(); - KeyPairGenerator kpg; - try { - kpg = KeyPairGenerator.getInstance(RsaSignatureVerifier.KEY_ALGORITHM); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException( - "BUG: illegal key algorithm - " + RsaSignatureVerifier.KEY_ALGORITHM, e); - } int[] keyLengths = { 512, 1024, 2048, 4096 }; for (int len : keyLengths) { log.info("testSignVerifyBytes: " + len); - kpg.initialize(len); - KeyPair keyPair = kpg.genKeyPair(); + KeyPair keyPair = RsaSignatureGenerator.getKeyPair(len); RsaSignatureGenerator sg = new RsaSignatureGenerator(keyPair.getPrivate().getEncoded()); RsaSignatureVerifier sv = new RsaSignatureVerifier(keyPair.getPublic().getEncoded()); assertTrue("Signature does not work!!!!", From 3e3819967b692c7905e6e5bd1147ac8cd4cdf5b1 Mon Sep 17 00:00:00 2001 From: Adrian Damian Date: Tue, 12 Dec 2023 17:21:51 -0800 Subject: [PATCH 3/3] Re-work after code review --- .../src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java b/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java index c55376c9..69f1c026 100644 --- a/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java +++ b/cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java @@ -92,7 +92,7 @@ * This class is used to verify signed messages. The class requires * an RSA public key to verify a message. * - *

The keys are passed to the class via a file or as a binary array. + *

The keys are passed to the class via a file or as in-memory byte array. * *

Format of the keys: * Public keys in the keys file must be in PEM TKCS#1These keys are