9.1 类加载器
9.1.2 类加载器的层次结构
9.1.4 编写你自己的类加载器
package classLoader;
import java.io.*;
import java.lang.reflect.*;
import java.nio.file.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* This program demonstrates a custom class loader that decrypts class files.
* @version 1.24 2016-05-10
* @author Cay Horstmann
*/
public class ClassLoaderTest
{
public static void main(String[] args)
{
EventQueue.invokeLater(() ->
{
JFrame frame = new ClassLoaderFrame();
frame.setTitle("ClassLoaderTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
}
/**
* This frame contains two text fields for the name of the class to load and the decryption key.
*/
class ClassLoaderFrame extends JFrame
{
private JTextField keyField = new JTextField("3", 4);
private JTextField nameField = new JTextField("Calculator", 30);
private static final int DEFAULT_WIDTH = 300;
private static final int DEFAULT_HEIGHT = 200;
public ClassLoaderFrame()
{
setSize(DEFAULT_WIDTH, DEFAULT_HEIGHT);
setLayout(new GridBagLayout());
add(new JLabel("Class"), new GBC(0, 0).setAnchor(GBC.EAST));
add(nameField, new GBC(1, 0).setWeight(100, 0).setAnchor(GBC.WEST));
add(new JLabel("Key"), new GBC(0, 1).setAnchor(GBC.EAST));
add(keyField, new GBC(1, 1).setWeight(100, 0).setAnchor(GBC.WEST));
JButton loadButton = new JButton("Load");
add(loadButton, new GBC(0, 2, 2, 1));
loadButton.addActionListener(event -> runClass(nameField.getText(), keyField.getText()));
pack();
}
/**
* Runs the main method of a given class.
* @param name the class name
* @param key the decryption key for the class files
*/
public void runClass(String name, String key)
{
try
{
ClassLoader loader = new CryptoClassLoader(Integer.parseInt(key));
Class<?> c = loader.loadClass(name);
Method m = c.getMethod("main", String[].class);
m.invoke(null, (Object) new String[] {});
}
catch (Throwable e)
{
JOptionPane.showMessageDialog(this, e);
}
}
}
/**
* This class loader loads encrypted class files.
*/
class CryptoClassLoader extends ClassLoader
{
private int key;
/**
* Constructs a crypto class loader.
* @param k the decryption key
*/
public CryptoClassLoader(int k)
{
key = k;
}
protected Class<?> findClass(String name) throws ClassNotFoundException
{
try
{
byte[] classBytes = null;
classBytes = loadClassBytes(name);
Class<?> cl = defineClass(name, classBytes, 0, classBytes.length);
if (cl == null) throw new ClassNotFoundException(name);
return cl;
}
catch (IOException e)
{
throw new ClassNotFoundException(name);
}
}
/**
* Loads and decrypt the class file bytes.
* @param name the class name
* @return an array with the class file bytes
*/
private byte[] loadClassBytes(String name) throws IOException
{
String cname = name.replace('.', '/') + ".caesar";
byte[] bytes = Files.readAllBytes(Paths.get(cname));
for (int i = 0; i < bytes.length; i++)
bytes[i] = (byte) (bytes[i] - key);
return bytes;
}
}
package classLoader;
import java.io.*;
/**
* Encrypts a file using the Caesar cipher.
* @version 1.01 2012-06-10
* @author Cay Horstmann
*/
public class Caesar
{
public static void main(String[] args) throws Exception
{
if (args.length != 3)
{
System.out.println("USAGE: java classLoader.Caesar in out key");
return;
}
try(FileInputStream in = new FileInputStream(args[0]);
FileOutputStream out = new FileOutputStream(args[1]))
{
int key = Integer.parseInt(args[2]);
int ch;
while ((ch = in.read()) != -1)
{
byte c = (byte) (ch + key);
out.write(c);
}
}
}
}
9.1.5 字节码校验
9.4 数字签名
9.4.1 消息摘要
package hash;
import java.io.*;
import java.nio.file.*;
import java.security.*;
/**
* This program computes the message digest of a file.
* @version 1.20 2012-06-16
* @author Cay Horstmann
*/
public class Digest
{
/**
* @param args args[0] is the filename, args[1] is optionally the algorithm
* (SHA-1, SHA-256, or 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[] input = Files.readAllBytes(Paths.get(args[0]));
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);
}
}
9.4.2 消息签名
9.4.3 校验签名
9.4.4 认证问题
9.4.5 证书签名
9.5 加密
9.5.1 对称密码
9.5.2 密钥生成
package 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)
{
inLength = in.read(inBytes);
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);
}
}
package aes;
import java.io.*;
import java.security.*;
import javax.crypto.*;
/**
* This program tests the AES cipher. Usage:<br>
* java aes.AESTest -genkey keyfile<br>
* java aes.AESTest -encrypt plaintext encrypted keyfile<br>
* java aes.AESTest -decrypt encrypted decrypted keyfile<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();
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]))
{
Key key = (Key) keyIn.readObject();
Cipher cipher = Cipher.getInstance("AES");
cipher.init(mode, key);
Util.crypt(in, out, cipher);
}
}
}
}
9.5.3 密码流
9.5.4 公共密钥密码
package rsa;
import java.io.*;
import java.security.*;
import javax.crypto.*;
/**
* This program tests the RSA cipher. Usage:<br>
* java rsa.RSATest -genkey public private<br>
* java rsa.RSATest -encrypt plaintext encrypted public<br>
* java rsa.RSATest -decrypt encrypted decrypted private<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();
// wrap with RSA public key
try (ObjectInputStream keyIn = new ObjectInputStream(new FileInputStream(args[3]));
DataOutputStream out = new DataOutputStream(new FileOutputStream(args[2]));
InputStream in = new FileInputStream(args[1]) )
{
Key publicKey = (Key) keyIn.readObject();
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]))
{
int length = in.readInt();
byte[] wrappedKey = new byte[length];
in.read(wrappedKey, 0, length);
// unwrap with RSA private key
Key privateKey = (Key) keyIn.readObject();
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);
Util.crypt(in, out, cipher);
}
}
}
}