📄 blowfish.java
字号:
* <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, rounds)) 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; } /** * <b>SPI</b>: Sets the specified algorithm parameter to the specified * value. * <p> * Blowfish has a single parameter, "rounds", which specifies the * number of rounds for this instance as a decimal String. * * @param param the string name of the parameter. * @param value the parameter value. * @exception InvalidParameterException if param is an invalid * parameter for this cipher implementation, the * parameter is already set and cannot be set again, a * security exception occurs, and so on. * @exception InvalidParameterTypeException if value is of the wrong * type. */ protected void engineSetParameter(String param, Object value) throws InvalidParameterException, InvalidParameterTypeException { if (!(value instanceof String)) throw new InvalidParameterTypeException(getAlgorithm() + ": value is not a String"); try { if (param.equals("rounds")) setRounds(Integer.parseInt((String) value)); } catch (Exception e) { throw new InvalidParameterException(e.toString()); } throw new InvalidParameterException(getAlgorithm() + ": " + param); } /** * <b>SPI</b>: Gets the value of the specified algorithm parameter. * <p> * Blowfish has a single parameter, "rounds", which specifies the * number of rounds for this instance as a decimal String. * * @param param the string name of the parameter. * @return the object that represents the parameter value, or null if there * is none. */ protected Object engineGetParameter(String param) { if (param.equals("rounds")) return Integer.toString(rounds); return null; }// Own methods//........................................................................... /** * Sets the number of rounds for this cipher. Allowed only when this * cipher is in the UNINITIALIZED state; otherwise an exception is * thrown. * <p> * If the specified number is invalid, an IllegalArgumentException is * thrown. * <p> * Note that there is not enough defined initial data for any number * of rounds other than 16 for the time being. * * @param r the desired number of rounds for this cipher. * @throw IllegalStateException if this cipher is not uninitialised. * @exception IllegalArgumentException if the given number of rounds is * not supported. */ public void setRounds(int r) { if (getState() != UNINITIALIZED) throw new IllegalStateException(getAlgorithm() + ": Cipher not in UNINITIALIZED state"); if (r < MIN_NOF_ROUNDS || r > MAX_NOF_ROUNDS) throw new IllegalArgumentException(getAlgorithm() + ": Invalid number of rounds"); rounds = r; } /** * Returns the currently set number of rounds for this instance. * * @return the number of rounds. */ public int getRounds() { return rounds; } /** * The normal entry to the encryption process. It is guaranteed * to be called with enough bytes in the input to carry on an * encryption of one full block. * <p> * The code of the Blowfish encryption engine, found here, is also * replicated in the BF_encrypt method found later. The reason for * this duplication is performance. This method outputs the result * in a byte array form, suitable for the user data encryption * operations, while BF_encrypt outputs its result as an int array * suitable for, and used during, the expansion of the user-key into * a Blowfish key schedule. * * @param in contains the input plaintext. * @param off index of in from which to start considering data. * @param out will contain the ciphertext block. * @param outOff index of out where the ciphertext will start. */ private void blockEncrypt (byte[] in, int off, byte[] out, int outOff) { int L = (in[off++] & 0xFF) << 24 | (in[off++] & 0xFF) << 16 | (in[off++] & 0xFF) << 8 | (in[off++] & 0xFF); int R = (in[off++] & 0xFF) << 24 | (in[off++] & 0xFF) << 16 | (in[off++] & 0xFF) << 8 | (in[off ] & 0xFF); if (rounds != DEFAULT_NOF_ROUNDS) { 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]; } R ^= P[rounds + 1]; } else { L ^= K0; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K1; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K2; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K3; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K4; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K5; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K6; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K7; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K8; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K9; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K10; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K11; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K12; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K13; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K14; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K15; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K16; R ^= K17; } 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; } /** * The normal entry to the decryption process. It is guaranteed * to be called with enough bytes in the input to carry on a * decryption of one full block. * <p> * Because the Blowfish cipher engine is designed to handle two * 32-bit blocks, this method's purpose is to transform on entry * and exit the data to/from 32-bit blocks; i.e. Java ints. * <p> * The input becomes two 32-bit blocks as Left and Right halves * onto which the Blowfish cipher function is applied ROUNDS times * in reverse order to that of the encryption. * * @param in contains the input plaintext. * @param off index of in from which to start considering data. * @param out will contain the ciphertext block. * @param outOff index of out where the ciphertext will start. */ private void blockDecrypt (byte[] in, int off, byte[] out, int outOff) { int L = (in[off++] & 0xFF) << 24 | (in[off++] & 0xFF) << 16 | (in[off++] & 0xFF) << 8 | (in[off++] & 0xFF); int R = (in[off++] & 0xFF) << 24 | (in[off++] & 0xFF) << 16 | (in[off++] & 0xFF) << 8 | (in[off ] & 0xFF); if (rounds != DEFAULT_NOF_ROUNDS) { 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--]; } R ^= P[0]; } else { L ^= K17; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K16; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K15; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K14; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K13; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K12; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K11; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K10; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K9; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K8; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K7; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K6; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K5; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K4; L ^= (((S[(R >>> 24) & 0xFF] + S[256 + ((R >>> 16) & 0xFF)]) ^ S[512 + ((R >>> 8) & 0xFF)]) + S[768 + (R & 0xFF)]) ^ K3; R ^= (((S[(L >>> 24) & 0xFF] + S[256 + ((L >>> 16) & 0xFF)]) ^ S[512 + ((L >>> 8) & 0xFF)]) + S[768 + (L & 0xFF)]) ^ K2;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -