2 三类算法

2.1 哈希算法

“Upon my death, my property shall be divided equally among my children; however, my son George shall receive nothing.”

“12 5F 09 03 E7 31 30 19 2E A6 E7 E4 90 43 84 B4 38 99 8F 67”

package com.galen.v2ch09.hash;

import java.io.*;
import java.nio.file.*;
import java.security.*;

/**
* This program computes the message digest of a file.
*
* @author Cay Horstmann
* @version 1.20 2012-06-16
*/
public class Digest {
/**
* @param args args[0] is the filename, args[1] is optionally the algorithm
*             (SHA-1, SHA-256, or MD5)
*             javac com/galen/v2ch09/hash/Digest.java
*             java com.galen.v2ch09.hash.Digest input.txt
*             java com.galen.v2ch09.hash.Digest input.txt MD5
*/
public static void main(String[] args) throws IOException, GeneralSecurityException {
String algname = args.length >= 2 ? args[1] : "SHA-1";
MessageDigest alg = MessageDigest.getInstance(algname);
byte[] hash = alg.digest(input);
String d = "";
for (int i = 0; i < hash.length; i++) {
int v = hash[i] & 0xFF;
if (v < 16) d += "0";
d += Integer.toString(v, 16).toUpperCase() + " ";
}
System.out.println(d);
}
}


(1) javac com/galen/v2ch09/hash/Digest.java ： 编译指定java文件。
(2) java com.galen.v2ch09.hash.Digest input.txt：运行Digest类，并传入input.txt文件，默认将使用“SHA-1”哈希算法。
(3) java com.galen.v2ch09.hash.Digest input.txt MD5 ： 运行Digest类，并传入input.txt 文件,使用MD5哈希算法。

2.2 对称加密算法

package com.galen.v2ch09.aes;

import java.io.*;
import java.security.*;
import javax.crypto.*;

/**
* This program tests the AES cipher. Usage:<br>
* javac com/galen/v2ch09/aes/Util.java<br>
* javac com/galen/v2ch09/aes/AESTest.java<br>
* java com.galen.v2ch09.aes.AESTest -genkey secret.key<br>
* java com.galen.v2ch09.aes.AESTest -encrypt plaintext.txt encrypted.txt secret.key<br>
* java com.galen.v2ch09.aes.AESTest -decrypt encrypted.txt decrypted.txt secret.key<br>
*
* @author Cay Horstmann
* @version 1.01 2012-06-10
*/
public class AESTest {
public static void main(String[] args)
throws IOException, GeneralSecurityException, ClassNotFoundException {
if (args[0].equals("-genkey")) {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom();
keygen.init(random);
SecretKey key = keygen.generateKey();
System.out.print(key.toString());
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(args[1]))) {
out.writeObject(key);
}
} else {
int mode;
if (args[0].equals("-encrypt")) {
mode = Cipher.ENCRYPT_MODE;
} else {
mode = Cipher.DECRYPT_MODE;
}

try (ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
InputStream in = new FileInputStream(args[1]);
OutputStream out = new FileOutputStream(args[2])) {
Cipher cipher = Cipher.getInstance("AES");
cipher.init(mode, key);
Util.crypt(in, out, cipher);
}
}
}
}


package com.galen.v2ch09.aes;

import java.io.*;
import java.security.*;
import javax.crypto.*;

public class Util {
/**
* Uses a cipher to transform the bytes in an input stream and sends the transformed bytes to an
* output stream.
*
* @param in     the input stream
* @param out    the output stream
* @param cipher the cipher that transforms the bytes
*/
public static void crypt(InputStream in, OutputStream out, Cipher cipher) throws IOException,
GeneralSecurityException {
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];

int inLength = 0;
boolean more = true;
while (more) {
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
} else more = false;
}
if (inLength > 0) outBytes = cipher.doFinal(inBytes, 0, inLength);
else outBytes = cipher.doFinal();
out.write(outBytes);
}
}



2.3 非对称加密算法

package com.galen.v2ch09.rsa;

import java.io.*;
import java.security.*;
import javax.crypto.*;

/**
* This program tests the RSA cipher. Usage:<br>
* javac com/galen/v2ch09/rsa/Util.java<br>
* javac com/galen/v2ch09/rsa/RSATest.java<br>
* java com.galen.v2ch09.rsa.RSATest -genkey publickey.key privatekey.key<br>
* java com.galen.v2ch09.rsa.RSATest -encrypt plaintext.txt rsaencrypted.txt publickey.key<br>
* java com.galen.v2ch09.rsa.RSATest -decrypt rsaencrypted.txt rsadecrypted.txt privatekey.key<br>
*
* @author Cay Horstmann
* @version 1.01 2012-06-10
*/
public class RSATest {
private static final int KEYSIZE = 512;

public static void main(String[] args)
throws IOException, GeneralSecurityException, ClassNotFoundException {
if (args[0].equals("-genkey")) {
KeyPairGenerator pairgen = KeyPairGenerator.getInstance("RSA");
SecureRandom random = new SecureRandom();
pairgen.initialize(KEYSIZE, random);
KeyPair keyPair = pairgen.generateKeyPair();
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(args[1]))) {
out.writeObject(keyPair.getPublic());
}
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(args[2]))) {
out.writeObject(keyPair.getPrivate());
}
} else if (args[0].equals("-encrypt")) {
KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom();
keygen.init(random);
SecretKey key = keygen.generateKey();

try (ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
DataOutputStream out = new DataOutputStream(new FileOutputStream(args[2]));
InputStream in = new FileInputStream(args[1])) {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.WRAP_MODE, publicKey);
byte[] wrappedKey = cipher.wrap(key);
out.writeInt(wrappedKey.length);
out.write(wrappedKey);

cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key);
Util.crypt(in, out, cipher);
}
} else {
try (DataInputStream in = new DataInputStream(new FileInputStream(args[1]));
ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
OutputStream out = new FileOutputStream(args[2])) {
byte[] wrappedKey = new byte[length];

// unwrap with RSA private key

Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.UNWRAP_MODE, privateKey);
Key key = cipher.unwrap(wrappedKey, "AES", Cipher.SECRET_KEY);

cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, key);

com.galen.v2ch09.rsa.Util.crypt(in, out, cipher);
}
}
}
}



package com.galen.v2ch09.rsa;

import java.io.*;
import java.security.*;
import javax.crypto.*;

public class Util {
/**
* Uses a cipher to transform the bytes in an input stream and sends the transformed bytes to an
* output stream.
*
* @param in     the input stream
* @param out    the output stream
* @param cipher the cipher that transforms the bytes
*/
public static void crypt(InputStream in, OutputStream out, Cipher cipher) throws IOException,
GeneralSecurityException {
int blockSize = cipher.getBlockSize();
int outputSize = cipher.getOutputSize(blockSize);
byte[] inBytes = new byte[blockSize];
byte[] outBytes = new byte[outputSize];

int inLength = 0;
;
boolean more = true;
while (more) {
if (inLength == blockSize) {
int outLength = cipher.update(inBytes, 0, blockSize, outBytes);
out.write(outBytes, 0, outLength);
} else more = false;
}
if (inLength > 0) outBytes = cipher.doFinal(inBytes, 0, inLength);
else outBytes = cipher.doFinal();
out.write(outBytes);
}
}



3 数字签名

java核心技术卷2【core java】中有这样一个例子，一位亿万富翁生前留下遗嘱：“我死了之后，我的财产将由我的孩子们评分，但是，我的儿子George应该拿不到一分钱”。遗嘱的信息是公开的（不用保密），但是遗嘱的内容不能被篡改。那么数字签名的作用，就类似于指纹或者个人手写签名的作用。

3.2 数字签名

1、Alice写了一个邮件；
2、使用hash算法，如MD5算法，计算得到该邮件内容的摘要（一个指定长度的hash字符串）；
3、Alice用它的私钥对摘要加密；
4、将邮件以及加密后的摘要发送给Bob；
5、Bob用Alice的公钥解密邮件摘要，得到摘要A；
6、Bob采用同样的hash算法计算该邮件的摘要，得到摘要B；

1、上述第5步，如果使用Alice的公钥解开了摘要，那么就说明该邮件是Alice发送的；
2、上述第5步，第6步得到的摘要A=摘要B，则证明邮件在传输过程中没有被修改过。

3.3 数字证书

1、首先Alice去找"证书中心"（certificate authority，简称CA），为公钥做认证。证书中心用自己的私钥，对Alice的公钥和一些相关信息一起加密，生成"数字证书"（Digital Certificate）：

2、A在邮件正文下方除了数字签名，另外加上这张数字证书

3、Bob收到Email后用CA的公钥解密这份数字证书，拿到Alice的公钥，然后验证数字签名，后面流程就和上一步的流程一样了，不再赘述。

(1) 假设数字证书被伪造了呢？

(2) 要是有1万个人要给B发邮件，难道Bob要保存1万份不同的CA公钥吗？

(3) 如何验证根证书可靠性？

4 内容加密

• 对于内容加密，有两种处理方式，对称加密（对称加密算法，对称密码）和非对称加密（非对称加密算法，公共密钥，私有密钥）。
• 对称加密，采用同一密码，运算快，安全度低；非对称加密，采用公私钥加密，运算慢，安全度高。当数据内容量大的情况下，我们采用对称加密，同时将对称密码采用非对称加密。（详细见2.3代码的实现方式）

5、源码说明

(1) 当使用javac命令编译源码时，需要将teminal定位到source folder目录（一般是source目录）的下一级目录，然后进行编译或者运行。否则，引用其他类时，会出现“错误：找不到符号”。如：

(2) source folder目录可以在project structure中看到：

(3) 代码中使用到的文件，统一放在 source folder（本例中为src）目录下，这样可以直接通过文件名获取到。

1、阮一峰老师的博文：【数据安全】一、数字签名是什么？
2、【数据安全】一、通俗理解数字签名，数字证书和https

12-16 1万+

08-02 453

11-08 581

12-12 7070

04-14 99

11-15 725

09-16 206

12-06 1万+

密码学与网络安全课程习题集及参考答案（一些思考题）

©️2020 CSDN 皮肤主题: 精致技术 设计师: CSDN官方博客

1.余额是钱包充值的虚拟货币，按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载，可以购买VIP、C币套餐、付费专栏及课程。