数字签名的实现

RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成的。

RSA是目前最有影响力的公钥加密算法,它能够抵抗到目前为止已知的绝大多数密码攻击,已被ISO推荐为公钥数据加密算法。

RSA算法是一种非对称密码算法,所谓非对称,就是指该算法需要一对密钥,使用其中一个加密,则需要用另一个才能解密。

关于RSA算法的原理,这里就不再详加介绍,网上各种资源一大堆。下面就开始介绍RSA加密解密JAVA类的具体实现。

import java.security.MessageDigest;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class Coder {

    public static final String KEY_SHA="SHA";
    public static final String KEY_MD5="MD5";

    /**
     * BASE64解密
     * @param key
     * @return
     * @throws Exception
     */
    public static byte[] decryptBASE64(String key) throws Exception{
        return (new BASE64Decoder()).decodeBuffer(key);
    }

    /**
     * BASE64加密
     * @param key
     * @return
     * @throws Exception
     */
    public static String encryptBASE64(byte[] key)throws Exception{
        return (new BASE64Encoder()).encodeBuffer(key);
    }

    /**
     * MD5加密
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] encryptMD5(byte[] data)throws Exception{
        MessageDigest md5 = MessageDigest.getInstance(KEY_MD5);
        md5.update(data);
        return md5.digest();
    }

    /**
     * SHA加密
     * @param data
     * @return
     * @throws Exception
     */
    public static byte[] encryptSHA(byte[] data)throws Exception{
        MessageDigest sha = MessageDigest.getInstance(KEY_SHA);
        sha.update(data);
        return sha.digest();
    }
}

  先提供Coder编码类,该类封装了基本的Base64、md5和SHA加密解密算法。Java对这些算法的实现提供了很好的API封装,开发人员只需调用这些API就可很简单方便的实现数据的加密与解密。

下面提供RSA加密解密类,该类为Coder类子类,因为其中对RSA公私密钥的保存进行了一层Base64加密处理。

RSA加密解密类静态常量

    public static final String KEY_ALGORTHM="RSA";//
    public static final String SIGNATURE_ALGORITHM="MD5withRSA";

    public static final String PUBLIC_KEY = "RSAPublicKey";//公钥  public static final String PRIVATE_KEY = "RSAPrivateKey";//私钥

RSA加密解密的实现,需要有一对公私密钥,公私密钥的初始化如下:

/**
     * 初始化密钥
     * @return
     * @throws Exception
     */
    public static Map<String,Object> initKey()throws Exception{
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORTHM);
        keyPairGenerator.initialize(1024);
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        //公钥
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
        //私钥
        RSAPrivateKey privateKey =  (RSAPrivateKey) keyPair.getPrivate();

        Map<String,Object> keyMap = new HashMap<String, Object>(2);
        keyMap.put(PUBLIC_KEY, publicKey);
        keyMap.put(PRIVATE_KEY, privateKey);

        return keyMap;
    }

从代码中可以看出密钥的初始化长度为1024位,密钥的长度越长,安全性就越好,但是加密解密所用的时间就会越多。而一次能加密的密文长度也与密钥的长度成正比。一次能加密的密文长度为:密钥的长度/8-11。所以1024bit长度的密钥一次可以加密的密文为1024/8-11=117bit。所以非对称加密一般都用于加密对称加密算法的密钥,而不是直接加密内容。对于小文件可以使用RSA加密,但加密过程仍可能会使用分段加密。

从map中获取公钥、私钥

/**
     * 取得公钥,并转化为String类型
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPublicKey(Map<String, Object> keyMap)throws Exception{
        Key key = (Key) keyMap.get(PUBLIC_KEY);
        return encryptBASE64(key.getEncoded());
    }

    /**
     * 取得私钥,并转化为String类型
     * @param keyMap
     * @return
     * @throws Exception
     */
    public static String getPrivateKey(Map<String, Object> keyMap) throws Exception{
        Key key = (Key) keyMap.get(PRIVATE_KEY);
        return encryptBASE64(key.getEncoded());
    }

对于RSA产生的公钥、私钥,我们可以有两种方式可以对信息进行加密解密。私钥加密-公钥解密 和 公钥加密-私钥解密。

私钥加密

/**
     * 用私钥加密
     * @param data    加密数据
     * @param key    密钥
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPrivateKey(byte[] data,String key)throws Exception{
        //解密密钥
        byte[] keyBytes = decryptBASE64(key);
        //取私钥
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);

        //对数据加密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, privateKey);

        return cipher.doFinal(data);
    }

私钥解密

/**
     * 用私钥解密 * @param data     加密数据
     * @param key    密钥
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPrivateKey(byte[] data,String key)throws Exception{
        //对私钥解密
        byte[] keyBytes = decryptBASE64(key);

        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        //对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);

        return cipher.doFinal(data);
    }

公钥加密

/**
     * 用公钥加密
     * @param data    加密数据
     * @param key    密钥
     * @return
     * @throws Exception
     */
    public static byte[] encryptByPublicKey(byte[] data,String key)throws Exception{
        //对公钥解密
        byte[] keyBytes = decryptBASE64(key);
        //取公钥
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
        Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        //对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);

        return cipher.doFinal(data);
    }

公钥解密

/**
     * 用公钥解密
     * @param data    加密数据
     * @param key    密钥
     * @return
     * @throws Exception
     */
    public static byte[] decryptByPublicKey(byte[] data,String key)throws Exception{
        //对私钥解密
        byte[] keyBytes = decryptBASE64(key);
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
        Key publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        //对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, publicKey);

        return cipher.doFinal(data);
    }

关于数字签名,先了解下何为数字签名。数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。数字签名是非对称密钥加密技术与数字摘要技术的应用。简单地说,所谓数字签名就是附加在数据单元上的一些数据,或是对数据单元所作的密码变换。这种数据或变换允许数据单元的接收者用以确认数据单元的来源和数据单元的完整性并保护数据,防止被人(例如接收者)进行伪造。

数字签名的主要功能如下:

保证信息传输的完整性、发送者的身份认证、防止交易中的抵赖发生。

数字签名技术是将摘要信息用发送者的私钥加密,与原文一起传送给接收者。接收者只有用发送者的公钥才能解密被加密的摘要信息,然后用对收到的原文产生一个摘要信息,与解密的摘要信息对比。如果相同,则说明收到的信息是完整的,在传输过程中没有被修改,否则说明信息被修改过,因此数字签名能够验证信息的完整性。

数字签名是个加密的过程,数字签名验证是个解密的过程。

数字签名算法依靠公钥加密技术来实现的。在公钥加密技术里,每一个使用者有一对密钥:一把公钥和一把私钥。公钥可以自由发布,但私钥则秘密保存;还有一个要求就是要让通过公钥推算出私钥的做法不可能实现。

普通的数字签名算法包括三种算法:

  1.密码生成算法;

  2.标记算法;

  3.验证算法。

通过RSA加密解密算法,我们可以实现数字签名的功能。我们可以用私钥对信息生成数字签名,再用公钥来校验数字签名,当然也可以反过来公钥签名,私钥校验。

私钥签名

/**
     *    用私钥对信息生成数字签名
     * @param data    //加密数据
     * @param privateKey    //私钥
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data,String privateKey)throws Exception{
        //解密私钥
        byte[] keyBytes = decryptBASE64(privateKey);
        //构造PKCS8EncodedKeySpec对象
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        //指定加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
        //取私钥匙对象
        PrivateKey privateKey2 = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
        //用私钥对信息生成数字签名
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(privateKey2);
        signature.update(data);

        return encryptBASE64(signature.sign());
    }

公钥校验

/**
     * 校验数字签名
     * @param data    加密数据
     * @param publicKey    公钥
     * @param sign    数字签名
     * @return
     * @throws Exception
     */
    public static boolean verify(byte[] data,String publicKey,String sign)throws Exception{
        //解密公钥
        byte[] keyBytes = decryptBASE64(publicKey);
        //构造X509EncodedKeySpec对象
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
        //指定加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORTHM);
        //取公钥匙对象
        PublicKey publicKey2 = keyFactory.generatePublic(x509EncodedKeySpec);

        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(publicKey2);
        signature.update(data);
        //验证签名是否正常
        return signature.verify(decryptBASE64(sign));

    }
时间: 2024-11-08 05:35:46

数字签名的实现的相关文章

JDK自带方法实现RSA数字签名

JDK只支持MD2withRSA, MD5withRSA, SHA1withRSA 其他的如SHA512withRSA需要第三方包支持,如BC(bouncy castle) JDK的密钥长度默认仍是1024 1 package jdbc.pro.lin; 2 3 import java.security.InvalidKeyException; 4 import java.security.NoSuchAlgorithmException; 5 import java.security.Priv

密码学之《数字签名》

周六要考密码学了,恰逢身体不舒服,没心情看数字什么的,来整理整理数字签名的一点儿知识点~简简单单的几行文字,看官笑看即可~ 什么是数字签名?有毛用? 数字签名主要用于对数字消息进行签名,以防消息的冒名伪造或篡改,也可以用作通信双方的身份鉴别. 为什么数字签名有这样那样的作用? 数字签名有这样几个特性: 1. 可信.任何人都可以验证签名的有效性 2. 不可伪造.除了合法的签名者,任何其他人伪造签名是困难的. 3. 不可复制.对一个消息的签名不能通过复制变成另一个消息的签名,若是复制得到,任何人都能

https 单向双向认证说明_数字证书, 数字签名, SSL(TLS) , SASL

转自:https 单向双向认证说明_数字证书, 数字签名, SSL(TLS) , SASL 因为项目中要用到TLS + SASL 来做安全认证层. 所以看了一些网上的资料, 这里做一个总结. 1. 首先推荐几个文章: 数字证书: http://www.cnblogs.com/hyddd/archive/2009/01/07/1371292.html 数字证书和SSL: http://www.2cto.com/Article/201203/121534.html 数字签名: http://www.

公钥,私钥和数字签名这样最好理解

http://blog.csdn.net/21aspnet/article/details/7249401 一.公钥加密 假设一下,我找了两个数字,一个是1,一个是2.我喜欢2这个数字,就保留起来,不告诉你们(私钥),然后我告诉大家,1是我的公钥. 我有一个文件,不能让别人看,我就用1加密了.别人找到了这个文件,但是他不知道2就是解密的私钥啊,所以他解不开,只有我可以用数字2,就是我的私钥,来解密.这样我就可以保护数据了. 我的好朋友x用我的公钥1加密了字符a,加密后成了b,放在网上.别人偷到了

Java 数字签名原理及产生

数字签名与数字证书 关于数字签名的介绍可以参考以上这篇. 这里稍微说一下不对称加密的方式: 用公钥加密的内容只能用私钥解密,用私钥加密的内容只能用公钥解密. 这样比对称加密更安全 Java 中数字签名的方式 跟普通文本加密的原理是一样的. Java 数字签名和数字证书的作用 毋庸置疑,这些都是为了安全性而考虑的. 比如对于applet 来说,它可以保护用户(客户端) 文件和私人数据不被恶意的程序或病毒感染和破坏,鉴别代码提供者的身份.对于开发者而言,通过使用API方法,能够将安全性功能集成到应用

数字签名和数字证书到底是个神马玩意?

数字签名和数字证书到底是个神马玩意?通过以下图文有了更深的理解啊, (感谢阮一峰的翻译,转载了一篇好文章啊,感谢.) 1. 鲍勃有两把钥匙,一把是公钥,另一把是私钥. 2. 鲍勃把公钥送给他的朋友们----帕蒂.道格.苏珊----每人一把. 3. 苏珊要给鲍勃写一封保密的信.她写完后用鲍勃的公钥加密,就可以达到保密的效果. 4. 鲍勃收信后,用私钥解密,就看到了信件内容.这里要强调的是,只要鲍勃的私钥不泄露,这封信就是安全的,即使落在别人手里,也无法解密. 5. 鲍勃给苏珊回信,决定采用"数字签

密码学初级教程(五)数字签名 Digital Signature

密码学家工具箱中的6个重要的工具: 对称密码 公钥密码 单向散列函数 消息认证码 数字签名 伪随机数生成器 提问: 有了消息认证码为什么还要有数字签名? 因为消息认证码无法防止否认.消息认证码可以识别消息是否被篡改或者发送者身份是否被伪装.(消息认证码保证完整性.可以进行认证) 为什么消息认证码无法防止否认,数字签名就能够否认呢? 消息认证码中,能够计算出MAC值的密钥(共享密钥)是由发送者和接受者双方共同持有的,因此发送者和接受者中的任何一方都能够计算MAC值,发送者也就可以声称“这个MAC值

数字签名

转载请表明出处:http://www.cnblogs.com/oumi/p/6680520.html 最近在项目中遇到了这样的场景,暂定2人A和B,现在A通过接口提供了服务与B.假定AB属于跨平台开发环境,为了数据顺利的实现交互,并且确保数据不被中途非法拦截篡改,现在提出了数字签名的解决方案,具体如下: 解决方案:再次提出了数字签名的概念,所谓的数字签名在别处是怎么定义的暂且不讨论,那么在本问中将其定义为对需要的传输的数据按照某种规则转换为特定的字符串和签名密钥Key.以及身份唯一识别码进行组合

数字签名原理

9.5.3  数字签名原理 数字签名是一种确保数据完整性和原始性的方法.数字签名可以提供有力的证据,表明自从数据被签名以来数据尚未发生更改,并且它可以确认对数据签名的人或实体的身份.数字签名实现了“完整性”和“认可性”这两项重要的安全功能,而这是实施安全电子商务的基本要求. 当数据以明文或未加密形式分发时,通常使用数字签名.在这种情况下,由于消息本身的敏感性无法保证加密,因此必须确保数据仍然保持其原来的格式,并且不是 由冒名者发送的.因为在分布式计算环境中,网络上具有适当访问权的任何人,无论是否

USB学习笔记连载(十六):USB数字签名

转载:http://blog.chinaaet.com/crazybingo/p/34487 曾记得在最开始安装驱动程序的时候出现过这个错误....但是最近我在别的电脑安装的时候又不出现这个错误了...搞不清楚所以然..就拿出来吹吹牛逼....当时我是这样做的..... 至此,由于Win7数字证书问题,安装失败....蛋疼的要死掉..(这是3个月以前的事情了...),然后有人大神告诉我,通过相关设置让电脑降低层级,即使能PC 测试模式,如下: 重启后看到右下角的水印,略带不爽 ,重新打开dseo