From b1598358789f3696f5bc45f06697c82ae166c5b7 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 29 Oct 2021 10:27:12 +0800 Subject: [PATCH] Update some classes in Ciphers package --- Ciphers/AES.java | 1160 +++++++++-------- Ciphers/AESEncryption.java | 158 ++- Ciphers/AffineCipher.java | 67 +- Ciphers/Caesar.java | 164 +-- Ciphers/ColumnarTranspositionCipher.java | 332 ++--- Ciphers/HillCipher.java | 281 ++-- Ciphers/RSA.java | 124 +- ...pleSubCipher.java => SimpleSubCipher.java} | 81 +- Ciphers/SimpleSubstitutionCipher.java | 121 +- Ciphers/Vigenere.java | 78 +- Ciphers/affineCipher.java | 83 -- 11 files changed, 1269 insertions(+), 1380 deletions(-) rename Ciphers/{simpleSubCipher.java => SimpleSubCipher.java} (61%) delete mode 100644 Ciphers/affineCipher.java diff --git a/Ciphers/AES.java b/Ciphers/AES.java index d5211d3b..f67616f8 100644 --- a/Ciphers/AES.java +++ b/Ciphers/AES.java @@ -9,597 +9,599 @@ import java.util.Scanner; */ public class AES { - /** - * Precalculated values for x to the power of 2 in Rijndaels galois field. Used as 'RCON' during - * the key expansion. - */ - private static final int[] RCON = { - 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, - 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, - 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, - 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, - 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, - 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, - 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, - 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, - 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, - 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, - 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, - 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, - 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, - 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, - 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, - 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d - }; - - /** - * Rijndael S-box Substitution table used for encryption in the subBytes step, as well as the key - * expansion. - */ - private static final int[] SBOX = { - 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, - 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, - 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, - 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, - 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, - 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, - 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, - 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, - 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, - 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, - 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, - 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, - 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, - 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, - 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, - 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 - }; - - /** Inverse Rijndael S-box Substitution table used for decryption in the subBytesDec step. */ - private static final int[] INVERSE_SBOX = { - 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, - 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, - 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, - 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, - 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, - 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, - 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, - 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, - 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, - 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, - 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, - 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, - 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, - 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, - 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, - 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D - }; - - /** - * Precalculated lookup table for galois field multiplication by 2 used in the MixColums step - * during encryption. - */ - private static final int[] MULT2 = { - 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, - 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, - 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, - 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, - 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, - 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, - 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, - 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, - 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, - 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, - 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, - 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, - 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, - 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, - 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, - 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 - }; - - /** - * Precalculated lookup table for galois field multiplication by 3 used in the MixColums step - * during encryption. - */ - private static final int[] MULT3 = { - 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, - 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, - 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, - 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, - 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, - 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, - 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, - 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, - 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, - 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, - 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, - 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, - 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, - 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, - 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, - 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a - }; - - /** - * Precalculated lookup table for galois field multiplication by 9 used in the MixColums step - * during decryption. - */ - private static final int[] MULT9 = { - 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, - 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, - 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, - 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, - 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, - 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, - 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, - 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, - 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, - 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, - 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, - 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, - 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, - 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, - 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, - 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46 - }; - - /** - * Precalculated lookup table for galois field multiplication by 11 used in the MixColums step - * during decryption. - */ - private static final int[] MULT11 = { - 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, - 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, - 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, - 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, - 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, - 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, - 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, - 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, - 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, - 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, - 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, - 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, - 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, - 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, - 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, - 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3 - }; - - /** - * Precalculated lookup table for galois field multiplication by 13 used in the MixColums step - * during decryption. - */ - private static final int[] MULT13 = { - 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, - 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, - 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, - 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, - 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, - 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, - 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, - 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, - 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, - 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, - 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, - 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, - 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, - 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, - 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, - 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97 - }; - - /** - * Precalculated lookup table for galois field multiplication by 14 used in the MixColums step - * during decryption. - */ - private static final int[] MULT14 = { - 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, - 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, - 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, - 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, - 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, - 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, - 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, - 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, - 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, - 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, - 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, - 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, - 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, - 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, - 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, - 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d - }; - - /** - * Subroutine of the Rijndael key expansion. - */ - public static BigInteger scheduleCore(BigInteger t, int rconCounter) { - StringBuilder rBytes = new StringBuilder(t.toString(16)); - - // Add zero padding - while (rBytes.length() < 8) { - rBytes.insert(0, "0"); - } - - // rotate the first 16 bits to the back - String rotatingBytes = rBytes.substring(0, 2); - String fixedBytes = rBytes.substring(2); - - rBytes = new StringBuilder(fixedBytes + rotatingBytes); - - // apply S-Box to all 8-Bit Substrings - for (int i = 0; i < 4; i++) { - StringBuilder currentByteBits = new StringBuilder(rBytes.substring(i * 2, (i + 1) * 2)); - - int currentByte = Integer.parseInt(currentByteBits.toString(), 16); - currentByte = SBOX[currentByte]; - - // add the current RCON value to the first byte - if (i == 0) { - currentByte = currentByte ^ RCON[rconCounter]; - } - - currentByteBits = new StringBuilder(Integer.toHexString(currentByte)); - - // Add zero padding - - while (currentByteBits.length() < 2) { - currentByteBits.insert(0, '0'); - } - - // replace bytes in original string - rBytes = new StringBuilder(rBytes.substring(0, i * 2) + currentByteBits + rBytes.substring((i + 1) * 2)); - } - - // t = new BigInteger(rBytes, 16); - // return t; - return new BigInteger(rBytes.toString(), 16); - } - - /** - * Returns an array of 10 + 1 round keys that are calculated by using Rijndael key schedule - * - * @return array of 10 + 1 round keys - */ - public static BigInteger[] keyExpansion(BigInteger initialKey) { - BigInteger[] roundKeys = { - initialKey, - new BigInteger("0"), - new BigInteger("0"), - new BigInteger("0"), - new BigInteger("0"), - new BigInteger("0"), - new BigInteger("0"), - new BigInteger("0"), - new BigInteger("0"), - new BigInteger("0"), - new BigInteger("0"), + /** + * Precalculated values for x to the power of 2 in Rijndaels galois field. Used as 'RCON' during + * the key expansion. + */ + private static final int[] RCON = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, + 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, + 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, + 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, + 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, + 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, + 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, + 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, + 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, + 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, + 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, + 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, + 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, + 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, + 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d }; - // initialize rcon iteration - int rconCounter = 1; + /** + * Rijndael S-box Substitution table used for encryption in the subBytes step, as well as the key + * expansion. + */ + private static final int[] SBOX = { + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 + }; - for (int i = 1; i < 11; i++) { + /** + * Inverse Rijndael S-box Substitution table used for decryption in the subBytesDec step. + */ + private static final int[] INVERSE_SBOX = { + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D + }; - // get the previous 32 bits the key - BigInteger t = roundKeys[i - 1].remainder(new BigInteger("100000000", 16)); + /** + * Precalculated lookup table for galois field multiplication by 2 used in the MixColums step + * during encryption. + */ + private static final int[] MULT2 = { + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, + 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, + 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, + 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, + 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, + 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, + 0x1b, 0x19, 0x1f, 0x1d, 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, + 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, 0x23, 0x21, 0x27, 0x25, + 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, + 0x7b, 0x79, 0x7f, 0x7d, 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, + 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, 0x83, 0x81, 0x87, 0x85, + 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, + 0xdb, 0xd9, 0xdf, 0xdd, 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, + 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, 0xe3, 0xe1, 0xe7, 0xe5 + }; - // split previous key into 8-bit segments - BigInteger[] prevKey = { - roundKeys[i - 1].remainder(new BigInteger("100000000", 16)), - roundKeys[i - 1] - .remainder(new BigInteger("10000000000000000", 16)) - .divide(new BigInteger("100000000", 16)), - roundKeys[i - 1] - .remainder(new BigInteger("1000000000000000000000000", 16)) - .divide(new BigInteger("10000000000000000", 16)), - roundKeys[i - 1].divide(new BigInteger("1000000000000000000000000", 16)), - }; + /** + * Precalculated lookup table for galois field multiplication by 3 used in the MixColums step + * during encryption. + */ + private static final int[] MULT3 = { + 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, + 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, + 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, + 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, + 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, + 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, + 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, + 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, + 0x9b, 0x98, 0x9d, 0x9e, 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, + 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, 0xbf, 0xbc, 0xb9, 0xba, + 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, + 0xcb, 0xc8, 0xcd, 0xce, 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, + 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, 0x4f, 0x4c, 0x49, 0x4a, + 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, + 0x3b, 0x38, 0x3d, 0x3e, 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, + 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, 0x1f, 0x1c, 0x19, 0x1a + }; - // run schedule core - t = scheduleCore(t, rconCounter); - rconCounter += 1; + /** + * Precalculated lookup table for galois field multiplication by 9 used in the MixColums step + * during decryption. + */ + private static final int[] MULT9 = { + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, 0x6c, 0x65, 0x7e, 0x77, + 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, + 0x3b, 0x32, 0x29, 0x20, 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, 0xc7, 0xce, 0xd5, 0xdc, + 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, + 0xe6, 0xef, 0xf4, 0xfd, 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, + 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, 0x21, 0x28, 0x33, 0x3a, + 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, + 0xec, 0xe5, 0xfe, 0xf7, 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, + 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, 0x10, 0x19, 0x02, 0x0b, + 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, + 0x47, 0x4e, 0x55, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, + 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, 0xf6, 0xff, 0xe4, 0xed, + 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, + 0xa1, 0xa8, 0xb3, 0xba, 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, + 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, 0x5d, 0x54, 0x4f, 0x46 + }; - // Calculate partial round key - BigInteger t0 = t.xor(prevKey[3]); - BigInteger t1 = t0.xor(prevKey[2]); - BigInteger t2 = t1.xor(prevKey[1]); - BigInteger t3 = t2.xor(prevKey[0]); + /** + * Precalculated lookup table for galois field multiplication by 11 used in the MixColums step + * during decryption. + */ + private static final int[] MULT11 = { + 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, 0x74, 0x7f, 0x62, 0x69, + 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, + 0x7b, 0x70, 0x6d, 0x66, 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, + 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, 0xbf, 0xb4, 0xa9, 0xa2, + 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, + 0x46, 0x4d, 0x50, 0x5b, 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, + 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, 0xf9, 0xf2, 0xef, 0xe4, + 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, + 0xf7, 0xfc, 0xe1, 0xea, 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, + 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, 0x33, 0x38, 0x25, 0x2e, + 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, + 0x3c, 0x37, 0x2a, 0x21, 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, + 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, 0x75, 0x7e, 0x63, 0x68, + 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, + 0x7a, 0x71, 0x6c, 0x67, 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, + 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, 0xbe, 0xb5, 0xa8, 0xa3 + }; - // Join round key segments - t2 = t2.multiply(new BigInteger("100000000", 16)); - t1 = t1.multiply(new BigInteger("10000000000000000", 16)); - t0 = t0.multiply(new BigInteger("1000000000000000000000000", 16)); - roundKeys[i] = t0.add(t1).add(t2).add(t3); - } - return roundKeys; - } + /** + * Precalculated lookup table for galois field multiplication by 13 used in the MixColums step + * during decryption. + */ + private static final int[] MULT13 = { + 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, 0x5c, 0x51, 0x46, 0x4b, + 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, + 0xbb, 0xb6, 0xa1, 0xac, 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, + 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, 0x37, 0x3a, 0x2d, 0x20, + 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, + 0xbd, 0xb0, 0xa7, 0xaa, 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, + 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, 0x8a, 0x87, 0x90, 0x9d, + 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, + 0xda, 0xd7, 0xc0, 0xcd, 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, + 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, 0x56, 0x5b, 0x4c, 0x41, + 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, + 0xb1, 0xbc, 0xab, 0xa6, 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, + 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, 0xeb, 0xe6, 0xf1, 0xfc, + 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, + 0x0c, 0x01, 0x16, 0x1b, 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, + 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, 0x80, 0x8d, 0x9a, 0x97 + }; - /** - * representation of the input 128-bit block as an array of 8-bit integers. - * - * @param block of 128-bit integers - * @return array of 8-bit integers - */ - public static int[] splitBlockIntoCells(BigInteger block) { + /** + * Precalculated lookup table for galois field multiplication by 14 used in the MixColums step + * during decryption. + */ + private static final int[] MULT14 = { + 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, 0x48, 0x46, 0x54, 0x5a, + 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, + 0xdb, 0xd5, 0xc7, 0xc9, 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, + 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, 0x73, 0x7d, 0x6f, 0x61, + 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, + 0x4d, 0x43, 0x51, 0x5f, 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, + 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, 0x3e, 0x30, 0x22, 0x2c, + 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, + 0x41, 0x4f, 0x5d, 0x53, 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, + 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, 0xe9, 0xe7, 0xf5, 0xfb, + 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, + 0x7a, 0x74, 0x66, 0x68, 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, + 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, 0xa4, 0xaa, 0xb8, 0xb6, + 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, + 0x37, 0x39, 0x2b, 0x25, 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, + 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, 0x9f, 0x91, 0x83, 0x8d + }; - int[] cells = new int[16]; - StringBuilder blockBits = new StringBuilder(block.toString(2)); + /** + * Subroutine of the Rijndael key expansion. + */ + public static BigInteger scheduleCore(BigInteger t, int rconCounter) { + StringBuilder rBytes = new StringBuilder(t.toString(16)); - // Append leading 0 for full "128-bit" string - while (blockBits.length() < 128) { - blockBits.insert(0, '0'); - } - - // split 128 to 8 bit cells - for (int i = 0; i < cells.length; i++) { - String cellBits = blockBits.substring(8 * i, 8 * (i + 1)); - cells[i] = Integer.parseInt(cellBits, 2); - } - - return cells; - } - - /** - * Returns the 128-bit BigInteger representation of the input of an array of 8-bit integers. - * - * @param cells that we need to merge - * @return block of merged cells - */ - public static BigInteger mergeCellsIntoBlock(int[] cells) { - - StringBuilder blockBits = new StringBuilder(); - for (int i = 0; i < 16; i++) { - StringBuilder cellBits = new StringBuilder(Integer.toBinaryString(cells[i])); - - // Append leading 0 for full "8-bit" strings - while (cellBits.length() < 8) { - cellBits.insert(0, '0'); - } - - blockBits.append(cellBits); - } - - return new BigInteger(blockBits.toString(), 2); - } - - /** - * @return ciphertext XOR key - */ - public static BigInteger addRoundKey(BigInteger ciphertext, BigInteger key) { - return ciphertext.xor(key); - } - - /** - * substitutes 8-Bit long substrings of the input using the S-Box and returns the result. - * - * @return subtraction Output - */ - public static BigInteger subBytes(BigInteger ciphertext) { - - int[] cells = splitBlockIntoCells(ciphertext); - - for (int i = 0; i < 16; i++) { - cells[i] = SBOX[cells[i]]; - } - - return mergeCellsIntoBlock(cells); - } - - /** - * substitutes 8-Bit long substrings of the input using the inverse S-Box for decryption and - * returns the result. - * - * @return subtraction Output - */ - public static BigInteger subBytesDec(BigInteger ciphertext) { - - int[] cells = splitBlockIntoCells(ciphertext); - - for (int i = 0; i < 16; i++) { - cells[i] = INVERSE_SBOX[cells[i]]; - } - - return mergeCellsIntoBlock(cells); - } - - /** - * Cell permutation step. Shifts cells within the rows of the input and returns the result. - */ - public static BigInteger shiftRows(BigInteger ciphertext) { - int[] cells = splitBlockIntoCells(ciphertext); - int[] output = new int[16]; - - // do nothing in the first row - output[0] = cells[0]; - output[4] = cells[4]; - output[8] = cells[8]; - output[12] = cells[12]; - - // shift the second row backwards by one cell - output[1] = cells[5]; - output[5] = cells[9]; - output[9] = cells[13]; - output[13] = cells[1]; - - // shift the third row backwards by two cell - output[2] = cells[10]; - output[6] = cells[14]; - output[10] = cells[2]; - output[14] = cells[6]; - - // shift the forth row backwards by tree cell - output[3] = cells[15]; - output[7] = cells[3]; - output[11] = cells[7]; - output[15] = cells[11]; - - return mergeCellsIntoBlock(output); - } - - /** - * Cell permutation step for decryption . Shifts cells within the rows of the input and returns - * the result. - */ - public static BigInteger shiftRowsDec(BigInteger ciphertext) { - int[] cells = splitBlockIntoCells(ciphertext); - int[] output = new int[16]; - - // do nothing in the first row - output[0] = cells[0]; - output[4] = cells[4]; - output[8] = cells[8]; - output[12] = cells[12]; - - // shift the second row forwards by one cell - output[1] = cells[13]; - output[5] = cells[1]; - output[9] = cells[5]; - output[13] = cells[9]; - - // shift the third row forwards by two cell - output[2] = cells[10]; - output[6] = cells[14]; - output[10] = cells[2]; - output[14] = cells[6]; - - // shift the forth row forwards by tree cell - output[3] = cells[7]; - output[7] = cells[11]; - output[11] = cells[15]; - output[15] = cells[3]; - - return mergeCellsIntoBlock(output); - } - - /** - * Applies the Rijndael MixColumns to the input and returns the result. - */ - public static BigInteger mixColumns(BigInteger ciphertext) { - - int[] cells = splitBlockIntoCells(ciphertext); - int[] outputCells = new int[16]; - - for (int i = 0; i < 4; i++) { - int[] row = {cells[i * 4], cells[i * 4 + 1], cells[i * 4 + 2], cells[i * 4 + 3]}; - - outputCells[i * 4] = MULT2[row[0]] ^ MULT3[row[1]] ^ row[2] ^ row[3]; - outputCells[i * 4 + 1] = row[0] ^ MULT2[row[1]] ^ MULT3[row[2]] ^ row[3]; - outputCells[i * 4 + 2] = row[0] ^ row[1] ^ MULT2[row[2]] ^ MULT3[row[3]]; - outputCells[i * 4 + 3] = MULT3[row[0]] ^ row[1] ^ row[2] ^ MULT2[row[3]]; - } - return mergeCellsIntoBlock(outputCells); - } - - /** - * Applies the inverse Rijndael MixColumns for decryption to the input and returns the result. - */ - public static BigInteger mixColumnsDec(BigInteger ciphertext) { - - int[] cells = splitBlockIntoCells(ciphertext); - int[] outputCells = new int[16]; - - for (int i = 0; i < 4; i++) { - int[] row = {cells[i * 4], cells[i * 4 + 1], cells[i * 4 + 2], cells[i * 4 + 3]}; - - outputCells[i * 4] = MULT14[row[0]] ^ MULT11[row[1]] ^ MULT13[row[2]] ^ MULT9[row[3]]; - outputCells[i * 4 + 1] = MULT9[row[0]] ^ MULT14[row[1]] ^ MULT11[row[2]] ^ MULT13[row[3]]; - outputCells[i * 4 + 2] = MULT13[row[0]] ^ MULT9[row[1]] ^ MULT14[row[2]] ^ MULT11[row[3]]; - outputCells[i * 4 + 3] = MULT11[row[0]] ^ MULT13[row[1]] ^ MULT9[row[2]] ^ MULT14[row[3]]; - } - return mergeCellsIntoBlock(outputCells); - } - - /** - * Encrypts the plaintext with the key and returns the result - * - * @param plainText which we want to encrypt - * @param key the key for encrypt - * @return EncryptedText - */ - public static BigInteger encrypt(BigInteger plainText, BigInteger key) { - BigInteger[] roundKeys = keyExpansion(key); - - // Initial round - plainText = addRoundKey(plainText, roundKeys[0]); - - // Main rounds - for (int i = 1; i < 10; i++) { - plainText = subBytes(plainText); - plainText = shiftRows(plainText); - plainText = mixColumns(plainText); - plainText = addRoundKey(plainText, roundKeys[i]); - } - - // Final round - plainText = subBytes(plainText); - plainText = shiftRows(plainText); - plainText = addRoundKey(plainText, roundKeys[10]); - - return plainText; - } - - /** - * Decrypts the ciphertext with the key and returns the result - * - * @param cipherText The Encrypted text which we want to decrypt - * @return decryptedText - */ - public static BigInteger decrypt(BigInteger cipherText, BigInteger key) { - - BigInteger[] roundKeys = keyExpansion(key); - - // Invert final round - cipherText = addRoundKey(cipherText, roundKeys[10]); - cipherText = shiftRowsDec(cipherText); - cipherText = subBytesDec(cipherText); - - // Invert main rounds - for (int i = 9; i > 0; i--) { - cipherText = addRoundKey(cipherText, roundKeys[i]); - cipherText = mixColumnsDec(cipherText); - cipherText = shiftRowsDec(cipherText); - cipherText = subBytesDec(cipherText); - } - - // Invert initial round - cipherText = addRoundKey(cipherText, roundKeys[0]); - - return cipherText; - } - - public static void main(String[] args) { - - try (Scanner input = new Scanner(System.in)) { - System.out.println("Enter (e) letter for encrpyt or (d) letter for decrypt :"); - char choice = input.nextLine().charAt(0); - String in; - switch (choice) { - case 'E', 'e' -> { - System.out.println("Choose a plaintext block (128-Bit Integer in base 16):"); - in = input.nextLine(); - BigInteger plaintext = new BigInteger(in, 16); - System.out.println("Choose a Key (128-Bit Integer in base 16):"); - in = input.nextLine(); - BigInteger encryptionKey = new BigInteger(in, 16); - System.out.println( - "The encrypted message is: \n" + encrypt(plaintext, encryptionKey).toString(16)); + // Add zero padding + while (rBytes.length() < 8) { + rBytes.insert(0, "0"); } - case 'D', 'd' -> { - System.out.println("Enter your ciphertext block (128-Bit Integer in base 16):"); - in = input.nextLine(); - BigInteger ciphertext = new BigInteger(in, 16); - System.out.println("Choose a Key (128-Bit Integer in base 16):"); - in = input.nextLine(); - BigInteger decryptionKey = new BigInteger(in, 16); - System.out.println( - "The deciphered message is:\n" + decrypt(ciphertext, decryptionKey).toString(16)); + + // rotate the first 16 bits to the back + String rotatingBytes = rBytes.substring(0, 2); + String fixedBytes = rBytes.substring(2); + + rBytes = new StringBuilder(fixedBytes + rotatingBytes); + + // apply S-Box to all 8-Bit Substrings + for (int i = 0; i < 4; i++) { + StringBuilder currentByteBits = new StringBuilder(rBytes.substring(i * 2, (i + 1) * 2)); + + int currentByte = Integer.parseInt(currentByteBits.toString(), 16); + currentByte = SBOX[currentByte]; + + // add the current RCON value to the first byte + if (i == 0) { + currentByte = currentByte ^ RCON[rconCounter]; + } + + currentByteBits = new StringBuilder(Integer.toHexString(currentByte)); + + // Add zero padding + + while (currentByteBits.length() < 2) { + currentByteBits.insert(0, '0'); + } + + // replace bytes in original string + rBytes = new StringBuilder(rBytes.substring(0, i * 2) + currentByteBits + rBytes.substring((i + 1) * 2)); + } + + // t = new BigInteger(rBytes, 16); + // return t; + return new BigInteger(rBytes.toString(), 16); + } + + /** + * Returns an array of 10 + 1 round keys that are calculated by using Rijndael key schedule + * + * @return array of 10 + 1 round keys + */ + public static BigInteger[] keyExpansion(BigInteger initialKey) { + BigInteger[] roundKeys = { + initialKey, + new BigInteger("0"), + new BigInteger("0"), + new BigInteger("0"), + new BigInteger("0"), + new BigInteger("0"), + new BigInteger("0"), + new BigInteger("0"), + new BigInteger("0"), + new BigInteger("0"), + new BigInteger("0"), + }; + + // initialize rcon iteration + int rconCounter = 1; + + for (int i = 1; i < 11; i++) { + + // get the previous 32 bits the key + BigInteger t = roundKeys[i - 1].remainder(new BigInteger("100000000", 16)); + + // split previous key into 8-bit segments + BigInteger[] prevKey = { + roundKeys[i - 1].remainder(new BigInteger("100000000", 16)), + roundKeys[i - 1] + .remainder(new BigInteger("10000000000000000", 16)) + .divide(new BigInteger("100000000", 16)), + roundKeys[i - 1] + .remainder(new BigInteger("1000000000000000000000000", 16)) + .divide(new BigInteger("10000000000000000", 16)), + roundKeys[i - 1].divide(new BigInteger("1000000000000000000000000", 16)), + }; + + // run schedule core + t = scheduleCore(t, rconCounter); + rconCounter += 1; + + // Calculate partial round key + BigInteger t0 = t.xor(prevKey[3]); + BigInteger t1 = t0.xor(prevKey[2]); + BigInteger t2 = t1.xor(prevKey[1]); + BigInteger t3 = t2.xor(prevKey[0]); + + // Join round key segments + t2 = t2.multiply(new BigInteger("100000000", 16)); + t1 = t1.multiply(new BigInteger("10000000000000000", 16)); + t0 = t0.multiply(new BigInteger("1000000000000000000000000", 16)); + roundKeys[i] = t0.add(t1).add(t2).add(t3); + } + return roundKeys; + } + + /** + * representation of the input 128-bit block as an array of 8-bit integers. + * + * @param block of 128-bit integers + * @return array of 8-bit integers + */ + public static int[] splitBlockIntoCells(BigInteger block) { + + int[] cells = new int[16]; + StringBuilder blockBits = new StringBuilder(block.toString(2)); + + // Append leading 0 for full "128-bit" string + while (blockBits.length() < 128) { + blockBits.insert(0, '0'); + } + + // split 128 to 8 bit cells + for (int i = 0; i < cells.length; i++) { + String cellBits = blockBits.substring(8 * i, 8 * (i + 1)); + cells[i] = Integer.parseInt(cellBits, 2); + } + + return cells; + } + + /** + * Returns the 128-bit BigInteger representation of the input of an array of 8-bit integers. + * + * @param cells that we need to merge + * @return block of merged cells + */ + public static BigInteger mergeCellsIntoBlock(int[] cells) { + + StringBuilder blockBits = new StringBuilder(); + for (int i = 0; i < 16; i++) { + StringBuilder cellBits = new StringBuilder(Integer.toBinaryString(cells[i])); + + // Append leading 0 for full "8-bit" strings + while (cellBits.length() < 8) { + cellBits.insert(0, '0'); + } + + blockBits.append(cellBits); + } + + return new BigInteger(blockBits.toString(), 2); + } + + /** + * @return ciphertext XOR key + */ + public static BigInteger addRoundKey(BigInteger ciphertext, BigInteger key) { + return ciphertext.xor(key); + } + + /** + * substitutes 8-Bit long substrings of the input using the S-Box and returns the result. + * + * @return subtraction Output + */ + public static BigInteger subBytes(BigInteger ciphertext) { + + int[] cells = splitBlockIntoCells(ciphertext); + + for (int i = 0; i < 16; i++) { + cells[i] = SBOX[cells[i]]; + } + + return mergeCellsIntoBlock(cells); + } + + /** + * substitutes 8-Bit long substrings of the input using the inverse S-Box for decryption and + * returns the result. + * + * @return subtraction Output + */ + public static BigInteger subBytesDec(BigInteger ciphertext) { + + int[] cells = splitBlockIntoCells(ciphertext); + + for (int i = 0; i < 16; i++) { + cells[i] = INVERSE_SBOX[cells[i]]; + } + + return mergeCellsIntoBlock(cells); + } + + /** + * Cell permutation step. Shifts cells within the rows of the input and returns the result. + */ + public static BigInteger shiftRows(BigInteger ciphertext) { + int[] cells = splitBlockIntoCells(ciphertext); + int[] output = new int[16]; + + // do nothing in the first row + output[0] = cells[0]; + output[4] = cells[4]; + output[8] = cells[8]; + output[12] = cells[12]; + + // shift the second row backwards by one cell + output[1] = cells[5]; + output[5] = cells[9]; + output[9] = cells[13]; + output[13] = cells[1]; + + // shift the third row backwards by two cell + output[2] = cells[10]; + output[6] = cells[14]; + output[10] = cells[2]; + output[14] = cells[6]; + + // shift the forth row backwards by tree cell + output[3] = cells[15]; + output[7] = cells[3]; + output[11] = cells[7]; + output[15] = cells[11]; + + return mergeCellsIntoBlock(output); + } + + /** + * Cell permutation step for decryption . Shifts cells within the rows of the input and returns + * the result. + */ + public static BigInteger shiftRowsDec(BigInteger ciphertext) { + int[] cells = splitBlockIntoCells(ciphertext); + int[] output = new int[16]; + + // do nothing in the first row + output[0] = cells[0]; + output[4] = cells[4]; + output[8] = cells[8]; + output[12] = cells[12]; + + // shift the second row forwards by one cell + output[1] = cells[13]; + output[5] = cells[1]; + output[9] = cells[5]; + output[13] = cells[9]; + + // shift the third row forwards by two cell + output[2] = cells[10]; + output[6] = cells[14]; + output[10] = cells[2]; + output[14] = cells[6]; + + // shift the forth row forwards by tree cell + output[3] = cells[7]; + output[7] = cells[11]; + output[11] = cells[15]; + output[15] = cells[3]; + + return mergeCellsIntoBlock(output); + } + + /** + * Applies the Rijndael MixColumns to the input and returns the result. + */ + public static BigInteger mixColumns(BigInteger ciphertext) { + + int[] cells = splitBlockIntoCells(ciphertext); + int[] outputCells = new int[16]; + + for (int i = 0; i < 4; i++) { + int[] row = {cells[i * 4], cells[i * 4 + 1], cells[i * 4 + 2], cells[i * 4 + 3]}; + + outputCells[i * 4] = MULT2[row[0]] ^ MULT3[row[1]] ^ row[2] ^ row[3]; + outputCells[i * 4 + 1] = row[0] ^ MULT2[row[1]] ^ MULT3[row[2]] ^ row[3]; + outputCells[i * 4 + 2] = row[0] ^ row[1] ^ MULT2[row[2]] ^ MULT3[row[3]]; + outputCells[i * 4 + 3] = MULT3[row[0]] ^ row[1] ^ row[2] ^ MULT2[row[3]]; + } + return mergeCellsIntoBlock(outputCells); + } + + /** + * Applies the inverse Rijndael MixColumns for decryption to the input and returns the result. + */ + public static BigInteger mixColumnsDec(BigInteger ciphertext) { + + int[] cells = splitBlockIntoCells(ciphertext); + int[] outputCells = new int[16]; + + for (int i = 0; i < 4; i++) { + int[] row = {cells[i * 4], cells[i * 4 + 1], cells[i * 4 + 2], cells[i * 4 + 3]}; + + outputCells[i * 4] = MULT14[row[0]] ^ MULT11[row[1]] ^ MULT13[row[2]] ^ MULT9[row[3]]; + outputCells[i * 4 + 1] = MULT9[row[0]] ^ MULT14[row[1]] ^ MULT11[row[2]] ^ MULT13[row[3]]; + outputCells[i * 4 + 2] = MULT13[row[0]] ^ MULT9[row[1]] ^ MULT14[row[2]] ^ MULT11[row[3]]; + outputCells[i * 4 + 3] = MULT11[row[0]] ^ MULT13[row[1]] ^ MULT9[row[2]] ^ MULT14[row[3]]; + } + return mergeCellsIntoBlock(outputCells); + } + + /** + * Encrypts the plaintext with the key and returns the result + * + * @param plainText which we want to encrypt + * @param key the key for encrypt + * @return EncryptedText + */ + public static BigInteger encrypt(BigInteger plainText, BigInteger key) { + BigInteger[] roundKeys = keyExpansion(key); + + // Initial round + plainText = addRoundKey(plainText, roundKeys[0]); + + // Main rounds + for (int i = 1; i < 10; i++) { + plainText = subBytes(plainText); + plainText = shiftRows(plainText); + plainText = mixColumns(plainText); + plainText = addRoundKey(plainText, roundKeys[i]); + } + + // Final round + plainText = subBytes(plainText); + plainText = shiftRows(plainText); + plainText = addRoundKey(plainText, roundKeys[10]); + + return plainText; + } + + /** + * Decrypts the ciphertext with the key and returns the result + * + * @param cipherText The Encrypted text which we want to decrypt + * @return decryptedText + */ + public static BigInteger decrypt(BigInteger cipherText, BigInteger key) { + + BigInteger[] roundKeys = keyExpansion(key); + + // Invert final round + cipherText = addRoundKey(cipherText, roundKeys[10]); + cipherText = shiftRowsDec(cipherText); + cipherText = subBytesDec(cipherText); + + // Invert main rounds + for (int i = 9; i > 0; i--) { + cipherText = addRoundKey(cipherText, roundKeys[i]); + cipherText = mixColumnsDec(cipherText); + cipherText = shiftRowsDec(cipherText); + cipherText = subBytesDec(cipherText); + } + + // Invert initial round + cipherText = addRoundKey(cipherText, roundKeys[0]); + + return cipherText; + } + + public static void main(String[] args) { + + try (Scanner input = new Scanner(System.in)) { + System.out.println("Enter (e) letter for encrpyt or (d) letter for decrypt :"); + char choice = input.nextLine().charAt(0); + String in; + switch (choice) { + case 'E', 'e' -> { + System.out.println("Choose a plaintext block (128-Bit Integer in base 16):"); + in = input.nextLine(); + BigInteger plaintext = new BigInteger(in, 16); + System.out.println("Choose a Key (128-Bit Integer in base 16):"); + in = input.nextLine(); + BigInteger encryptionKey = new BigInteger(in, 16); + System.out.println( + "The encrypted message is: \n" + encrypt(plaintext, encryptionKey).toString(16)); + } + case 'D', 'd' -> { + System.out.println("Enter your ciphertext block (128-Bit Integer in base 16):"); + in = input.nextLine(); + BigInteger ciphertext = new BigInteger(in, 16); + System.out.println("Choose a Key (128-Bit Integer in base 16):"); + in = input.nextLine(); + BigInteger decryptionKey = new BigInteger(in, 16); + System.out.println( + "The deciphered message is:\n" + decrypt(ciphertext, decryptionKey).toString(16)); + } + default -> System.out.println("** End **"); + } } - default -> System.out.println("** End **"); - } } - } } diff --git a/Ciphers/AESEncryption.java b/Ciphers/AESEncryption.java index 142aefdd..9857b49d 100644 --- a/Ciphers/AESEncryption.java +++ b/Ciphers/AESEncryption.java @@ -1,13 +1,8 @@ package Ciphers; +import javax.crypto.*; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.KeyGenerator; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; /** * This example program shows how AES encryption and decryption can be done in Java. Please note @@ -16,82 +11,83 @@ import javax.crypto.SecretKey; */ public class AESEncryption { - private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); - /** - * 1. Generate a plain text for encryption 2. Get a secret key (printed in hexadecimal form). In - * actual use this must by encrypted and kept safe. The same key is required for decryption. - */ - public static void main(String[] args) throws Exception { - String plainText = "Hello World"; - SecretKey secKey = getSecretEncryptionKey(); - byte[] cipherText = encryptText(plainText, secKey); - String decryptedText = decryptText(cipherText, secKey); + private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray(); - System.out.println("Original Text:" + plainText); - System.out.println("AES Key (Hex Form):" + bytesToHex(secKey.getEncoded())); - System.out.println("Encrypted Text (Hex Form):" + bytesToHex(cipherText)); - System.out.println("Descrypted Text:" + decryptedText); - } + /** + * 1. Generate a plain text for encryption 2. Get a secret key (printed in hexadecimal form). In + * actual use this must by encrypted and kept safe. The same key is required for decryption. + */ + public static void main(String[] args) throws Exception { + String plainText = "Hello World"; + SecretKey secKey = getSecretEncryptionKey(); + byte[] cipherText = encryptText(plainText, secKey); + String decryptedText = decryptText(cipherText, secKey); - /** - * gets the AES encryption key. In your actual programs, this should be safely stored. - * - * @return secKey (Secret key that we encrypt using it) - * @throws NoSuchAlgorithmException (from KeyGenrator) - */ - public static SecretKey getSecretEncryptionKey() throws NoSuchAlgorithmException { - KeyGenerator aesKeyGenerator = KeyGenerator.getInstance("AES"); - aesKeyGenerator.init(128); // The AES key size in number of bits - return aesKeyGenerator.generateKey(); - } - - /** - * Encrypts plainText in AES using the secret key - * - * @return byteCipherText (The encrypted text) - * @throws NoSuchPaddingException (from Cipher) - * @throws NoSuchAlgorithmException (from Cipher) - * @throws InvalidKeyException (from Cipher) - * @throws BadPaddingException (from Cipher) - * @throws IllegalBlockSizeException (from Cipher) - */ - public static byte[] encryptText(String plainText, SecretKey secKey) - throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, - IllegalBlockSizeException, BadPaddingException { - // AES defaults to AES/ECB/PKCS5Padding in Java 7 - Cipher aesCipher = Cipher.getInstance("AES"); - aesCipher.init(Cipher.ENCRYPT_MODE, secKey); - return aesCipher.doFinal(plainText.getBytes()); - } - - /** - * Decrypts encrypted byte array using the key used for encryption. - * - * @return plainText - */ - public static String decryptText(byte[] byteCipherText, SecretKey secKey) - throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, - IllegalBlockSizeException, BadPaddingException { - // AES defaults to AES/ECB/PKCS5Padding in Java 7 - Cipher aesCipher = Cipher.getInstance("AES"); - aesCipher.init(Cipher.DECRYPT_MODE, secKey); - byte[] bytePlainText = aesCipher.doFinal(byteCipherText); - return new String(bytePlainText); - } - - /** - * Convert a binary byte array into readable hex form Old library is deprecated on OpenJdk 11 and - * this is faster regarding other solution is using StringBuilder - * - * @return hexHash - */ - public static String bytesToHex(byte[] bytes) { - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + System.out.println("Original Text:" + plainText); + System.out.println("AES Key (Hex Form):" + bytesToHex(secKey.getEncoded())); + System.out.println("Encrypted Text (Hex Form):" + bytesToHex(cipherText)); + System.out.println("Descrypted Text:" + decryptedText); + } + + /** + * gets the AES encryption key. In your actual programs, this should be safely stored. + * + * @return secKey (Secret key that we encrypt using it) + * @throws NoSuchAlgorithmException (from KeyGenrator) + */ + public static SecretKey getSecretEncryptionKey() throws NoSuchAlgorithmException { + KeyGenerator aesKeyGenerator = KeyGenerator.getInstance("AES"); + aesKeyGenerator.init(128); // The AES key size in number of bits + return aesKeyGenerator.generateKey(); + } + + /** + * Encrypts plainText in AES using the secret key + * + * @return byteCipherText (The encrypted text) + * @throws NoSuchPaddingException (from Cipher) + * @throws NoSuchAlgorithmException (from Cipher) + * @throws InvalidKeyException (from Cipher) + * @throws BadPaddingException (from Cipher) + * @throws IllegalBlockSizeException (from Cipher) + */ + public static byte[] encryptText(String plainText, SecretKey secKey) + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, + IllegalBlockSizeException, BadPaddingException { + // AES defaults to AES/ECB/PKCS5Padding in Java 7 + Cipher aesCipher = Cipher.getInstance("AES"); + aesCipher.init(Cipher.ENCRYPT_MODE, secKey); + return aesCipher.doFinal(plainText.getBytes()); + } + + /** + * Decrypts encrypted byte array using the key used for encryption. + * + * @return plainText + */ + public static String decryptText(byte[] byteCipherText, SecretKey secKey) + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, + IllegalBlockSizeException, BadPaddingException { + // AES defaults to AES/ECB/PKCS5Padding in Java 7 + Cipher aesCipher = Cipher.getInstance("AES"); + aesCipher.init(Cipher.DECRYPT_MODE, secKey); + byte[] bytePlainText = aesCipher.doFinal(byteCipherText); + return new String(bytePlainText); + } + + /** + * Convert a binary byte array into readable hex form Old library is deprecated on OpenJdk 11 and + * this is faster regarding other solution is using StringBuilder + * + * @return hexHash + */ + public static String bytesToHex(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = HEX_ARRAY[v >>> 4]; + hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + } + return new String(hexChars); } - return new String(hexChars); - } } diff --git a/Ciphers/AffineCipher.java b/Ciphers/AffineCipher.java index 679f742c..d84fb843 100644 --- a/Ciphers/AffineCipher.java +++ b/Ciphers/AffineCipher.java @@ -1,36 +1,23 @@ -//The ‘key’ for the Affine cipher consists of 2 numbers, we’ll call them a and b. -// The following discussion assumes the use of a 26 character alphabet (m = 26). -// a should be chosen to be relatively prime to m (i.e. a should have no factors in common with m). - package Ciphers; -import java.util.Scanner; +class AffineCipher { -class AffineCipher -{ - static Scanner in = new Scanner(System.in); + // Key values of a and b + static int a = 17; + static int b = 20; - static String encryptMessage(char[] msg) - { - System.out.println("Enter key value a for encryption : "); - int a = in.nextInt(); - - System.out.println("Enter key value b for encryption : "); - int b = in.nextInt(); - - /// Initially empty cipher String + static String encryptMessage(char[] msg) { + /// Cipher Text initially empty String cipher = ""; - for (int i = 0; i < msg.length; i++) - { + for (int i = 0; i < msg.length; i++) { // Avoid space to be encrypted /* applying encryption formula ( a x + b ) mod m {here x is msg[i] and m is 26} and added 'A' to bring it in range of ascii alphabet[ 65-90 | A-Z ] */ - if (msg[i] != ' ') - { + if (msg[i] != ' ') { cipher = cipher + (char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A'); - } else // append space character + } else // else simply append space character { cipher += msg[i]; } @@ -38,42 +25,30 @@ class AffineCipher return cipher; } - static String decryptCipher(String cipher) - { - System.out.println("Enter key value a for decryption : "); - int a = in.nextInt(); - - System.out.println("Enter key value b for decryption : "); - int b = in.nextInt(); - + static String decryptCipher(String cipher) { String msg = ""; int a_inv = 0; int flag = 0; //Find a^-1 (the multiplicative inverse of a //in the group of integers modulo m.) - for (int i = 0; i < 26; i++) - { + for (int i = 0; i < 26; i++) { flag = (a * i) % 26; // Check if (a*i)%26 == 1, - // if so, then i will be the multiplicative inverse of a - if (flag == 1) - { + // then i will be the multiplicative inverse of a + if (flag == 1) { a_inv = i; } } - for (int i = 0; i < cipher.length(); i++) - { + for (int i = 0; i < cipher.length(); i++) { /*Applying decryption formula a^-1 ( x - b ) mod m {here x is cipher[i] and m is 26} and added 'A' to bring it in range of ASCII alphabet[ 65-90 | A-Z ] */ - if (cipher.charAt(i) != ' ') - { + if (cipher.charAt(i) != ' ') { msg = msg + (char) (((a_inv * ((cipher.charAt(i) + 'A' - b)) % 26)) + 'A'); - } - else // append space character + } else //else simply append space character { msg += cipher.charAt(i); } @@ -82,17 +57,17 @@ class AffineCipher return msg; } - // Main method - public static void main(String[] args) - { + // Driver code + public static void main(String[] args) { String msg = "AFFINE CIPHER"; - // Encrypting message + // Calling encryption function String cipherText = encryptMessage(msg.toCharArray()); System.out.println("Encrypted Message is : " + cipherText); - // Decrypting message + // Calling Decryption function System.out.println("Decrypted Message is: " + decryptCipher(cipherText)); } } + diff --git a/Ciphers/Caesar.java b/Ciphers/Caesar.java index 8bd38844..70f6b526 100644 --- a/Ciphers/Caesar.java +++ b/Ciphers/Caesar.java @@ -11,105 +11,105 @@ import java.util.Scanner; */ public class Caesar { - /** - * Encrypt text by shifting every Latin char by add number shift for ASCII Example : A + 1 -> B - * - * @return Encrypted message - */ - public static String encode(String message, int shift) { - StringBuilder encoded = new StringBuilder(); + /** + * Encrypt text by shifting every Latin char by add number shift for ASCII Example : A + 1 -> B + * + * @return Encrypted message + */ + public static String encode(String message, int shift) { + StringBuilder encoded = new StringBuilder(); - shift %= 26; + shift %= 26; - final int length = message.length(); - for (int i = 0; i < length; i++) { + final int length = message.length(); + for (int i = 0; i < length; i++) { - // int current = message.charAt(i); //using char to shift characters because ascii - // is in-order latin alphabet - char current = message.charAt(i); // Java law : char + int = char + // int current = message.charAt(i); //using char to shift characters because ascii + // is in-order latin alphabet + char current = message.charAt(i); // Java law : char + int = char - if (IsCapitalLatinLetter(current)) { + if (IsCapitalLatinLetter(current)) { - current += shift; - encoded.append((char) (current > 'Z' ? current - 26 : current)); // 26 = number of latin letters + current += shift; + encoded.append((char) (current > 'Z' ? current - 26 : current)); // 26 = number of latin letters - } else if (IsSmallLatinLetter(current)) { + } else if (IsSmallLatinLetter(current)) { - current += shift; - encoded.append((char) (current > 'z' ? current - 26 : current)); // 26 = number of latin letters + current += shift; + encoded.append((char) (current > 'z' ? current - 26 : current)); // 26 = number of latin letters - } else { - encoded.append(current); - } + } else { + encoded.append(current); + } + } + return encoded.toString(); } - return encoded.toString(); - } - /** - * Decrypt message by shifting back every Latin char to previous the ASCII Example : B - 1 -> A - * - * @return message - */ - public static String decode(String encryptedMessage, int shift) { - StringBuilder decoded = new StringBuilder(); + /** + * Decrypt message by shifting back every Latin char to previous the ASCII Example : B - 1 -> A + * + * @return message + */ + public static String decode(String encryptedMessage, int shift) { + StringBuilder decoded = new StringBuilder(); - shift %= 26; + shift %= 26; - final int length = encryptedMessage.length(); - for (int i = 0; i < length; i++) { - char current = encryptedMessage.charAt(i); - if (IsCapitalLatinLetter(current)) { + final int length = encryptedMessage.length(); + for (int i = 0; i < length; i++) { + char current = encryptedMessage.charAt(i); + if (IsCapitalLatinLetter(current)) { - current -= shift; - decoded.append((char) (current < 'A' ? current + 26 : current)); // 26 = number of latin letters + current -= shift; + decoded.append((char) (current < 'A' ? current + 26 : current)); // 26 = number of latin letters - } else if (IsSmallLatinLetter(current)) { + } else if (IsSmallLatinLetter(current)) { - current -= shift; - decoded.append((char) (current < 'a' ? current + 26 : current)); // 26 = number of latin letters + current -= shift; + decoded.append((char) (current < 'a' ? current + 26 : current)); // 26 = number of latin letters - } else { - decoded.append(current); - } + } else { + decoded.append(current); + } + } + return decoded.toString(); } - return decoded.toString(); - } - /** - * @return true if character is capital Latin letter or false for others - */ - private static boolean IsCapitalLatinLetter(char c) { - return c >= 'A' && c <= 'Z'; - } - - /** - * @return true if character is small Latin letter or false for others - */ - private static boolean IsSmallLatinLetter(char c) { - return c >= 'a' && c <= 'z'; - } - - public static void main(String[] args) { - Scanner input = new Scanner(System.in); - System.out.println("Please enter the message (Latin Alphabet)"); - String message = input.nextLine(); - System.out.println(message); - System.out.println("Please enter the shift number"); - int shift = input.nextInt() % 26; - System.out.println("(E)ncode or (D)ecode ?"); - char choice = input.next().charAt(0); - switch (choice) { - case 'E': - case 'e': - System.out.println( - "ENCODED MESSAGE IS \n" + encode(message, shift)); // send our function to handle - break; - case 'D': - case 'd': - System.out.println("DECODED MESSAGE IS \n" + decode(message, shift)); - default: - System.out.println("default case"); + /** + * @return true if character is capital Latin letter or false for others + */ + private static boolean IsCapitalLatinLetter(char c) { + return c >= 'A' && c <= 'Z'; + } + + /** + * @return true if character is small Latin letter or false for others + */ + private static boolean IsSmallLatinLetter(char c) { + return c >= 'a' && c <= 'z'; + } + + public static void main(String[] args) { + Scanner input = new Scanner(System.in); + System.out.println("Please enter the message (Latin Alphabet)"); + String message = input.nextLine(); + System.out.println(message); + System.out.println("Please enter the shift number"); + int shift = input.nextInt() % 26; + System.out.println("(E)ncode or (D)ecode ?"); + char choice = input.next().charAt(0); + switch (choice) { + case 'E': + case 'e': + System.out.println( + "ENCODED MESSAGE IS \n" + encode(message, shift)); // send our function to handle + break; + case 'D': + case 'd': + System.out.println("DECODED MESSAGE IS \n" + decode(message, shift)); + default: + System.out.println("default case"); + } + input.close(); } - input.close(); - } } diff --git a/Ciphers/ColumnarTranspositionCipher.java b/Ciphers/ColumnarTranspositionCipher.java index 272ebe92..ab5df61e 100644 --- a/Ciphers/ColumnarTranspositionCipher.java +++ b/Ciphers/ColumnarTranspositionCipher.java @@ -9,191 +9,193 @@ import java.util.Objects; */ public class ColumnarTranspositionCipher { - private static String keyword; - private static Object[][] table; - private static String abecedarium; - public static final String ABECEDARIUM = - "abcdefghijklmnopqrstuvwxyzABCDEFG" + "HIJKLMNOPQRSTUVWXYZ0123456789,.;:-@"; - private static final String ENCRYPTION_FIELD = "≈"; - private static final char ENCRYPTION_FIELD_CHAR = '≈'; + private static String keyword; + private static Object[][] table; + private static String abecedarium; + public static final String ABECEDARIUM = + "abcdefghijklmnopqrstuvwxyzABCDEFG" + "HIJKLMNOPQRSTUVWXYZ0123456789,.;:-@"; + private static final String ENCRYPTION_FIELD = "≈"; + private static final char ENCRYPTION_FIELD_CHAR = '≈'; - /** - * Encrypts a certain String with the Columnar Transposition Cipher Rule - * - * @param word Word being encrypted - * @param keyword String with keyword being used - * @return a String with the word encrypted by the Columnar Transposition Cipher Rule - */ - public static String encrpyter(String word, String keyword) { - ColumnarTranspositionCipher.keyword = keyword; - abecedariumBuilder(500); - table = tableBuilder(word); - Object[][] sortedTable = sortTable(table); - StringBuilder wordEncrypted = new StringBuilder(); - for (int i = 0; i < sortedTable[i].length; i++) { - for (int j = 1; j < sortedTable.length; j++) { - wordEncrypted.append(sortedTable[j][i]); - } + /** + * Encrypts a certain String with the Columnar Transposition Cipher Rule + * + * @param word Word being encrypted + * @param keyword String with keyword being used + * @return a String with the word encrypted by the Columnar Transposition Cipher Rule + */ + public static String encrpyter(String word, String keyword) { + ColumnarTranspositionCipher.keyword = keyword; + abecedariumBuilder(500); + table = tableBuilder(word); + Object[][] sortedTable = sortTable(table); + StringBuilder wordEncrypted = new StringBuilder(); + for (int i = 0; i < sortedTable[i].length; i++) { + for (int j = 1; j < sortedTable.length; j++) { + wordEncrypted.append(sortedTable[j][i]); + } + } + return wordEncrypted.toString(); } - return wordEncrypted.toString(); - } - /** - * Encrypts a certain String with the Columnar Transposition Cipher Rule - * - * @param word Word being encrypted - * @param keyword String with keyword being used - * @param abecedarium String with the abecedarium being used. null for default one - * @return a String with the word encrypted by the Columnar Transposition Cipher Rule - */ - public static String encrpyter(String word, String keyword, String abecedarium) { - ColumnarTranspositionCipher.keyword = keyword; - ColumnarTranspositionCipher.abecedarium = Objects.requireNonNullElse(abecedarium, ABECEDARIUM); - table = tableBuilder(word); - Object[][] sortedTable = sortTable(table); - StringBuilder wordEncrypted = new StringBuilder(); - for (int i = 0; i < sortedTable[0].length; i++) { - for (int j = 1; j < sortedTable.length; j++) { - wordEncrypted.append(sortedTable[j][i]); - } + /** + * Encrypts a certain String with the Columnar Transposition Cipher Rule + * + * @param word Word being encrypted + * @param keyword String with keyword being used + * @param abecedarium String with the abecedarium being used. null for default one + * @return a String with the word encrypted by the Columnar Transposition Cipher Rule + */ + public static String encrpyter(String word, String keyword, String abecedarium) { + ColumnarTranspositionCipher.keyword = keyword; + ColumnarTranspositionCipher.abecedarium = Objects.requireNonNullElse(abecedarium, ABECEDARIUM); + table = tableBuilder(word); + Object[][] sortedTable = sortTable(table); + StringBuilder wordEncrypted = new StringBuilder(); + for (int i = 0; i < sortedTable[0].length; i++) { + for (int j = 1; j < sortedTable.length; j++) { + wordEncrypted.append(sortedTable[j][i]); + } + } + return wordEncrypted.toString(); } - return wordEncrypted.toString(); - } - /** - * Decrypts a certain encrypted String with the Columnar Transposition Cipher Rule - * - * @return a String decrypted with the word encrypted by the Columnar Transposition Cipher Rule - */ - public static String decrypter() { - StringBuilder wordDecrypted = new StringBuilder(); - for (int i = 1; i < table.length; i++) { - for (Object item : table[i]) { - wordDecrypted.append(item); - } + /** + * Decrypts a certain encrypted String with the Columnar Transposition Cipher Rule + * + * @return a String decrypted with the word encrypted by the Columnar Transposition Cipher Rule + */ + public static String decrypter() { + StringBuilder wordDecrypted = new StringBuilder(); + for (int i = 1; i < table.length; i++) { + for (Object item : table[i]) { + wordDecrypted.append(item); + } + } + return wordDecrypted.toString().replaceAll(ENCRYPTION_FIELD, ""); } - return wordDecrypted.toString().replaceAll(ENCRYPTION_FIELD, ""); - } - /** - * Builds a table with the word to be encrypted in rows by the Columnar Transposition Cipher Rule - * - * @return An Object[][] with the word to be encrypted filled in rows and columns - */ - private static Object[][] tableBuilder(String word) { - Object[][] table = new Object[numberOfRows(word) + 1][keyword.length()]; - char[] wordInChards = word.toCharArray(); - // Fils in the respective numbers - table[0] = findElements(); - int charElement = 0; - for (int i = 1; i < table.length; i++) { - for (int j = 0; j < table[i].length; j++) { - if (charElement < wordInChards.length) { - table[i][j] = wordInChards[charElement]; - charElement++; + /** + * Builds a table with the word to be encrypted in rows by the Columnar Transposition Cipher Rule + * + * @return An Object[][] with the word to be encrypted filled in rows and columns + */ + private static Object[][] tableBuilder(String word) { + Object[][] table = new Object[numberOfRows(word) + 1][keyword.length()]; + char[] wordInChards = word.toCharArray(); + // Fils in the respective numbers + table[0] = findElements(); + int charElement = 0; + for (int i = 1; i < table.length; i++) { + for (int j = 0; j < table[i].length; j++) { + if (charElement < wordInChards.length) { + table[i][j] = wordInChards[charElement]; + charElement++; + } else { + table[i][j] = ENCRYPTION_FIELD_CHAR; + } + } + } + return table; + } + + /** + * Determines the number of rows the table should have regarding the Columnar Transposition Cipher + * Rule + * + * @return an int with the number of rows that the table should have in order to respect the + * Columnar Transposition Cipher Rule. + */ + private static int numberOfRows(String word) { + if (word.length() / keyword.length() > word.length() / keyword.length()) { + return (word.length() / keyword.length()) + 1; } else { - table[i][j] = ENCRYPTION_FIELD_CHAR; + return word.length() / keyword.length(); } - } } - return table; - } - /** - * Determines the number of rows the table should have regarding the Columnar Transposition Cipher - * Rule - * - * @return an int with the number of rows that the table should have in order to respect the - * Columnar Transposition Cipher Rule. - */ - private static int numberOfRows(String word) { - if (word.length() / keyword.length() > word.length() / keyword.length()) { - return (word.length() / keyword.length()) + 1; - } else { - return word.length() / keyword.length(); - } - } - - /** @return charValues */ - private static Object[] findElements() { - Object[] charValues = new Object[keyword.length()]; - for (int i = 0; i < charValues.length; i++) { - int charValueIndex = abecedarium.indexOf(keyword.charAt(i)); - charValues[i] = charValueIndex > -1 ? charValueIndex : null; - } - return charValues; - } - - /** - * @return tableSorted - */ - private static Object[][] sortTable(Object[][] table) { - Object[][] tableSorted = new Object[table.length][table[0].length]; - for (int i = 0; i < tableSorted.length; i++) { - System.arraycopy(table[i], 0, tableSorted[i], 0, tableSorted[i].length); - } - for (int i = 0; i < tableSorted[0].length; i++) { - for (int j = i + 1; j < tableSorted[0].length; j++) { - if ((int) tableSorted[0][i] > (int) table[0][j]) { - Object[] column = getColumn(tableSorted, tableSorted.length, i); - switchColumns(tableSorted, j, i, column); + /** + * @return charValues + */ + private static Object[] findElements() { + Object[] charValues = new Object[keyword.length()]; + for (int i = 0; i < charValues.length; i++) { + int charValueIndex = abecedarium.indexOf(keyword.charAt(i)); + charValues[i] = charValueIndex > -1 ? charValueIndex : null; } - } + return charValues; } - return tableSorted; - } - /** - * @return columnArray - */ - private static Object[] getColumn(Object[][] table, int rows, int column) { - Object[] columnArray = new Object[rows]; - for (int i = 0; i < rows; i++) { - columnArray[i] = table[i][column]; + /** + * @return tableSorted + */ + private static Object[][] sortTable(Object[][] table) { + Object[][] tableSorted = new Object[table.length][table[0].length]; + for (int i = 0; i < tableSorted.length; i++) { + System.arraycopy(table[i], 0, tableSorted[i], 0, tableSorted[i].length); + } + for (int i = 0; i < tableSorted[0].length; i++) { + for (int j = i + 1; j < tableSorted[0].length; j++) { + if ((int) tableSorted[0][i] > (int) table[0][j]) { + Object[] column = getColumn(tableSorted, tableSorted.length, i); + switchColumns(tableSorted, j, i, column); + } + } + } + return tableSorted; } - return columnArray; - } - private static void switchColumns( - Object[][] table, int firstColumnIndex, int secondColumnIndex, Object[] columnToSwitch) { - for (int i = 0; i < table.length; i++) { - table[i][secondColumnIndex] = table[i][firstColumnIndex]; - table[i][firstColumnIndex] = columnToSwitch[i]; + /** + * @return columnArray + */ + private static Object[] getColumn(Object[][] table, int rows, int column) { + Object[] columnArray = new Object[rows]; + for (int i = 0; i < rows; i++) { + columnArray[i] = table[i][column]; + } + return columnArray; } - } - /** - * Creates an abecedarium with a specified ascii inded - * - * @param value Number of characters being used based on the ASCII Table - */ - private static void abecedariumBuilder(int value) { - StringBuilder t = new StringBuilder(); - for (int i = 0; i < value; i++) { - t.append((char) i); + private static void switchColumns( + Object[][] table, int firstColumnIndex, int secondColumnIndex, Object[] columnToSwitch) { + for (int i = 0; i < table.length; i++) { + table[i][secondColumnIndex] = table[i][firstColumnIndex]; + table[i][firstColumnIndex] = columnToSwitch[i]; + } } - abecedarium = t.toString(); - } - private static void showTable() { - for (Object[] table1 : table) { - for (Object item : table1) { - System.out.print(item + " "); - } - System.out.println(); + /** + * Creates an abecedarium with a specified ascii inded + * + * @param value Number of characters being used based on the ASCII Table + */ + private static void abecedariumBuilder(int value) { + StringBuilder t = new StringBuilder(); + for (int i = 0; i < value; i++) { + t.append((char) i); + } + abecedarium = t.toString(); } - } - public static void main(String[] args) { - String keywordForExample = "asd215"; - String wordBeingEncrypted = "This is a test of the Columnar Transposition Cipher"; - System.out.println("### Example of Columnar Transposition Cipher ###\n"); - System.out.println("Word being encryped ->>> " + wordBeingEncrypted); - System.out.println( - "Word encrypted ->>> " - + ColumnarTranspositionCipher.encrpyter(wordBeingEncrypted, keywordForExample)); - System.out.println("Word decryped ->>> " + ColumnarTranspositionCipher.decrypter()); - System.out.println("\n### Encrypted Table ###"); - showTable(); - } + private static void showTable() { + for (Object[] table1 : table) { + for (Object item : table1) { + System.out.print(item + " "); + } + System.out.println(); + } + } + + public static void main(String[] args) { + String keywordForExample = "asd215"; + String wordBeingEncrypted = "This is a test of the Columnar Transposition Cipher"; + System.out.println("### Example of Columnar Transposition Cipher ###\n"); + System.out.println("Word being encryped ->>> " + wordBeingEncrypted); + System.out.println( + "Word encrypted ->>> " + + ColumnarTranspositionCipher.encrpyter(wordBeingEncrypted, keywordForExample)); + System.out.println("Word decryped ->>> " + ColumnarTranspositionCipher.decrypter()); + System.out.println("\n### Encrypted Table ###"); + showTable(); + } } diff --git a/Ciphers/HillCipher.java b/Ciphers/HillCipher.java index 0a3b5030..2150576f 100644 --- a/Ciphers/HillCipher.java +++ b/Ciphers/HillCipher.java @@ -1,172 +1,165 @@ package Ciphers; -import java.util.*; +import java.util.Scanner; /* -* Java Implementation of Hill Cipher -* Hill cipher is a polyalphabetic substitution cipher. Each letter is represented by a number belonging to the set Z26 where A=0 , B=1, ..... Z=25. -* To encrypt a message, each block of n letters (since matrix size is n x n) is multiplied by an invertible n × n matrix, against modulus 26. -* To decrypt the message, each block is multiplied by the inverse of the matrix used for encryption. -* The cipher key and plaintext/ciphertext are user inputs. -* @author Ojasva Jain -*/ + * Java Implementation of Hill Cipher + * Hill cipher is a polyalphabetic substitution cipher. Each letter is represented by a number belonging to the set Z26 where A=0 , B=1, ..... Z=25. + * To encrypt a message, each block of n letters (since matrix size is n x n) is multiplied by an invertible n × n matrix, against modulus 26. + * To decrypt the message, each block is multiplied by the inverse of the matrix used for encryption. + * The cipher key and plaintext/ciphertext are user inputs. + * @author Ojasva Jain + */ -public class HillCipher{ -static Scanner in = new Scanner (System.in); +public class HillCipher { + static Scanner in = new Scanner(System.in); -/* Following function encrypts the message -*/ -static void encrypt(String message) -{ - message = message.toUpperCase(); - // Get key matrix - System.out.println("Enter key matrix size"); - int n = in.nextInt(); - System.out.println("Enter Key/encryptionKey matrix "); - int keyMatrix[][] = new int [n][n]; - for(int i=0;i=message.length()){ messageVector[i][0] = 23;} - else - messageVector[i][0] = (message.charAt(j))%65; - System.out.println(messageVector[i][0]); - j++; - } - int x, i; - for (i = 0; i < n; i++) - { - cipherMatrix[i][0] = 0; - - for (x = 0; x < n; x++) - { - cipherMatrix[i][0] += keyMatrix[i][x] * messageVector[x][0]; + /* Following function encrypts the message + */ + static void encrypt(String message) { + message = message.toUpperCase(); + // Get key matrix + System.out.println("Enter key matrix size"); + int n = in.nextInt(); + System.out.println("Enter Key/encryptionKey matrix "); + int keyMatrix[][] = new int[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + keyMatrix[i][j] = in.nextInt(); } - System.out.println(cipherMatrix[i][0]); - cipherMatrix[i][0] = cipherMatrix[i][0] % 26; } - for (i = 0; i < n; i++) - CipherText += (char)(cipherMatrix[i][0] + 65); -} -System.out.println("Ciphertext: "+ CipherText); -} -//Following function decrypts a message -static void decrypt(String message) -{ - message = message.toUpperCase(); - // Get key matrix - System.out.println("Enter key matrix size"); - int n = in.nextInt(); - System.out.println("Enter inverseKey/decryptionKey matrix "); - int keyMatrix[][] = new int [n][n]; - for(int i=0;i= message.length()) { + messageVector[i][0] = 23; + } else + messageVector[i][0] = (message.charAt(j)) % 65; + System.out.println(messageVector[i][0]); + j++; + } + int x, i; + for (i = 0; i < n; i++) { + cipherMatrix[i][0] = 0; + + for (x = 0; x < n; x++) { + cipherMatrix[i][0] += keyMatrix[i][x] * messageVector[x][0]; + } + System.out.println(cipherMatrix[i][0]); + cipherMatrix[i][0] = cipherMatrix[i][0] % 26; + } + for (i = 0; i < n; i++) + CipherText += (char) (cipherMatrix[i][0] + 65); + } + System.out.println("Ciphertext: " + CipherText); } - //check if det = 0 - if(determinant(keyMatrix,n)%26 == 0) - { - System.out.println("Invalid key, as determinant = 0. Program Terminated"); - return; - } - //solving for the required plaintext message - int [][]messageVector = new int[n][1]; - String PlainText=""; - int plainMatrix [][] = new int [n][1]; - int j = 0; - while(j=message.length()){ messageVector[i][0] = 23;} - else - messageVector[i][0] = (message.charAt(j))%65; - System.out.println(messageVector[i][0]); - j++; + + //Following function decrypts a message + static void decrypt(String message) { + message = message.toUpperCase(); + // Get key matrix + System.out.println("Enter key matrix size"); + int n = in.nextInt(); + System.out.println("Enter inverseKey/decryptionKey matrix "); + int keyMatrix[][] = new int[n][n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + keyMatrix[i][j] = in.nextInt(); + } } - int x, i; - for (i = 0; i < n; i++) - { - plainMatrix[i][0] = 0; - - for (x = 0; x < n; x++) - { + //check if det = 0 + if (determinant(keyMatrix, n) % 26 == 0) { + System.out.println("Invalid key, as determinant = 0. Program Terminated"); + return; + } + //solving for the required plaintext message + int[][] messageVector = new int[n][1]; + String PlainText = ""; + int plainMatrix[][] = new int[n][1]; + int j = 0; + while (j < message.length()) { + for (int i = 0; i < n; i++) { + if (j >= message.length()) { + messageVector[i][0] = 23; + } else + messageVector[i][0] = (message.charAt(j)) % 65; + System.out.println(messageVector[i][0]); + j++; + } + int x, i; + for (i = 0; i < n; i++) { + plainMatrix[i][0] = 0; + + for (x = 0; x < n; x++) { plainMatrix[i][0] += keyMatrix[i][x] * messageVector[x][0]; } - + plainMatrix[i][0] = plainMatrix[i][0] % 26; } - for (i = 0; i < n; i++) - PlainText += (char)(plainMatrix[i][0] + 65); + for (i = 0; i < n; i++) + PlainText += (char) (plainMatrix[i][0] + 65); + } + System.out.println("Plaintext: " + PlainText); } - System.out.println("Plaintext: "+PlainText); -} -// Determinant calculator -public static int determinant(int a[][], int n){ - int det = 0, sign = 1, p = 0, q = 0; + // Determinant calculator + public static int determinant(int a[][], int n) { + int det = 0, sign = 1, p = 0, q = 0; - if(n==1){ - det = a[0][0]; - } - else{ - int b[][] = new int[n-1][n-1]; - for(int x = 0 ; x < n ; x++){ - p=0;q=0; - for(int i = 1;i < n; i++){ - for(int j = 0; j < n;j++){ - if(j != x){ - b[p][q++] = a[i][j]; - if(q % (n-1) == 0){ - p++; - q=0; + if (n == 1) { + det = a[0][0]; + } else { + int b[][] = new int[n - 1][n - 1]; + for (int x = 0; x < n; x++) { + p = 0; + q = 0; + for (int i = 1; i < n; i++) { + for (int j = 0; j < n; j++) { + if (j != x) { + b[p][q++] = a[i][j]; + if (q % (n - 1) == 0) { + p++; + q = 0; + } } } } + det = det + a[0][x] * determinant(b, n - 1) * sign; + sign = -sign; } - det = det + a[0][x] *determinant(b, n-1) * sign; - sign = -sign; } + return det; } - return det; -} -// Function to implement Hill Cipher -static void hillcipher(String message) -{ - message.toUpperCase(); - System.out.println("What do you want to process from the message?"); - System.out.println("Press 1: To Encrypt"); - System.out.println("Press 2: To Decrypt"); - short sc = in.nextShort(); - if(sc == 1) - encrypt(message); - else if(sc == 2) - decrypt(message); - else - System.out.println("Invalid input, program terminated."); -} + // Function to implement Hill Cipher + static void hillcipher(String message) { + message.toUpperCase(); + System.out.println("What do you want to process from the message?"); + System.out.println("Press 1: To Encrypt"); + System.out.println("Press 2: To Decrypt"); + short sc = in.nextShort(); + if (sc == 1) + encrypt(message); + else if (sc == 2) + decrypt(message); + else + System.out.println("Invalid input, program terminated."); + } -// Driver code -public static void main(String[] args) - { - // Get the message to be encrypted - System.out.println("Enter message"); - String message = in.nextLine(); - hillcipher(message); + // Driver code + public static void main(String[] args) { + // Get the message to be encrypted + System.out.println("Enter message"); + String message = in.nextLine(); + hillcipher(message); } } diff --git a/Ciphers/RSA.java b/Ciphers/RSA.java index 43a940c4..e7f94be2 100644 --- a/Ciphers/RSA.java +++ b/Ciphers/RSA.java @@ -1,74 +1,76 @@ package Ciphers; +import javax.swing.*; import java.math.BigInteger; import java.security.SecureRandom; -import javax.swing.JOptionPane; -/** @author Nguyen Duy Tiep on 23-Oct-17. */ +/** + * @author Nguyen Duy Tiep on 23-Oct-17. + */ public final class RSA { - public static void main(String[] args) { + public static void main(String[] args) { - RSA rsa = new RSA(1024); - String text1 = JOptionPane.showInputDialog("Enter a message to encrypt :"); + RSA rsa = new RSA(1024); + String text1 = JOptionPane.showInputDialog("Enter a message to encrypt :"); - String ciphertext = rsa.encrypt(text1); - JOptionPane.showMessageDialog(null, "Your encrypted message : " + ciphertext); + String ciphertext = rsa.encrypt(text1); + JOptionPane.showMessageDialog(null, "Your encrypted message : " + ciphertext); - JOptionPane.showMessageDialog(null, "Your message after decrypt : " + rsa.decrypt(ciphertext)); - } - - private BigInteger modulus, privateKey, publicKey; - - public RSA(int bits) { - generateKeys(bits); - } - - /** - * @return encrypted message - */ - public synchronized String encrypt(String message) { - return (new BigInteger(message.getBytes())).modPow(publicKey, modulus).toString(); - } - - /** - * @return encrypted message as big integer - */ - public synchronized BigInteger encrypt(BigInteger message) { - return message.modPow(publicKey, modulus); - } - - /** - * @return plain message - */ - public synchronized String decrypt(String encryptedMessage) { - return new String((new BigInteger(encryptedMessage)).modPow(privateKey, modulus).toByteArray()); - } - - /** - * @return plain message as big integer - */ - public synchronized BigInteger decrypt(BigInteger encryptedMessage) { - return encryptedMessage.modPow(privateKey, modulus); - } - - /** - * Generate a new public and private key set. - */ - public synchronized void generateKeys(int bits) { - SecureRandom r = new SecureRandom(); - BigInteger p = new BigInteger(bits / 2, 100, r); - BigInteger q = new BigInteger(bits / 2, 100, r); - modulus = p.multiply(q); - - BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE)); - - publicKey = new BigInteger("3"); - - while (m.gcd(publicKey).intValue() > 1) { - publicKey = publicKey.add(new BigInteger("2")); + JOptionPane.showMessageDialog(null, "Your message after decrypt : " + rsa.decrypt(ciphertext)); } - privateKey = publicKey.modInverse(m); - } + private BigInteger modulus, privateKey, publicKey; + + public RSA(int bits) { + generateKeys(bits); + } + + /** + * @return encrypted message + */ + public synchronized String encrypt(String message) { + return (new BigInteger(message.getBytes())).modPow(publicKey, modulus).toString(); + } + + /** + * @return encrypted message as big integer + */ + public synchronized BigInteger encrypt(BigInteger message) { + return message.modPow(publicKey, modulus); + } + + /** + * @return plain message + */ + public synchronized String decrypt(String encryptedMessage) { + return new String((new BigInteger(encryptedMessage)).modPow(privateKey, modulus).toByteArray()); + } + + /** + * @return plain message as big integer + */ + public synchronized BigInteger decrypt(BigInteger encryptedMessage) { + return encryptedMessage.modPow(privateKey, modulus); + } + + /** + * Generate a new public and private key set. + */ + public synchronized void generateKeys(int bits) { + SecureRandom r = new SecureRandom(); + BigInteger p = new BigInteger(bits / 2, 100, r); + BigInteger q = new BigInteger(bits / 2, 100, r); + modulus = p.multiply(q); + + BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE)); + + publicKey = new BigInteger("3"); + + while (m.gcd(publicKey).intValue() > 1) { + publicKey = publicKey.add(new BigInteger("2")); + } + + privateKey = publicKey.modInverse(m); + } } diff --git a/Ciphers/simpleSubCipher.java b/Ciphers/SimpleSubCipher.java similarity index 61% rename from Ciphers/simpleSubCipher.java rename to Ciphers/SimpleSubCipher.java index 779ca9b3..2e47700f 100644 --- a/Ciphers/simpleSubCipher.java +++ b/Ciphers/SimpleSubCipher.java @@ -1,19 +1,18 @@ package ciphers; - -import java.util.*; - + +import java.util.HashMap; +import java.util.Map; + /** - * - * The simple substitution cipher is a cipher that has been in use for many hundreds of years - * (an excellent history is given in Simon Singhs 'the Code Book'). - * It basically consists of substituting every plaintext character for a different ciphertext character. + * The simple substitution cipher is a cipher that has been in use for many hundreds of years + * (an excellent history is given in Simon Singhs 'the Code Book'). + * It basically consists of substituting every plaintext character for a different ciphertext character. * It differs from the Caesar cipher in that the cipher alphabet is not simply the alphabet shifted, * it is completely jumbled. - * */ - -public class simpleSubCipher { - + +public class SimpleSubCipher { + /** * Encrypt text by replacing each element with its opposite character. * @@ -23,32 +22,32 @@ public class simpleSubCipher { */ public static String encode(String message, String cipherSmall) { String encoded = ""; - + // This map is used to encode - Map cipherMap = new HashMap(); - + Map cipherMap = new HashMap<>(); + char beginSmallLetter = 'a'; char beginCapitalLetter = 'A'; - + cipherSmall = cipherSmall.toLowerCase(); String cipherCapital = cipherSmall.toUpperCase(); - + // To handle Small and Capital letters - for(int i = 0; i < cipherSmall.length(); i++){ - cipherMap.put(beginSmallLetter++,cipherSmall.charAt(i)); - cipherMap.put(beginCapitalLetter++,cipherCapital.charAt(i)); + for (int i = 0; i < cipherSmall.length(); i++) { + cipherMap.put(beginSmallLetter++, cipherSmall.charAt(i)); + cipherMap.put(beginCapitalLetter++, cipherCapital.charAt(i)); } - - for(int i = 0; i < message.length(); i++){ - if(Character.isAlphabetic(message.charAt(i))) + + for (int i = 0; i < message.length(); i++) { + if (Character.isAlphabetic(message.charAt(i))) encoded += cipherMap.get(message.charAt(i)); else encoded += message.charAt(i); } - + return encoded; } - + /** * Decrypt message by replacing each element with its opposite character in cipher. * @@ -58,35 +57,35 @@ public class simpleSubCipher { */ public static String decode(String encryptedMessage, String cipherSmall) { String decoded = ""; - - - Map cipherMap = new HashMap(); - + + + Map cipherMap = new HashMap(); + char beginSmallLetter = 'a'; char beginCapitalLetter = 'A'; - + cipherSmall = cipherSmall.toLowerCase(); String cipherCapital = cipherSmall.toUpperCase(); - - for(int i = 0; i < cipherSmall.length(); i++){ - cipherMap.put(cipherSmall.charAt(i),beginSmallLetter++); - cipherMap.put(cipherCapital.charAt(i),beginCapitalLetter++); + + for (int i = 0; i < cipherSmall.length(); i++) { + cipherMap.put(cipherSmall.charAt(i), beginSmallLetter++); + cipherMap.put(cipherCapital.charAt(i), beginCapitalLetter++); } - - for(int i = 0; i < encryptedMessage.length(); i++){ - if(Character.isAlphabetic(encryptedMessage.charAt(i))) + + for (int i = 0; i < encryptedMessage.length(); i++) { + if (Character.isAlphabetic(encryptedMessage.charAt(i))) decoded += cipherMap.get(encryptedMessage.charAt(i)); else decoded += encryptedMessage.charAt(i); } - + return decoded; } - + public static void main(String[] args) { - String a = encode("defend the east wall of the castle","phqgiumeaylnofdxjkrcvstzwb"); - String b = decode(a,"phqgiumeaylnofdxjkrcvstzwb"); + String a = encode("defend the east wall of the castle", "phqgiumeaylnofdxjkrcvstzwb"); + String b = decode(a, "phqgiumeaylnofdxjkrcvstzwb"); System.out.println(b); } - + } diff --git a/Ciphers/SimpleSubstitutionCipher.java b/Ciphers/SimpleSubstitutionCipher.java index 2ac68554..7b924b0e 100644 --- a/Ciphers/SimpleSubstitutionCipher.java +++ b/Ciphers/SimpleSubstitutionCipher.java @@ -1,6 +1,7 @@ package Ciphers; -import java.util.*; +import java.util.HashMap; +import java.util.Map; /** * The simple substitution cipher is a cipher that has been in use for many hundreds of years (an @@ -13,71 +14,73 @@ import java.util.*; */ public class SimpleSubstitutionCipher { - /** - * Encrypt text by replacing each element with its opposite character. - * - * @return Encrypted message - */ - public static String encode(String message, String cipherSmall) { - StringBuilder encoded = new StringBuilder(); + /** + * Encrypt text by replacing each element with its opposite character. + * + * @return Encrypted message + */ + public static String encode(String message, String cipherSmall) { + StringBuilder encoded = new StringBuilder(); - // This map is used to encode - Map cipherMap = new HashMap<>(); + // This map is used to encode + Map cipherMap = new HashMap<>(); - char beginSmallLetter = 'a'; - char beginCapitalLetter = 'A'; + char beginSmallLetter = 'a'; + char beginCapitalLetter = 'A'; - cipherSmall = cipherSmall.toLowerCase(); - String cipherCapital = cipherSmall.toUpperCase(); + cipherSmall = cipherSmall.toLowerCase(); + String cipherCapital = cipherSmall.toUpperCase(); - // To handle Small and Capital letters - for (int i = 0; i < cipherSmall.length(); i++) { - cipherMap.put(beginSmallLetter++, cipherSmall.charAt(i)); - cipherMap.put(beginCapitalLetter++, cipherCapital.charAt(i)); + // To handle Small and Capital letters + for (int i = 0; i < cipherSmall.length(); i++) { + cipherMap.put(beginSmallLetter++, cipherSmall.charAt(i)); + cipherMap.put(beginCapitalLetter++, cipherCapital.charAt(i)); + } + + for (int i = 0; i < message.length(); i++) { + if (Character.isAlphabetic(message.charAt(i))) encoded.append(cipherMap.get(message.charAt(i))); + else encoded.append(message.charAt(i)); + } + + return encoded.toString(); } - for (int i = 0; i < message.length(); i++) { - if (Character.isAlphabetic(message.charAt(i))) encoded.append(cipherMap.get(message.charAt(i))); - else encoded.append(message.charAt(i)); + /** + * Decrypt message by replacing each element with its opposite character in cipher. + * + * @return message + */ + public static String decode(String encryptedMessage, String cipherSmall) { + StringBuilder decoded = new StringBuilder(); + + Map cipherMap = new HashMap<>(); + + char beginSmallLetter = 'a'; + char beginCapitalLetter = 'A'; + + cipherSmall = cipherSmall.toLowerCase(); + String cipherCapital = cipherSmall.toUpperCase(); + + for (int i = 0; i < cipherSmall.length(); i++) { + cipherMap.put(cipherSmall.charAt(i), beginSmallLetter++); + cipherMap.put(cipherCapital.charAt(i), beginCapitalLetter++); + } + + for (int i = 0; i < encryptedMessage.length(); i++) { + if (Character.isAlphabetic(encryptedMessage.charAt(i))) + decoded.append(cipherMap.get(encryptedMessage.charAt(i))); + else decoded.append(encryptedMessage.charAt(i)); + } + + return decoded.toString(); } - return encoded.toString(); - } - - /** - * Decrypt message by replacing each element with its opposite character in cipher. - * - * @return message - */ - public static String decode(String encryptedMessage, String cipherSmall) { - StringBuilder decoded = new StringBuilder(); - - Map cipherMap = new HashMap<>(); - - char beginSmallLetter = 'a'; - char beginCapitalLetter = 'A'; - - cipherSmall = cipherSmall.toLowerCase(); - String cipherCapital = cipherSmall.toUpperCase(); - - for (int i = 0; i < cipherSmall.length(); i++) { - cipherMap.put(cipherSmall.charAt(i), beginSmallLetter++); - cipherMap.put(cipherCapital.charAt(i), beginCapitalLetter++); + /** + * TODO remove main and make JUnit Testing + */ + public static void main(String[] args) { + String a = encode("defend the east wall of the castle", "phqgiumeaylnofdxjkrcvstzwb"); + String b = decode(a, "phqgiumeaylnofdxjkrcvstzwb"); + System.out.println(b); } - - for (int i = 0; i < encryptedMessage.length(); i++) { - if (Character.isAlphabetic(encryptedMessage.charAt(i))) - decoded.append(cipherMap.get(encryptedMessage.charAt(i))); - else decoded.append(encryptedMessage.charAt(i)); - } - - return decoded.toString(); - } - - /** TODO remove main and make JUnit Testing */ - public static void main(String[] args) { - String a = encode("defend the east wall of the castle", "phqgiumeaylnofdxjkrcvstzwb"); - String b = decode(a, "phqgiumeaylnofdxjkrcvstzwb"); - System.out.println(b); - } } diff --git a/Ciphers/Vigenere.java b/Ciphers/Vigenere.java index 86ce52cf..680ae31e 100644 --- a/Ciphers/Vigenere.java +++ b/Ciphers/Vigenere.java @@ -8,55 +8,55 @@ package Ciphers; */ public class Vigenere { - public static String encrypt(final String message, final String key) { + public static String encrypt(final String message, final String key) { - StringBuilder result = new StringBuilder(); + StringBuilder result = new StringBuilder(); - for (int i = 0, j = 0; i < message.length(); i++) { - char c = message.charAt(i); - if (Character.isLetter(c)) { - if (Character.isUpperCase(c)) { - result.append((char) ((c + key.toUpperCase().charAt(j) - 2 * 'A') % 26 + 'A')); + for (int i = 0, j = 0; i < message.length(); i++) { + char c = message.charAt(i); + if (Character.isLetter(c)) { + if (Character.isUpperCase(c)) { + result.append((char) ((c + key.toUpperCase().charAt(j) - 2 * 'A') % 26 + 'A')); - } else { - result.append((char) ((c + key.toLowerCase().charAt(j) - 2 * 'a') % 26 + 'a')); + } else { + result.append((char) ((c + key.toLowerCase().charAt(j) - 2 * 'a') % 26 + 'a')); + } + } else { + result.append(c); + } + j = ++j % key.length(); } - } else { - result.append(c); - } - j = ++j % key.length(); + return result.toString(); } - return result.toString(); - } - public static String decrypt(final String message, final String key) { - StringBuilder result = new StringBuilder(); + public static String decrypt(final String message, final String key) { + StringBuilder result = new StringBuilder(); - for (int i = 0, j = 0; i < message.length(); i++) { + for (int i = 0, j = 0; i < message.length(); i++) { - char c = message.charAt(i); - if (Character.isLetter(c)) { - if (Character.isUpperCase(c)) { - result.append((char) ('Z' - (25 - (c - key.toUpperCase().charAt(j))) % 26)); + char c = message.charAt(i); + if (Character.isLetter(c)) { + if (Character.isUpperCase(c)) { + result.append((char) ('Z' - (25 - (c - key.toUpperCase().charAt(j))) % 26)); - } else { - result.append((char) ('z' - (25 - (c - key.toLowerCase().charAt(j))) % 26)); + } else { + result.append((char) ('z' - (25 - (c - key.toLowerCase().charAt(j))) % 26)); + } + } else { + result.append(c); + } + + j = ++j % key.length(); } - } else { - result.append(c); - } - - j = ++j % key.length(); + return result.toString(); } - return result.toString(); - } - public static void main(String[] args) { - String text = "Hello World!"; - String key = "itsakey"; - System.out.println(text); - String ciphertext = encrypt(text, key); - System.out.println(ciphertext); - System.out.println(decrypt(ciphertext, key)); - } + public static void main(String[] args) { + String text = "Hello World!"; + String key = "itsakey"; + System.out.println(text); + String ciphertext = encrypt(text, key); + System.out.println(ciphertext); + System.out.println(decrypt(ciphertext, key)); + } } diff --git a/Ciphers/affineCipher.java b/Ciphers/affineCipher.java deleted file mode 100644 index 8542884c..00000000 --- a/Ciphers/affineCipher.java +++ /dev/null @@ -1,83 +0,0 @@ -package Ciphers; -class affineCipher -{ - - // Key values of a and b - static int a = 17; - static int b = 20; - - static String encryptMessage(char[] msg) - { - /// Cipher Text initially empty - String cipher = ""; - for (int i = 0; i < msg.length; i++) - { - // Avoid space to be encrypted - /* applying encryption formula ( a x + b ) mod m - {here x is msg[i] and m is 26} and added 'A' to - bring it in range of ascii alphabet[ 65-90 | A-Z ] */ - if (msg[i] != ' ') - { - cipher = cipher - + (char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A'); - } else // else simply append space character - { - cipher += msg[i]; - } - } - return cipher; - } - - static String decryptCipher(String cipher) - { - String msg = ""; - int a_inv = 0; - int flag = 0; - - //Find a^-1 (the multiplicative inverse of a - //in the group of integers modulo m.) - for (int i = 0; i < 26; i++) - { - flag = (a * i) % 26; - - // Check if (a*i)%26 == 1, - // then i will be the multiplicative inverse of a - if (flag == 1) - { - a_inv = i; - } - } - for (int i = 0; i < cipher.length(); i++) - { - /*Applying decryption formula a^-1 ( x - b ) mod m - {here x is cipher[i] and m is 26} and added 'A' - to bring it in range of ASCII alphabet[ 65-90 | A-Z ] */ - if (cipher.charAt(i) != ' ') - { - msg = msg + (char) (((a_inv * - ((cipher.charAt(i) + 'A' - b)) % 26)) + 'A'); - } - else //else simply append space character - { - msg += cipher.charAt(i); - } - } - - return msg; - } - - // Driver code - public static void main(String[] args) - { - String msg = "AFFINE CIPHER"; - - // Calling encryption function - String cipherText = encryptMessage(msg.toCharArray()); - System.out.println("Encrypted Message is : " + cipherText); - - // Calling Decryption function - System.out.println("Decrypted Message is: " + decryptCipher(cipherText)); - - } -} -