CA(Certification Authoritcation)是PKI系统中通信双方都信任的实体,是数字证书认证中心的简称,是指发放、管理、废除数字证书的机构,被称为可信第三方(Trusted Third Party,简称TTP)。CA的作用是检查证书持有者身份的合法性,并签发证书(在证书上签字),以防证书被伪造或篡改,以及对证书和密钥进行管理。
CA作为可信第三方的重要条件之一就是CA的行为具有非否认性。作为第三方而不是简单的上级,就必须能让信任者有追究自己责任的能力。
CA通过证书证实他人的公钥信息,证书上有CA的签名。用户如果因为信任证书而导致了损失,证书可以作为有效的证据用于追究CA的法律责任。正是因为CA愿意给出承担责任的承诺,所以也被称为可信第三方。证书中绑定了公钥数据、和相应私钥拥有者的身份信息,并带有CA的数字签名。证书中也包含了CA的名称,以便于依赖方找到CA的公钥、验证证书上的数字签名。
验证证书的时候,需要得到CA的公钥。用户的公钥可以通过证书来证明,那CA的公钥如何获得呢?可以再让另一个CA来发证书,但最终总有一个CA的公钥的获得过程缺乏证明。PKI技术并不把这样一个循环问题留给自己,而是依赖其它的安全信道来解决。因为CA毕竟不多,可以通过广播、电视或报纸等公开的权威的媒介,甚至通过发布红头文件的方式来公告CA的公钥。
公告CA的公钥可以有多种形式,为了兼容程序的处理,人们一般也以证书的形式发布CA的公钥。CA给自己签发一张证书,证明自己拥有这个公钥,这就是自签名证书(Self-Signed Certificate)。
CA自签名证书其实不是真正的数字证书,而仅仅是拥有证书形式的一个公钥,所以CA自签名证书必须从可信的途径获取。例如,任何人都可以产生一对公私密钥对,并声称自己就是可信任的CA,然后签发一张自签名证书、并通过网络随意传播。CA自签名证书可以通过权威媒体或面对面USB硬盘等进行传输
数字证书是认证中心CA签名的消息,是由CA签发的一个声明,证明证书主体("证书申请者"拥有了证书后即成为"证书主体")与证书中所包含的公钥的惟一对应关系。证书包括证书申请者的名称及相关信息、申请者的公钥、签发证书的CA的数字签名及证书的有效期等内容。一个人要从认证中心获得证书,通常要提供证明个人或单位身份的信息。证书主要有两个作用,一个是加密通信,一个是数字签名。
加密通信是保证数据不被别人截获并且不被知道通信内容的,主要是两个层次,一个是通信双方身份确认,避免对方是冒充的,另一个是数据通过公钥加密传输和使用私钥解密。这方面常见的具体应用就是SSL和HTTPS。
数字签名是用于识别签名者身份的,这个从字面就可以理解。你使用你的私钥进行签名,然后用户看到你的签名后用公钥检查,发现的确是你的数字签名,就可以了。这个常见的应用有代码发行商签名,就是签名控件的那种,邮件数字签名,电子公章等。签发一个证书的时候要提供具体用途的,比如说:邮件签名,软件开发商签名,IPSec加密,服务器通信加密等,如果越出指定范围的用途都是不受信任的。
现在常用的证书都是采用X.509结构的,这个是一个国际标准。具体的证书包装格式有PKCS#7,PKCS#10,PKCS#12,CER等等,其中PKCS#12是把公钥和私钥放在一起的,便于证书拥有者使用。
生成数字证书的途径有两个,一个是通过自己的私钥签名生成自己信任的证书,另一个是想颁发证书的机构发送证书申请(Certificate Signing Request CSR),让信任的证书机构对公共密钥签名,生成数字证书。
公钥和私钥就是俗称的不对称加密方式,是从以前的对称加密(使用用户名与密码)方式的提高,每个通信方均需要两个密钥,即公钥和私钥,这两把密钥可以互为加解密。公钥,就是给大家用的,你可以通过电子邮件发布,可以通过网站让别人下载,公钥其实是用来加密用的。私钥,就是自己的,必须非常小心保存,最好加上密码,私钥是用来解密。公钥与私钥的作用是:用公钥加密的内容只能用私钥解密,用私钥加密的内容只能用公钥解密。
公钥私钥的原则:
1. 一个公钥对应一个私钥。
2. 密钥对中,让大家都知道的是公钥,不告诉大家,只有自己知道的,是私钥。
3. 如果用其中一个密钥加密数据,则只有对应的那个密钥才可以解密。
4. 如果用其中一个密钥可以进行解密数据,则该数据必然是对应的那个密钥进行的加密。
加密是将数据资料加密,使得非法用户即使取得加密过的资料,也无法获取正确的资料内容,所以数据加密可以保护数据,防止监听攻击。其重点在于数据的安全性。身份认证是用来判断某个身份的真实性,确认身份后,系统才可以依不同的身份给予不同的权限。加密就是通过编码信息隐藏的过程,需要加密的数据称为密文,而未加密的数据称为明文,密钥是用于加密和解密数据的信息。
明文数据-->加密(加密密钥)-->密文数据-->解密(解密密钥)-->明文数据
用电子邮件的方式说明一下,使用公钥与私钥的目的就是实现安全的电子邮件:
1. 我发送给你的内容必须加密,在邮件的传输过程中不能被别人看到。
2. 必须保证是我发送的邮件,不是别人冒充我的。
要达到这样的目标必须发送邮件的两人都有公钥和私钥。
比如说,我要给你发送一个加密的邮件。首先,我必须拥有你的公钥,你也必须拥有我的公钥。我用你的公钥给这个邮件加密,这样就保证这个邮件不被别人看到,而且保证这个邮件在传送过程中没有被修改。你收到邮件后,用你的私钥就可以解密,就能看到内容。
其次我用我的私钥给这个邮件加密,发送到你手里后,你可以用我的公钥解密。因为私钥只有我手里有,这样就保证了这个邮件是我发送的。
加密分为对称加密和非对称加密,使用加密、解密相同的密钥成为对称加密;使用加密、解密不同的密钥成为非对称加密,如用公开的密钥加密,用私有的密钥解密。
对称加密算法:
DES、AES、IDEA、RC2、RC4、SKIPJACK、Blowfish算法等(块加密算法)
生成DES密钥最简单方法是使用KeyGenerator类
KenGenerator.getInstance("DES")
要加密数据块可以使用Cipher或CipherOutputStream
Cipher.getInstance("DESede")
cipher.init(...);
ciper.update(...);
非对称加密算法:
RSA、HD算法等(公钥加密、私钥解密)
举例1.
public class TestDESEncryDecry {
private static String str = "1234567812345678";
public static void main(String[] args) {
System.out.println("==============明文=============");
System.out.println(str);
System.out.println();
byte[] bytes = str.getBytes("utf-8");
KeyGenerator ken = KeyGenerator.getInstance("DESEDE");
ken.init(168);
SecretKey key = ken.generateKey();
byte[] codes = key.getEncoded();
if (null != codes) {
System.out.println("================显示密钥==================");
for (int j = 0; j < codes.length; j++) {
System.out.print(codes[j] + ", ");
if ((j % 8) == 7) {
System.out.println();
}
}
System.out.println();
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryBytest = cipher.doFinal(bytes);
System.out.println("==============密文=================");
for (int j = 0; j < encryBytest.length; j++) {
System.out.print(encryBytest[j]+", ");
if ((j % 8) == 7) {
System.out.println();
}
}
System.out.println();
cipher.init(Cipher.DECRYPT_MODE, key);
byte [] decryBytes = cipher.doFinal(encryBytest);
String str = new String(decryBytes);
System.out.println("==============解密后的原文===============");
System.out.println(str);
}
}
}
举例2.
public class TestRSAEncryDecry {
private static String str = "I have a friend !";
public static void main(String[] args) {
try {
System.out.println("===============明文===============");
System.out.println(str);
System.out.println();
byte [] bytes = str.getBytes("utf-8");
KeyPairGenerator key = KeyPairGenerator.getInstance("RSA");
key.initialize(1024);
KeyPair pair = key.genKeyPair();
PublicKey pub = pair.getPublic();
PrivateKey pri = pair.getPrivate();
//保存公钥
FileOutputStream fos = new FileOutputStream("pub.dat");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(pub);
//保存私钥
FileOutputStream fos2 = new FileOutputStream("pri.dat");
ObjectOutputStream os2 = new ObjectOutputStream(fos2);
os2.writeObject(pri);
RSAPublicKey rpub = (RSAPublicKey) pair.getPublic();
BigInteger e = rpub.getPublicExponent();
BigInteger n = rpub.getModulus();
System.out.println("e = "+e+"\r\nn = "+n);
BigInteger m = new BigInteger(bytes);
BigInteger bi = m.modPow(e, n);
System.out.println("=================密文==================");
System.out.println(bi);
RSAPrivateKey rpri = (RSAPrivateKey) pair.getPrivate();
BigInteger e2 = rpri.getPrivateExponent();
BigInteger n2 = rpri.getModulus();
BigInteger bi2 = bi.modPow(e2, n2);
System.out.println("===============解密后的原文==================");
byte [] chars = bi2.toByteArray();
for (int j = 0 ; j < chars.length ; j++) {
System.out.print((char)chars[j]);
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
<<To Be Continued>>