I am developing a Java (JDK 1.8) application using standard (built in) DSA classes in order to verify digital signatures.
I have data files and the expected signatures stored in text files as shown below:
// Signature part R:
4226 3F05 F103 E3BE 59BF 3903 37F8 0375 8802 5D8F.
// Signature part S:
AF21 15B0 16E4 1761 75B8 C7D4 F877 5AB7 26BB AE72.
Note that the signature is expressed in the form of (R,S) pair as described in the FIPS 186-3 NIST Standard.
In order to verify the signature I am calling the method verify(byte[] signature) from java.security.Signature. This method expects a byte array that represents the signature to be verified. However, I do not know how to convert the (R,S) pair into a byte array. Therefore I am not able to verify the signature.
So, I would like to know:
1) Is there a way of converting (R, S) pair into a DSA byte array signature as expected by the verify() method?; Or,
2) Is there a way of getting the R and S values from the Java Signature instance class so that I can compare these values to the ones I have?
Thanks in advance.
EDIT: the solution proposed by @dave_thompson_085 worked pretty well! See below the complete source code:
// read DSA parameters from file or other means
BigInteger r = new BigInteger(...);
BigInteger s = new BigInteger(...);
BigInteger p = new BigInteger(...);
BigInteger q = new BigInteger(...);
BigInteger g = new BigInteger(...);
BigInteger y = new BigInteger(...);
// get the public key
KeySpec publicKeySpec = new DSAPublicKeySpec(y, p, q, g);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
// read the input file to be checked and update signature
Signature signature = Signature.getInstance("SHA1withDSA");
signature.initVerify(publicKey);
File inputFile = new File(...);
try (BufferedInputStream is = new BufferedInputStream(new FileInputStream(inputFile))) {
byte[] buffer = new byte[1024];
while (is.available() != 0) {
int len = is.read(buffer);
signature.update(buffer, 0, len);
}
}
// convert (r, s) to ASN.1 DER encoding
// assuming you have r and s as !!positive!! BigIntegers
// (if you have unsigned byte[] as shown in your Q,
// use BigInteger r = new BigInteger (1, bytes) etc.
byte[] rb = r.toByteArray();
byte[] sb = s.toByteArray(); // sign-padded if necessary
// these lines are more verbose than necessary to show the structure
// compiler will fold or you can do so yourself
int off = (2 + 2) + rb.length;
int tot = off + (2 - 2) + sb.length;
byte[] der = new byte[tot + 2];
der[0] = 0x30;
der[1] = (byte) (tot & 0xff);
der[2 + 0] = 0x02;
der[2 + 1] = (byte) (rb.length & 0xff);
System.arraycopy(rb, 0, der, 2 + 2, rb.length);
der[off + 0] = 0x02;
der[off + 1] = (byte) (sb.length & 0xff);
System.arraycopy(sb, 0, der, off + 2, sb.length);
// verifies if the signature is valid
boolean isValid = signature.verify(des);