Difference between revisions of "AES Java Implementation"

From Second Life Wiki
Jump to navigation Jump to search
Line 5: Line 5:
== Base64Coder ==
== Base64Coder ==
<java>package lslAESCrypto;
<java>package lslAESCrypto;
/**
/**
  * A Base64 Encoder/Decoder.
  * A Base64 Encoder/Decoder.
Line 10: Line 11:
  * This class is used to encode and decode data in Base64 format as described in
  * This class is used to encode and decode data in Base64 format as described in
  * RFC 1521.
  * RFC 1521.
  * <p>
  * </p>
* This is "Open Source" software and released under the <a
* href="http://www.gnu.org/licenses/lgpl.html">GNU/LGPL</a> license.<br>
* It is provided "as is" without warranty of any kind.<br>
* Copyright 2003: Christian d'Heureuse, Inventec Informatik AG, Switzerland.<br>
* Home page: <a href="http://www.source-code.biz">www.source-code.biz</a>
  */
  */
public class Base64Coder {
public class Base64Coder {
/** Mapping table from 6-bit nibbles to Base64 characters. */
/** Mapping table from 6-bits to Base64 characters. */
private static final char[] map1 = new char[] { 'A', 'B', 'C', 'D', 'E', 'F',
private static char[] BITS_TO_BASE64_CHAR =
'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'+', '/' };
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+',
/** Mapping table from Base64 characters to 6-bit nibbles. */
'/' };
private static final byte[] map2 = new byte[] { -1, -1, -1, -1, -1, -1, -1, -1,
 
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/** Mapping table from Base64 characters to 6-bits. */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62,
private static byte[] BASE64_CHAR_TO_BITS =
-1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1,
new byte[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1,
47, 48, 49, 50, 51, -1, -1, -1, -1, -1, };
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
47, 48, 49, 50, 51, -1, -1, -1, -1, -1, };


/**
/**
Line 45: Line 44:
*            if the input is not valid Base64 encoded data.
*            if the input is not valid Base64 encoded data.
*/
*/
public static byte[] decode(final char[] in) {
public static byte[] decode(final char[] in)
int iLen = in.length;
throws IllegalArgumentException {
if (iLen % 4 != 0)
int len = in.length;
if (len % 4 != 0)
throw new IllegalArgumentException(
throw new IllegalArgumentException(
"Length of Base64 encoded input string is not a multiple of 4.");
"Length of Base64 encoded input string is not a multiple of 4.");
while ((iLen > 0) && (in[iLen - 1] == '='))
 
iLen--;
// Ignore trailing equals
final int oLen = (iLen * 3) / 4;
while ((len > 0) && (in[len - 1] == '='))
final byte[] out = new byte[oLen];
--len;
int ip = 0;
 
int op = 0;
final byte[] bytes = new byte[(len * 3) / 4];
while (ip < iLen) {
int o = 0;
final int i0 = in[ip++];
 
final int i1 = in[ip++];
for (int i = 0; i < len;) {
final int i2 = ip < iLen ? in[ip++] : 'A';
try {
final int i3 = ip < iLen ? in[ip++] : 'A';
final char c0 = in[i++];
if ((i0 > 127) || (i1 > 127) || (i2 > 127) || (i3 > 127))
final char c1 = in[i++];
throw new IllegalArgumentException(
final char c2 = (i < len) ? in[i++] : 'A';
"Illegal character in Base64 encoded data.");
final char c3 = (i < len) ? in[i++] : 'A';
final int b0 = Base64Coder.map2[i0];
 
final int b1 = Base64Coder.map2[i1];
if ((c0 > 127) || (c1 > 127) || (c2 > 127) || (c3 > 127))
final int b2 = Base64Coder.map2[i2];
throw new IllegalArgumentException(
final int b3 = Base64Coder.map2[i3];
"Invalid base64 character");
if ((b0 < 0) || (b1 < 0) || (b2 < 0) || (b3 < 0))
 
throw new IllegalArgumentException(
final byte b0 = Base64Coder.BASE64_CHAR_TO_BITS[c0];
"Illegal character in Base64 encoded data.");
final byte b1 = Base64Coder.BASE64_CHAR_TO_BITS[c1];
final int o0 = (b0 << 2) | (b1 >>> 4);
final byte b2 = Base64Coder.BASE64_CHAR_TO_BITS[c2];
final int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
final byte b3 = Base64Coder.BASE64_CHAR_TO_BITS[c3];
final int o2 = ((b2 & 3) << 6) | b3;
 
out[op++] = (byte) o0;
if ((b0 < 0) || (b1 < 0) || (b2 < 0) || (b3 < 0))
if (op < oLen) out[op++] = (byte) o1;
throw new IllegalArgumentException(
if (op < oLen) out[op++] = (byte) o2;
"Invalid base64 character");
 
bytes[o++] = (byte) ((b0 << 2) | (b1 >>> 4));
if (o < bytes.length) {
bytes[o++] = (byte) (((b1 & 0xF) << 4) | (b2 >>> 2));
if (o < bytes.length)
bytes[o++] = (byte) (((b2 & 0x3) << 6) | b3);
}
} catch (final ArrayIndexOutOfBoundsException e) {
throw new IllegalArgumentException("Invalid base64 character");
}
}
}
return out;
 
return bytes;
}
}


Line 116: Line 127:
*/
*/
public static char[] encode(final byte[] in) {
public static char[] encode(final byte[] in) {
return Base64Coder.encode(in, in.length);
return Base64Coder.encode(in, 0, in.length);
}
}


Line 125: Line 136:
* @param in
* @param in
*            an array containing the data bytes to be encoded.
*            an array containing the data bytes to be encoded.
* @param iLen
* @param offset
*            number of bytes to process in <code>in</code>.
*            the offset into the array at which to begin reading.
* @param bits
*            number of <b>bits</b> to process from <code>in</code>.
* @return A character array with the Base64 encoded data.
* @return A character array with the Base64 encoded data.
*/
*/
public static char[] encode(final byte[] in, final int iLen) {
public static char[] encode(
final int oDataLen = (iLen * 4 + 2) / 3; // output length without
final byte[] in,
// padding
final int offset,
final int oLen = ((iLen + 2) / 3) * 4; // output length including
final int bits) {
// padding
int length = bits / 8;
final char[] out = new char[oLen];
if ((length * 8) < bits) ++length;
int ip = 0;
 
int op = 0;
final char[] chars = new char[((length + 2) / 3) * 4];
while (ip < iLen) {
final int out = ((length * 4) + 2) / 3;
final int i0 = in[ip++] & 0xff;
 
final int i1 = ip < iLen ? in[ip++] & 0xff : 0;
int mask = ~(-1 << (8 - (bits % 8))) | ~(-1 << (bits % 8));
final int i2 = ip < iLen ? in[ip++] & 0xff : 0;
if (mask == 0) mask = 0xFF;
final int o0 = i0 >>> 2;
 
final int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
int o = 0;
final int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
final int end = length + offset;
final int o3 = i2 & 0x3F;
for (int i = offset; i < end;) {
out[op++] = Base64Coder.map1[o0];
final int b0 = ((i + 1) == end) ? in[i++] & mask : in[i++] & 0xFF;
out[op++] = Base64Coder.map1[o1];
final int b1 =
out[op] = op < oDataLen ? Base64Coder.map1[o2] : '=';
(i < length) ? (((i + 1) == end) ? in[i++] & mask
op++;
: in[i++] & 0xFF) : 0;
out[op] = op < oDataLen ? Base64Coder.map1[o3] : '=';
final int b2 =
op++;
(i < length) ? (((i + 1) == end) ? in[i++] & mask
: in[i++] & 0xFF) : 0;
 
final int i0 = (b0 >>> 2);
final int i1 = (((b0 & 0x3) << 4) | (b1 >>> 4));
final int i2 = (((b1 & 0xF) << 2) | (b2 >>> 6));
final int i3 = b2 & 0x3F;
 
chars[o++] = Base64Coder.BITS_TO_BASE64_CHAR[i0];
chars[o++] = Base64Coder.BITS_TO_BASE64_CHAR[i1];
chars[o] = (o < out) ? Base64Coder.BITS_TO_BASE64_CHAR[i2] : '=';
++o;
chars[o] = (o < out) ? Base64Coder.BITS_TO_BASE64_CHAR[i3] : '=';
++o;
}
}
return out;
 
return chars;
}
 
/**
* Produces a base64 string from the provided byte-array.
*
* @param bytes
*            the byte-array to read-from.
* @return the base64 encoded string produced.
*/
public static String encodeString(final byte[] bytes) {
return Base64Coder.encodeString(bytes, 0, bytes.length);
}
 
/**
* Produces a base64 string from the provided byte-array slice.
*
* @param bytes
*            the byte-array to read-from.
* @param offset
*            the offset into the array at which to begin reading.
* @param bits
*            number of <b>bits</b> to process from <code>bytes</code>.
* @return the base64 encoded string produced.
*/
public static String encodeString(
final byte[] bytes,
final int offset,
final int bits) {
return new String(Base64Coder.encode(bytes, offset, bits));
}
}


Line 168: Line 224:


/** Dummy constructor. */
/** Dummy constructor. */
private Base64Coder() {}
private Base64Coder() { /* Blocking constructor */}


}</java>
}</java>

Revision as of 08:36, 20 August 2009

Description

The following is a simple Java example of AES encryption and decryption, compatible with the LSL AES Engine by Haravikk Mistral.

Required Classes

Base64Coder

<java>package lslAESCrypto;

/**

* A Base64 Encoder/Decoder.

*

* This class is used to encode and decode data in Base64 format as described in * RFC 1521. *

*/

public class Base64Coder { /** Mapping table from 6-bits to Base64 characters. */ private static char[] BITS_TO_BASE64_CHAR = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };

/** Mapping table from Base64 characters to 6-bits. */ private static byte[] BASE64_CHAR_TO_BITS = new byte[] { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, };

/** * Decodes a byte array from Base64 format. No blanks or line breaks are * allowed within the Base64 encoded data. * * @param in * a character array containing the Base64 encoded data. * @return An array containing the decoded data bytes. * @throws IllegalArgumentException * if the input is not valid Base64 encoded data. */ public static byte[] decode(final char[] in) throws IllegalArgumentException { int len = in.length; if (len % 4 != 0) throw new IllegalArgumentException( "Length of Base64 encoded input string is not a multiple of 4.");

// Ignore trailing equals while ((len > 0) && (in[len - 1] == '=')) --len;

final byte[] bytes = new byte[(len * 3) / 4]; int o = 0;

for (int i = 0; i < len;) { try { final char c0 = in[i++]; final char c1 = in[i++]; final char c2 = (i < len) ? in[i++] : 'A'; final char c3 = (i < len) ? in[i++] : 'A';

if ((c0 > 127) || (c1 > 127) || (c2 > 127) || (c3 > 127)) throw new IllegalArgumentException( "Invalid base64 character");

final byte b0 = Base64Coder.BASE64_CHAR_TO_BITS[c0]; final byte b1 = Base64Coder.BASE64_CHAR_TO_BITS[c1]; final byte b2 = Base64Coder.BASE64_CHAR_TO_BITS[c2]; final byte b3 = Base64Coder.BASE64_CHAR_TO_BITS[c3];

if ((b0 < 0) || (b1 < 0) || (b2 < 0) || (b3 < 0)) throw new IllegalArgumentException( "Invalid base64 character");

bytes[o++] = (byte) ((b0 << 2) | (b1 >>> 4)); if (o < bytes.length) { bytes[o++] = (byte) (((b1 & 0xF) << 4) | (b2 >>> 2)); if (o < bytes.length) bytes[o++] = (byte) (((b2 & 0x3) << 6) | b3); } } catch (final ArrayIndexOutOfBoundsException e) { throw new IllegalArgumentException("Invalid base64 character"); } }

return bytes; }

/** * Decodes a byte array from Base64 format. * * @param s * a Base64 String to be decoded. * @return An array containing the decoded data bytes. * @throws IllegalArgumentException * if the input is not valid Base64 encoded data. */ public static byte[] decode(final String s) { return Base64Coder.decode(s.toCharArray()); }

/** * Decodes a string from Base64 format. * * @param s * a Base64 String to be decoded. * @return A String containing the decoded data. * @throws IllegalArgumentException * if the input is not valid Base64 encoded data. */ public static String decodeString(final String s) { return new String(Base64Coder.decode(s)); }

/** * Encodes a byte array into Base64 format. No blanks or line breaks are * inserted. * * @param in * an array containing the data bytes to be encoded. * @return A character array with the Base64 encoded data. */ public static char[] encode(final byte[] in) { return Base64Coder.encode(in, 0, in.length); }

/** * Encodes a byte array into Base64 format. No blanks or line breaks are * inserted. * * @param in * an array containing the data bytes to be encoded. * @param offset * the offset into the array at which to begin reading. * @param bits * number of bits to process from in. * @return A character array with the Base64 encoded data. */ public static char[] encode( final byte[] in, final int offset, final int bits) { int length = bits / 8; if ((length * 8) < bits) ++length;

final char[] chars = new char[((length + 2) / 3) * 4]; final int out = ((length * 4) + 2) / 3;

int mask = ~(-1 << (8 - (bits % 8))) | ~(-1 << (bits % 8)); if (mask == 0) mask = 0xFF;

int o = 0; final int end = length + offset; for (int i = offset; i < end;) { final int b0 = ((i + 1) == end) ? in[i++] & mask : in[i++] & 0xFF; final int b1 = (i < length) ? (((i + 1) == end) ? in[i++] & mask : in[i++] & 0xFF) : 0; final int b2 = (i < length) ? (((i + 1) == end) ? in[i++] & mask : in[i++] & 0xFF) : 0;

final int i0 = (b0 >>> 2); final int i1 = (((b0 & 0x3) << 4) | (b1 >>> 4)); final int i2 = (((b1 & 0xF) << 2) | (b2 >>> 6)); final int i3 = b2 & 0x3F;

chars[o++] = Base64Coder.BITS_TO_BASE64_CHAR[i0]; chars[o++] = Base64Coder.BITS_TO_BASE64_CHAR[i1]; chars[o] = (o < out) ? Base64Coder.BITS_TO_BASE64_CHAR[i2] : '='; ++o; chars[o] = (o < out) ? Base64Coder.BITS_TO_BASE64_CHAR[i3] : '='; ++o; }

return chars; }

/** * Produces a base64 string from the provided byte-array. * * @param bytes * the byte-array to read-from. * @return the base64 encoded string produced. */ public static String encodeString(final byte[] bytes) { return Base64Coder.encodeString(bytes, 0, bytes.length); }

/** * Produces a base64 string from the provided byte-array slice. * * @param bytes * the byte-array to read-from. * @param offset * the offset into the array at which to begin reading. * @param bits * number of bits to process from bytes. * @return the base64 encoded string produced. */ public static String encodeString( final byte[] bytes, final int offset, final int bits) { return new String(Base64Coder.encode(bytes, offset, bits)); }

/** * Encodes a string into Base64 format. No blanks or line breaks are * inserted. * * @param s * a String to be encoded. * @return A String with the Base64 encoded data. */ public static String encodeString(final String s) { return new String(Base64Coder.encode(s.getBytes())); }

/** Dummy constructor. */ private Base64Coder() { /* Blocking constructor */}

}</java>

HexCoder

<java>package lslAESCrypto; /**

* The following is a simple set of static methods for converting from hex to
* bytes and vice-versa
* 
* @author Haravikk Mistral
* @date Sep 15, 2008, 3:26:42 PM
* @version 1.0
*/

public class HexCoder { /** * Quick converts bytes to hex-characters * * @param bytes * the byte-array to convert * @return the hex-representation */ public static String bytesToHex(final byte[] bytes) { final StringBuffer s = new StringBuffer(bytes.length * 2); for (int i = 0; i < bytes.length; ++i) { s.append(Character.forDigit((bytes[i] >> 4) & 0xF, 16)); s.append(Character.forDigit(bytes[i] & 0xF, 16)); } return s.toString(); }

/** * Quickly converts hex-characters to bytes * * @param s * the hex-string * @return the bytes represented */ public static byte[] hexToBytes(final String s) { final byte[] bytes = new byte[s.length() / 2]; for (int i = 0; i < bytes.length; ++i) bytes[i] = (byte) Integer.parseInt( s.substring(2 * i, (2 * i) + 2), 16); return bytes; } } </java>

Class

<java>package lslAESCrypto;

import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException; import javax.crypto.Cipher; import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec;

/**

*

* This is a class designed to process AES messages sent from the LSL * implementation of AES which can be found here:
<a * href="https://wiki.secondlife.com/wiki/AES_LSL_Implementation">https://wiki.secondlife.com/wiki/AES_LSL_Implementation</a> *

*

* This Java class will be updated to support the same modes of operation as the * LSL implementation. It currently assumes that keys and input-vectors are * processed as hex-strings, and that text is received as plain-text, while * ciphertext will be handled as base64 strings. *

* 
* @author Haravikk
* @date Sep 15, 2008, 4:18:48 PM
* @version 1.0
*/

public class LSLAESCrypto { /** Our currently set block-cipher mode */ protected LSLAESCryptoMode mode = LSLAESCryptoMode.CBC;

/** Out currently set padding mode */ protected LSLAESCryptoPad pad = LSLAESCryptoPad.NoPadding;

/** The currently loaded key */ protected SecretKeySpec keySpec = null; /** The currently loaded input-vector */ protected IvParameterSpec ivSpec = null;

/** The currently active cipher */ protected Cipher cipher = null;

/** * Creates an instance of an LSL compatible AES handler. * * @param mode * the cipher-block mode of operation * @param pad * the padding scheme to use * @param hexKey * the key to start with (represented as hexadecimal string) * @param hexIV * the input vector to start with (represented as hexadecimal * string) * @throws NoSuchAlgorithmException * if the AES algorithm is not supported by the current JVM * @throws NoSuchPaddingException * if the padding scheme chosen is not supported by the current * JVM */ public LSLAESCrypto( final LSLAESCryptoMode mode, final LSLAESCryptoPad pad, final String hexKey, final String hexIV) throws NoSuchAlgorithmException, NoSuchPaddingException { this.init(mode, pad, hexKey, hexIV); }

/** * Decrypts a base64 ciphertext into plain-text * * @param base64ciphertext * the ciphertext to decrypt * @return the plain-text that was originally encrypted * @throws InvalidKeyException * if the currently loaded key is not valid * @throws InvalidAlgorithmParameterException * if the AES algorithm is not supported by the current JVM * @throws IllegalBlockSizeException * if the ciphertext is somehow unreadable (bad base64 * conversion) * @throws BadPaddingException * if the chosen mode of operation requires padded data */ public String decrypt(final String base64ciphertext) throws InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { this.cipher.init(Cipher.DECRYPT_MODE, this.keySpec, this.ivSpec); return new String( this.cipher.doFinal(Base64Coder.decode(base64ciphertext))); }

/** * Encrypts plain-text into a base64 string * * @param text * the plain-text to encrypt * @return the base64 ciphertext produced * @throws IllegalBlockSizeException * if the plain text is somehow invalid * @throws BadPaddingException * if the chosen mode of operation requires padded data * @throws InvalidKeyException * if the currently loaded key is invalid * @throws InvalidAlgorithmParameterException * if the AES algorithm is not supported by the current JVM */ public String encrypt(final String text) throws IllegalBlockSizeException, BadPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { this.cipher.init(Cipher.ENCRYPT_MODE, this.keySpec, this.ivSpec); return new String( Base64Coder.encode(this.cipher.doFinal(text.getBytes()))); }

/** * Initialises this AES instance with a mode, pad, key, and input vector in * a single operation * * @param mode * the cipher-block mode of operation * @param pad * the padding scheme to use * @param hexKey * the key to use as a hexadecimal string * @param hexIV * the input-vector to use as a hexadecimal string * @throws NoSuchAlgorithmException * if the AES algorithm is not supported by the current JVM * @throws NoSuchPaddingException * if the padding method is not supported by the current JVM */ public void init( final LSLAESCryptoMode mode, final LSLAESCryptoPad pad, final String hexKey, final String hexIV) throws NoSuchAlgorithmException, NoSuchPaddingException { if ((mode == null) || (pad == null) || (hexKey == null) || (hexIV == null)) throw new IllegalArgumentException("No arguments may be null");

this.setMode(mode); this.setPad(pad); this.setKey(hexKey); this.setInputVector(hexIV);

this.createCipher(); }

/** * Sets the input-vector for this engine to use * * @param hexIV * a hexadecimal input-vector to use */ public void setInputVector(final String hexIV) { if (hexIV == null) throw new IllegalArgumentException("Input-vector may not be null!");

this.ivSpec = new IvParameterSpec(HexCoder.hexToBytes(hexIV)); }

/** * Sets the key for this engine to use * * @param hexKey * a hexadecimal key to use */ public void setKey(final String hexKey) { if (hexKey == null) throw new IllegalArgumentException("Key may not be null!");

this.keySpec = new SecretKeySpec(HexCoder.hexToBytes(hexKey), "AES"); }

/** * Sets the mode of this implementation * * @param mode * the mode to set */ public void setMode(final LSLAESCryptoMode mode) { if (mode == null) throw new IllegalArgumentException("Mode may not be null!");

this.mode = mode; }

/** * Sets the padding scheme of this implementation * * @param pad * the padding scheme to use */ public void setPad(final LSLAESCryptoPad pad) { if (pad == null) throw new IllegalArgumentException("Pad may not be null!");

this.pad = pad; }

/** * Creates a new cipher instance for processing * * @throws NoSuchPaddingException * if the padding scheme set is invalid * @throws NoSuchAlgorithmException * if AES is not supported by this JVM */ protected void createCipher() throws NoSuchAlgorithmException, NoSuchPaddingException { this.cipher = Cipher.getInstance("AES/" + this.mode + "/" + this.pad); }

/** Defines modes of operation combatible with LSL */ public enum LSLAESCryptoMode { /** Cipher-Block-Chaining mode */ CBC, /** Cipher FeedBack mode */ CFB; }

/** Defines padding schemes compatible with LSL */ public enum LSLAESCryptoPad { /** No padding. Doesn't work with CBC. */ NoPadding, /** Equivalent to PAD_ZEROES or PAD_RANDOM in LSL */ ISO10126Padding; } }</java>

Examples

Encryption

<java>import lslAESCrypto.LSLAESCrypto; import lslAESCrypto.LSLAESCrypto.LSLAESCryptoMode; import lslAESCrypto.LSLAESCrypto.LSLAESCryptoPad;

/** */ public class ExampleEncrypt { /** * @param args * @throws Exception */ public static void main(final String[] args) throws Exception { final String myKey = "1234567890ABCDEF0123456789ABCDEF"; final String myIV = "89ABCDEF0123456789ABCDEF01234567"; final String myMsg = "Hello world! I am a lovely message waiting to be encrypted!";

final LSLAESCrypto aes = new LSLAESCrypto( LSLAESCryptoMode.CFB, LSLAESCryptoPad.NoPadding, myKey, myIV); System.out.println(aes.encrypt(myMsg)); } }</java>

Decryption

<java>import lslAESCrypto.LSLAESCrypto; import lslAESCrypto.LSLAESCrypto.LSLAESCryptoMode; import lslAESCrypto.LSLAESCrypto.LSLAESCryptoPad;

/** */ public class ExampleDecrypt { /** * @param args * @throws Exception */ public static void main(final String[] args) throws Exception { final String myKey = "1234567890ABCDEF0123456789ABCDEF"; final String myIV = "89ABCDEF0123456789ABCDEF01234567"; final String myMsg = "Mdn6jGTwRPMOKTYTTdDKGm9KScz26LIz96KVOGAeMw3hpwByPfa07PDRHxRW4TIh5dmu5LlhKpTQChi=";

final LSLAESCrypto aes = new LSLAESCrypto( LSLAESCryptoMode.CFB, LSLAESCryptoPad.NoPadding, myKey, myIV); System.out.println(aes.decrypt(myMsg)); } }</java>