一、数字签名简介
数字签名是指使用密码算法,对待发的数据(报文或票证等)进行加密处理,生成一段数据摘要信息附在原文上一起发送。这种信息类似于现实中的签名或印章,接收方对其进行验证,判断原文真伪。数字签名可以提供完整性保护和不可否认服务。其中,完整性保护主要针对解决篡改问题,不可否认服务主要针对解决抵赖性问题。
数字签名系统有两个基本组件:公用密钥加密和哈希算法(即安全散列函数)。
二、数字签名的过程
在数字签名方面,目前应用比较广泛的是利用RSA计算签名和数字签名标准DSS。其中,利用RSA方法进行数字签名得到了广泛的应用。该方法的过程如下:
1:要签名的报文作为一个散列函数的输入,产生一个定长的安全散列码,一般称为消息摘要。 2:使用发方的私有密钥对这个消息摘要进行加密就形成签名。将报文和签名传送出去。 3:收方接受报文并根据报文产生一个消息摘要,同时使用发方的公开密钥对签名进行解密。 4:如果计算得出的消息摘要和解密后的签名互相匹配,那么签名就是有效的。 5:因为只有发方知道密钥,因此只有发方才能产生有效的签名。
数字签名算法一般分为两个步骤:产生消息摘要和生成数字签名。 首先,系统根据一定的单向加密算法计算出消息的消息摘要。
使用单向散列函数的目的是将任意长度的消息压缩成为某一固定长度的消息摘要。单向散列函数又称为单向Hash函数,它不是加密算法,却在密码学中有着广泛的应用,与各种加密算法有着密切的关系。具体的数学模型不关心,交由专业人士去研究吧。
三、数字签名的实现
采用RSA算法进行数据签名:
3.1 生成密钥对(采用的是apache的commons-codec的Base64算法)
public void generater() { try { Base64 base64 = new Base64(); //采用RSA算法获取密钥对生成器 KeyPairGenerator keygen = KeyPairGenerator .getInstance("RSA"); // 初始化随机产生器 SecureRandom secrand = new SecureRandom(); secrand.setSeed("daidetian".getBytes()); keygen.initialize(1024, secrand); //返回一个密钥对 KeyPair keys = keygen.genKeyPair(); //提取公钥 PublicKey pubkey = keys.getPublic(); //提取私钥 PrivateKey prikey = keys.getPrivate(); pubKey = base64.encodeToString(pubkey.getEncoded()); priKey = base64.encodeToString(prikey.getEncoded()); System.out.println("pubKey = " + new String(pubKey)); System.out.println("priKey = " + new String(priKey)); } catch (java.lang.Exception e) { System.out.println("生成密钥对失败"); e.printStackTrace(); } }
3.2 对数据签名
public static byte[] sign(byte[] prikeyText,String plainText){ try { Base64 base64 = new Base64(); PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(base64.decode(prikeyText)); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PrivateKey priKey = keyFactory.generatePrivate(priPKCS8); //实例化Signature,具体算法不懂 Signature signature = Signature.getInstance("MD5withRSA"); signature.initSign(priKey); signature.update(plainText.getBytes()); //获取签名 String signed = base64.encodeToString(signature.sign()); return signed.getBytes(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeySpecException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (SignatureException e) { e.printStackTrace(); } return null;}
3.3 验证签名
public static boolean verify(byte[] pubKeyText,String plainText,byte[] signText){ try { //采用X509标准 X509EncodedKeySpec bobPubKeySepc = new X509EncodedKeySpec(Base64.decode(pubKeyText)); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); PublicKey pubKey = keyFactory.generatePublic(bobPubKeySepc); byte[] signed = Base64.decode(signText); Signature signaturerChecker = Signature.getInstance("MD5withRSA"); signaturerChecker.initVerify(pubKey); signaturerChecker.update(plainText.getBytes()); //验证签名 if(signaturerChecker.verify(signed)){ return true; } else { return false; } } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (InvalidKeySpecException e) { e.printStackTrace(); } catch (InvalidKeyException e) { e.printStackTrace(); } catch (SignatureException e) { e.printStackTrace(); } return false;}
四、应用场景
4.1 解决篡改问题
篡改指内容被敌方人恶意修改或者删除之后用恶意内容伪装,使得收方得到的内容不是来自发方的原有内容。信息篡改属于主动攻击的一种。在用户发出信息的过程之中,敌方可能会对用户发出的信息进行修改或者删除,让对方得到的不是原有的信息。比如在发送方给接收方发出某个命令的时候敌方可能会将命令进行修改,改成其他的命令,让接收方做出一些对双方交易有害的事情。
篡改无法完全避免,但为安全起见,我们必须能够判断一段消息是否被篡改。当得知信息被篡改时,能够作出丢弃的决定。
可以通过数字签名方法来避免篡改。一般思路如下:
1:将信息生成数字签名,并将数字签名用接收方的公钥加密。
2:接收方用自己的私钥解密数字签名,然后将消息再生成一次签名,将两个签名作比较,得出结论。
4.2 解决抵赖问题
抵赖指以下两种情况,一是收方收到信息,然后否认收到发过来的信息;另一种是发方发送有害信息,然后否认发送过该信息。抵赖问题也是网络安全中的一个重要问题。此活动属于主动攻击的一种,它的特点主要体现在发送方和接收方中有一方充当敌方的角色。这个活动和篡改活动的区别就在于,焦点集中在知道敌方身份的情况下,怎样用证据证明它曾经对网络安全进行过攻击。这种活动主要表现在:当发送方充当敌方时,发送方传输给接收方一个信息,然后否认传送过此信息,如某恶意发送方向另一方传输一个消息,该消息中包含了一些重大举措,当接收方执行这些举措之后,对自己造成了巨大的伤害,追究发送方的责任,但发送方否认发过此信息;当接收方充当敌方的时候,收到了发送方法送过来的信息,但否认此消息来自于发送方,如发送方向接收方发送了网上银行的一些转账手续,接收方接受了转账之后,却声称自己从来没有收到这个信息。使得发送方的利益受到损害。
与篡改问题相较,区别在于先验明正身,再将操作信息进行存储。