密码学基本概念
密码学是研究如何隐密地传递信息的学科。在现代特别指对信息以及其传输的数学性研究,常被认为是数学和计算机科学的分支,和信息论也密切相关。密码技术是的核心技术。密码技术在古代就已经得到应用,但仅限于外交和军事等重要领域。随着现代计算机技术的飞速发展,密码技术正在不断向更多其他领域渗透。它是集数学、计算机科学、电子与通信等诸多学科于一身的交叉学科。区块链技术的出现展现了以密码技术为核心构建信息系统安全的新潮流,未来区块链密码技术将会在安全问题方面发挥重大的作用;当然从传统意义上来说,。
现代密码技术不仅仅提供信息的加密与解密功能,还能有效地保护信息的完整性和不可否认性。
密码学的基本功能
1、 机密性: 机密性指的是发送方和指定的接收方能够理解传输的报文内容,即便窃听者截取到加密了的报文,但不能还原出原来的信息,也就是不能知道报文的内容,做到了保密.
2、鉴别:发送方和接收方都应该能证实通讯过程所涉及的另一方他们所声称的身份,也就是说第三者不能冒充跟你通信的。对方能对对方的身份进行鉴别。
3、报文完整性:即使发送方和接收方可以互相鉴别对方,但他们还需要确保其通信的内容在传输的过程中未被改变
4、不可否认性:如果我们收到通讯对方的报文后证实报文确实来自所宣称的发送方,发送方也不能在发送报文以后否认自己发送过报文;
密码学的基本模型
密码学算法的分类
消息编码:Base64
消息摘要:MD5、SHA类、 MAC
对称密码:DES 、3DES、 AES
非对称密码:RSA、DH密钥交换
数字签名:RSASignature、DSASignature
Base64
Base64 严格意思上讲并不是一个加解密算法,只能算一个非严格意义上加解密算法或加解密算法的近亲,Base64内容传送编码被设计用来把任意序列的8位字节描述为一种不易被人直接识别的形式
(The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable.)
由于某些系统中只能使用ASCII字符。Base64就是用来将非ASCII字符的数据转换成ASCII字符的一种方法。
base64特别适合在http,mime协议下快速传输数据。
base64其实不是安全领域下的加密解密算法。虽然有时候经常看到所谓的base64加密解密。其实base64只能算是一个编码算法,对数据内容进行编码来适合传输。虽然base64编码过后原文也变成不能看到的字符格式,但是这种方式很初级,很简单。
代码实现
try {
String testString = "foryou";
byte[] bytes = testString.getBytes("UTF-8");
String encrypt = Base64.getEncoder().encodeToString(bytes);
System.out.println(encrypt);
//Zm9yeW91
byte[] decode = Base64.getDecoder().decode(encrypt);
System.out.println(new String(decode, "UTF-8"));
//foryou
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
消息摘要
摘要算法又称哈希算法,它表示,相同的输入数据始终得到相同的输出,不同的输入数据尽量得到不同的输出。
Java中的Object.hashCode()方法就是一个摘要算法,它可以输入任意数据,它的输出是一个int类型,即4个字节的固定长度数据,同时,相同的输入会得到相同的输出,这也是重写equals方法必须重写hashCode方法的原因。
MD(Message Digest) :
生成的消息摘要都是128位的。
包括:MD2,MD4,MD5
从安全性上说:MD5 > MD4 > MD2
算法 | 摘要长度 | 实现方 |
---|---|---|
MD2 | 128 | JDK |
MD4 | 128 | Bouncy Castle |
MD5 | 128 | JDK |
MD5 算法实现
public static String getFileMd5(String path) throws Exception {
FileInputStream fileInputStream = new FileInputStream(path);
DigestInputStream digestInputStream = new DigestInputStream(fileInputStream, MessageDigest.getInstance("MD5"));
byte[] buffer = new byte[1024];
int read = digestInputStream.read();
while (read != -1) {
read = digestInputStream.read(buffer, 0, 1024);
}
MessageDigest messageDigest = digestInputStream.getMessageDigest();
byte[] digest = messageDigest.digest();
return new String(digest, StandardCharsets.UTF_8);
}
SHA(Secure Hash Algorithm):
安全散列算法
包括:SHA-1,SHA-2(SHA-224,SHA-256,SHA-384,SHA-512)
算法 | 摘要长度 | 实现方 |
---|---|---|
SHA-1 | 160 | JDK |
SHA-224 | 224 | Bouncy Castle |
SHA-256 | 256 | JDK |
SHA-384 | 384 | JDK |
SHA-512 | 512 | JDK |
MD5的摘要的长度为128bit,SHA-1摘要长度160bit。多出32bit意味着什么呢?不同明文的碰撞几率降低了2^32 = 。
Android apk 解压后的META-INF的文件是用来做安全检验的,Android 的打包签名里使用到摘要算SHA1和SHA256 由于我们使用的签名工具signapk使用java接口所写,我们简单看下Android数字签名的生成
- 程序遍历apk包中的所有文件(entry),对,逐个生成SHA的数字签名信息,再用Base64进行编码。具体代码见这个方法:
for (JarEntry entry: byName.values()) {
String name = entry.getName();
if (!entry.isDirectory() &&
(stripPattern == null || !stripPattern.matcher(name).matches())) {
InputStream data = jar.getInputStream(entry);
while ((num = data.read(buffer)) > 0) {
if (md_sha1 != null) md_sha1.update(buffer, 0, num);
if (md_sha256 != null) md_sha256.update(buffer, 0, num);
}
Attributes attr = null;
if (input != null) attr = input.getAttributes(name);
attr = attr != null ? new Attributes(attr) : new Attributes();
if (md_sha1 != null) {
attr.putValue("SHA1-Digest",
new String(Base64.encode(md_sha1.digest()), "ASCII"));
}
if (md_sha256 != null) {
attr.putValue("SHA-256-Digest",
new String(Base64.encode(md_sha256.digest()), "ASCII"));
}
output.getEntries().put(name, attr);
}
}
Android签名算法稍后在数字签名里详细说下
MAC
MAC(Message Authentication Code ),消息认证码算法)是含有密钥散列函数算法,兼容MD和SHA算法的特性,并在此基础上加入了密钥。因此,MAC也称为HMAC。 使用“消息认证代码的密钥散列法”(HMAC)
HmacMD2,HmacMD4,HmacMD5,HmacSHA1,HmacSHA224,HmacSHA256,HmacSHA38,HmacSHA512
算法 | 摘要长度 | 实现方 |
---|---|---|
HmacMD2 | 128 | JDK |
HmacMD4 | 128 | Bouncy Castle |
HmacMD5 | 128 | JDK |
HmacSHA-1 | 160 | JDK |
HmacSHA-224 | 224 | Bouncy Castle |
HmacSHA-256 | 256 | JDK |
HmacSHA-384 | 384 | JDK |
HmacSHA-512 | 512 | JDK |
对称加密:
对称加密就是指,加密和解密使用同一个密钥的加密方式。主要有DES,3DES,AES等
DES全称为Data Encryption Standard,即数据加密标准,3DES(或称为Triple DES)是三重数据加密算法(TDEA,Triple Data Encryption Algorithm)块密码的通称。它相当于是对每个数据块应用三次DES加密算法
虽然3DES提高DES的安全强度,但是它低效的加密实现较慢的速度,无法更优的实现加密,就提出了改进的高级加密算法即AES(Advanced Encryption Standard) 它的特点,,AES 目前是128位,192,256位的。
String testString = "foryou";
KeyGenerator aes = KeyGenerator.getInstance("AES");
aes.init(128);
SecretKey secretKey = aes.generateKey();
byte[] encoded = secretKey.getEncoded();
//构造密钥
SecretKeySpec skey = new SecretKeySpec(encoded, "AES");
//创建AES加密器
Cipher cipher = Cipher.getInstance("AES");
byte[] byteContent = testString.getBytes(StandardCharsets.UTF_8);
//使用加密器的加密模式
cipher.init(Cipher.ENCRYPT_MODE, skey);
// 加密
byte[] result = cipher.doFinal(byteContent);
System.out.println(new String(result,StandardCharsets.UTF_8));
cipher.init(Cipher.DNCRYPT_MODE,secretKey);
byte[] enctypt = cipher.doFinal();
System.out.println(new String(enctypt));
非对称加密
非对称加密跟对称加密不同,密钥分为公钥PublicKey和私钥PrivateKey,公钥和私钥是相互配对的,数据通过公钥加密之后,可以用私钥进行解密,反之,用私钥进行加密之后,也可以用公钥进行解密,公钥一般是分发给客户端使用,对外是公开的,而私钥则一般是服务端保留,不对外公开,常用的非对称加密算法有RSA、Elgamal、背包算法、Rabin、D-H、ECC等,目前RSA是应用最广泛的非对称加密算法
解决了
DH算法的简介
DH密钥交换算法简单的说就是允许两名用户在公开媒体上交换信息以生成“的、可以共享的密钥。也就是由甲方产出一对密钥(公钥、私钥),乙方依照甲方公钥产生乙方密钥对(公钥、私钥)。
以此为基线,作为数据传输保密基础,同时双方使用同一种对称加密算法构建本地密钥(SecretKey)对数据加密。这样,在互通了本地密钥(SecretKey)算法后,甲乙双方公开自己的公钥,使用对方的公钥和刚才产生的私钥加密数据,同时可以使用对方的公钥和自己的私钥对数据解密。不单单是甲乙双方两方,可以扩展为多方共享数据通讯,这样就完成了网络交互数据的安全通讯。
RSA算法的简介
由Ron Rivest、 Adi Shamir 和 Leonard Adleman三位学者提出的非对称加密算法。RSA 算法基于一个十分简单的数论事实:将两个大素数相乘十分容易,但是想要对其乘积进行因式分解却极其困难,因此可以将乘积公开作为加密密钥。它是第一个既能用于数据加密也能用于数字签名的算法。
RSA 数学原理
加解密公式
RSA加密:密文 = 明文^E mod N 公钥(E,N)
RSA解密:明文 = 密文^D mod N 私钥(D,N)模拟生成密钥对
1.求N:p=17 q=19 N=pq = 323
2.求L:L=lcm(p-1,q-1)=lcm(16,18) = 144
3.求E:gcd(E,L)=1 E=5
4.求D:ED mod L = 1 D=29
5.公钥(5,323) 私钥(29,323)加密
密文 = 明文^E mod N = 123^5 mod 323 = 225解密
明文 = 密文^D mod N = 225^29 mod 323 = 123
毫不夸张地说,只要有计算机网络的地方,就有 RSA 算法。并且RSA算法目前是绝对安全可靠
目前除了暴力破解,还没有更好的办法,如果以目前的计算速度,破解需要50年以上,则这个算法就是安全的。 维基百科这样描述:
"对极决定了RSA算法的可靠性。换言之,对一极大整数做因数分解愈困难,RSA算法愈可靠。
假如有人找到一种快速因数分解的算法,那么RSA的可靠性就会极度下降。但找到这样的算法的可能性是非常小的。今天只有短的RSA密钥才可能被暴力破解。到2008年为止,世界上还没有任何可靠的攻击RSA算法的方式。
只要密钥长度足够长,用RSA加密的信息实际上是不能被解破的。"
数字签名
带有密钥(公钥和私钥)的消息摘要算法,是。
签名和数字签名 鉴别 和抗否认性,保证数据不被编辑,替换,修改.
数字摘要算法包括RSASignature(JDK)、DSASignature(JDK)、ECDSASignature(Bouncy Castle)
RSASignature 将 RSA 公钥密码算法按照数字签名的方式运用
1.MD (MD2withRSA、MD5withRSA)
2.SHA (SHA1withRSA、SHA256withRSA、SHA384withRSA、SHA512withRSA)
DSASignature DSA 算法实现就是 RSA 数字签名算法实现的简装版,仅支持 SHA 系列算法
只支持SHA1withDSA算法
Android 签名二
/** Returns the expected signature algorithm for this key type. */
private static String getSignatureAlgorithm(X509Certificate cert) {
String sigAlg = cert.getSigAlgName().toUpperCase(Locale.US);
String keyType = cert.getPublicKey().getAlgorithm().toUpperCase(Locale.US);
if ("RSA".equalsIgnoreCase(keyType)) {
if (getDigestAlgorithm(cert) == USE_SHA256) {
return "SHA256withRSA";
} else {
return "SHA1withRSA";
}
} else if ("EC".equalsIgnoreCase(keyType)) {
return "SHA256withECDSA";
} else {
throw new IllegalArgumentException("unsupported key type: " + keyType);
}
}
Android签名的时候,首先将将生成的摘要写入MANIFEST.MF文件,然后用RSA 非对称加密算法密钥签名生成CERT.SF文件,CERT.RSA文件中保存了公钥、所采用的加密算法等信息,大概通过这三部,就完成了对apk的签名 更多Android 签名和校验的参考 Android APK 签名比对
密码学技术在Https 里的应用
HTTPS其实是有两部分组成:HTTP + SSL / TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据,
至于Https 不得不说的一个概念
为什么要有数字证书?
对于请求方来说,它怎么能确定它所得到的公钥一定是从目标主机那里发布的,而且没有被篡改过呢?亦或者请求的目标主机本本身就从事窃取用户信息的不正当行为呢?这时候,我们需要有一个权威的值得信赖的第三方机构(一般是由政府审核并授权的机构)来统一对外发放主机机构的公钥,只要请求方这种机构获取公钥,就避免了上述问题的发生。
证书包含哪些内容
- 证书颁发机构的名称
- 证书本身的数字签名
- 证书持有者公钥
- 证书签名用到的Hash算法
SSL/TLS 的握手过程
客户端首次发出请求
由于客户端(如浏览器)对一些加解密算法的支持程度不一样,但是在TLS协议传输过程中必须使用同一套加解密算法才能保证数据能够正常的加解密。在TLS握手阶段,客户端首先要告知服务端,自己支持哪些加密算法,所以客户端需要将本地支持的加密套件(Cipher Suite)的列表传送给服务端。除此之外,客户端还要产生一个随机数,这个随机数一方面需要在客户端保存,另一方面需要传送给服务端,客户端的随机数需要跟服务端产生的随机数结合起来产生后面要讲到的 。
服务端首次回应
服务端在接收到客户端的Client Hello之后,服务端需要确定加密协议的版本,以及加密的算法,然后也生成一个随机数,以及将自己的证书发送给客户端一并发送给客户端,这里的随机数是整个过程的第二个随机数。
客户端再次回应
客户端首先会对服务器下发的证书进行验证,验证通过之后,则会继续下面的操作,客户端再次产生一个随机数(第三个随机数),然后使用服务器证书中的,以及放一个ChangeCipherSpec消息即编码改变的消息,还有整个前面所有消息的hash值,进行服务器验证,然后用新秘钥加密一段数据一并发送到服务器,确保正式通信前无误。
客户端使用前面的,使用与服务器确定的加密算法,生成一个Session Secret。
ChangeCipherSpec
ChangeCipherSpec是一个独立的协议,体现在数据包中就是一个字节的数据,用于告知服务端,客户端已经切换到之前协商好的加密套件(Cipher Suite)的状态,准备使用之前协商好的加密套件加密数据并传输了。
服务器再次响应
服务端在接收到客户端传过来的第三个随机数的 加密数据之后,使用对这段加密数据进行解密,并对数据进行验证,也会使用跟客户端同样的方式生成秘钥,一切准备好之后,也会给客户端发送一个 ChangeCipherSpec,告知客户端已经切换到协商过的加密套件状态,准备使用加密套件和 Session Secret加密数据了。之后,服务端也会使用 Session Secret 加密一段 Finish 消息发送给客户端,以验证之前通过握手建立起来的加解密通道是否成功。
后续客户端与服务器间通信
确定秘钥之后,服务器与客户端之间就会通过商定的秘钥加密消息了,进行通讯了。整个握手过程也就基本完成了。
值得特别提出的是:
SSL协议在握手阶段使用的是非对称加密,在传输阶段使用的是对称加密,也就是说在SSL上传送的数据是使用!因为非对称加密的速度缓慢,耗费资源。其实当客户端和主机使用非对称加密方式建立连接后,客户端和主机已经决定好了在传输过程使用的对称加密算法和关键的对称加密密钥,由于这个过程本身是安全可靠的,也即对称加密密钥是不可能被窃取盗用的,因此,保证了在传输过程中对数据进行对称加密也是安全可靠的,因为除了客户端和主机之外,不可能有第三方窃取并解密出对称加密密钥!如果有人窃听通信,他可以知道双方选择的加密方法,以及三个随机数中的两个。整个通话的安全,只取决于第三个随机数(Premaster secret)能不能被破解。
在这里,只有 random3 是能够保证不被第三人知道的,为什么公开的 random1 和 random2 有存在的必要?为什么不直接生成 master secret 发过去?
查了查资料,这里是因为。加入随机参数,使得:即使现在所有密钥都泄露了,历史消息也不会被破解。感兴趣可以看如何理解前向安全性?和完美前向保密(perfect forward secrecy)区别?