mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-23 04:20:16 +08:00
Format code with prettier (#3375)
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
package com.thealgorithms.ciphers;
|
||||
|
||||
import javax.crypto.*;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import javax.crypto.*;
|
||||
|
||||
/**
|
||||
* This example program shows how AES encryption and decryption can be done in
|
||||
@ -26,8 +26,12 @@ public class AESEncryption {
|
||||
String decryptedText = decryptText(cipherText, secKey);
|
||||
|
||||
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(
|
||||
"AES Key (Hex Form):" + bytesToHex(secKey.getEncoded())
|
||||
);
|
||||
System.out.println(
|
||||
"Encrypted Text (Hex Form):" + bytesToHex(cipherText)
|
||||
);
|
||||
System.out.println("Descrypted Text:" + decryptedText);
|
||||
}
|
||||
|
||||
@ -38,7 +42,8 @@ public class AESEncryption {
|
||||
* @return secKey (Secret key that we encrypt using it)
|
||||
* @throws NoSuchAlgorithmException (from KeyGenrator)
|
||||
*/
|
||||
public static SecretKey getSecretEncryptionKey() throws NoSuchAlgorithmException {
|
||||
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();
|
||||
@ -55,8 +60,7 @@ public class AESEncryption {
|
||||
* @throws IllegalBlockSizeException (from Cipher)
|
||||
*/
|
||||
public static byte[] encryptText(String plainText, SecretKey secKey)
|
||||
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
|
||||
IllegalBlockSizeException, BadPaddingException {
|
||||
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);
|
||||
@ -69,8 +73,7 @@ public class AESEncryption {
|
||||
* @return plainText
|
||||
*/
|
||||
public static String decryptText(byte[] byteCipherText, SecretKey secKey)
|
||||
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
|
||||
IllegalBlockSizeException, BadPaddingException {
|
||||
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);
|
||||
|
@ -15,10 +15,9 @@ class AffineCipher {
|
||||
{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 =
|
||||
cipher + (char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A');
|
||||
} else { // else simply append space character
|
||||
cipher += msg[i];
|
||||
}
|
||||
}
|
||||
@ -46,10 +45,12 @@ class AffineCipher {
|
||||
{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 =
|
||||
msg +
|
||||
(char) (
|
||||
((a_inv * ((cipher.charAt(i) + 'A' - b)) % 26)) + 'A'
|
||||
);
|
||||
} else { //else simply append space character
|
||||
msg += cipher.charAt(i);
|
||||
}
|
||||
}
|
||||
@ -66,7 +67,8 @@ class AffineCipher {
|
||||
System.out.println("Encrypted Message is : " + cipherText);
|
||||
|
||||
// Calling Decryption function
|
||||
System.out.println("Decrypted Message is: " + decryptCipher(cipherText));
|
||||
|
||||
System.out.println(
|
||||
"Decrypted Message is: " + decryptCipher(cipherText)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,21 +25,16 @@ public class Caesar {
|
||||
|
||||
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
|
||||
|
||||
if (IsCapitalLatinLetter(current)) {
|
||||
|
||||
current += shift;
|
||||
encoded.append((char) (current > 'Z' ? current - 26 : current)); // 26 = number of latin letters
|
||||
|
||||
} else if (IsSmallLatinLetter(current)) {
|
||||
|
||||
current += shift;
|
||||
encoded.append((char) (current > 'z' ? current - 26 : current)); // 26 = number of latin letters
|
||||
|
||||
} else {
|
||||
encoded.append(current);
|
||||
}
|
||||
@ -62,15 +57,11 @@ public class Caesar {
|
||||
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
|
||||
|
||||
} else if (IsSmallLatinLetter(current)) {
|
||||
|
||||
current -= shift;
|
||||
decoded.append((char) (current < 'a' ? current + 26 : current)); // 26 = number of latin letters
|
||||
|
||||
} else {
|
||||
decoded.append(current);
|
||||
}
|
||||
@ -91,12 +82,13 @@ public class Caesar {
|
||||
private static boolean IsSmallLatinLetter(char c) {
|
||||
return c >= 'a' && c <= 'z';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string array which contains all the possible decoded combination.
|
||||
*/
|
||||
public static String[] bruteforce(String encryptedMessage) {
|
||||
String[] listOfAllTheAnswers = new String[27];
|
||||
for (int i=0; i<=26; i++) {
|
||||
for (int i = 0; i <= 26; i++) {
|
||||
listOfAllTheAnswers[i] = decode(encryptedMessage, i);
|
||||
}
|
||||
|
||||
@ -117,24 +109,32 @@ public class Caesar {
|
||||
System.out.println("Please enter the shift number");
|
||||
shift = input.nextInt() % 26;
|
||||
System.out.println(
|
||||
"ENCODED MESSAGE IS \n" + encode(message, shift)); // send our function to handle
|
||||
"ENCODED MESSAGE IS \n" + encode(message, shift)
|
||||
); // send our function to handle
|
||||
break;
|
||||
case 'D':
|
||||
case 'd':
|
||||
System.out.println("Please enter the shift number");
|
||||
shift = input.nextInt() % 26;
|
||||
System.out.println("DECODED MESSAGE IS \n" + decode(message, shift));
|
||||
System.out.println(
|
||||
"DECODED MESSAGE IS \n" + decode(message, shift)
|
||||
);
|
||||
break;
|
||||
case 'B':
|
||||
case 'b':
|
||||
String[] listOfAllTheAnswers = bruteforce(message);
|
||||
for (int i =0; i<=26; i++) {
|
||||
System.out.println("FOR SHIFT " + String.valueOf(i) + " decoded message is " + listOfAllTheAnswers[i]);
|
||||
for (int i = 0; i <= 26; i++) {
|
||||
System.out.println(
|
||||
"FOR SHIFT " +
|
||||
String.valueOf(i) +
|
||||
" decoded message is " +
|
||||
listOfAllTheAnswers[i]
|
||||
);
|
||||
}
|
||||
default:
|
||||
System.out.println("default case");
|
||||
}
|
||||
|
||||
|
||||
input.close();
|
||||
}
|
||||
}
|
||||
|
@ -12,8 +12,9 @@ public class ColumnarTranspositionCipher {
|
||||
private static String keyword;
|
||||
private static Object[][] table;
|
||||
private static String abecedarium;
|
||||
public static final String ABECEDARIUM
|
||||
= "abcdefghijklmnopqrstuvwxyzABCDEFG" + "HIJKLMNOPQRSTUVWXYZ0123456789,.;:-@";
|
||||
public static final String ABECEDARIUM =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFG" +
|
||||
"HIJKLMNOPQRSTUVWXYZ0123456789,.;:-@";
|
||||
private static final String ENCRYPTION_FIELD = "≈";
|
||||
private static final char ENCRYPTION_FIELD_CHAR = '≈';
|
||||
|
||||
@ -49,9 +50,14 @@ public class ColumnarTranspositionCipher {
|
||||
* @return a String with the word encrypted by the Columnar Transposition
|
||||
* Cipher Rule
|
||||
*/
|
||||
public static String encrpyter(String word, String keyword, String abecedarium) {
|
||||
public static String encrpyter(
|
||||
String word,
|
||||
String keyword,
|
||||
String abecedarium
|
||||
) {
|
||||
ColumnarTranspositionCipher.keyword = keyword;
|
||||
ColumnarTranspositionCipher.abecedarium = Objects.requireNonNullElse(abecedarium, ABECEDARIUM);
|
||||
ColumnarTranspositionCipher.abecedarium =
|
||||
Objects.requireNonNullElse(abecedarium, ABECEDARIUM);
|
||||
table = tableBuilder(word);
|
||||
Object[][] sortedTable = sortTable(table);
|
||||
StringBuilder wordEncrypted = new StringBuilder();
|
||||
@ -114,7 +120,9 @@ public class ColumnarTranspositionCipher {
|
||||
* order to respect the Columnar Transposition Cipher Rule.
|
||||
*/
|
||||
private static int numberOfRows(String word) {
|
||||
if (word.length() / keyword.length() > word.length() / keyword.length()) {
|
||||
if (
|
||||
word.length() / keyword.length() > word.length() / keyword.length()
|
||||
) {
|
||||
return (word.length() / keyword.length()) + 1;
|
||||
} else {
|
||||
return word.length() / keyword.length();
|
||||
@ -139,12 +147,22 @@ public class ColumnarTranspositionCipher {
|
||||
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);
|
||||
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);
|
||||
Object[] column = getColumn(
|
||||
tableSorted,
|
||||
tableSorted.length,
|
||||
i
|
||||
);
|
||||
switchColumns(tableSorted, j, i, column);
|
||||
}
|
||||
}
|
||||
@ -164,7 +182,11 @@ public class ColumnarTranspositionCipher {
|
||||
}
|
||||
|
||||
private static void switchColumns(
|
||||
Object[][] table, int firstColumnIndex, int secondColumnIndex, Object[] columnToSwitch) {
|
||||
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];
|
||||
@ -195,13 +217,22 @@ public class ColumnarTranspositionCipher {
|
||||
|
||||
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");
|
||||
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());
|
||||
"Word encrypted ->>> " +
|
||||
ColumnarTranspositionCipher.encrpyter(
|
||||
wordBeingEncrypted,
|
||||
keywordForExample
|
||||
)
|
||||
);
|
||||
System.out.println(
|
||||
"Word decryped ->>> " + ColumnarTranspositionCipher.decrypter()
|
||||
);
|
||||
System.out.println("\n### Encrypted Table ###");
|
||||
showTable();
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class HillCipher {
|
||||
}
|
||||
}
|
||||
//check if det = 0
|
||||
validateDeterminant(keyMatrix,matrixSize);
|
||||
validateDeterminant(keyMatrix, matrixSize);
|
||||
|
||||
int[][] messageVector = new int[matrixSize][1];
|
||||
String CipherText = "";
|
||||
@ -76,7 +76,7 @@ public class HillCipher {
|
||||
}
|
||||
}
|
||||
//check if det = 0
|
||||
validateDeterminant(keyMatrix,n);
|
||||
validateDeterminant(keyMatrix, n);
|
||||
|
||||
//solving for the required plaintext message
|
||||
int[][] messageVector = new int[n][1];
|
||||
@ -155,9 +155,11 @@ public class HillCipher {
|
||||
}
|
||||
}
|
||||
|
||||
static void validateDeterminant(int[][] keyMatrix, int n){
|
||||
static void validateDeterminant(int[][] keyMatrix, int n) {
|
||||
if (determinant(keyMatrix, n) % 26 == 0) {
|
||||
System.out.println("Invalid key, as determinant = 0. Program Terminated");
|
||||
System.out.println(
|
||||
"Invalid key, as determinant = 0. Program Terminated"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -169,4 +171,4 @@ public class HillCipher {
|
||||
String message = userInput.nextLine();
|
||||
hillCipher(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,12 +15,12 @@ package com.thealgorithms.ciphers;
|
||||
public class Polybius {
|
||||
|
||||
private static final char[][] key = {
|
||||
// 0 1 2 3 4
|
||||
/* 0 */ {'A', 'B', 'C', 'D', 'E'},
|
||||
/* 1 */ {'F', 'G', 'H', 'I', 'J'},
|
||||
/* 2 */ {'K', 'L', 'M', 'N', 'O'},
|
||||
/* 3 */ {'P', 'Q', 'R', 'S', 'T'},
|
||||
/* 4 */ {'V', 'W', 'X', 'Y', 'Z'}
|
||||
// 0 1 2 3 4
|
||||
/* 0 */{ 'A', 'B', 'C', 'D', 'E' },
|
||||
/* 1 */{ 'F', 'G', 'H', 'I', 'J' },
|
||||
/* 2 */{ 'K', 'L', 'M', 'N', 'O' },
|
||||
/* 3 */{ 'P', 'Q', 'R', 'S', 'T' },
|
||||
/* 4 */{ 'V', 'W', 'X', 'Y', 'Z' },
|
||||
};
|
||||
|
||||
private static String findLocationByCharacter(final char character) {
|
||||
@ -49,11 +49,11 @@ public class Polybius {
|
||||
public static String decrypt(final String ciphertext) {
|
||||
final char[] chars = ciphertext.toCharArray();
|
||||
final StringBuilder plaintext = new StringBuilder();
|
||||
for(int i = 0; i < chars.length; i+=2) {
|
||||
for (int i = 0; i < chars.length; i += 2) {
|
||||
int pozitionX = Character.getNumericValue(chars[i]);
|
||||
int pozitionY = Character.getNumericValue(chars[i + 1]);
|
||||
plaintext.append(key[pozitionX][pozitionY]);
|
||||
}
|
||||
return plaintext.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -68,5 +68,4 @@ class ProductCipher {
|
||||
System.out.println(plaintext);
|
||||
sc.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
package com.thealgorithms.ciphers;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.math.BigInteger;
|
||||
import java.security.SecureRandom;
|
||||
import javax.swing.*;
|
||||
|
||||
/**
|
||||
* @author Nguyen Duy Tiep on 23-Oct-17.
|
||||
@ -10,14 +10,21 @@ import java.security.SecureRandom;
|
||||
public final class RSA {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
RSA rsa = new RSA(1024);
|
||||
String text1 = JOptionPane.showInputDialog("Enter a message to encrypt :");
|
||||
String text1 = JOptionPane.showInputDialog(
|
||||
"Enter a message to encrypt :"
|
||||
);
|
||||
|
||||
String ciphertext = rsa.encrypt(text1);
|
||||
JOptionPane.showMessageDialog(null, "Your encrypted message : " + ciphertext);
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"Your encrypted message : " + ciphertext
|
||||
);
|
||||
|
||||
JOptionPane.showMessageDialog(null, "Your message after decrypt : " + rsa.decrypt(ciphertext));
|
||||
JOptionPane.showMessageDialog(
|
||||
null,
|
||||
"Your message after decrypt : " + rsa.decrypt(ciphertext)
|
||||
);
|
||||
}
|
||||
|
||||
private BigInteger modulus, privateKey, publicKey;
|
||||
@ -30,7 +37,8 @@ public final class RSA {
|
||||
* @return encrypted message
|
||||
*/
|
||||
public synchronized String encrypt(String message) {
|
||||
return (new BigInteger(message.getBytes())).modPow(publicKey, modulus).toString();
|
||||
return (new BigInteger(message.getBytes())).modPow(publicKey, modulus)
|
||||
.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -44,7 +52,10 @@ public final class RSA {
|
||||
* @return plain message
|
||||
*/
|
||||
public synchronized String decrypt(String encryptedMessage) {
|
||||
return new String((new BigInteger(encryptedMessage)).modPow(privateKey, modulus).toByteArray());
|
||||
return new String(
|
||||
(new BigInteger(encryptedMessage)).modPow(privateKey, modulus)
|
||||
.toByteArray()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,7 +74,8 @@ public final class RSA {
|
||||
BigInteger q = new BigInteger(bits / 2, 100, r);
|
||||
modulus = p.multiply(q);
|
||||
|
||||
BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
|
||||
BigInteger m =
|
||||
(p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
|
||||
|
||||
publicKey = new BigInteger("3");
|
||||
|
||||
|
@ -84,9 +84,11 @@ public class SimpleSubCipher {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
String a = encode("defend the east wall of the castle", "phqgiumeaylnofdxjkrcvstzwb");
|
||||
String a = encode(
|
||||
"defend the east wall of the castle",
|
||||
"phqgiumeaylnofdxjkrcvstzwb"
|
||||
);
|
||||
String b = decode(a, "phqgiumeaylnofdxjkrcvstzwb");
|
||||
System.out.println(b);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -85,7 +85,10 @@ public class SimpleSubstitutionCipher {
|
||||
* 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 a = encode(
|
||||
"defend the east wall of the castle",
|
||||
"phqgiumeaylnofdxjkrcvstzwb"
|
||||
);
|
||||
String b = decode(a, "phqgiumeaylnofdxjkrcvstzwb");
|
||||
System.out.println(b);
|
||||
}
|
||||
|
@ -9,17 +9,27 @@ package com.thealgorithms.ciphers;
|
||||
public class Vigenere {
|
||||
|
||||
public static String encrypt(final String message, final String key) {
|
||||
|
||||
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'));
|
||||
|
||||
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'));
|
||||
result.append(
|
||||
(char) (
|
||||
(c + key.toLowerCase().charAt(j) - 2 * 'a') %
|
||||
26 +
|
||||
'a'
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
result.append(c);
|
||||
@ -33,14 +43,20 @@ public class Vigenere {
|
||||
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) ('Z' - (25 - (c - key.toUpperCase().charAt(j))) % 26));
|
||||
|
||||
result.append(
|
||||
(char) (
|
||||
'Z' - (25 - (c - key.toUpperCase().charAt(j))) % 26
|
||||
)
|
||||
);
|
||||
} else {
|
||||
result.append((char) ('z' - (25 - (c - key.toLowerCase().charAt(j))) % 26));
|
||||
result.append(
|
||||
(char) (
|
||||
'z' - (25 - (c - key.toLowerCase().charAt(j))) % 26
|
||||
)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
result.append(c);
|
||||
|
@ -4,21 +4,22 @@ import java.util.BitSet;
|
||||
|
||||
// https://en.wikipedia.org/wiki/A5/1
|
||||
public class A5Cipher {
|
||||
|
||||
private final A5KeyStreamGenerator keyStreamGenerator;
|
||||
private static final int KEY_STREAM_LENGTH = 228; // 28.5 bytes so we need to pad bytes or something
|
||||
|
||||
public A5Cipher( BitSet sessionKey, BitSet frameCounter ) {
|
||||
public A5Cipher(BitSet sessionKey, BitSet frameCounter) {
|
||||
keyStreamGenerator = new A5KeyStreamGenerator();
|
||||
keyStreamGenerator.initialize( sessionKey, frameCounter );
|
||||
keyStreamGenerator.initialize(sessionKey, frameCounter);
|
||||
}
|
||||
|
||||
public BitSet encrypt( BitSet plainTextBits ) {
|
||||
public BitSet encrypt(BitSet plainTextBits) {
|
||||
// create a copy
|
||||
var result = new BitSet( KEY_STREAM_LENGTH );
|
||||
result.xor( plainTextBits );
|
||||
var result = new BitSet(KEY_STREAM_LENGTH);
|
||||
result.xor(plainTextBits);
|
||||
|
||||
var key = keyStreamGenerator.getNextKeyStream();
|
||||
result.xor( key );
|
||||
result.xor(key);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -26,5 +27,4 @@ public class A5Cipher {
|
||||
public void resetCounter() {
|
||||
keyStreamGenerator.reInitialize();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import java.util.BitSet;
|
||||
|
||||
// TODO: raise exceptions for improper use
|
||||
public class A5KeyStreamGenerator extends CompositeLFSR {
|
||||
|
||||
private BitSet initialFrameCounter;
|
||||
private BitSet frameCounter;
|
||||
private BitSet sessionKey;
|
||||
@ -11,32 +12,35 @@ public class A5KeyStreamGenerator extends CompositeLFSR {
|
||||
private static final int KEY_STREAM_LENGTH = 228; // 28.5 bytes so we need to pad bytes or something
|
||||
|
||||
@Override
|
||||
public void initialize( BitSet sessionKey, BitSet frameCounter ) {
|
||||
public void initialize(BitSet sessionKey, BitSet frameCounter) {
|
||||
this.sessionKey = sessionKey;
|
||||
this.frameCounter = (BitSet) frameCounter.clone();
|
||||
this.initialFrameCounter = (BitSet) frameCounter.clone();
|
||||
registers.clear();
|
||||
LFSR lfsr1 = new LFSR( 19, 8, new int[]{ 13, 16, 17, 18 } );
|
||||
LFSR lfsr2 = new LFSR( 22, 10, new int[]{ 20, 21 } );
|
||||
LFSR lfsr3 = new LFSR( 23, 10, new int[]{ 7, 20, 21, 22 } );
|
||||
registers.add( lfsr1 );
|
||||
registers.add( lfsr2 );
|
||||
registers.add( lfsr3 );
|
||||
registers.forEach( lfsr -> lfsr.initialize( sessionKey, frameCounter ) );
|
||||
LFSR lfsr1 = new LFSR(19, 8, new int[] { 13, 16, 17, 18 });
|
||||
LFSR lfsr2 = new LFSR(22, 10, new int[] { 20, 21 });
|
||||
LFSR lfsr3 = new LFSR(23, 10, new int[] { 7, 20, 21, 22 });
|
||||
registers.add(lfsr1);
|
||||
registers.add(lfsr2);
|
||||
registers.add(lfsr3);
|
||||
registers.forEach(lfsr -> lfsr.initialize(sessionKey, frameCounter));
|
||||
}
|
||||
|
||||
public void reInitialize() {
|
||||
this.initialize( sessionKey, initialFrameCounter );
|
||||
this.initialize(sessionKey, initialFrameCounter);
|
||||
}
|
||||
|
||||
public BitSet getNextKeyStream() {
|
||||
for ( int cycle = 1; cycle <= INITIAL_CLOCKING_CYCLES; ++cycle )
|
||||
this.clock();
|
||||
for (
|
||||
int cycle = 1;
|
||||
cycle <= INITIAL_CLOCKING_CYCLES;
|
||||
++cycle
|
||||
) this.clock();
|
||||
|
||||
BitSet result = new BitSet( KEY_STREAM_LENGTH );
|
||||
for ( int cycle = 1; cycle <= KEY_STREAM_LENGTH; ++cycle ) {
|
||||
BitSet result = new BitSet(KEY_STREAM_LENGTH);
|
||||
for (int cycle = 1; cycle <= KEY_STREAM_LENGTH; ++cycle) {
|
||||
boolean outputBit = this.clock();
|
||||
result.set( cycle - 1, outputBit );
|
||||
result.set(cycle - 1, outputBit);
|
||||
}
|
||||
|
||||
reInitializeRegisters();
|
||||
@ -45,10 +49,10 @@ public class A5KeyStreamGenerator extends CompositeLFSR {
|
||||
|
||||
private void reInitializeRegisters() {
|
||||
incrementFrameCounter();
|
||||
registers.forEach( lfsr -> lfsr.initialize( sessionKey, frameCounter ) );
|
||||
registers.forEach(lfsr -> lfsr.initialize(sessionKey, frameCounter));
|
||||
}
|
||||
|
||||
private void incrementFrameCounter() {
|
||||
Utils.increment( frameCounter, FRAME_COUNTER_LENGTH );
|
||||
Utils.increment(frameCounter, FRAME_COUNTER_LENGTH);
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
public abstract class CompositeLFSR implements BaseLFSR {
|
||||
|
||||
protected final List<LFSR> registers = new ArrayList<>();
|
||||
|
||||
/**
|
||||
@ -16,20 +17,24 @@ public abstract class CompositeLFSR implements BaseLFSR {
|
||||
public boolean clock() {
|
||||
boolean majorityBit = getMajorityBit();
|
||||
boolean result = false;
|
||||
for ( var register : registers ) {
|
||||
for (var register : registers) {
|
||||
result ^= register.getLastBit();
|
||||
if ( register.getClockBit() == majorityBit )
|
||||
register.clock();
|
||||
if (register.getClockBit() == majorityBit) register.clock();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean getMajorityBit() {
|
||||
Map<Boolean, Integer> bitCount = new TreeMap<>();
|
||||
bitCount.put( false, 0 );
|
||||
bitCount.put( true, 0 );
|
||||
bitCount.put(false, 0);
|
||||
bitCount.put(true, 0);
|
||||
|
||||
registers.forEach( lfsr -> bitCount.put( lfsr.getClockBit(), bitCount.get( lfsr.getClockBit() ) + 1 ) );
|
||||
return bitCount.get( false ) <= bitCount.get( true );
|
||||
registers.forEach(lfsr ->
|
||||
bitCount.put(
|
||||
lfsr.getClockBit(),
|
||||
bitCount.get(lfsr.getClockBit()) + 1
|
||||
)
|
||||
);
|
||||
return bitCount.get(false) <= bitCount.get(true);
|
||||
}
|
||||
}
|
||||
|
@ -3,71 +3,72 @@ package com.thealgorithms.ciphers.a5;
|
||||
import java.util.BitSet;
|
||||
|
||||
public class LFSR implements BaseLFSR {
|
||||
|
||||
private final BitSet register;
|
||||
private final int length;
|
||||
private final int clockBitIndex;
|
||||
private final int[] tappingBitsIndices;
|
||||
|
||||
public LFSR( int length, int clockBitIndex, int[] tappingBitsIndices ) {
|
||||
public LFSR(int length, int clockBitIndex, int[] tappingBitsIndices) {
|
||||
this.length = length;
|
||||
this.clockBitIndex = clockBitIndex;
|
||||
this.tappingBitsIndices = tappingBitsIndices;
|
||||
register = new BitSet( length );
|
||||
register = new BitSet(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize( BitSet sessionKey, BitSet frameCounter ) {
|
||||
public void initialize(BitSet sessionKey, BitSet frameCounter) {
|
||||
register.clear();
|
||||
clock( sessionKey, SESSION_KEY_LENGTH );
|
||||
clock( frameCounter, FRAME_COUNTER_LENGTH );
|
||||
clock(sessionKey, SESSION_KEY_LENGTH);
|
||||
clock(frameCounter, FRAME_COUNTER_LENGTH);
|
||||
}
|
||||
|
||||
private void clock( BitSet key, int keyLength ) {
|
||||
private void clock(BitSet key, int keyLength) {
|
||||
// We start from reverse because LFSR 0 index is the left most bit
|
||||
// while key 0 index is right most bit, so we reverse it
|
||||
for ( int i = keyLength - 1; i >= 0; --i ) {
|
||||
var newBit = key.get( i ) ^ xorTappingBits();
|
||||
pushBit( newBit );
|
||||
for (int i = keyLength - 1; i >= 0; --i) {
|
||||
var newBit = key.get(i) ^ xorTappingBits();
|
||||
pushBit(newBit);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clock() {
|
||||
return pushBit( xorTappingBits() );
|
||||
return pushBit(xorTappingBits());
|
||||
}
|
||||
|
||||
public boolean getClockBit() {
|
||||
return register.get( clockBitIndex );
|
||||
return register.get(clockBitIndex);
|
||||
}
|
||||
|
||||
public boolean get( int bitIndex ) {
|
||||
return register.get( bitIndex );
|
||||
public boolean get(int bitIndex) {
|
||||
return register.get(bitIndex);
|
||||
}
|
||||
|
||||
public boolean getLastBit() {
|
||||
return register.get( length - 1 );
|
||||
return register.get(length - 1);
|
||||
}
|
||||
|
||||
private boolean xorTappingBits() {
|
||||
boolean result = false;
|
||||
for ( int i : tappingBitsIndices ) {
|
||||
result ^= register.get( i );
|
||||
for (int i : tappingBitsIndices) {
|
||||
result ^= register.get(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean pushBit( boolean bit ) {
|
||||
private boolean pushBit(boolean bit) {
|
||||
boolean discardedBit = rightShift();
|
||||
register.set( 0, bit );
|
||||
register.set(0, bit);
|
||||
return discardedBit;
|
||||
}
|
||||
|
||||
private boolean rightShift() {
|
||||
boolean discardedBit = get( length - 1 );
|
||||
for ( int i = length - 1; i > 0; --i ) {
|
||||
register.set( i, get( i - 1 ) );
|
||||
boolean discardedBit = get(length - 1);
|
||||
for (int i = length - 1; i > 0; --i) {
|
||||
register.set(i, get(i - 1));
|
||||
}
|
||||
register.set( 0, false );
|
||||
register.set(0, false);
|
||||
return discardedBit;
|
||||
}
|
||||
|
||||
|
@ -7,15 +7,16 @@ package com.thealgorithms.ciphers.a5;
|
||||
import java.util.BitSet;
|
||||
|
||||
public class Utils {
|
||||
public static boolean increment( BitSet bits, int size ) {
|
||||
|
||||
public static boolean increment(BitSet bits, int size) {
|
||||
int i = size - 1;
|
||||
while ( i >= 0 && bits.get( i ) ) {
|
||||
bits.set( i--, false );/*from w w w . j a v a 2s .c o m*/
|
||||
while (i >= 0 && bits.get(i)) {
|
||||
bits.set(i--, false);/*from w w w . j a v a 2s .c o m*/
|
||||
}
|
||||
if ( i < 0 ) {
|
||||
if (i < 0) {
|
||||
return false;
|
||||
}
|
||||
bits.set( i, true );
|
||||
bits.set(i, true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user