├── README.md ├── utils.py ├── LICENSE └── hill_cipher.py /README.md: -------------------------------------------------------------------------------- 1 | # Hill-Cipher 2 | Hill cipher implementation in Python 3 | 4 | **Usage:** 5 | 6 | `python3 hill_cipher.py` 7 | 8 | Once done, it asks for the plain text and key matrix. 9 | 10 | **Sample values:** 11 | 12 | **Plain Text** : "ACT" 13 | 14 | **Key Matrix** : 15 | 16 | 6 24 1 17 | 18 | 13 16 10 19 | 20 | 20 17 15 21 | 22 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | def multi_inverse(b, n): 2 | r1 = n 3 | r2 = b 4 | t1 = 0 5 | t2 = 1 6 | 7 | while(r1 > 0): 8 | q = int(r1/r2) 9 | r = r1 - q * r2 10 | r1 = r2 11 | r2 = r 12 | t = t1 - q * t2 13 | t1 = t2 14 | t2 = t 15 | 16 | if(r1 == 1): 17 | inv_t = t1 18 | break 19 | 20 | return inv_t 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kushashwa Ravi Shrimali 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /hill_cipher.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import math 3 | import utils 4 | 5 | # decryption function 6 | def decrypt(key_matrix_inv, cipher_text): 7 | """ 8 | Arguments: key matrix inverse, cipher text 9 | Returns: plain text 10 | """ 11 | print("Matrix Inverse is: \n", key_matrix_inv) 12 | dimensions = len(cipher_text) 13 | 14 | # create cipher text matrix (ASCII Values - 65 to get from 0 to X) 15 | 16 | cipher_text_matrix = [] 17 | for i in range(dimensions): 18 | cipher_text_matrix.append(ord(cipher_text[i]) - 65) 19 | 20 | cipher_text_matrix = np.array(cipher_text_matrix) 21 | print("Cipher Key Matrix: \n", cipher_text_matrix) 22 | 23 | # multiply inverse with cipher text matrix 24 | result = np.array(np.dot(key_matrix_inv, cipher_text_matrix)) 25 | 26 | # BUG 27 | # print(result[0][1], int(result[0][1])) 28 | print("Decrypted Matrix\n", result) 29 | 30 | # create empty string for plain text 31 | plain_text = "" 32 | # convert result matrix to plain text by using chr() 33 | for i in range(dimensions): 34 | plain_text += chr(int(round(result[0][i], 0) % 26 + 65)) 35 | 36 | # return the decrypted plain text 37 | return plain_text 38 | 39 | if __name__ == "__main__": 40 | # take input from the user 41 | plain_text = str(input("Plain Text: ")) 42 | 43 | # dimensions of the matrix = length(plain text) x length(plain text) 44 | dimensions = len(plain_text) 45 | 46 | # plain text matrix 47 | plain_text_matrix = [] 48 | 49 | # creating a column matrix for plain text characters 50 | for i in range(dimensions): 51 | plain_text_matrix.append(ord(plain_text[i]) - 65) 52 | 53 | plain_text_matrix = np.array(plain_text_matrix) 54 | 55 | print("Plain Text Matrix\n", plain_text_matrix) 56 | 57 | print("Enter values for the key: ") 58 | 59 | # take values for the key matrix 60 | key_matrix = [] 61 | for i in range(dimensions): 62 | row_ = [] 63 | for j in range(dimensions): 64 | value = int(input(str(i) + ", " + str(j) + " value: ")) 65 | row_.append(value) 66 | key_matrix.append(row_) 67 | 68 | print("Key Matrix: \n") 69 | 70 | # for encryption 71 | key_matrix = np.array(key_matrix) 72 | # for decryption 73 | # key_matrix_inv = (np.linalg.inv(np.matrix(key_matrix)) % 26) 74 | # key_matrix_inv = utils.multi_inverse(np.linalg.det(key_matrix), 26) * \ 75 | # np.matrix(key_matrix).getH() 76 | # print(np.matrix(key_matrix).getH()) 77 | 78 | # calculate key matrix inverse using modulo multiplicative inverse 79 | key_matrix_inv = np.linalg.inv(np.matrix(key_matrix)) * \ 80 | np.linalg.det(key_matrix) * \ 81 | utils.multi_inverse(np.linalg.det(key_matrix), 26) % 26 82 | 83 | print(key_matrix) 84 | 85 | print("Inverse Key Matrix: \n", key_matrix_inv) 86 | 87 | result = key_matrix.dot(plain_text_matrix) 88 | 89 | print("Cipher Matrix: \n", result) 90 | 91 | cipher_text = "" 92 | 93 | for i in range(dimensions): 94 | cipher_text += chr(result[i] % 26 + 65) 95 | 96 | print("Cipher Text: \n", cipher_text) 97 | 98 | decrypted_plain_text = decrypt(key_matrix_inv, cipher_text) 99 | 100 | print("Decrypted plain text: ", decrypted_plain_text) 101 | --------------------------------------------------------------------------------