java安全之数字签名及证书

来源:互联网 发布:淘宝怎么看直播 编辑:程序博客网 时间:2024/05/22 13:15

MD5/SHA的应用

消息摘要是一种算法:无论原始数据多长,消息摘要的结果都是固定长度的;原始数据任意bit位的变化,都会导致消息摘要的结果有很大的不同,且根据结果推算出原始数据的概率极低。消息摘要可以看作原始数据的指纹,指纹不同则原始数据不同。

数字摘要与MD5/SHA算法

ü  通用处理方式:调用MessageDigest对象的update和digest方法

ü  流数据的特殊处理: 使用DigestInputStream或DigestOutputStream包装MessageDigest对象,调用DigestInputStream的read方法或DigestOutputStream的write方法读写完数据并将流关闭后,再调用MessageDigest对象的digest方法,流中的数据就全被摘要处理了。

基于MAC(消息验证码)的数字摘要

ü  MAC,Message Authentication Code ,密钥被用作消息摘要生成过程的一部分。

ü  防止内容和摘要同时被篡改,在一定成都上起到了验证发送者身份。

ü  步骤: KeyGenerator.getInstanceàKeyGeneraotr.generateKey àMac.getInstance à Mac.init(secretyKey) à Mac.update à Mac.doFinal

 

JDK 1.4 支持 HMAC/SHA-1 和 HMAC/MD5 消息认证码算法。

MAC摘要的代码:

         privatestatic void MacDigest() throws Exception{

                   PBEKeySpeckeySpec = new PBEKeySpec("abcde".toCharArray());

                   SecretKeyFactorykeyFactory = SecretKeyFactory.getInstance("PBEWithMD5AndDES");

                   SecretKeykey = keyFactory.generateSecret(keySpec);

                  

                   Macmac = Mac.getInstance("HmacMD5");

                   mac.init(key);

                   byte[]source = new byte[]{1,2,3,5};                 

                   byte[]dest = mac.doFinal(source);

                   System.out.println(dest.length);

                   for(inti=0;i<dest.length;i++){

                            System.out.println(dest[i]+ ",");

                   }                          

         }

由于由于加密时所涉及的secretkey不好记忆和交换,上面的代码也演示了基于口令的加密方案,即使用口令来生成secretkey。

 

数字签名

 数字签名的基础是公钥和私钥的非对称加密,发送者使用私钥加密消息摘要(签名),接收者使用公钥解密消息摘要以验证签名是否是某个人的。

基本步骤:

•    得到keyPairGenerator的实例对象,并调用其generateKeyPair()方法创建KeyPair对象。

•    调用KeyPair对象的getPrivate和getPublic方法,分别得到PrivateKey对象和PublicKey对象。

•    得到Signature的实例对象,调用其initSign()方法和指定PrivateKey对象,然后调用update方法和sign方法产生签名

•    调用Signature对象的initVerify()方法和指定PublicKey对象,然后调用update方法和verify()方法对原始数据的签名进行验证。

扩展步骤:

•    把公钥和私钥分别保存为公钥文件和私钥文件,把公钥文件传递给对方,用私钥文件对其他文件进行签名后,再把其他文件和签名的结果文件传递给对方,让对方用公钥文件进行签名验证。

 

私钥就像一个人的笔迹或印章,是每个人独有的,同时又是人人可以检验的。使用私钥加密消息摘要,就像在文件上签名或盖章,确认了数据的身份。

代码1:

                   KeyPairGeneratorkeyPairGenerator = KeyPairGenerator.getInstance("RSA");

                   KeyPairkeyPair = keyPairGenerator.generateKeyPair();

                   PrivateKeyprivateKey = keyPair.getPrivate();

                   PublicKeypublicKey = keyPair.getPublic();

                           

                   Signaturesignature = Signature.getInstance("MD5withRSA");

                   signature.initSign(privateKey);

                   byte[]src = new byte[]{1,2,3,4,5,6,7,};

                   signature.update(src);

                   byte[]signed = signature.sign();

                  

                   signature.initVerify(publicKey);

                   signature.update(src);

                   System.out.println(

                   signature.verify(signed));

代码2:

         privatestatic void sign() throws Exception{

                   FileInputStreamfisPrivateKey = new FileInputStream("private.key");

                   ObjectInputStreamoisPrivateKey = new ObjectInputStream(fisPrivateKey);

                   PrivateKeyprivateKey = (PrivateKey)oisPrivateKey.readObject();

                   oisPrivateKey.close();

                   fisPrivateKey.close();

                  

                   Signaturesignature = Signature.getInstance("MD5withRSA");

                   signature.initSign(privateKey);

                   FileInputStreamfis = new FileInputStream("src.txt");

                   byte[]src = new byte[1024];

                   intlen = 0;

                   while((len=fis.read(src))!=-1){

                            signature.update(src,0,len);

                   }

                   fis.close();

                  

                   byte[]signed = signature.sign();

                   System.out.println(signed.length);

                   FileOutputStreamfos = new FileOutputStream("signed.dat");

                   fos.write(signed);

                   fos.close();

         }

        

         privatestatic void verify() throws Exception{

                   FileInputStreamfisPublicKey = new FileInputStream("public.key");

                   ObjectInputStreamoisPublicKey = new ObjectInputStream(fisPublicKey);

                   PublicKeypublicKey = (PublicKey)oisPublicKey.readObject();

                   oisPublicKey.close();

                   fisPublicKey.close();

                  

                   Signaturesignature = Signature.getInstance("MD5withRSA");

                   signature.initVerify(publicKey);

                   FileInputStreamfis = new FileInputStream("src.txt");

                   byte[]src = new byte[1024];

                   intlen = 0;

                   while((len=fis.read(src))!=-1){

                            signature.update(src,0,len);

                   }

                   fis.close();

                  

                   FileInputStreamfisSigned = new FileInputStream("signed.dat");

                   byte[]signed = new byte[fisSigned.available()];

                   intreaded =0;

                   inttotal = 0;

                   System.out.println(signed.length);

                           

                   while(total<signed.length){

                          //此方法的第三个参数len长度不能大于b.length- off,并且len等于0时直接返回,所以不能用while(readed!=-1)进行判断

                            readed= fisSigned.read(signed,total,signed.length-total);

                            total+= readed;

                   }

                  

                   fisSigned.close();

                   System.out.println(

                   signature.verify(signed));

         }

 

数字证书的创建与查看

l  按照默认方式创建证书

•    默认创建的keystore文件为用户主目录下的.keystore。

•    默认的key和证书的alias为mykey。

l  在默认存储位置创建指定alias名称的证书。

l  在指定的存储位置创建指定alias名称的证书。

l  显示keystore中的证书信息

•    显示所有证书的条目列表:keytool–list

•    显示某个证书的详细信息:keytool-list -v -alias zxx

l  将数字证书导出为文件

•    keytool -exportcert -alias zxx -file zxx.cer 

•    生成可打印的证书:keytool-exportcert -alias zxx -file zxx.cer –rfc

l  显示数字证书文件中的证书信息

•    keytool -printcert -file zxx.cer

•    直接双击zxx.cer,用window系统的内置程序打开zxx.cer

 

在jdk的keytool工具帮助页面中,搜索“keystore”和”cacerts”就可以知道key的默认存储位置和信任证书的存储位置。

  1. keytool -genkeypair  (java6修改了以前的一些命令选项,所以,不能完全按tomcat的ssl部分的文档来做,另外,在命令后可以指定选项,也可以不指定选项,一些选项不指定,会采用对应的默认值,有些选项没有默认值,则会提示输入)
  2. keytool -genkeypair -alias xxx 后面部分是为证书指定别名,否则采用默认的名称为mykey。
  3.  keytool -list 和keytool -list -v 看看keystore中有哪些项目。

在演示keytool时,先产生一个key,这时候要为新创建的keystore指定password,给大家看keystore文件的位置,然后再产生一个alias相同的key,这时候必须先指定keystore的密码,才能进入该keystore,进入后报告alias重名的错误,然后再产生另外一个alias的key。

 

针对数字证书的编程

在java程序中使用Certificate类来描述通用的数字证书,其子类X509Certificate则专用于描述X.509类别的数字证书,这两个类中最常用的方法如下:

•    getPublicKey()

•    getSignature()

•    getNotBefore()

•    getNotAfter()

•    getSigAlgName()

•    checkValidity(),只是验证证书的日期是否有效,不验证签发者的签名和权威性。

•    verify(),用证书签发者的公钥去验证证书上的签名是否有效。

直接根据证书文件获取Certificate对象的基本步骤:

•    得到CertificateFactory的实例对象。

•    调用CertificateFactory对象的generateCertificate()方法,并传入指向证书文件的InputStream流对象作为参数。

•    将得到的Certificate对象强转为X509Certificate类型,或者调用其toString方法()。

从keystore中提取Certificate对象的基本步骤:

•    得到KeyStore对象。

•    调用KeyStore对象的load()方法,并传入指向密钥库文件的InputStream流对象和代表密码的字符数组。

•    调用KeyStore对象的getCertificate()方法,并传入要获取的证书的alias名称。

•    将得到的Certificate对象强转为X509Certificate类型,或者调用其toString方法()。

 

看看KeyStore类的帮助文档,就知道怎样使用KeyStore对象了。

代码1:

         privatestatic void loadCertificateFromStore() throws Exception{

                   KeyStorekeyStore = KeyStore.getInstance("jks");

                   FileInputStreamfis = new FileInputStream("C:\\Documents andSettings\\IBM\\.keystore");

                   keyStore.load(fis,"123456".toCharArray());

                   fis.close();

                  

                   Certificatecert = keyStore.getCertificate("mykey");

                   System.out.println(cert.toString());

         }

        

         privatestatic void loadCertificateFromFile() throws Exception{

                   CertificateFactoryfactory = CertificateFactory.getInstance("X.509");

                   FileInputStreamfis = new FileInputStream("C:\\Java\\jdk1.6.0_21\\bin\\zxx1.cer");           

                   Certificatecert = factory.generateCertificate(fis);

                   fis.close();

                  

                   X509Certificatex509cert = (X509Certificate)cert;

                   System.out.println("公钥:" +x509cert.getPublicKey());

                   System.out.println("签名:" +x509cert.getSignature());

                   System.out.println("签名算法:" +x509cert.getSigAlgName());

                   System.out.println("类型:" +x509cert.getType());     

                   System.out.println("证书所有者:"+ x509cert.getSubjectDN());        

                   System.out.println("证书发布者:"+ x509cert.getIssuerDN());

                   System.out.println("证书起始有效日期:"+ x509cert.getNotBefore());   

                   System.out.println("证书终止有效日期:"+ x509cert.getNotAfter());               

                           

         }

 

keytool的其他应用

删除指定alias名称的证书。

修改keystore的密码。

改变某个证书的alias名称。

产生CSR(Certificate Signing Request)文件

•    介绍如何通过证书链来确保证书的可靠性

导入数字证书文件

•    增加受信任的证书项

•    导入被CA签过名的数字证书

对于证书链,必须先导入CA的证书后,才能导入被签名的证书。

 

和现实生活中一样,要有权威的机构检查证书中内容的真实性,然后再签发证书(在证书上盖章)。即权威机构(CA)用自己的私钥对证书进行数字签名,而这些CA 的公钥已经以证书的形式包含在许多操作系统中。 

 

直接执行keytool命令,就会显示出所有选项的提示信息,在jdk文档中看keytool的帮助信息更全面。

导入数字证书:

1.to add it to the list of trustedcertificates, or

2. to import a certificate reply receivedfrom a CA as the result of submitting a Certificate Signing Request (see the-certreq command) to that CA.

命令列表:

 

针对keystore的编程

KeyStore类中最常用的方法如下:

•    aliases()

•    store(),可用于修改整个keystore的口令

•    setKeyEntry(alias,privatekey,pass,chain),可用于修改原有key的密码

•    setCertificateEntry,用于保存trustedCertEntry

•    containsAlias()

•    deleteAlias()

•    getCertificate()

•    getCertificateChain()

数字证书的签发与校验:

•    属简单了解的知识

 

0 0
原创粉丝点击