/*
* Copyright 2017 ZhangJiupeng
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cc.agentx.security;
import cc.agentx.util.KeyHelper;
import org.bouncycastle.crypto.StreamBlockCipher;
import org.bouncycastle.crypto.engines.BlowfishEngine;
import org.bouncycastle.crypto.modes.CFBBlockCipher;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.params.ParametersWithIV;
import javax.crypto.spec.SecretKeySpec;
public class BlowfishCipher extends Cipher {
// encryption mode
public static final int BLOWFISH_CFB = 16;
private final int keyLength;
private final StreamBlockCipher cipher;
/**
* <b>Notice: </b><br/>
* 1. in <code>new CFBBlockCipher(engine, <b>8</b> * 8);</code> the IV length (8) is
* reference to the shadowsocks's design.
*
* @see <a href="https://shadowsocks.org/en/spec/cipher.html">
* https://shadowsocks.org/en/spec/cipher.html</a>#Cipher
*/
public BlowfishCipher(String password, int mode) {
key = new SecretKeySpec(password.getBytes(), "BF");
keyLength = mode;
BlowfishEngine engine = new BlowfishEngine();
cipher = new CFBBlockCipher(engine, 8 * 8);
}
public static boolean isValidMode(int mode) {
return mode == 16;
}
@Override
protected void _init(boolean isEncrypt, byte[] iv) {
String keyStr = new String(key.getEncoded());
ParametersWithIV params = new ParametersWithIV(
new KeyParameter(KeyHelper.generateKeyDigest(keyLength, keyStr)), iv
);
cipher.init(isEncrypt, params);
}
@Override
protected byte[] _encrypt(byte[] originData) {
byte[] encryptedData = new byte[originData.length];
cipher.processBytes(originData, 0, originData.length, encryptedData, 0);
return encryptedData;
}
@Override
protected byte[] _decrypt(byte[] encryptedData) {
byte[] originData = new byte[encryptedData.length];
cipher.processBytes(encryptedData, 0, encryptedData.length, originData, 0);
return originData;
}
@Override
public int getIVLength() {
return 8;
}
}