📄 blowfish.java
字号:
L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K1; R ^= K0; } out[outOff++] = (byte)(R >>> 24); out[outOff++] = (byte)(R >>> 16); out[outOff++] = (byte)(R >>> 8); out[outOff++] = (byte) R; out[outOff++] = (byte)(L >>> 24); out[outOff++] = (byte)(L >>> 16); out[outOff++] = (byte)(L >>> 8); out[outOff ] = (byte) L; } /** * Expands a user-key to a working Blowfish P array (P) and S-box * data (S). * <p> * The key bytes are first extracted from the user-key and then * used, repetitively if need be, to build the contents of this * key schedule and S-box values. * <p> * The Blowfish algorithm uses a single key schedule for both encryption * and decryption. The process (key byte values and algorithm formulae) * are used in one direction during encryption and simply reversed * during decryption. * * @param key the user-key object to use. * @exception InvalidKeyException if one of the following occurs: <ul> * <li> key.getEncoded() == null; * <li> key.getEncoded().length is invalid. * </ul> * @exception CryptixException if any one of the two self-tests fail. * The two self-tests are as follows: <ol> * <li> encrypt 0 ten times using the initial S and P boxes * values. Check the result against a known value. If equal * decrypt the result 10 times and compare it to 0; * <li> complete the key expansion process and use the newly * formed key to encrypt 10 times 0; decrypt the result 10 * times and compare. * </ol> */ private void makeKey (Key key) throws InvalidKeyException, CryptixException { byte[] userkey = key.getEncoded(); if (userkey == null) throw new InvalidKeyException(getAlgorithm() + ": Null user key"); int len = userkey.length; if (len < MIN_USER_KEY_LENGTH || len > MAX_USER_KEY_LENGTH) throw new InvalidKeyException(getAlgorithm() + ": Invalid user key length"); // If native library available then use it. If not or if // native method returned error then revert to 100% Java. if (native_lock != null) { synchronized(native_lock) { try { linkStatus.check(native_ks(native_cookie, userkey, rounds)); return; } catch (Error error) { native_finalize(); native_lock = null;if (DEBUG && debuglevel > 0) debug(error + ". Will use 100% Java."); } } } System.arraycopy(S0, 0, S, 0, 256); System.arraycopy(S1, 0, S, 256, 256); System.arraycopy(S2, 0, S, 512, 256); System.arraycopy(S3, 0, S, 768, 256); System.arraycopy(P0, 0, P, 0, rounds + 2); // // Self test #1 // 1. Encrypt 0 ten times using initial S-Boxes and a zero-value key. // Check result against pre-computed value. // 2. Decrypt it 10 times and check if == 0. // int[] block = {0, 0}; int st = 0; for (st = 0; st < 10; st++) BF_encrypt(block[0], block[1], block, 0); if (block[0] != 0xAAFE4EBD || block[1] != 0x26D725FC) throw new CryptixException(getAlgorithm() + ": Self Test 1 failed: encrypt^10(0) = " + Hex.toString(block));if (DEBUG && debuglevel >= 3) debug("Self Test 1 Good"); while (--st >= 0) BF_decrypt(block[0], block[1], block, 0); if (block[0] != 0 || block[1] != 0) throw new CryptixException(getAlgorithm() + ": Self Test 1 failed: decrypt^10(encrypt^10(0)) = " + Hex.toString(block));// if (len > MAX_USER_KEY_LENGTH) len = MAX_USER_KEY_LENGTH; int ri; for (int i = 0, j = 0; i < rounds + 2; i++) { ri = 0; for (int k = 0; k < 4; k++) { ri = (ri << 8) | (userkey[j++] & 0xFF); j %= len; } P[i] ^= ri; } // use the former to effectively generate the P-array for this key BF_encrypt(0, 0, P, 0); for (int i = 2; i < rounds + 2; i += 2) BF_encrypt(P[i - 2], P[i - 1], P, i); // and the S-boxes BF_encrypt(P[rounds], P[rounds + 1], S, 0); for (int i = 2; i < 1024; i += 2) BF_encrypt(S[i - 2], S[i - 1], S, i); // // Self test #2 // Encrypt 0 ten times. Decrypt it ten times. Should be the same. // for (st = 0; st < 10; st++) BF_encrypt(block[0], block[1], block, 0); while (--st >= 0) BF_decrypt(block[0], block[1], block, 0); if (block[0] != 0 || block[1] != 0) throw new CryptixException(getAlgorithm() + ": Self Test 2 failed: decrypt^10(encrypt^10(0)) = " + Hex.toString(block));if (DEBUG && debuglevel >= 3) debug("Self Test 2 Good"); if (rounds == DEFAULT_NOF_ROUNDS) { // unfold the P array into individual Ki's. K0 = P[0]; K1 = P[1]; K2 = P[2]; K3 = P[3]; K4 = P[4]; K5 = P[5]; K6 = P[6]; K7 = P[7]; K8 = P[8]; K9 = P[9]; K10 = P[10]; K11 = P[11]; K12 = P[12]; K13 = P[13]; K14 = P[14]; K15 = P[15]; K16 = P[16]; K17 = P[17]; } } /** * See description in <code>blockEncrypt</code> above. * <p> * This method is only called by the <code>makeKey</code> method to * generate the key schedule from user data. It outputs the result to an * int array. * * @param L left half (32-bit) of the plain text block. * @param R right half (32-bit) of the plain text block. * @param out the int array where the result will be saved. * @param outOff where the data starts in the byte array. * @see #blockEncrypt */ private void BF_encrypt (int L, int R, int[] out, int outOff) { L ^= P[0]; for (int i = 0; i < rounds; ) { R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ P[++i]; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ P[++i]; } out[outOff++] = R ^ P[rounds + 1]; out[outOff ] = L; } /** * See description in <code>blockDecrypt</code> above. * <p> * This method is only called by the <code>makeKey</code> method during * self-test operation. * * @param L left half (32-bit) of the ciphertext block, * @param R right half (32-bit) of the ciphertext block. * @param out the int array where the result will be saved. * @param outOff where the data starts in the byte array. * @see #blockDecrypt */ private void BF_decrypt (int L, int R, int[] out, int outOff) { L ^= P[rounds + 1]; for (int i = rounds; i > 0; ) { R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ P[i--]; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ P[i--]; } out[outOff++] = R ^ P[0]; out[outOff ] = L; }// Test methods//...........................................................................//// Don't expand this code please without thinking about it,// much better to write a separate program.// /** Entry point for very basic <code>self_test</code>. */ public static void main(String[] args) { try { self_test(); } catch (Exception e) { e.printStackTrace(); } } /** * This is (apparently) the official certification data. * Use decimal as Java grumbles about hex values > 0x7F. */ private static final byte[][][] tests = { { // cert 1 { // key 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122 }, { 66, 76, 79, 87, 70, 73, 83, 72}, // plain { 50, 78, -48, -2, -12, 19, -94, 3} // cipher }, { // cert 2 { 87, 104, 111, 32, 105, 115, 32, 74, 111, 104, 110, 32, 71, 97, 108, 116, 63 }, { -2, -36, -70, -104, 118, 84, 50, 16}, { -52, -111, 115, 43, -128, 34, -10, -124} }, { // cert 3 - Ayn Rand with 4th () and 8th (d) chars hi bit set. { 65, 121, 110, -96, 82, 97, 110, -28}, // key { -2, -36, -70, -104, 118, 84, 50, 16}, // plain { -31, 19, -12, 16, 44, -4, -50, 67} // cipher } }; /** * Do some basic tests. * Three of the certification data are included only, no output, * success or exception. * If you want more, write a test program! * * @see cryptix.examples.TestBlowfish */ private static void self_test() throws Exception { Cipher cryptor = Cipher.getInstance("Blowfish", "Cryptix"); RawSecretKey userKey; byte[] tmp; for (int i = 0; i < tests.length; i++) { userKey = new RawSecretKey("Blowfish", tests[i][0]); cryptor.initEncrypt(userKey); tmp = cryptor.crypt(tests[i][1]); if (!ArrayUtil.areEqual(tests[i][2], tmp)) throw new CryptixException("encrypt #"+ i +" failed"); cryptor.initDecrypt(userKey); tmp = cryptor.crypt(tests[i][2]); if (!ArrayUtil.areEqual(tests[i][1], tmp)) throw new CryptixException("decrypt #"+ i +" failed"); }if (DEBUG && debuglevel > 0) debug("Self-test OK"); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -