1,java.policy
设置文件访问权限:java.io.FilePermission eg: grant codeBase "http://www.pepress.com.cn/-" { permission java.io.FilePermission "c:/temp/-","read"; } 设置系统属性访问权限:java.util.PropertyPermission eg: grant codeBase "File:/e:/java/-" { permission java.util.PropertyPermission "user.home", "read"; } 激活安全管理器:java.lang.SecurityManage System.setSecurityManager(new SecurityManager()); 2, 密钥的产生: A. 对称加密的密钥:只有一个(加密算法通常有:BlowFish, DESede) javax.crypto.KeyGenerator keygen=KeyGenerator.getInstance("DESede"); keygen.init(1024); java.security.Key mykey=keygen.generateKey(); B. 非对称加密的密钥:一对 javax.crypto.KeyPairGenerator keypairgen=KeyPairGenerator.getInstance("RSA"); keypairgen.initialize(1024); java.security.KeyPair mykeypair=keypairgen.generateKeyPair(); java.security.PrivateKey pvk=mykeypair.getPrivate(); 3, 密钥的保存与恢复: 保存:非对称加密的公钥:直接可以写入字节数组byte[] java.security.PublicKey pbk=mykeypair.getPublic(); byte [] encodedPbk= pbk.getEncoded(); 保存:非对称加密的密钥,单钥密钥: 需要加密后保存。 使用Cipher类的wrap方法。 恢复公钥: PublicKey pbk=mykeypair.getPublic(); byte [] pbkbytes=pbk.getEncoded(); java.security.spec.X509EncodedKeySpec x509keyspec=new X509EncodedKeySpec(pbkbytes); java.security.KeyFactory keyfac=KeyFactory.getInstance("RSA"); PublicKey pbkrecover=keyfac.generatePublic(x509keyspec); 恢复密钥: PrivateKey pvk=mykeypair.getPrivate(); byte [] pvkbytes=pvk.getEncoded(); java.security.spec.PKCS8EncodedKeySpec pkcs8keyspec=new PKCS8EncodedKeySpec(pvkbytes); java.security.KeyFactory keyfacpri=KeyFactory.getInstance("RSA"); PrivateKey pvkrecover=keyfacpri.generatePrivate(pkcs8keyspec); 4,//非对称加密:用公钥加密,用私钥解密, 对称加密用相同的key Cipher cipher =Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, pbk); String toencrypt="I want to be encrypted"; byte [] cipherbytes=cipher.doFinal(toencrypt.getBytes()); cipher=Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, pvk); String todecrypte="I've been encrypted,now I want to be decrypted"; byte [] cipherbytess=cipher.doFinal(todecrypte.getBytes()); 5, 对称加密与 非对称加密的结合: 通常可以用对称加密加密数据,用非对称加密加密 对称加密的密钥。 6,文件加密解密: javax.crypt.CipherInputStream, javax.crypt.CipherOutputStream 先new一个Cipher, 然后使用到 CipherOutputStream里面去(CipherOutputStream去包装文件输出流) KeyGenerator keygen=KeyGenerator.getInstance("DESede"); keygen.init(1024); Key mykey=keygen.generateKey(); Cipher cipher =Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE,mykey); CipherOutputStream cos=new CipherOutputStream(new FileOutputStream("xx.xxx"),cipher); 7, 数字签名: 实现方法有两种:因为验证更多出现,所以RSA更常用。 DSA:只能进行签名,不能用来加密数据。 DSA用来签名的速度很快 RSA: 非对称加密的逆运用,用私钥签名,用公钥验证。 RSA用来验证的速度很快 8,用数字签名实现B/S用户登录认证系统: A. B生成密钥对,把公钥发送给S. B,在需要身份验证时,S发送一段信息到客户机,客户机签名,然后返回给服务器。 C. 服务器对收到的结果进行验证,即可确认客户机身份。 9,数字签名:java.security.Signature //数字签名:用私钥签名 Signature signature=Signature.getInstance("SHA1WithRSA"); signature.initSign(pvk); String tobesigned="I want to be signed"; signature.update(tobesigned.getBytes()); byte [] signedbytes=signature.sign(); //数字签名:用公钥验证 signature=Signature.getInstance("SHA1WithRSA"); signature.initVerify(pbk); signature.update(tobesigned.getBytes()); signature.verify(signedbytes); 10,SSL:Security Socket Layer, 运行于TCP/IP之上,用了对称加密和非对称加密 SSLServerSocketFactory sslSocket=(SSLServerSocketFactory)SSLServerSocketFactory.getDefault(); ServerSocket serSocket=sslSocket.createServerSocket(8080); HTTP上面包一层SSL,就成了HTTPS SSL 的英文全称是 “Secure Sockets Layer” ,中文名为 “ 安全套接层协议层 ” ,它是网景( Netscape )公司提出的基于 WEB 应用的安全协议,当前版本为3.0。 SSL 协议指定了一种在应用程序协议(如 HTTP 、 Telenet 、 NMTP 和 FTP 等)和 TCP/IP 协议之间提供数据安全性分层的机制,它为 TCP/IP 连接提供数据加密、服务器认证、消息完整性以及可选的客户机认证。它已被广泛地用于Web浏览器与服务器之间的身份认证和加密数据传输。SSL协议位于TCP/IP协议与各种应用层协议之间,为数据通讯提供安全支持。SSL协议可分为两层: SSL记录协议(SSL Record Protocol):它建立在可靠的传输协议(如TCP)之上,为高层协议提供数据封装、压缩、加密等基本功能的支持。 SSL握手协议(SSL Handshake Protocol):它建立在SSL记录协议之上,用于在实际的数据传输开始前,通讯双方进行身份认证、协商加密算法、交换加密密钥等。 SSL的局限:主要表现在客户端,并不是所有的客户端都能支持SSL; 而且SSL只是一个网络安全协议,只用来保护通信,其他安全问题如文件访问,内存安全等 要配合其他措施使用。 12, ACL: Access Control Lists 加密与解密: 所有的数据都是通过二进制来传输的,加密也就是将原有的二进制流数据顺序打乱或者是插入另外的二进制数据,使得读取后的字符是不规则的乱码,而解密就是通过加密的原理还原已有数据的过程. 加密算法: 1,单向散列:Hash算法 将任意长度的消息压缩到某一固定长度(消息摘要)的函数(该过程不可逆)。用处:数字签名,消息的完整性检测,消息起源的认证检测。常见算法:MD5,SHA, N-hash, RIPE_MD, HAVAL.加密:由于Hash函数为不可逆算法,所以只能使用hash函数作为加密的中间步骤。解密:一般不需要了解Hash函数具体内容。 MD5: Message Digest,消息摘要算法,对输入的消息运算产生128位散列值。将任意长度的字节串变换成一个128位的大整数,并且是不可逆的字符串变换算法。 SHA: Secure Hash Algorithm,安全散列算法,SHA-1, SHA-256,SHA-384,SHA-512,产生160,256,384,512位的散列值。 CRC: Cyclic Redundancy Check,循环冗余校验,CRC-16, CRC-32 2,公开密钥算法:非对称算法 用于加密的密钥 不同于 用于解密的密钥, 而且解密密钥 不能根据 加密密钥 计算出来。 加密密钥可以公开,即陌生人能够用加密密钥加密信息,但是只有相应的解密密钥才能解密信息, 加密密钥叫做公钥,解密密钥叫做私钥。 常见算法:大整数因子分解系统(eg, RSA), 离散对数系统(eg, DSA), 椭圆曲线离散对数系统 (eg, ECC) RSA: 第一个能用于数据加密也能用于数字签名的算法。以发明者的名字命名: Ron Rivest, Adi Shamir, Leonard Adleman. 基于大数分解成两个大素数。 DSA: Digital Signature Algorithm, (DSS: Digital Signature Standard) 3, 对称算法: 加密密钥和解密密钥是完全相同的。 BlowFish: 64位分组及可变密钥长度的分组密钥算法。 Tips: API:Application Programming Interface SPI:Service Provider Interface ShareWare:共享软件 Byte-code:字节码 Java平台为安全和加密服务提供了两组API:JCA和JCE。 JCA (Java Cryptography Architecture)提供基本的加密框架,如证书、数字签名、消息摘要和密钥对产生器; JCE在JCA的基础上作了扩展,包括加密算法、密钥交换、密钥产生和消息鉴别服务等接口。 JCE: Java Cryptographic Extension JCA:Java Cryptographic Architecture javax.crypto.Cipher类提供加密和解密功能,该类是JCE框架的核心。 与所有的引擎类一样,可以通过调用Cipher类中的getInstance静态工厂方法得到Cipher对象。 public static Cipher getInstance(String transformation); public static Cipher getInstance(String transformation,String provider); 参数transformation是一个字符串,它描述了由指定输入产生输出所进行的操作或操作集合。 参数transformation总是包含密码学算法名称,比如DES,也可以在后面包含模式和填充方式。 参数transformation可以是下列两种形式之一: “algorithm/mode/padding” “algorithm” 例如下面的例子就是有效的transformation形式: "DES/CBC/PKCS5Padding" "DES" 如果没有指定模式或填充方式,就使用特定提供者指定的默认模式或默认填充方式。例如,SunJCE提供者使用ECB作为DES、DES-EDE和 Blowfish等Cipher的默认模式,并使用PKCS5Padding作为它们默认的填充方案。这意味着在SunJCE提供者中,下列形式的声明是 等价的:Cipher c1=Cipher.getInstance("DES/ECB/PKCS5Padding"); Cipher c1=Cipher.getInstance("DES"); 当 以流加密方式请求以块划分的cipher时,可以在模式名后面跟上一次运算需要操作的bit数目,例如采用"DES/CFB8/NoPadding"和 "DES/OFB32/PKCS5Padding"形式的transformation参数。如果没有指定数目,则使用提供者指定的默认值(例如 SunJCE提供者使用的默认值是64bit)。 getInstance工厂方法返回的对象没有进行初始化,因此在使用前必须进行初始化。 通过getInstance得到的Cipher对象必须使用下列四个模式之一进行初始化,这四个模式在Cipher类中被定义为final integer常数,我们可以使用符号名来引用这些模式: ENCRYPT_MODE,加密数据 DECRYPT_MODE,解密数据 WRAP_MODE,将一个Key封装成字节,可以用来进行安全传输 UNWRAP_MODE,将前述已封装的密钥解开成java.security.Key对象 每个Cipher初始化方法使用一个模式参数opmod,并用此模式初始化Cipher对象。此外还有其他参数,包括密钥key、包含密钥的证书certificate、算法参数params和随机源random。 我们可以调用以下的init方法之一来初始化Cipher对象: public void init(int opmod,Key key); public void init(int opmod,Certificate certificate); public void init(int opmod,Key key,SecureRandom random); public void init(int opmod,Certificate certificate,SecureRandom random); public void init(int opmod,Key key,AlgorithmParameterSpec params); public void init(int opmod,Key key,AlgorithmParameterSpec params,SecureRandom random); public void init(int opmod,Key key,AlgorithmParameters params); public void init(int opmod,Key key,AlgorithmParameters params,SecureRandom random); 必须指出的是,加密和解密必须使用相同的参数。当Cipher对象被初始化时,它将失去以前得到的所有状态。即,初始化Cipher对象与新建一个Cipher实例然后将它初始化是等价的。 可以调用以下的doFinal()方法之一完成单步的加密或解密数据: public byte[] doFinal(byte[] input); public byte[] doFinal(byte[] input,int inputOffset,int inputLen); public int doFinal(byte[] input,int inputOffset,int inputLen,byte[] output); public int doFinal(byte[] input,int inputOffset,int inputLen,byte[] output,int outputOffset); 在多步加密或解密数据时,首先需要一次或多次调用update方法,用以提供加密或解密的所有数据: public byte[] update(byte[] input); public byte[] update(byte[] input,int inputOffset,int inputLen); public int update(byte[] input,int inputOffset,int inputLen,byte[] output); public int update(byte[] input,int inputOffset,int inputLen,byte[] output,int outputOffset); 如果还有输入数据,多步操作可以使用前面提到的doFinal方法之一结束。如果没有数据,多步操作可以使用下面的doFinal方法之一结束: public byte[] doFinal(); public int doFinal(byte[] output,int outputOffset); 如果在transformation参数部分指定了padding或unpadding方式,则所有的doFinal方法都要注意所用的padding或unpadding方式。 调用doFinal方法将会重置Cipher对象到使用init进行初始化时的状态,就是说,Cipher对象被重置,使得可以进行更多数据的加密或解密,至于这两种模式,可以在调用init时进行指定。 包裹wrap密钥必须先使用WRAP_MODE初始化Cipher对象,然后调用以下方法: public final byte[] wrap(Key key); 如果将调用wrap方法的结果(wrap后的密钥字节)提供给解包裹unwrap的人使用,必须给接收者发送以下额外信息: (1)密钥算法名称: 密钥算法名称可以调用Key接口提供的getAlgorithm方法得到: public String getAlgorithm(); (2)被包裹密钥的类型(Cipher.SECRET_KEY,Cipher.PRIVATE_KEY,Cipher.PUBLIC_KEY) 为了对调用wrap方法返回的字节进行解包,必须先使用UNWRAP_MODE模式初始化Cipher对象,然后调用以下方法 : public final Key unwrap(byte[] wrappedKey,String wrappedKeyAlgorithm,int wrappedKeyType)); 其 中,参数wrappedKey是调用wrap方法返回的字节,参数wrappedKeyAlgorithm是用来包裹密钥的算法,参数 wrappedKeyType是被包裹密钥的类型,该类型必须是Cipher.SECRET_KEY,Cipher.PRIVATE_KEY, Cipher.PUBLIC_KEY三者之一。 SunJCE提供者实现的cipher算法使用如下参数: (1)采用CBC、CFB、OFB、PCBC模式的DES、DES-EDE和Blowfish算法。,它们使用初始化向量IV作为参数。可以使用javax.crypto.spec.IvParameterSpec类并使用给定的IV参数来初始化Cipher对象。 (2)PBEWithMD5AndDES使用的参数是一个由盐值和迭代次数组成的参数集合。可以使用javax.crypto.spec.PBEParameterSpec类并利用给定盐值和迭代次数来初始化Cipher对象。 注意:如果使用SealedObject类,就不必为解密运算参数的传递和保存担心。这个类在加密对象内容中附带了密封和加密的参数,可以使用相同的参数对其进行解封和解密。 Cipher 中的某些update和doFinal方法允许调用者指定加密或解密数据的输出缓存。此时,保证指定的缓存足够大以容纳加密或解密运算的结果是非常重要 的,可以使用Cipher的以下方法来决定输出缓存应该有多大:public int getOutputSize(int inputLen) |