Skip to content

Commit

Permalink
Merge pull request #236 from andamian/CADC-12974
Browse files Browse the repository at this point in the history
Instantiate RSASignatureGenerator and RSASignatureValidator with in m… (CADC-12974)
  • Loading branch information
pdowler authored Dec 13, 2023
2 parents 346a639 + 3e38199 commit bc5d642
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 93 deletions.
2 changes: 1 addition & 1 deletion cadc-util/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
125 changes: 68 additions & 57 deletions cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
* <p>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.
* <p>The key is passed to the class via a file or as a binary array.
*
* <p>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-----".
Expand Down Expand Up @@ -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);
}
}

/**
Expand Down Expand Up @@ -288,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());
Expand All @@ -323,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;
}
}
82 changes: 47 additions & 35 deletions cadc-util/src/main/java/ca/nrc/cadc/util/RsaSignatureVerifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,7 @@
* This class is used to verify signed messages. The class requires
* an RSA public key to verify a message.
*
* <p>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.
* <p>The keys are passed to the class via a file or as in-memory byte array.
*
* <p>Format of the keys:
* Public keys in the keys file must be in PEM TKCS#1These keys are
Expand Down Expand Up @@ -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.
*
Expand All @@ -165,6 +163,16 @@ 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
Expand All @@ -183,7 +191,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()) {
Expand All @@ -198,68 +206,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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -77,6 +80,22 @@ public void testSignVerify() throws Exception {
}
}

@Test
public void testSignVerifyBytes() throws Exception {
final String testString = "cadcauthtest1-" + new Date();
int[] keyLengths = { 512, 1024, 2048, 4096 };
for (int len : keyLengths) {
log.info("testSignVerifyBytes: " + len);

KeyPair keyPair = RsaSignatureGenerator.getKeyPair(len);
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();
Expand Down

0 comments on commit bc5d642

Please sign in to comment.