The Code
Create a file called CryptBot.java with the following imports
and fields:
import org.jibble.pircbot.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class CryptBot extends PircBot {
private Cipher cipher;
private SecretKey key;
private IvParameterSpec p;
Now define the constructor for CryptBot. If you want to use two of
these bots on the same server, they will have to have different
nicknames, so the first argument to the constructor will be for the
bot's name. Each bot will need to be told what the
pass phrase or key is, so the second argument keyString is used to
take this. The first 24 bytes of the keyString will be used to make a
DES-EDE
("triple-DES")
key, so it is padded with zero bytes if it is too short.
The constructor will also initialize the instance fields used to
encrypt and decrypt messages. Append this to the CryptBot class:
public CryptBot(String name, String keyString) throws GeneralSecurityException {
setName(name);
byte[] keyBytes = new byte[24];
int length = Math.min(keyBytes.length, keyString.length( ));
System.arraycopy(keyString.getBytes( ), 0, keyBytes, 0, length);
DESedeKeySpec spec = new DESedeKeySpec(keyBytes);
SecretKeyFactory keyFactory =
SecretKeyFactory.getInstance("DESede");
key = keyFactory.generateSecret(spec);
cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
p = new IvParameterSpec(keyBytes);
}
Now to make a simple method to encrypt or decrypt an array of bytes.
The parameter encrypt is set to
true if the array is to be encrypted; otherwise,
it will try to decrypt the array. The resulting array is returned by
the method. If the message could not be decrypted, the original array
is returned. Append the following method to the CryptBot class:
public byte[] crypt(byte[] input, boolean encrypt) {
byte[] output = input;
try {
cipher.init(encrypt ? Cipher.ENCRYPT_MODE:Cipher.DECRYPT_MODE, key, p);
output = cipher.doFinal(input);
}
catch (GeneralSecurityException e) {
// Unable to encypt or decrypt. Leave the input as it was.
}
return output;
}
The sendEncryptedMessage method will allow us to
send an encrypted message from the bot. The key will be used to
encrypt the message, allowing it to be read by anyone else who holds
a copy of the key. The first parameter is used to specify the target,
which can be a nickname or a channel. The second parameter specifies
the message, which gets encrypted, and the resulting bytes are sent
encoded as hexadecimal digits. Append this method to the CryptBot
class:
public void sendEncryptedMessage(String target, String message) {
byte[] plainText = message.getBytes( );
byte[] encrypted = crypt(plainText, true);
StringBuffer buffer = new StringBuffer( );
for (int i = 0; i < encrypted.length; i++) {
String hex = Integer.toString(
(encrypted[i] & 0xff) + 0x100, 16).substring(1);
buffer.append(hex);
}
System.out.println("Sending encrypted message: " + new String(encrypted));
sendMessage(target, buffer.toString( ));
}
Now you can add one final method to allow each bot to receive private
messages. This method overrides the
onPrivateMessage method in the PircBot abstract
class. When private messages are received, the bot will try to
decrypt them and print out the decrypted message. Append this method
to the CryptBot class:
public void onPrivateMessage(String sender, String login,
String hostname, String message) {
try {
byte[] encrypted = new byte[message.length( ) / 2];
for (int i = 0; i < message.length( ); i += 2) {
String hex = message.substring(i, i + 2);
encrypted[i / 2] = (byte) Integer.parseInt(hex, 16);
}
byte[] plainText = crypt(encrypted, false);
message = new String(plainText);
System.out.println("Plain text from " + sender + ": " + message);
}
catch (Exception e) {
// Message was not in a suitable format.
}
}
}
Piecing together all of the preceding code, you end up with the
complete CryptBot class. All you need to do now is write a main
method to instantiate a couple of them and tell them to talk to each
other.
Save this in a file called CryptBotMain.java:
public class CryptBotMain {
public static void main(String[] args) throws Exception {
String keyString = "my top secret key";
CryptBot bot1 = new CryptBot("CryptBot1", keyString);
CryptBot bot2 = new CryptBot("CryptBot2", keyString);
bot1.connect("irc.freenode.net");
bot2.connect("irc.freenode.net");
bot1.sendEncryptedMessage("CryptBot2", "Hello");
bot1.sendEncryptedMessage("CryptBot2", "freenode rocks");
bot1.sendEncryptedMessage("CryptBot2", "This is a secret message!");
}
}
Note that both bots are constructed with different nicknames so they
can join the same server. Both bots are given the same keyString, so
they will be able to decrypt messages from each other.