上期谈了关于数字签名的原理以及作用方式,接下来我们接聊一下数字签名在使用中的具体方式以及步骤和一些要关注的问题。当然通过数字签名的第一步就是生成一对密钥对,包括一个公钥和一个私钥,具体的代码如下所示(注意这种方式的公钥和私钥的生成需要依赖1.5以上的JDK,但是如果在1.4JDK的环境下可以通过修改JDK的配置,并添加进新的Jar包也可以使用)
<pre name="code" class="java">
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); //创建‘密匙对’生成器
kpg.initialize(2048); //指定密匙长度(取值范围:512~2048)
KeyPair kp = kpg.genKeyPair(); //生成‘密匙对’,其中包含着一个公匙和一个私匙的信息
PublicKey public_key = kp.getPublic(); //获得公匙
PrivateKey private_key = kp.getPrivate(); //获得私匙
// 输出公匙
System.out.println("public key:");
String publicKey = Base64.encode(public_key.getEncoded());
System.out.println(publicKey);
// 输出私匙
System.out.println("private key:");
String privateKey = Base64.encode(private_key.getEncoded());
System.out.println(privateKey);
接下来就是如何对于我们所得到的公钥和私钥进行应用了。
以下的部分是我们进行签名的生成的方法其中的PRIVATEKEYT是之前我方直接生成的私钥
大部分步骤为JDK提供的相关方法的标准执行步骤,直接照抄即可
</pre><p><span style="background-color: rgb(240, 240, 240);"> //对于数据进行转码 将原来的输入String直接转码为我们需要的String</span></p><p></p><pre name="code" class="java">
byte[] text = Base64.encode(organString.getBytes("UTF-8"))
.replaceAll("\n", "").replaceAll("\r", "").getBytes();
//首先要解码
byte[] privateKeyBytes = Base64.decode(PRIVATEKEY);
//将编码好的私钥创建对象
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
Signature signatureChecker = Signature.getInstance(ALGORITHM);
signatureChecker.initSign(privateKey);
signatureChecker.update(text);
return Base64.encode(signatureChecker.sign());
当然我们不光只要对于报文进行签名,我们还要对于受到的报文以及签名有一个正确的验证
public static boolean verify(String inData, String inSign)
throws Exception {
if(inData == null || "".equals(inData) ||inSign == null||"".equals(inSign)){
return false;
}
//对于数据进行转码 将原来的输入String直接转码为我们需要的String
byte[] text = Base64.encode(inData.getBytes()).replaceAll("\n", "")
.replaceAll("\r", "").getBytes();
//首先要编码
byte[] publicKeyBytes = Base64.decode(PUBLICKEY);
byte[] signedText = Base64.decode(inSign);
//将编码好的私钥创建对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKeyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Signature signatureChecker = Signature.getInstance(ALGORITHM);
signatureChecker.initVerify(publicKey);
signatureChecker.update(text);
return signatureChecker.verify(signedText);
}
这里我们要重点注意几个问题当时在调试的时候经过了很大的麻烦
1)报文的回车和空格的问题:在我们的这种方式的处理报文的时候(我当时使用的XML)免不了出现换行和空格的情况,双方交互的时候应该约定好将所有空格和回车进行处理之后再进行加密的验证
2)报文中的中文乱码问题:有时候就是不能通过验证的原因,在实际调试中也许这个就会浪费不少的调试时间,所以如果在调试中报文出现中文的话,先要试着能不能先使用不含中文的报文进行调试
3)转码的次数问题:在有时候调试的时候会遇见到由于使用encode64导致的前后次数不对称的问题,所以这里首先要得到确保,不然调试的过程都会白费