您的位置:首页 > 编程语言 > Java开发

Java的安全学习(包括加密,数字签名,证书和认证)

2015-07-10 20:27 459 查看
转:http://blog.csdn.net/wbw1985/article/details/5506515

(1)消息摘要:

消息摘要(Message Digest)又称为数字摘要(Digital Digest)。它是一个唯一对应一个消息或文本的固定长度的值,它由一个单向Hash加密函数对消息进行作用而产生。如果消息在途中改变了,则接收者通过对收到消息的新产生的摘要与原摘要比较,就可知道消息是否被改变了。因此消息摘要保证了消息的完整性。
消息摘要采用单向Hash 函数将需加密的明文"摘要"成一串128bit的密文,这一串密文亦称为数字指纹(Finger Print),它有固定的长度,且不同的明文摘要成密文,其结果总是不同的,而同样的明文其摘要必定一致。这样这串摘要便可成为验证明文是否是"真身"的"指纹"了。

这是一种与消息认证码结合使用以确保消息完整性的技术。主要使用单向散列函数算法,可用于检验消息的完整性,和通过散列密码直接以文本形式保存等,目前广泛使用的算法有MD4、MD5、SHA-1,在java中进行消息摘要很简单:下面举一个简单的例子

/**

*MessageDigestTest.java

*/

import java.security.MessageDigest;

/**

*单一的消息摘要算法,不使用密码.可以用来对明文消息(如:密码)隐藏保存

*/

public class MessageDigestTest{

 public static void main(String[] args) throws Exception{

  String str="123";

  byte[] plainText=str.getBytes("UTF8");

  //使用getInstance("算法")来获得消息摘要,这里使用SHA-1的160位算法

  MessageDigest messageDigest=MessageDigest.getInstance("SHA-1");

  System.out.println("/n"+messageDigest.getProvider().getInfo());

  //开始使用算法

  messageDigest.update(plainText);

  System.out.println("/nDigest:");

  //输出算法运算结果

  System.out.println(new String(messageDigest.digest(),"UTF8"));

 }

}

(还可以通过消息认证码来进行加密实现,javax.crypto.Mac提供了一个解决方案,有兴趣者可以参考相关API文档,本文只是简单介绍什么是摘要算法。)

(2)私公钥和私钥:

公钥和私钥就是俗称的不对称加密方式,是从以前的对称加密(使用用户名与密码)方式的提高。用电子邮件的方式说明一下原理。

  使用公钥与私钥的目的就是实现安全的电子邮件,必须实现如下目的:

  1.我发送给你的内容必须加密,在邮件的传输过程中不能被别人看到。

  2.必须保证是我发送的邮件,不是别人冒充我的。

  要达到这样的目标必须发送邮件的两人都有公钥和私钥。

  公钥,就是给大家用的,你可以通过电子邮件发布,可以通过网站让别人下载,公钥其实是用来加密/验章用的。私钥,就是自己的,必须非常小心保存,最好加上密码,私钥是用来解密/签章,首先就Key的所有权来说,私钥只有个人拥有。公钥与私钥的作用是:用公钥加密的内容只能用私钥解密,用私钥加密的内容只能用公钥解密。

  比如说,我要给你发送一个加密的邮件。首先,我必须拥有你的公钥,你也必须拥有我的公钥。

  首先,我用你的公钥给这个邮件加密,这样就保证这个邮件不被别人看到,而且保证这个邮件在传送过程中没有被修改。你收到邮件后,用你的私钥就可以解密,就能看到内容。

  其次我用我的私钥给这个邮件加密,发送到你手里后,你可以用我的公钥解密。因为私钥只有我手里有,这样就保证了这个邮件是我发送的。

  当A->B资料时,A会使用B的公钥加密,这样才能确保只有B能解开,否则普罗大众都能解开加密的讯息,就是去了资料的保密性。验证方面则是使用签验章的机制,A传资料给大家时,会以自己的私钥做签章,如此所有收到讯息的人都可以用A的公钥进行验章,便可确认讯息是由A发出来的了。

I.私匙加密解密实例:

/**

*PrivateTest.java

*/

import javax.crypto.Cipher;

import javax.crypto.KeyGenerator;

import java.security.Key;

/**

*私鈅加密,保证消息机密性

*/

public class PrivateTest{

 public static void main(String[] args) throws Exception{

String str="123";

   byte[] plainText=str.getBytes("UTF8");

    

  //通过KeyGenerator形成一个key

  System.out.println("/nStart generate AES key");

  KeyGenerator keyGen=KeyGenerator.getInstance("AES");

  keyGen.init(128);

  Key key=keyGen.generateKey();

  System.out.println("Finish generating DES key");

  //获得一个私鈅加密类Cipher,ECB是加密方式,PKCS5Padding是填充方法

  Cipher cipher=Cipher.getInstance("AES/ECB/PKCS5Padding");

  System.out.println("/n"+cipher.getProvider().getInfo());

  //使用私鈅加密

  System.out.println("/nStart encryption:");

  cipher.init(Cipher.ENCRYPT_MODE,key);

  byte[] cipherText=cipher.doFinal(plainText);

  System.out.println("Finish encryption:");

  System.out.println(new String(cipherText,"UTF8"));

//使用私鈅解密

  System.out.println("/nStart decryption:");

  cipher.init(Cipher.DECRYPT_MODE,key);

  byte[] newPlainText=cipher.doFinal(cipherText);

  System.out.println("Finish decryption:");

  System.out.println(new String(newPlainText,"UTF8"));

 }

}

II.公匙加密,私匙解密实例:

/**

*PublicTest.java

*/

import java.security.Key;

import javax.crypto.Cipher;

import java.security.KeyPairGenerator;

import java.security.KeyPair;

/**

*一个简单的公鈅加密例子,Cipher类使用KeyPairGenerator生成的公鈅和私鈅

*/

public class PublicTest{

 public static void main(String[] args) throws Exception{

  String str="123";

   byte[] plainText=str.getBytes("UTF8");

  //构成一个RSA密钥

  System.out.println("/nStart generating RSA key");

  KeyPairGenerator keyGen=KeyPairGenerator.getInstance("RSA");

  keyGen.initialize(1024);

  KeyPair key=keyGen.generateKeyPair();

  System.out.println("Finish generating RSA key");

  //获得一个RSA的Cipher类,使用公鈅加密

  Cipher cipher=Cipher.getInstance("RSA/ECB/PKCS1Padding");

  System.out.println("/n"+cipher.getProvider().getInfo());

  System.out.println("/nStart encryption");

  cipher.init(Cipher.ENCRYPT_MODE,key.getPublic());

  byte[] cipherText=cipher.doFinal(plainText);

  System.out.println("Finish encryption:");

  System.out.println(new String(cipherText,"UTF8"));

  //使用私鈅解密

  System.out.println("/nStart decryption");

  cipher.init(Cipher.DECRYPT_MODE,key.getPrivate());

  byte[] newPlainText=cipher.doFinal(cipherText);

  System.out.println("Finish decryption:");

  System.out.println(new String(newPlainText,"UTF8"));

 }

}

(3)数字签名:

I.电子商务中数据传输的几个安全性需求


1. 数据的保密性:用于防止非法用户进入系统及合法用户对系统资源的非法使用;通过对一些敏感的数据文件进行加密来保护系统之间的数据交换,防止除接收方之外的第三方截获数据及即使获取文件也无法得到其内容。如在电子交易中,避免遭到黑客的袭击使信用卡信息丢失的问题。

  2. 数据的完整性:防止非法用户对进行交换的数据进行无意或恶意的修改、插入,防止交换的数据丢失等。

  3. 数据的不可否认性:对数据和信息的来源进行验证,以确保数据由合法的用户发出;防止数据发送方在发出数据后又加以否认;同时防止接收方在收到数据后又否认曾收到过此数据及篡改数据。

  上述需求对应于防火墙、加密、数字签名、身份认证等技术,但其关键在于数字签名技术。

II. 数字签名的含义

 数字签名是通过一个单向函数对要传送的报文进行处理得到的用以认证报文来源并核实报文是否发生变化的一个字母数字串。

III.数字签名的实现方法

实现数字签名有很多方法,目前数字签名采用较多的是公钥加密技术,如基于RSA Date Security 公司的PKCS( Public Key Cryptography Standards )、Digital Signature Algorithm、x.509、PGP(Pretty Good Privacy). 1994年美国标准与技术协会公布了数字签名标准(DSS)而使公钥加密技术广泛应用。&127;公钥加密系统采用的是非对称加密算法

IIII.实例

**

*DigitalSignatureTest.java

*/

import java.security.Signature;

import java.security.KeyPairGenerator;

import java.security.KeyPair;

import java.security.SignatureException;

/**

*数字签名,使用RSA私钥对对消息摘要签名,然后使用公鈅验证 测试

*/

public class DigitalSignatureTest{

 public static void main(String[] args) throws Exception{

  String str="123";

   byte[] plainText=str.getBytes("UTF8");

  //形成RSA公钥对

  System.out.println("/nStart generating RSA key");

  KeyPairGenerator keyGen=KeyPairGenerator.getInstance("RSA");

  keyGen.initialize(1024);

  KeyPair key=keyGen.generateKeyPair();

  System.out.println("Finish generating RSA key");

  //使用私鈅签名

  Signature sig=Signature.getInstance("SHA1WithRSA");

  sig.initSign(key.getPrivate());

  sig.update(plainText);

  byte[] signature=sig.sign();

  System.out.println(sig.getProvider().getInfo());

  System.out.println("/nSignature:");

  System.out.println(new String(signature,"UTF8"));

  //使用公鈅验证

  System.out.println("/nStart signature verification");

  sig.initVerify(key.getPublic());

  sig.update(plainText);

  try{

   if(sig.verify(signature)){

    System.out.println("Signature verified");

   }else System.out.println("Signature failed");

   }catch(SignatureException e){

    System.out.println("Signature failed");

   }

  }

}

(4)数字证书

I.概念:是数字形式的标识,与护照或驾驶员执照十分相似。数字证书是数字凭据,它提供有关实体标识的信息以及其他支持信息。数字证书是由成为证书颁发机构(CA)的权威机构颁发的。由于数字证书有证书权威机构颁发,因此由该权威机构担保证书信息的有效性。此外,数字证书只在特定的时间段内有效。

  数字证书包含证书中所标识的实体的公钥(就是说你的证书里有你的公钥),由于证书将公钥与特定的个人匹配,并且该证书的真实性由颁发机构保证(就是说可以让大家相信你的证书是真的),因此,数字证书为如何找到用户的公钥并知道它是否有效这一问题提供了解决方案。

II.数字证书的原理

数字证书采用公钥体制,即利用一对互相匹配的密钥进行加密、解密。每个用户自己设定一把特定的仅为本人所知的私有密钥(私钥),用它进行解密和签名;同时设定一把公共密钥(公钥)并由本人公开,为一组用户所共享,用于加密和验证签名。当发送一份保密文件时,发送方使用接收方的公钥对数据加密,而接收方则使用自己的私钥解密,这样信息就可以安全无误地到达目的地了。通过数字的手段保证加密过程是一个不可逆过程,即只有用私有密钥才能解密.在公开密钥密码体制中,常用的一种是RSA体制。

  用户也可以采用自己的私钥对信息加以处理,由于密钥仅为本人所有,这样就产生了别人无法生成的文件,也就形成了数字签名。采用数字签名,能够确认以下两点:

  (1)保证信息是由签名者自己签名发送的,签名者不能否认或难以否认;

  (2)保证信息自签发后到收到为止未曾作过任何修改,签发的文件是真实文件。

III.java实例操作:

密钥库:java平台为你提供了密钥库,用作密钥和证书的资源库。从物理上讲,密钥库是缺省名称为 .keystore 的文件(有一个选项使它成为加密文件)。密钥和证书可以拥有名称(称为别名),每个别名都由唯一的密码保护。密钥库本身也受密码保护;您可以选择让每个别名密码与主密钥库密码匹配。

  使用工具keytool,进行自我认证:

  1、创建密钥库keytool -genkey -v -alias YourKeyName -keyalg RSA 默认在自己的home目录下(windows系统是c:/documents and settings/<你的用户名> 目录下的.keystore文件),创建我们用 RSA 算法生成别名为 feiUserKey 的自签名的证书,如果使用了-keystore mm 就在当前目录下创建一个密钥库mm文件来保存密钥和证书。

  2、查看证书:keytool -list 列举了密钥库的所有的证书

  也可以在dos下输入keytool -help查看帮助。

(5)JAR的签名

前面我们已将讲了怎样创建自己的证书了,现在可以开始了解怎样对JAR文件签名,JAR文件在Java中相当于 ZIP 文件,允许将多个 Java 类文件打包到一个具有 .jar 扩展名的文件中,然后可以对这个jar文件进行数字签名,以证实其来源和真实性。该 JAR 文件的接收方可以根据发送方的签名决定是否信任该代码,并可以确信该内容在接收之前没有被篡改过。同时在部署中,可以通过在策略文件中放置访问控制语句根据签名者的身份分配对机器资源的访问权。这样,有些Applet的安全检验访问就得以进行。

  使用jarsigner工具可以对jar文件进行签名:

  现在假设我们有个Test.jar文件(可以使用jar命令行工具生成):

  jarsigner Test.jar YourKeyName (这里我们上面创建了该别名的证书) ,详细信息可以输入jarsigner查看帮助

  验证其真实性:jarsigner -verify Test.jar(注意,验证的是jar是否被修改了,但不检验减少的,如果增加了新的内容,也提示,但减少的不会提示。)

  使用Applet中::<applet code="Test.class" archive="Test.jar" width="150" height="100"></applet>然后浏览器就会提示你:准许这个会话-拒绝-始终准许-查看证书等。

(6)安全套接字层(SSL Secure Sockets Layer)和传输层安全性(TLS Transport Layer Security)  

I.简介:

安全套接字层 (SSL):一种由 Netscape Communications 开发的提议开放式标准,用以建立安全通讯通道,以防止如信用卡号等这样的重要信息被截获。

安全套接字层是用于服务器之上的一个加密系统,它可以确保在客户机与服务器之间传输的数据仍然是安全与隐密的。要使服务器和客户机使用 SSL 进行安全的通信,服务器必须有两样东西:

  密钥对(Key pair) —— 一个密钥对包括一个公钥和一个私钥。这两个密钥用来对消息进行加密和解密,以确保在因特网上传输时的隐密性和机密性。

  证书(Certificate) —— 证书用来进行身份验证或者身份确认。证书可以是自签(self-signed)证书,也可以是颁发(issued)证书。自签证书是为自己私有的 Web 网络创建的证书。颁发证书是认证中心(certificate authority,CA)或者证书签署者提供(颁发)给您的证书。

  SSL 使用安全握手来初始化客户机与服务器之间的安全连接。在握手期间,客户机和服务器对它们将要为此会话使用的密钥及加密方法达成一致。客户机使用服务器证书验证服务器。握手之后,SSL 被用来加密和解密 HTTPS(组合 SSL 和 HTTP 的一个独特协议)请求和服务器响应中的所有信息,包括:

  客户机正在请求的 URL。

  提交的表单的内容。

  访问授权信息(比如用户名和密码)。

  所有在客户机与服务器之间发送的数据。

II.总结:

安全套接字层和传输层安全性是用于在客户机和服务器之间构建安全的通信通道的协议。它也用来为客户机认证服务器,以及(不太常用的)为服务器认证客户机。该协议在浏览器应用程序中比较常见,浏览器窗口底部的锁表明 SSL/TLS 有效:

  1)当使用 SSL/TLS(通常使用 https:// URL)向站点进行请求时,从服务器向客户机发送一个证书。客户机使用已安装的公共 CA 证书通过这个证书验证服务器的身份,然后检查 IP 名称(机器名)与客户机连接的机器是否匹配。

  2)客户机生成一些可以用来生成对话的私钥(称为会话密钥)的随机信息,然后用服务器的公钥对它加密并将它发送到服务器。服务器用自己的私钥解密消息,然后用该随机信息派生出和客户机一样的私有会话密钥。通常在这个阶段使用 RSA 公钥算法。

  3)客户机和服务器使用私有会话密钥和私钥算法(通常是 RC4)进行通信。使用另一个密钥的消息认证码来确保消息的完整性。

  java中javax.net.ssl.SSLServerSocketFactory类提供了一个很好的SSLServerSocker的工厂类,熟悉Socket编程的读者可以去练习。当编写完服务器端之后,在浏览器上输入https://主机名:端口 就会通过SSL/TLS进行通话了。注意:运行服务端的时候要带系统环境变量运行:javax.net.ssl.keyStore=密钥库(创建证书时,名字应该为主机名,比如localhost)和javax.net.ssl.keyStorePassword=你的密码

http://baike.baidu.com/view/2396437.htm?fr=ala0_1

http://baike.baidu.com/view/41470.htm

http://www.pconline.com.cn/pcjob/process/other/others/0512/732815_3.html

http://baike.baidu.com/view/297231.htm

java 用aes "AES/ECB/PKCS5Padding" 加密后怎么用php解密 请php高手帮帮忙

以下是java代码

public class AesCrypImpl{

private String algorithm = "AES";

private String transformation = "AES/ECB/PKCS5Padding";

private String key = "21V32fe_e3.tu1A8";

private String provider;

private ThreadLocal <JavaCrypto> local = new ThreadLocal <JavaCrypto>();

private JavaCrypto getLocalCrypto() {

JavaCrypto current = local.get();

if (current == null) {

current = new JavaCrypto(algorithm, transformation, key, provider);

local.set(current);

}

return current;

}

private static class JavaCrypto {

private Cipher enCipher;

private Cipher deCipher;

public JavaCrypto(String algorithm, String transformation, String key,

String provider) {

super();

try {

SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(),

algorithm);

if (provider == null) {

enCipher = Cipher.getInstance(transformation);

deCipher = Cipher.getInstance(transformation);

} else {

enCipher = Cipher.getInstance(transformation, provider);

deCipher = Cipher.getInstance(transformation, provider);

}

enCipher.init(Cipher.ENCRYPT_MODE, secretKey);

deCipher.init(Cipher.DECRYPT_MODE, secretKey);

} catch (NoSuchAlgorithmException e) {

throw new RuntimeException(e);

} catch (NoSuchPaddingException e) {

throw new RuntimeException(e);

} catch (InvalidKeyException e) {

throw new RuntimeException(e);

} catch (NoSuchProviderException e) {

throw new RuntimeException(e);

}

}

public byte[] encrypt(byte[] bs) {

try {

return enCipher.doFinal(bs);

} catch (IllegalBlockSizeException e) {

throw new RuntimeException(e);

} catch (BadPaddingException e) {

throw new RuntimeException(e);

}

}

public byte[] dectypt(byte[] bs) {

try {

return deCipher.doFinal(bs);

} catch (IllegalBlockSizeException e) {

throw new RuntimeException(e);

} catch (BadPaddingException e) {

throw new RuntimeException(e);

}

}

}

public String dectypt(String s) {

return dectypt(s, null);

}

public String dectypt(String s, String charset) {

if (s == null) {

throw new NullPointerException("dectypt string can't be null");

}

try {

byte[] bs = (charset != null) ? Base64.decodeBase64(s

.getBytes(charset)) : Base64.decodeBase64(s.getBytes());

bs = dectypt(bs);

String back = (charset != null) ? new String(bs, charset)

: new String(bs);

back = back.trim();

return back;

} catch (UnsupportedEncodingException e) {

throw new RuntimeException(e);

}

}

public byte[] dectypt(byte[] bytes) {

if (bytes == null) {

throw new NullPointerException("dectypt bytes can't be null");

}

return this.getLocalCrypto().dectypt(bytes);

}

public String encrypt(String s) {

return encrypt(s, null);

}

public String encrypt(String s, String charset) {

if (s == null) {

throw new NullPointerException("encrypt string can't be null");

}

try {

byte[] bs = (charset != null) ? this.encrypt(s.getBytes(charset))

: this.encrypt(s.getBytes());

bs = Base64.encodeBase64(bs);

return (charset != null) ? new String(bs, charset) : new String(bs);

} catch (UnsupportedEncodingException e) {

throw new RuntimeException(e);

}

}

public byte[] encrypt(byte[] bytes) {

if (bytes == null) {

throw new NullPointerException("encrypt bytes can't be null");

}

return this.getLocalCrypto().encrypt(bytes);

}

public String getAlgorithm() {

return algorithm;

}

public void setAlgorithm(String algorithm) {

this.algorithm = algorithm;

}

public String getKey() {

return key;

}

public void setKey(String key) {

this.key = key;

}

public String getTransformation() {

return transformation;

}

public void setTransformation(String transformation) {

this.transformation = transformation;

}

public String getProvider() {

return provider;

}

public void setProvider(String provider) {

this.provider = provider;

}

public static void main(String[] args) throws UnsupportedEncodingException {

AesCrypImpl a = new AesCrypImpl();

String aaa = a.encrypt("genevieve");

System.out.println(aaa);

byte[] bs = Base64.encodeBase64("genevieve".getBytes());

System.out.println(new String(bs) );

//String dd = URLDecoder.decode("HORd4oijA6qhR%2Fdxod%2BlIg%3D%3D", "UTF-8");

//System.out.println(dd);

//String aa = a.dectypt(URLDecoder.decode("HORd4oijA6qhR%2Fdxod%2BlIg%3D%3D", "UTF-8"), "UTF-8");

//System.out.println(aa);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: