如何製作一個好的加密器?
我正在使用自己的 PRNG 為流密碼製作加密器軟體,作為校際科學競賽的項目。我怎樣才能製作一個,以便在它生成偽隨機編號之後。它可以辨識每個字元並進行轉換。任何人都可以用 Python 或虛擬碼算法來解釋這一點。
我試著自己做一個,但我不確定它是否會起作用。它是這樣工作的:首先,程序開始計算並記錄我們輸入的每個字元,有點像鍵盤記錄器。它必須能夠唯一地辨識每個字元。然後它進行換檔。如果它足夠好,我可以按原樣使用它還是必須進行更改。
說你有價值 $ n $ 這是字母表的大小(即構成明文和密文的字元範圍)。並說 $ m = x \times n $ 是您擁有的不高於的最大值 $ y $ 在哪裡 $ y $ 是您的隨機數生成器產生的最大尺寸。
對於每個字元:
- 從隨機數生成器中取值,直到你的值小於 $ m $ , 呼叫這個值 $ r_i $ ;
- 計算 $ s_i $ 這很簡單 $ r_i \bmod n $ ;
- 計算 $ p_i $ 這是字母表中目前字元的位置;
- 計算 $ c_i = (p_i + s_i) \bmod n $
- 將角色帶到位置 $ c_i $ 的字母表和顯示。
扭轉:
- 從隨機數生成器中取值,直到你的值小於 $ m $ , 呼叫這個值 $ r_i $ ;
- 計算 $ s_i $ 這很簡單 $ r_i \bmod n $ ;
- 計算 $ c_i $ 這是字母表中目前字元的位置(字母表中的第一個字元位於位置 0);
- 計算 $ p_i = (c_i - s_i) \bmod n $
- 將角色帶到位置 $ p_i $ 的字母表和顯示。
在上述計算中,我假設隨機數生成器從 $ 0 $ 取決於 $ y $ (所以沒有 $ y $ )。這些字元在一個字母表中,它們有一個索引 $ 0 $ 取決於 $ n $ (所以沒有 $ n $ ).
如果 $ y = n $ (隨機數生成器的最大值與字母的大小相同)那麼方案當然更簡單。您可以只取隨機數生成器的下一個值並呼叫它 $ s_i $ ,跳過前兩個步驟。
Java 中的範例實現(抱歉,不太了解 Python):
import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; public class StreamCryptUsingAlphabet { private String alphabet; private int n; private int y; private int m; private SecureRandom rng; public StreamCryptUsingAlphabet(String alphabet, int y) { this.alphabet = alphabet; this.n = alphabet.length(); if (y < n) { throw new IllegalArgumentException("y is too small"); } this.y = y; // % is the remainder operator, same as modulus for positive numbers this.m = y - y % n; } public void init(byte[] seed) { try { rng = SecureRandom.getInstance("SHA1PRNG"); } catch (NoSuchAlgorithmException e) { throw new IllegalStateException("RNG not available"); } rng.setSeed(seed); } private int nextS() { int r; do { r = rng.nextInt(y); } while (r >= m); return r % n; } public String encrypt(String plaintext) { String ciphertext = ""; for (int i = 0; i < plaintext.length(); i++) { int p = indexInAlphabet(plaintext.charAt(i)); int s = nextS(); int c = (p + s) % n; ciphertext += characterInAlphabet(c); } return ciphertext; } public String decrypt(String ciphertext) { String plaintext = ""; for (int i = 0; i < ciphertext.length(); i++) { int c = indexInAlphabet(ciphertext.charAt(i)); int s = nextS(); // Java's remainder requires me to add n first int p = (c - s + n) % n; plaintext += characterInAlphabet(p); } return plaintext; } private int indexInAlphabet(char c) { String s = String.valueOf(c); return alphabet.indexOf(s); } private char characterInAlphabet(int i) { return alphabet.charAt(i); } public static void main(String[] args) { byte[] key = "Khan".getBytes(StandardCharsets.US_ASCII); StreamCryptUsingAlphabet sc = new StreamCryptUsingAlphabet( "abcdefghijklmnopqrstuvwxyz", 80); sc.init(key); String ct = sc.encrypt("owlstead"); sc.init("Khan".getBytes(StandardCharsets.US_ASCII)); String pt = sc.decrypt(ct); System.out.println(pt); } }
下一部分解釋瞭如果密鑰流是偽隨機位流通常會做什麼……
通常,如果您生成了隨機密鑰流,那麼我們使用 XOR 來加密純文字。為此,明文也需要是二進制的。所以如果明文實際上是文本,我們需要對其進行字元編碼。常用的編碼是 US ASCII 和 UTF-8。但是,這將產生二進制密文,因此如果要將其表示為字元串,則可以使用 base 64 編碼。
要解密您首先要對您收到的數據進行 base 64 解碼以檢索密文。然後解密,然後使用字元解碼從二進制明文中檢索文本。
所以上面是通常在電腦內完成的事情。