?? idea.java
字號:
invertKey(); } /** * <b>SPI</b>: This is the main engine method for updating data. * <p> * <i>in</i> and <i>out</i> may be the same array, and the input and output * regions may overlap. * * @param in the input data. * @param inOffset the offset into in specifying where the data starts. * @param inLen the length of the subarray. * @param out the output array. * @param outOffset the offset indicating where to start writing into * the out array. * @return the number of bytes written. * @exception CryptixException if the native library is being used, and it * reports an error. */ protected int engineUpdate(byte[] in, int inOffset, int inLen, byte[] out, int outOffset) { if (inLen < 0) throw new IllegalArgumentException("inLen < 0"); int blockCount = inLen / BLOCK_SIZE; inLen = blockCount * BLOCK_SIZE; boolean doEncrypt = (getState() == ENCRYPT); // Avoid overlapping input and output regions. if (in == out && (outOffset >= inOffset && outOffset < (long)inOffset+inLen || inOffset >= outOffset && inOffset < (long)outOffset+inLen)) { byte[] newin = new byte[inLen]; System.arraycopy(in, inOffset, newin, 0, inLen); in = newin; inOffset = 0; } if (native_lock != null) { synchronized(native_lock) { // If in == null || out == 0, evaluating their lengths will throw a // NullPointerException. if (inOffset < 0 || (long)inOffset + inLen > in.length || outOffset < 0 || (long)outOffset + inLen > out.length) throw new ArrayIndexOutOfBoundsException(getAlgorithm() + ": Arguments to native_crypt would cause a buffer overflow"); // In future, we may pass more than one block to native_crypt to reduce // native method overhead. for (int i = 0; i < blockCount; i++) { if (0 == native_crypt(native_cookie, in, inOffset, out, outOffset, doEncrypt)) throw new CryptixException(getAlgorithm() + ": Error in native code"); inOffset += BLOCK_SIZE; outOffset += BLOCK_SIZE; } } } else if (doEncrypt) { // state == ENCRYPT for (int i = 0; i < blockCount; i++) { blockEncrypt(in, inOffset, out, outOffset); inOffset += BLOCK_SIZE; outOffset += BLOCK_SIZE; } } else { // state == DECRYPT for (int i = 0; i < blockCount; i++) { blockDecrypt(in, inOffset, out, outOffset); inOffset += BLOCK_SIZE; outOffset += BLOCK_SIZE; } } return inLen; }// Own methods//............................................................................ /** * Expands a user-key to a working key schedule. * <p> * IDEA has separate key schedules for encryption and decryption. This * generates the encryption schedule; calling <code>invertKey</code> * afterward will generate the decryption schedule. * * @param key the user-key object to use. * @exception InvalidKeyException if one of the following occurs: <ul> * <li> key.getEncoded() == null; * <li> The length of the user key array is outside the * permissible limits. * </ul> * @exception CryptixException if a self-test fails. */ private void makeKey(Key key) throws InvalidKeyException, CryptixException { byte[] userkey = key.getEncoded(); if (userkey == null) throw new InvalidKeyException(getAlgorithm() + ": Null user key"); if (userkey.length != 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)); return; } catch (Error error) { native_finalize(); native_lock = null;if (DEBUG && debuglevel > 0) debug(error + ". Will use 100% Java."); } } } /* * Expand user key of 128 bits to full 832 bits of encryption key. */ ks[0] = (short)((userkey[ 0] & 0xFF) << 8 | (userkey[ 1] & 0xFF)); ks[1] = (short)((userkey[ 2] & 0xFF) << 8 | (userkey[ 3] & 0xFF)); ks[2] = (short)((userkey[ 4] & 0xFF) << 8 | (userkey[ 5] & 0xFF)); ks[3] = (short)((userkey[ 6] & 0xFF) << 8 | (userkey[ 7] & 0xFF)); ks[4] = (short)((userkey[ 8] & 0xFF) << 8 | (userkey[ 9] & 0xFF)); ks[5] = (short)((userkey[10] & 0xFF) << 8 | (userkey[11] & 0xFF)); ks[6] = (short)((userkey[12] & 0xFF) << 8 | (userkey[13] & 0xFF)); ks[7] = (short)((userkey[14] & 0xFF) << 8 | (userkey[15] & 0xFF)); for (int i = 0, zoff = 0, j = 8; j < INTERNAL_KEY_LENGTH; i &= 7, j++) { i++; ks[i + 7 + zoff] = (short)((ks[(i & 7) + zoff] << 9) | ((ks[((i + 1) & 7) + zoff] >>> 7) & 0x1FF)); zoff += i & 8; } } /** * IDEA, being a symmetric cipher, uses the same algorithm for both * encryption and decryption. What changes is the key. For the inverse * operation (of either encryption or decryption) the following method * inverts the key to make it ready for application of the cipher method. */ private void invertKey () { if (native_lock == null) { int i, j = 4, k = INTERNAL_KEY_LENGTH - 1; short[] temp = new short[INTERNAL_KEY_LENGTH]; temp[k--] = inv(ks[3]); temp[k--] = (short) -ks[2]; temp[k--] = (short) -ks[1]; temp[k--] = inv(ks[0]); for (i = 1; i < ROUNDS; i++, j += 6) { temp[k--] = ks[j + 1]; temp[k--] = ks[j]; temp[k--] = inv(ks[j + 5]); temp[k--] = (short) -ks[j + 3]; temp[k--] = (short) -ks[j + 4]; temp[k--] = inv(ks[j + 2]); } temp[k--] = ks[j + 1]; temp[k--] = ks[j]; temp[k--] = inv(ks[j + 5]); temp[k--] = (short) -ks[j + 4]; temp[k--] = (short) -ks[j + 3]; temp[k--] = inv(ks[j + 2]); System.arraycopy(temp, 0, ks, 0, INTERNAL_KEY_LENGTH); } } /** * IDEA encryption/decryption algorithm using the current key schedule. * * @param in an array containing the plaintext block * @param inOffset the starting offset of the plaintext block * @param out an array containing the ciphertext block * @param inOffset the starting offset of the ciphertext block */ private void blockEncrypt (byte[] in, int inOffset, byte[] out, int outOffset) { short x1 = (short)(((in[inOffset++] & 0xFF) << 8) | (in[inOffset++] & 0xFF)), x2 = (short)(((in[inOffset++] & 0xFF) << 8) | (in[inOffset++] & 0xFF)), x3 = (short)(((in[inOffset++] & 0xFF) << 8) | (in[inOffset++] & 0xFF)), x4 = (short)(((in[inOffset++] & 0xFF) << 8) | (in[inOffset ] & 0xFF)), s2, s3; int i = 0, round = ROUNDS; while (round-- > 0) { x1 = mul(x1, ks[i++]); x2 += ks[i++]; x3 += ks[i++]; x4 = mul(x4, ks[i++]); s3 = x3; x3 = mul(x1 ^ x3, ks[i++]); s2 = x2; x2 = mul(x3 + (x2 ^ x4), ks[i++]); x3 += x2; x1 ^= x2; x4 ^= x3; x2 ^= s3; x3 ^= s2; } s2 = mul(x1, ks[i++]); out[outOffset++] = (byte)(s2 >>> 8); out[outOffset++] = (byte) s2; s2 = (short)(x3 + ks[i++]); out[outOffset++] = (byte)(s2 >>> 8); out[outOffset++] = (byte) s2; s2 = (short)(x2 + ks[i++]); out[outOffset++] = (byte)(s2 >>> 8); out[outOffset++] = (byte) s2; s2 = mul(x4, ks[i]); out[outOffset++] = (byte)(s2 >>> 8); out[outOffset ] = (byte) s2; } /** * IDEA uses the same algorithm for both encryption and decryption. Only the * key schedule changes. */ private void blockDecrypt (byte[] in, int inOffset, byte[] out, int outOffset) { blockEncrypt(in, inOffset, out, outOffset); } /** * Multiplication modulo (2**16)+1. */ private static short mul (int a, int b) { a &= 0xFFFF; b &= 0xFFFF; int p; if (a != 0) { if (b != 0) { p = a * b; b = p & 0xFFFF; a = p >>> 16; return (short)(b - a + (b < a ? 1 : 0)); } else return (short)(1 - a); } else return (short)(1 - b); } /** * Compute inverse of x, modulo (2**16)+1, using Euclidean gcd algorithm. * * The Euclidean part of this algorithm could live in a * general purpose math library, but then it would probably * end up too slow. */ private static short inv (short xx) { int x = xx & 0xFFFF; // only lower 16 bits if (x <= 1) return (short)x; // 0 and 1 are self-inverse int t1 = 0x10001 / x; // Since x >= 2, this fits into 16 bits int y = 0x10001 % x; if (y == 1) return (short)(1 - t1); int t0 = 1; int q; do { q = x / y; x = x % y; t0 += q * t1; if (x == 1) return (short)t0; q = y / x; y %= x; t1 += q * t0; } while (y != 1); return (short)(1 - t1); }// 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 argv[]) { try { self_test(); } catch(Throwable t) { t.printStackTrace(); } } // // This is (apparently) the official certification data. // Use ints as Java grumbles about negative hex values. // static final private byte[][][] tests = { { // cert 1 { 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8}, // key { 0, 0, 0, 1, 0, 2, 0, 3}, // plain { 17, -5, -19, 43, 1, -104, 109, -27}, // cipher }, { // cert 8 { 58, -104, 78, 32, 0, 25, 93, -77, 46, -27, 1, -56, -60, 124, -22, 96}, { 1, 2, 3, 4, 5, 6, 7, 8}, { -105, -68, -40, 32, 7, -128, -38, -122}, }, { // cert 9 { 0, 100, 0, -56, 1, 44, 1, -112, 1, -12, 2, 88, 2, -68, 3, 32}, // key { 5, 50, 10, 100, 20, -56, 25, -6}, // plain { 101, -66, -121, -25, -94, 83, -118, -19}, // 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.IDEA */ public static void self_test() throws Throwable { Cipher cryptor = Cipher.getInstance("IDEA", "Cryptix"); RawSecretKey userKey; byte[] tmp; for (int i = 0; i < tests.length; i++) { userKey = new RawSecretKey("IDEA", 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 + -