Trying to code signature verification using Sun JCE with test vectors from the CAVP program.
i'm given public key exponent, and modulus, as well as the message and signature. I do the following:
private static boolean verifySignature(String algo, PrintStream oPS, byte[] message, byte[] modulus, byte[] exponent, byte[] sigBytes, int saltlen) throws Exception
{
Signature sig = Signature.getInstance(algo);
KeyFactory keyMaker = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
new BigInteger(modulus),
new BigInteger(exponent));
RSAPublicKey pubKey = (RSAPublicKey)keyMaker.generatePublic(pubKeySpec);
System.out.println("algorithm is " + algo);
sig.initVerify(pubKey);
Utils.outputValue("n", modulus, modulus.length, System.out, false);
Utils.outputValue("e", exponent, exponent.length, System.out, false);
Utils.outputValue("Msg", message, message.length, System.out, false);
Utils.outputValue("S", sigBytes, sigBytes.length, System.out, false);
BigInteger Nvalue = pubKey.getPublicExponent();
Utils.outputValue("key value of n", Nvalue.toByteArray(), System.out, false);
BigInteger Evalue=pubKey.getModulus();
Utils.outputValue("key value of e", Evalue.toByteArray(), System.out, false);
sig.update(message);
if(sig.verify(sigBytes))
oPS.println("Result = P");
else
oPS.println("Result = F");
.
.
.
The algo is something like "SHA1withRSA", and i build the public key as shown. When i list the resulting modulus and exponent from the key itself, they have become reversed.
n = 009de541c71a95389d9e8619ea1d6e2c69ed6c703701e518351676022ab98395d6b35a38b024f92bce6dd1c5be9d51dffd1687d19dceee73f2c73e4436b955231255f6e3e360ba84462311e10e65932fe069bed2d42c5bf2f88141828bdad3796184870cb8cf3019da264e56b39eccf7224d43a1b98d788b40a4042aac790e946f
e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003
Msg = 64b13df4b008ccccd5ce146018481c2568bbe2b93ec658d1c7f4ad734592cd65b3be2be5a7c1be9a7d9f49cbb2ece0cf8ee0a8c406aede84e0121bd51829d6e083862ae5b282d92c19d3923f70616f565a55c2134572116f91a85ff5f4e6ad2e1d31c15c97f3266af19574241c4fd2a4143fb80cc2b9fa7b22df0239a1715c35
S = 5b4458f6aeff91c4699ee9bdf8757987fb8db229814a2992945ac53bcf19b9179e53cfed258726d205107ac000d41e570fe8c4fb321fc9b4b5469c60cd20032195f314ba6e6b0b30a51c9834242daa1ce525ec90380106568e782ea164baeda5d884defe6e720e9dd63618b823412445e17f991a6daa21bd62bdc73d7d8a20e5
key value of n = 03
key value of e = 009de541c71a95389d9e8619ea1d6e2c69ed6c703701e518351676022ab98395d6b35a38b024f92bce6dd1c5be9d51dffd1687d19dceee73f2c73e4436b955231255f6e3e360ba84462311e10e65932fe069bed2d42c5bf2f88141828bdad3796184870cb8cf3019da264e56b39eccf7224d43a1b98d788b40a4042aac790e946f
Some of these tests are supposed to fail, but some should succeed. None verify correctly... Any thought? Thanks.
Application is below, followed by one set of sample input.
package cavp.rsa;
import cavp.*;
import java.io.*;
import java.security.KeyFactory;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;
import java.security.PublicKey;
import java.util.Date;
import java.math.BigInteger;
public class RSASigVerify
{
private static boolean verboseFlag=false;
public static void main(String[] args) throws Exception
{
String requestFile;
String responseFile;
int saltLen=-1;
int argstart=0;
if(args.length < 2)
throw new Exception("missing parameters");
if(args.length == 3) {
if(args[0].equals("-saltlen")) {
saltLen=Integer.parseInt(args[1]);
if(saltLen < 0)
throw new Exception("bad -saltlen parameter ");
argstart=2;
} else {
if(args[0].equals("-x931")) {
saltLen=-2;
argstart=1;
}
} else {
if(args.length > 3)
throw new Exception("invalid invocation");
}
requestFile=args[argstart];
responseFile=args[argstart+1];
if(processFile(requestFile, responseFile, saltLen))
System.out.println("Failed to process file " + requestFile);
else
System.out.println("Processing complete for " + requestFile);
}
private static boolean processFile(String rqfn, String rspfn, int saltLen) throws Exception
{
File inFile = new File(rqfn), outFile = new File(rspfn);
if(!inFile.exists() || !inFile.isFile() || !inFile.canRead()) {
System.out.println("Bad input File " + rqfn);
return true;
}
FileReader inFR = new FileReader(inFile);
BufferedReader inBR = new BufferedReader(inFR);
PrintStream outPS = new PrintStream(outFile);
String input, keyword, value, digestType=null;
int p, v, q, i, lnum=0;
byte[] Msg=null, nBytes=null, eBytes=null, sigBytes=null;
boolean msgFound=false, nFound=false, eFound=false, sigFound=false;
try {
while((input = inBR.readLine()) != null ) {
lnum++;
if((p = input.indexOf('=')) < 0) {
outPS.println(input);
continue;
}
if(input.charAt(p-1) == ' ')
keyword=input.substring(0,p-1);
else
keyword=input.substring(0, p);
p++;
for(i=p; i
if(input.charAt(i) == ' ')
p++;
else
break;
}
if((v = input.indexOf('\n')) > 0) {
for(q=v-1; q>p+1; q--) {
if(input.charAt(q) != ' ')
break;
}
} else {
if((v = input.indexOf(' ', p)) > 0) {
q=v-1;
} else {
q=input.length();
}
}
value=input.substring(p,q);
if(keyword.indexOf("n") >= 0) {
nBytes=Utils.hexStringToByteArray(value);
if(nBytes.length <= 0) {
System.out.println("bad value for modulus");
return true;
}
nFound=true;
} else {
if(keyword.equals("e")) {
eBytes=Utils.hexStringToByteArray(value);
if(eBytes.length <= 0) {
System.out.println("bad value for private exponent");
return true;
}
eFound=true;
} else {
if(keyword.equals("SHAAlg")) {
if(!value.equals("SHA1") && !value.equals("SHA224") && !value.equals("SHA256") && !value.equals("SHA384") &&
!value.equals("SHA512")) {
System.out.println("Bad SHAAlg parameter " + input);
return true;
}
digestType=value + "withRSA";
} else {
if(keyword.equals("Msg")) {
if(msgFound) {
System.out.println("more than one Msg found");
return true;
} else
msgFound=true;
String tempMsg;
if((value.length() & 0x01) != 0) {
tempMsg="0" + value;
} else {
tempMsg=value;
}
Msg=Utils.hexStringToByteArray(tempMsg);
if(Msg.length <= 0) {
System.out.println("bad Msg parameter");
return true;
}
} else {
if(keyword.equals("S")) {
sigBytes=Utils.hexStringToByteArray(value);
if(sigBytes.length <= 0) {
System.out.println("bad signature parameter");
return true;
}
sigFound=true;
} else {
if(keyword.equals("Result")) {
continue;
}
}
}
}
}
}
outPS.println(input);
if(digestType != null && msgFound && nFound && eFound && sigFound) {
if(verifySignature(digestType, outPS, Msg, nBytes, eBytes, sigBytes, saltLen)) {
throw new Exception("error in digest generator");
}
msgFound=false;
eFound=false;
sigFound=false;
}
}
} catch( FileNotFoundException e) {
System.out.println("error processing file");
}
inFR.close();
outPS.close();
return false;
}
private static boolean verifySignature(String algo, PrintStream oPS, byte[] message, byte[] modulus, byte[] exponent, byte[] sigBytes, int saltlen) throws Exception
{
// yet to implement saltLen == -2 for X9.31 padding
// saltLen >= 0 for PSS Signatures
Signature sig = Signature.getInstance(algo);
KeyFactory keyMaker = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(
new BigInteger(modulus),
new BigInteger(exponent));
RSAPublicKey pubKey = (RSAPublicKey)keyMaker.generatePublic(pubKeySpec);
System.out.println("algorithm is " + algo);
sig.initVerify(pubKey);
sig.update(message);
if(sig.verify(sigBytes))
oPS.println("Result = P");
else
oPS.println("Result = F");
return false;
}
}
The following is one vector from the input:
# CAVS 11.5
# "SigVer PKCS#1 Ver 1.5" information for
# Mod sizes selected: 1024 2048
# SHA Algorithm selected:SHA1 SHA256
# Generated on Mon Nov 28 14:03:58 2011
[mod = 1024]
n = 9de541c71a95389d9e8619ea1d6e2c69ed6c703701e518351676022ab98395d6b35a38b024f92bce6dd1c5be9d>51dffd1687d19dceee73f2c73e4436b955231255f6e3e360ba84462311e10e65932fe069bed2d42c5bf2f88141>828bdad3796184870cb8cf3019da264e56b39eccf7224d43a1b98d788b40a4042aac790e946f
SHAAlg = SHA1
e = 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000>000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000>0000000000000000000000000000000000000000000000000000000000000000000000000003
Msg = 64b13df4b008ccccd5ce146018481c2568bbe2b93ec658d1c7f4ad734592cd65b3be2be5a7c1be9a7d9f49cbb2>ece0cf8ee0a8c406aede84e0121bd51829d6e083862ae5b282d92c19d3923f70616f565a55c2134572116f91a8>5ff5f4e6ad2e1d31c15c97f3266af19574241c4fd2a4143fb80cc2b9fa7b22df0239a1715c35
S = 5b4458f6aeff91c4699ee9bdf8757987fb8db229814a2992945ac53bcf19b9179e53cfed258726d205107ac000>d41e570fe8c4fb321fc9b4b5469c60cd20032195f314ba6e6b0b30a51c9834242daa1ce525ec90380106568e78>2ea164baeda5d884defe6e720e9dd63618b823412445e17f991a6daa21bd62bdc73d7d8a20e5*
Here is a vector file which should Pass:
# CAVS 11.5
# "SigVer PKCS#1 Ver 1.5" information for
# Mod sizes selected: 1024 2048
# SHA Algorithm selected:SHA1 SHA256
# Generated on Mon Nov 28 14:03:58 2011
[mod = 1024]
n = 9de541c71a95389d9e8619ea1d6e2c69ed6c703701e518351676022ab98395d6b35a38b024f92bce6dd1c5be9d51dffd1687d19dceee73f2c73e4436b955231255f6e3e360ba84462311e10e65932fe069bed2d42c5bf2f88141828bdad3796184870cb8cf3019da264e56b39eccf7224d43a1b98d788b40a4042aac790e946f
SHAAlg = SHA1
e = 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011
Msg = fe196459e8232a9f94e8c93d88ddae7d38be7a10e2dd03ffb7bb9be43bd59659eec006b12c78c9e652f6c6d3220073a369459b8adea95eb34ede7979f634c7d931b208275365e201d4f82582b18553b70fab605721e1b6ae4d097cdb8a49183b0d16f22524917bd862176fb1fc1357a2731751df732c13dafc662e72bfbb9067
S = 94af4ce7f323d1bf4904a673d2884e30a55a108c44e4eb2bfc0a0f061f46fefe23fe74c760e947bd1fbf1bb1a30d66b3d7dccfb425d3a6551dd444f90d4f06c3e0da6dc3c7a45e062b08d24553f0091acae47ffaae495e13da66308dd9e0be87e2b960ab823f83e55815b66a1076ab238cc3883cbf7312521d0988214bb07d96