文章内容
一、历史背景
父辈或更早的前辈们经常会有一个印戳,上面刻有名字等证明身份的图案,每次办事的时候经常会使用这个戳去盖而不是手写签名。

到后来这方方式逐渐被淘汰掉了,改成了手写签名。为什么会被淘汰?主要原因是这样的形式的戳比较容易被伪造,只要找到刻章工匠们就可以做出一模一样的戳且无法辨认真实性。使用手写签名之后安全性和不可抵赖性得到了提高。

二、数字签名
- 定义:带有密钥(公钥、私钥)的消息摘要算法
- 作用:验证数据完整性、认证数据来源、不可抵赖
- 说明:遵循使用私钥进行签名,使用公钥对签名的数据进行验证的规则。
- 常用的数字签名算法有:RSA、DSA、ECDSA
三、算法举例
1、MD5withRSA
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | import java.security.*; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; /** * RMD5withRSA数字签名使用例子 * 签名,验签 public class MD5withRSADemo { private static final char[] HEXES = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; /** * byte数组 转换成 16进制小写字符串 */ public static String bytes2Hex( byte [] bytes) { if (bytes == null || bytes.length == 0 ) { return null ; } StringBuilder hex = new StringBuilder(); for ( byte b : bytes) { hex.append(HEXES[(b >> 4 ) & 0x0F ]); hex.append(HEXES[b & 0x0F ]); } return hex.toString(); } public static void main(String[] args) throws Exception { // 加密字符串 String src = "EasyJava" ; KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "RSA" ); keyPairGenerator.initialize( 512 ); KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 初始化公钥和私钥 RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic(); RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate(); System.out.println( "公钥:" + Base64.getEncoder().encodeToString(rsaPublicKey.getEncoded())); System.out.println( "私钥:" + Base64.getEncoder().encodeToString(rsaPrivateKey.getEncoded())); // 私钥签名 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance( "RSA" ); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); Signature signature = Signature.getInstance( "MD5withRSA" ); signature.initSign(privateKey); signature.update(src.getBytes( "utf-8" )); byte [] signResult = signature.sign(); System.out.println( "签名结果:" + bytes2Hex(signResult)); // 公钥验证 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded()); keyFactory = KeyFactory.getInstance( "RSA" ); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); signature = Signature.getInstance( "MD5withRSA" ); signature.initVerify(publicKey); signature.update(src.getBytes()); boolean verifyResult = signature.verify(signResult); System.out.println( "验证结果:" + verifyResult); } } |
执行结果:
1 2 3 4 | 公钥:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAINcPA9dHlPQn17iMwTPJxU5Hyd/OecYjW8NLP8GH5e0hpfax51JWQV9C5sKBzahjR5/49hVv3GbGoqYg2NVGLcCAwEAAQ== 私钥:MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAg1w8D10eU9CfXuIzBM8nFTkfJ3855xiNbw0s/wYfl7SGl9rHnUlZBX0LmwoHNqGNHn/j2FW/cZsaipiDY1UYtwIDAQABAkBT83J+7ygesMnpve6VOD7mFWePuoOq6coaGvWS1rsCHHbInY04kvZxlZBTf4Y69qAoVbjqGL0Dh6TouhWyyi6hAiEAwp88R0bHZlG3giz5iN5U1IgWdTk9NG3vcf9NkJSPv+0CIQCsyZQGsZn8pkBnOFPc675D4HqvYveLA0A6pVxqD+C+swIgDncVXNrW4TT7pbJADbswpOdEfAv4D5iILnniQve3w3UCIEeq6KIKIlO/5XCq1WYJxgZDYr/CbeiT9Z0dn4JCibavAiBJ+rwnhiHglwmh0jrpt9PgGkZ+6iy1gr6aHAxlu6jxpw== 签名结果:193cc28101b94bfd13564272d39d1eb53509d6bd621d2eae8a2be20b130663d4c7b1bab92ee0e7ebf7a1e5c2d4cf4ceb09ff7eb5ecc30adf8d51c9bc3909081f 验证结果:true |
2、SHA1withDSA
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | import java.security.*; import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; /** * SHA1withDSA数字签名使用例子 * 签名,验签 */ public class SHA1withDSADemo { private static final char [] HEXES = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' }; /** * byte数组 转换成 16进制小写字符串 */ public static String bytes2Hex( byte [] bytes) { if (bytes == null || bytes.length == 0 ) { return null ; } StringBuilder hex = new StringBuilder(); for ( byte b : bytes) { hex.append(HEXES[(b >> 4 ) & 0x0F ]); hex.append(HEXES[b & 0x0F ]); } return hex.toString(); } public static void main(String[] args) throws Exception { // 加密字符串 String src = "EasyJava" ; KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "DSA" ); keyPairGenerator.initialize( 512 ); KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 初始化公钥和私钥 DSAPublicKey dsaPublicKey = (DSAPublicKey) keyPair.getPublic(); DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) keyPair.getPrivate(); System.out.println( "公钥:" + Base64.getEncoder().encodeToString(dsaPublicKey.getEncoded())); System.out.println( "私钥:" + Base64.getEncoder().encodeToString(dsaPrivateKey.getEncoded())); // 私钥签名 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(dsaPrivateKey.getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance( "DSA" ); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); Signature signature = Signature.getInstance( "SHA1withDSA" ); signature.initSign(privateKey); signature.update(src.getBytes()); byte [] signResult = signature.sign(); System.out.println( "签名结果:" + bytes2Hex(signResult)); // 公钥验证 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(dsaPublicKey.getEncoded()); keyFactory = KeyFactory.getInstance( "DSA" ); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); signature = Signature.getInstance( "SHA1withDSA" ); signature.initVerify(publicKey); signature.update(src.getBytes()); boolean verifyResult = signature.verify(signResult); System.out.println( "验证结果:" + verifyResult); } } |
执行结果:
1 2 3 4 | 公钥:MIHxMIGoBgcqhkjOOAQBMIGcAkEA/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0ImbzRMqzVDZkVG9xD7nN1kuFwIVAJYu3cw2nLqOuyYO5rahJtk0bjjFAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykA0QAAkEAztIwIQWBN9CKDdDaf2o/nQxgcfnTXMKZnzCbWpPS0SVoJ4PPVm2KivFqv/vbJYQuQpg3rNlaMbXmf0mtodI4iQ== 私钥:MIHGAgEAMIGoBgcqhkjOOAQBMIGcAkEA/KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0ImbzRMqzVDZkVG9xD7nN1kuFwIVAJYu3cw2nLqOuyYO5rahJtk0bjjFAkBnhHGyepz0TukaScUUfbGpqvJE8FpDTWSGkx0tFCcbnjUDC3H9c9oXkGmzLik1Yw4cIGI1TQ2iCmxBblC+eUykBBYCFGfMn8teKDz6Tvj356ARoniYW4RB 签名结果:302c0214110c199ba3e2aeb580e7b83c54c7b658601f34060214155e9e33c96d93e701639dbbd9247adc949aeb7e 验证结果:true |
3、SHA1withECDSA
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | import java.security.*; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; /** * SHA1withECDSA数字签名使用例子 * 签名,验签 */ public class SHA1withECDSADemo { private static final char [] HEXES = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' }; /** * byte数组 转换成 16进制小写字符串 */ public static String bytes2Hex( byte [] bytes) { if (bytes == null || bytes.length == 0 ) { return null ; } StringBuilder hex = new StringBuilder(); for ( byte b : bytes) { hex.append(HEXES[(b >> 4 ) & 0x0F ]); hex.append(HEXES[b & 0x0F ]); } return hex.toString(); } public static void main(String[] args) throws Exception { // 加密字符串 String src = "EasyJava" ; KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance( "EC" ); keyPairGenerator.initialize( 256 ); KeyPair keyPair = keyPairGenerator.generateKeyPair(); // 初始化公钥和私钥 ECPublicKey ecPublicKey = (ECPublicKey) keyPair.getPublic(); ECPrivateKey ecPrivateKey = (ECPrivateKey) keyPair.getPrivate(); System.out.println( "公钥:" + Base64.getEncoder().encodeToString(ecPublicKey.getEncoded())); System.out.println( "私钥:" + Base64.getEncoder().encodeToString(ecPrivateKey.getEncoded())); // 私钥签名 PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(ecPrivateKey.getEncoded()); KeyFactory keyFactory = KeyFactory.getInstance( "EC" ); PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec); Signature signature = Signature.getInstance( "SHA1withECDSA" ); signature.initSign(privateKey); signature.update(src.getBytes()); byte [] signResult = signature.sign(); System.out.println( "签名结果:" + bytes2Hex(signResult)); // 公钥验证 X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(ecPublicKey.getEncoded()); keyFactory = KeyFactory.getInstance( "EC" ); PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec); signature = Signature.getInstance( "SHA1withECDSA" ); signature.initVerify(publicKey); signature.update(src.getBytes()); boolean verifyResult = signature.verify(signResult); System.out.println( "验证结果:" + verifyResult); } } |
执行结果:
1 2 3 4 | 公钥:MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEMz4FvvFpr8sIOVJE6BbloaLAMMBfUppeTEuH4KNjkAwV5I5yrkSRz9c4AU6LhqSiKn5teMzOfFqDzI+0Jkx4qA== 私钥:MEECAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQcEJzAlAgEBBCDwwpzQDrwSTAsAtvDI0RnRpWXGu+MzMPFMkoHpD0EDsA== 签名结果:3045022100bdd946f1748a90c9e0241a804b1f75f065d06426d1a7e374003691128c6924db022013eb70b7e0b4fb8d5e104ba954305c339c59234d9e0acc6c27cb7010b384416e 验证结果:true |