📄 encryptionmanager.java
字号:
/**
This class handles all the necessary steps to achieve a secure link between two socket connections.
All encryption is eventually done using the Rijndael algorithm which is fast but relies on both parties having the same encryption key.
To get around this problem, a random key is generated and exchanged using RSA. One of the connections should generate an RSA public key that
is transmitted to the other connection. The second connection will then generate the Rijndael key and send it back using the first connection's
public key.
To use this class, one of the connections should call the method "generateRSAkey", then call "initialiseHandshaking".
The other connection should just call "waitForHandshaking". Once this process is complete, either connection can use the "encryptWithRijndael" to
encrypt messages and "decryptWithRijndael" to decrypt received messages.
Using a higher length RSA key gives more security but takes longer to generate and encrypt/decrypt (although it is only used once to send the Rijndael key).
A key length of 1024 bits should be fine for some time.
Last updated 17th Aug 2006
*/
import java.io.*;
import java.net.*;
import java.security.SecureRandom;
import java.util.*;
import java.util.zip.*;
import rsa.*;
import rijndael.*;
public class encryptionManager
{
/** our RSA private key */
private privateKey myPrivateKey;
/** the RSA public key representing a remote user we wish to communicate with */
private publicKey remotePublicKey;
/** random session key for Rijndael encryption (as string) */
private String RijndaelSessionKey;
/** the actual Rijndael session key */
private Object RijndaelKey;
/** size of Rijndael keys */
public int RijndaelKeySize = 256;
/** secure random number generator - SecureRandom is slower than Random but it is important to generate really random keys */
private SecureRandom secRand = new SecureRandom();
/** our parent */
private chat parent;
/** constructor */
public encryptionManager(chat parent)
{
this.parent = parent;
}
/** generate a new RSA key */
public void generateRSAkey(int RSAkeyLength)
{
log("Generating " + RSAkeyLength + "-bit RSA key using prime probability of " + rsa.privateKey.PRIME_PROBABILITY + "...");
myPrivateKey = new privateKey(RSAkeyLength);
log("Generated " + RSAkeyLength + "-bit RSA key successfully");
}
/** ensures a private key exists */
public void ensurePrivateKeyExists()
{
if (myPrivateKey == null)
generateRSAkey(Integer.parseInt(parent.txtRSAkeyLength.getText()));
}
/** start the handshaking */
public void initialiseHandshaking(InputStream in, OutputStream out) throws IOException, ClassNotFoundException, java.security.InvalidKeyException
{
ensurePrivateKeyExists();
transmitRSAkey(new ObjectOutputStream(out));
receiveRijndaelSessionKey(new ObjectInputStream(in));
createRijndaelKey();
}
/** wait for the handshaking to be initialised by the remote machine */
public void waitForHandshaking(InputStream in, OutputStream out) throws IOException, ClassNotFoundException, java.security.InvalidKeyException
{
receiveRSAkey(new ObjectInputStream(in));
generateRijndaelSessionKey();
transmitRijndaelSessionKey(new ObjectOutputStream(out));
createRijndaelKey();
}
/** returns the size of the remote public key */
public int getRemotePublicKeyLength()
{
return remotePublicKey.N.bitLength();
}
/** encrypts a string using the Rijndael session key */
public String encryptWithRijndael(String msg) throws IOException
{
// Rijndael crypto needs to be done in blocks
while (msg.length() % Rijndael_Algorithm.blockSize() > 0) // pad msg to multiple of 16 bytes
msg += " ";
StringBuffer ct = new StringBuffer();
byte[] block = new byte[Rijndael_Algorithm.blockSize()];
int msgIndex = 0;
int blockIndex = 0;
while (msgIndex < msg.length())
{
block[blockIndex] = (byte)msg.charAt(msgIndex);
blockIndex++;
msgIndex++;
if (blockIndex == Rijndael_Algorithm.blockSize())
{
// System.out.println(toHex(block));
ct.append(toHex(Rijndael_Algorithm.blockEncrypt(block, 0, RijndaelKey)));
blockIndex = 0;
block = new byte[Rijndael_Algorithm.blockSize()];
}
}
// System.out.println("ct=" + ct);
return ct.toString();
}
/** decrypts a string using the Rijndael session key */
public String decryptWithRijndael(String msg) throws IOException
{
//System.out.println("msg=" + msg);
byte[] ct = fromHex(msg);
StringBuffer pt = new StringBuffer();
byte[] block = new byte[Rijndael_Algorithm.blockSize()];
int msgIndex = 0;
int blockIndex = 0;
while (msgIndex < ct.length)
{
block[blockIndex] = ct[msgIndex];
blockIndex++;
msgIndex++;
if (blockIndex == Rijndael_Algorithm.blockSize())
{
// System.out.println(toHex(block));
pt.append(new String(Rijndael_Algorithm.blockDecrypt(block, 0, RijndaelKey)));
blockIndex = 0;
block = new byte[Rijndael_Algorithm.blockSize()];
}
}
return pt.toString().trim();
}
/** encrypts a byte array using the Rijndael session key */
public byte[] encryptWithRijndael(byte[] msg) throws IOException
{
String plainText = toHex(msg);
String cipherText = encryptWithRijndael(plainText);
return fromHex(cipherText);
// return cipherText.getBytes();
}
/** decrypts a string using the Rijndael session key */
public byte[] decryptWithRijndael(byte[] msg) throws IOException
{
// String cipherText = new String(msg);
String cipherText = toHex(msg);
String plainText = decryptWithRijndael(cipherText);
return fromHex(plainText);
}
/** translate a byte array into hex */
public static String toHex(byte[] b)
{
StringBuffer sb = new StringBuffer();
for(int i = 0; i < b.length;i++)
sb.append(lpad(Long.toHexString(b[i] & 0xff), '0', 2) );
return sb.toString().toUpperCase();
}
/** translate a string of hex characters into a byte array */
public static byte[] fromHex(String s)
{
byte[] b = new byte[s.length() / 2];
for (int i = 0; i < s.length()/2; i++)
b[i] = (byte)Integer.parseInt(s.substring(i*2, i*2+2), 16);
return b;
}
/** left pad a string */
public static String lpad(String s, char c, int size)
{
StringBuffer sb = new StringBuffer(s);
while (sb.length() < size)
sb.insert(0, c);
return sb.toString();
}
/*** PRIVATE METHODS FOLLOW */
/** send our public key to the remote machine */
private void transmitRSAkey(ObjectOutputStream objectOut) throws IOException
{
log("Transmitting our RSA public key");
objectOut.writeObject(myPrivateKey.getPublicKey());
objectOut.flush();
log("Transmitted our RSA public key");
}
/** reads a public key from a remote machine */
private void receiveRSAkey(ObjectInputStream objectIn) throws IOException, ClassNotFoundException
{
log("Awaiting public key from remote");
remotePublicKey = (publicKey)objectIn.readObject();
log("Received " + remotePublicKey.N.bitLength() + "-bit public RSA key from remote");
}
/** generates a random Rijndael session key */
private void generateRijndaelSessionKey()
{
log("Generating " + RijndaelKeySize + "-bit AES key");
int stringLength = RijndaelKeySize / 8;
// log("Session key str len=" + stringLength);
RijndaelSessionKey = genRandomString(stringLength, true);
// log("Generated Rijndael key: " + RijndaelSessionKey + " of " + RijndaelSessionKey.length() + " bytes");
// print key in binary
/*for (int i = 1; i <= RijndaelSessionKey.length(); i++)
{
String charAsBits = Integer.toBinaryString((int)RijndaelSessionKey.charAt(i-1));
while (charAsBits.length() < 8) // 8 for Ascii keys
charAsBits = "0" + charAsBits;
System.out.print(charAsBits);
}
System.out.println();
*/
}
/** transmits the Rijndael session key to the remote machine */
private void transmitRijndaelSessionKey(ObjectOutputStream objectOut) throws IOException
{
log("Transmitting AES key");
sendMessageWithRSA(objectOut, RijndaelSessionKey);
log("Transmitted AES key");
}
/** reads the Rijndael session key from the remote machine */
private void receiveRijndaelSessionKey(ObjectInputStream objectIn) throws IOException, ClassNotFoundException
{
log("Awaiting AES key");
RijndaelSessionKey = readMessageWithRSA(objectIn);
log("Received " + (RijndaelSessionKey.length() * 8) + "-bit AES key");
}
/** create the Rijndael engine used for encryption/decryption */
private void createRijndaelKey() throws java.security.InvalidKeyException, UnsupportedEncodingException
{
RijndaelKey = Rijndael_Algorithm.makeKey(RijndaelSessionKey.getBytes());
}
/** sends a line of text to the remote machine using RSA */
private void sendMessageWithRSA(ObjectOutputStream objectOut, String msg) throws IOException
{
// encrypt it using the public key sent by the remote machine
ArrayList cipherText = remotePublicKey.encrypt(msg);
// transmit the encrypted text
objectOut.writeObject(cipherText);
objectOut.flush();
}
/** reads a line of text from the remote machine using RSA */
private String readMessageWithRSA(ObjectInputStream objectIn) throws IOException, ClassNotFoundException
{
// read the encrypted text
ArrayList cipherText = (ArrayList)objectIn.readObject();
// decrypt the text
String plainText = myPrivateKey.decrypt(cipherText);
return plainText;
}
/** compresses some text */
private String compress(String s) throws IOException
{
ByteArrayOutputStream bout = new ByteArrayOutputStream();
GZIPOutputStream zout = new GZIPOutputStream(bout);
ObjectOutputStream out = new ObjectOutputStream(zout);
out.writeObject(s);
out.flush();
out.close();
zout.close();
bout.close();
return bout.toString("ISO-8859-1");
}
/** decompresses some text */
private String decompress(String s) throws IOException
{
try
{
ByteArrayInputStream bin = new ByteArrayInputStream(s.getBytes("ISO-8859-1"));
GZIPInputStream zin = new GZIPInputStream(bin);
ObjectInputStream in = new ObjectInputStream(zin);
String decompressed = (String)in.readObject();
in.close();
zin.close();
bin.close();
return decompressed;
}
catch (ClassNotFoundException e)
{
// won't happen
return null;
}
}
/** generates a random string of either Ascii or Unicode characters */
public String genRandomString(int length, boolean asciiOnly)
{
StringBuffer tmp = new StringBuffer();
if (asciiOnly)
{
for (int i = 0; i < length; i++)
{
int r = Math.round(secRand.nextFloat() * 95)+32;
tmp.append((char)r);
}
}
else
{
for (int i = 0; i < length; i++)
tmp.append((char)secRand.nextInt());
}
return tmp.toString();
}
/** logs a debug message */
private void log(String msg)
{
parent.log(msg);
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -