I'm using AES encryption/decryption algorithm in my application.
On the server side I use c# to encrypt/decrypt the data.
And on client side(android) I use java to decrypt the data.
C# encryption/decryption code
static readonly string PasswordHash = "52";
static readonly string SaltKey = "dfkjsadfinewdfadsfkmeoinmsdflksdflk";
static readonly string VIKey = "#EUBRHDFBFG8867";
public static string Encrypt(string plainText)
{
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash,Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding =PaddingMode.Zeros };
var encryptor = symmetricKey.CreateEncryptor(keyBytes,Encoding.ASCII.GetBytes(VIKey));
byte[] cipherTextBytes;
using (var memoryStream = new MemoryStream())
{
using (var cryptoStream = new CryptoStream(memoryStream, encryptor,CryptoStreamMode.Write))
{
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length);
cryptoStream.FlushFinalBlock();
cipherTextBytes = memoryStream.ToArray();
cryptoStream.Close();
}
memoryStream.Close();
}
return Convert.ToBase64String(cipherTextBytes);
}
public static string Decrypt(string encryptedText)
{
byte[] cipherTextBytes = Convert.FromBase64String(encryptedText);
byte[] keyBytes = new Rfc2898DeriveBytes(PasswordHash,Encoding.ASCII.GetBytes(SaltKey)).GetBytes(256 / 8);
var symmetricKey = new RijndaelManaged() { Mode = CipherMode.CBC, Padding =PaddingMode.None }
var decryptor = symmetricKey.CreateDecryptor(keyBytes,Encoding.ASCII.GetBytes(VIKey));
var memoryStream = new MemoryStream(cipherTextBytes);
var cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read);
byte[] plainTextBytes = new byte[cipherTextBytes.Length];
int decryptedByteCount = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length);
memoryStream.Close();
cryptoStream.Close();
return Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount).TrimEnd("\0".ToCharArray());
}
Java Decryption method
public String decrypt(String dataToDecrypt) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException, UnsupportedEncodingException
{
byte[] encryptedCombinedBytes = Base64.decodeBase64(dataToDecrypt.getBytes());
String saltKey = "dfkjsadfinewdfadsfkmeoinmsdflksdflk";
String password = "52";
String IVKey = "#EUBRHDFBFG8867";
PBKDF2Parameters p = new PBKDF2Parameters("HmacSHA256", "ASCII", saltKey.getBytes(), 8);
byte[] mEncryptedPassword = new PBKDF2Engine(p).deriveKey(password);
byte[] ivbytes = Arrays.copyOfRange(IVKey.getBytes(), 0, 16);
SecretKeySpec mSecretKeySpec = new SecretKeySpec(mEncryptedPassword, "AES");
Cipher mCipher = Cipher.getInstance("AES/CBC/NoPadding");
mCipher.init(Cipher.DECRYPT_MODE, mSecretKeySpec, new IvParameterSpec(ivbytes));
byte[] encryptedTextBytes = Arrays.copyOfRange(encryptedCombinedBytes, 16, encryptedCombinedBytes.length);
byte[] decryptedTextBytes = mCipher.doFinal(encryptedTextBytes);
return new String(decryptedTextBytes, "UTF-8");
}
C# decryption method works fine and give the result string.
I cannot figure out the problem in Java decryption code. It runs and give me some garbage value.
EDIT
I can not edit anything on the server side.I just have to replicate the decryption in java decryption.
I dont know how to use passwordHash, saltKey and IVkey
First of all, you've switched the password and the salt around.
Second, PBKDF2 uses HMAC/SHA-1 as default. As far as I know that's also the default for Rfc2898DeriveBytes:
Implements password-based key derivation functionality, PBKDF2, by using a pseudo-random number generator based on HMACSHA1.
You should also never call getBytes without specifying the character set in Java, but this is probably not an issue for your current runtime.
These are comments on the code only; do not use CBC over network connections without integrity/authenticity protection.
Related
I am using one encryption/decryption method used in java and applying it in php . I have almost reached to the end but there is one mistake which I found that my decrypted string is not what i was expecting ,
This is my java code
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
public static String encrypt(String message, String key) throws GeneralSecurityException, UnsupportedEncodingException {
if (message == null || key == null) {
throw new IllegalArgumentException("text to be encrypted and key should not be null");
}
Cipher cipher = Cipher.getInstance(ALGORITHM);
byte[] messageArr = message.getBytes();
byte[] keyparam = key.getBytes();
SecretKeySpec keySpec = new SecretKeySpec(keyparam, "AES");
byte[] ivParams = new byte[16];
byte[] encoded = new byte[messageArr.length + 16];
System.arraycopy(ivParams, 0, encoded, 0, 16);
System.arraycopy(messageArr, 0, encoded, 16, messageArr.length);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, new IvParameterSpec(ivParams));
byte[] encryptedBytes = cipher.doFinal(encoded);
encryptedBytes = Base64.getEncoder().encode(encryptedBytes);
return new String(encryptedBytes);
}
public static String decrypt(String encryptedStr, String key) throws GeneralSecurityException, UnsupportedEncodingException {
if (encryptedStr == null || key == null) {
throw new IllegalArgumentException("text to be decrypted and key should not be null");
}
Cipher cipher = Cipher.getInstance(ALGORITHM);
byte[] keyparam = key.getBytes();
SecretKeySpec keySpec = new SecretKeySpec(keyparam, "AES");
byte[] encoded = encryptedStr.getBytes();
encoded = Base64.getDecoder().decode(encoded);
byte[] decodedEncrypted = new byte[encoded.length - 16];
System.arraycopy(encoded, 16, decodedEncrypted, 0, encoded.length - 16);
byte[] ivParams = new byte[16];
System.arraycopy(encoded, 0, ivParams, 0, ivParams.length);
cipher.init(Cipher.DECRYPT_MODE, keySpec, new IvParameterSpec(ivParams));
byte[] decryptedBytes = cipher.doFinal(decodedEncrypted);
return new String(decryptedBytes);
}
now i have done this in php like this
$encKey = 'encryptionKey';
$cipher = "aes-256-cbc";
$data = 'some data';
$encryption_key = openssl_random_pseudo_bytes(32);
$iv_size = openssl_cipher_iv_length($cipher);
$iv = openssl_random_pseudo_bytes($iv_size);
$ciphertext_raw = openssl_encrypt(json_encode($data), 'aes-256-cbc', $encKey, $options = OPENSSL_RAW_DATA, $iv);
//$ciphertext_raw = openssl_encrypt(json_encode($data), $cipher, $encKey, $options=OPENSSL_RAW_DATA, $iv);
$encrypted_data = base64_encode($iv . $ciphertext_raw);
print_r($encrypted_data);
now the problem is when i encrypt one string in php and decrypt it in java code it add some escape sequence but when i encrypt that same string in java and decrypt it in java it is proper and accurate and i am not sure why this is happening ... may be i am doing some thing wrong
as I have to do this encryption in php using java code i am not sure that is this process going in right way or there is some error .
this is the string which i am encrypting
String str = "vendor_id=INT_GTW&format=json&msg_code=KBEX99&data={\"header\":{\"msg_code\":\"KBEX99\",\"source\":\"INSTANTPAY\",\"channel\":\"CONBNK\",\"txn_ref_number\":\"INSTANTPAY_CONBNK_00001\",\"txn_datetime\":\"1498118309808\",\"ip\":\"1\",\"device_id\":\"XYWZPQR123\",\"api_version\":\"1.0.0\"},\"detail\":{\"entity\":\"INSTANTPAY\",\"intent\":\"REG\",\"user_identifier\":\"INSTANTPAY28423928\",\"crn\":\"105683710\",\"p1\":\"105683710\",\"p2\":\"\",\"p3\":\"INSTANTPAY\",\"p4\":\"\",\"p5\":\"\",\"p6\":\"\",\"p7\":\"\",\"p8\":\"\",\"p9\":\"\",\"p10\":\"\",\"p11\":\"\",\"p12\":\"\",\"p13\":\"\",\"p14\":\"\",\"p15\":\"\",\"p16\":\"\",\"p17\":\"\",\"p18\":\"\",\"p19\":\"\",\"p20\":\"\"}}";
and this is decrypted string
vendor_id=INT_GTW&format=json&msg_code=KBEX99&data={"header":{"msg_code":"KBEX99","source":"INSTANTPAY","channel":"CONBNK","txn_ref_number":"INSTANTPAY_CONBNK_00001","txn_datetime":"1498118309808","ip":"1","device_id":"XYWZPQR123","api_version":"1.0.0"},"detail":{"entity":"INSTANTPAY","intent":"REG","user_identifier":"INSTANTPAY28423928","crn":"105683710","p1":"105683710","p2":"","p3":"INSTANTPAY","p4":"","p5":"","p6":"","p7":"","p8":"","p9":"","p10":"","p11":"","p12":"","p13":"","p14":"","p15":"","p16":"","p17":"","p18":"","p19":"","p20":""}}
but when i am doing it in php and decrypting
"vendor_id=INT_GTW&format=json&msg_code=KBEX99&data={\"header\":{\"msg_code\":\"KBEX99\",\"source\":\"INSTANTPAY\",\"channel\":\"CONBNK\",\"txn_ref_number\":\"INSTANTPAY_CONBNK_00001\",\"txn_datetime\":\"1498118309808\",\"ip\":\"1\",\"device_id\":\"XYWZPQR123\",\"api_version\":\"1.0.0\"},\"detail\":{\"entity\":\"INSTANTPAY\",\"intent\":\"REG\",\"user_identifier\":\"INSTANTPAY28423928\",\"crn\":\"105683710\",\"p1\":\"105683710\",\"p2\":\"\",\"p3\":\"INSTANTPAY\",\"p4\":\"\",\"p5\":\"\",\"p6\":\"\",\"p7\":\"\",\"p8\":\"\",\"p9\":\"\",\"p10\":\"\",\"p11\":\"\",\"p12\":\"\",\"p13\":\"\",\"p14\":\"\",\"p15\":\"\",\"p16\":\"\",\"p17\":\"\",\"p18\":\"\",\"p19\":\"\",\"p20\":\"\"}}"
i am getting this
So any encryption decryption expert please help me in this ...
Thank you !!
Good afternoon. Interested in the question someone tried to decrypt data in Java that was encrypted in Ruby.
I'm trying to encrypt a word in Ruby (using the Marshal module) and decrypt in Java. If the Marshal module is used, can it be transferred to other languages or not?
This is my test in Ruby:
let(:key) { "12345678901234567890123456789012" }
let(:str) { "Serhii" }
it "encrypt_content" do
crypt = ActiveSupport::MessageEncryptor.new(key, cipher: 'aes-256-cbc')
encrypted_content = crypt.encrypt_and_sign(str)
encrypted_content
end
The code methods are:
def encrypt_and_sign(value, expires_at: nil, expires_in: nil, purpose: nil)
verifier.generate(_encrypt(value, expires_at: expires_at, expires_in: expires_in, purpose: purpose))
end
def _encrypt(value, **metadata_options)
cipher = new_cipher
cipher.encrypt
cipher.key = #secret
iv = cipher.random_iv
cipher.auth_data = "" if aead_mode?
encrypted_data = cipher.update(Messages::Metadata.wrap(#serializer.dump(value), metadata_options))
encrypted_data << cipher.final
blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"`enter code here`
blob = "#{blob}--#{::Base64.strict_encode64 cipher.auth_tag}" if aead_mode?
blob
end
The decrypt Java is:
private static final String key = "12345678901234567890123456789012";
#SneakyThrows
public static String decrypt(String encrypted) {
byte[] firstByte = Base64.getDecoder().decode(encrypted.replaceAll("\n", "").getBytes(StandardCharsets.UTF_8));
String first = new String(firstByte);
String[] parts = first.split("--");
byte[] secondByte = Base64.getDecoder().decode(parts[0].getBytes(StandardCharsets.UTF_8));
String second = new String(secondByte);
String[] parts2 = second.split("--");
byte[] encryptedData = Base64.getDecoder().decode(parts2[0].getBytes(StandardCharsets.UTF_8));
SecretKeySpec aesKey = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, aesKey, new IvParameterSpec(new byte[16]));
byte[] result = cipher.doFinal(encryptedData);
return new String(result);
}
public static void main(String[] args) throws Exception {
String encrypted = "S3l0cVEybDRUM2sxU1hFMk5YVlhOa3A2VXpRNFEyZFFibTVwZVdRMVdEUlpN\n" +
"bkkxUzBaUGNsbFJaejB0TFRWWlVtVkNVWEJXZWxselJuWkVhbFJyWlU5VmNr\n" +
"RTlQUT09LS0yZDA5M2FhZTg0OTJjZmIyZjdiNDA0ZWVkNGU2ZmQ4NDQ1ZTM4\n" +
"ZjIx";
System.out.println("Decrypted: " + decrypt(encrypted));
}
}
Result �'��m�Qի���
What could be the reason?
The exact code that is produced by Ruby is not specified (which I would consider a bug), you can find the format by reading the source code, especially this part:
blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}"
blob = "#{blob}--#{::Base64.strict_encode64 cipher.auth_tag}" if aead_mode?
Where the IV is a random IV, generated using Cipher::new of the openssl module.
I used the following to encrypt a string using a password
static String algorithm = "PBEWITHSHA256AND128BITAES-CBC-BC";
static byte[] salt = "b9v4n38s".getBytes(StandardCharsets.UTF_8);
static int derivedKeyLength = 128;
static int iterations = 20000;
public static byte[] encrypt(String plainText, String password) throws NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException, NoSuchAlgorithmException {
Security.addProvider(new BouncyCastleProvider());
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, iterations, derivedKeyLength);
SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
SecretKey key = f.generateSecret(spec);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] text = plainText.getBytes(StandardCharsets.UTF_8);
byte[] encrypted = cipher.doFinal(text);
return encrypted;
}
The result of this is base64 encoded and sent as arg[0] to .Net (arg[1] is the same password). Now I'm trying to decrypt that string in .Net with this code
private static string Decrypt(string[] args)
{
int derivedKeyLength = 128;
int iterations = 20000;
string algorithm = "PBEWITHSHA256AND128BITAES-CBC-BC";
byte[] salt = Encoding.UTF8.GetBytes("b9v4n38s");
PbeParametersGenerator pGen = new Pkcs12ParametersGenerator(new Sha256Digest());
pGen.Init(Encoding.UTF8.GetBytes(args[1]), salt, iterations);
ICipherParameters par = pGen.GenerateDerivedParameters("AES256", derivedKeyLength);
IBufferedCipher c = CipherUtilities.GetCipher(algorithm);
c.Init(false, par);
var input = Convert.FromBase64String(args[0]);
byte[] enc = c.DoFinal(input);
var decoded = Encoding.UTF8.GetString(enc);
return decoded;
}
Unfortunately it fails on DoFinal with message Org.BouncyCastle.Crypto.InvalidCipherTextException: 'pad block corrupted'
SecretKeyFactory.getInstance(algorithm) uses the same algorithm string as Cipher.getInstance(algorithm) in java but if I try pGen.GenerateDerivedParameters(algorithm, derivedKeyLength); in .Net it throws Org.BouncyCastle.Security.SecurityUtilityException: 'Algorithm PBEWITHSHA256AND128BITAES-CBC-BC not recognised.'
I'm not set on this algorithm, just looking for a way to encrypt a string in Java and decrypt it in .Net.
A possible C#/BC code to decrypt a ciphertext generated with the posted Java code is:
using System;
using System.Text;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Security;
...
private static string algorithm = "PBEWITHSHA256AND128BITAES-CBC-BC";
private static byte[] salt = Encoding.UTF8.GetBytes("b9v4n38s");
private static int iterations = 20000;
public static string Decrypt(string ciphertextB64, string password)
{
IBufferedCipher cipher = CipherUtilities.GetCipher(algorithm);
Asn1Encodable algParams = PbeUtilities.GenerateAlgorithmParameters(algorithm, salt, iterations);
ICipherParameters cipherParams = PbeUtilities.GenerateCipherParameters(algorithm, password.ToCharArray(), algParams);
cipher.Init(false, cipherParams);
byte[] cipherBytes = Convert.FromBase64String(ciphertextB64);
byte[] decrypted = cipher.DoFinal(cipherBytes);
return Encoding.UTF8.GetString(decrypted);
}
Test:
string decrypted = Decrypt("mBy4YwAvUpvoSJhzBnpOCJw2kCayvdYfLJ/12x0BgUKh5m5bvArSheMMs2U5rYyE", "MyPassword");
Console.WriteLine(decrypted); // The quick brown fox jumps over the lazy dog
where the ciphertext was generated with the Java code using the password MyPassword.
Please note that a static salt is generally insecure (except for testing purposes of course).
I need to implement an encryption and decryption method pair using C# that uses "AES/ECB/PKCS5Padding". The original code is in Java. Here is the encryption method in Java:
public static String Encrypt(String plainText, byte[] key2) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
byte[] encryptedTextBytes=null;
byte[] key3 =null;
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key3= sha.digest(key2);
key3 = copyOf(key3, 16);
SecretKeySpec keySpec = new SecretKeySpec(key3, "AES");
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
return new Base64().encode(encryptedTextBytes);
}
And this is my attempt at reconstructing it in C#:
public static string Encrypt_AES(string plainText, byte[] key2)
{
var sha = new System.Security.Cryptography.SHA1CryptoServiceProvider();
byte[] key3 = new byte[16];
sha.TransformFinalBlock(key2, 0, key2.Length);
var tmpkey = sha.Hash;
Array.Copy(tmpkey, key3, 16);
var aes = new System.Security.Cryptography.AesCryptoServiceProvider();
aes.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
aes.Mode = System.Security.Cryptography.CipherMode.ECB;
aes.Key = key3;
var plainTextBytes = Encoding.UTF8.GetBytes(plainText);
var encryptor = aes.CreateEncryptor();
byte[] encryptedTextBytes = encryptor.TransformFinalBlock(plainTextBytes, 0, plainTextBytes.Length);
return Convert.ToBase64String(encryptedTextBytes);
}
After encrypting some content and sending it to a remote service, the service replies with an error saying that it could not decrypt the message. So I'm assuming something is wrong with it.
I also have an example for a decrypt method in Java. I implemented that method too and tried to encrypt and decrypt some text locally. When I do that, the Decrypt_AES method is throwing a CryptographicException at TransformFinalBlock() saying "Padding is invalid and cannot be removed." Maybe I'm using the CryptoProvider classes wrong?
Here are the Java and C# versions of the decrypt function:
Java
public static String Decrypt(String encryptedText, byte[] key2) throws NoSuchAlgorithmException,NoSuchPaddingException,InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
byte[] decryptedTextBytes=null;
byte[] key3 =null;
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key3= sha.digest(key2);
key3 = copyOf(key3, 16);
SecretKeySpec keySpec = new SecretKeySpec(key3, "AES");
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
byte[] encryptedTextBytes = new Base64().decode(encryptedText);
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
return new String(decryptedTextBytes);
}
C#
public static string Decrypt_AES(byte[] key2, string encryptedText)
{
var sha = new System.Security.Cryptography.SHA1CryptoServiceProvider();
byte[] key3 = new byte[16];
sha.TransformFinalBlock(key2, 0, key2.Length);
var tmpkey = sha.Hash;
Array.Copy(tmpkey, key3, 16);
var aes = new System.Security.Cryptography.AesCryptoServiceProvider();
aes.Padding = System.Security.Cryptography.PaddingMode.PKCS7;
aes.Mode = System.Security.Cryptography.CipherMode.ECB;
aes.Key = key3;
var encryptedBytes = Encoding.UTF8.GetBytes(encryptedText);
var decryptor = aes.CreateDecryptor();
var decryptedBytes = decryptor.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length);
return System.Text.Encoding.UTF8.GetString(decryptedBytes);
}
Thank you for any hint in advance!
You are not Base64-decoding your ciphertext in your decrypt method.
var encryptedBytes = Encoding.UTF8.GetBytes(encryptedText);
should be changed to something like
var encryptedBytes = Convert.FromBase64String(encryptedText);
If I have a BlockCipher and a byte[] that I got from a String containing a secret message, what's the easiest way to get a byte[] of the message encrypted?
In the normal Java API, I could just do cipher.doFinal(secretMessage), but there doesn't seem to be anything like that here, it only processes blocks.
I know I can use a BufferedBlockCipher, but this still doesn't simplify things significantly. What's the easiest high-level way to use this cipher?
OK, so using the lightweight API and counter mode, which is one of the easiest and modern modes you would get:
public class BouncyEncrypt {
private static final int IV_SIZE = 16;
public static void main(String[] args) throws Exception {
// key should really consist of 16 random bytes
byte[] keyData = new byte[256 / Byte.SIZE];
KeyParameter key = new KeyParameter(keyData);
byte[] ciphertext = encryptWithAES_CTR(key, "owlstead");
System.out.println(decryptWithAES_CTR(key, ciphertext));
}
private static byte[] encryptWithAES_CTR(KeyParameter key, String in)
throws IllegalArgumentException, UnsupportedEncodingException,
DataLengthException {
// iv should be unique for each encryption with the same key
byte[] ivData = new byte[IV_SIZE];
SecureRandom rng = new SecureRandom();
rng.nextBytes(ivData);
ParametersWithIV iv = new ParametersWithIV(key, ivData);
SICBlockCipher aesCTR = new SICBlockCipher(new AESFastEngine());
aesCTR.init(true, iv);
byte[] plaintext = in.getBytes("UTF-8");
byte[] ciphertext = new byte[ivData.length + plaintext.length];
System.arraycopy(ivData, 0, ciphertext, 0, IV_SIZE);
aesCTR.processBytes(plaintext, 0, plaintext.length, ciphertext, IV_SIZE);
return ciphertext;
}
private static String decryptWithAES_CTR(KeyParameter key, byte[] ciphertext)
throws IllegalArgumentException, UnsupportedEncodingException,
DataLengthException {
if (ciphertext.length < IV_SIZE) {
throw new IllegalArgumentException("Ciphertext too short to contain IV");
}
ParametersWithIV iv = new ParametersWithIV(key, ciphertext, 0, IV_SIZE);
SICBlockCipher aesCTR = new SICBlockCipher(new AESFastEngine());
aesCTR.init(true, iv);
byte[] plaintext = new byte[ciphertext.length - IV_SIZE];
aesCTR.processBytes(ciphertext, IV_SIZE, plaintext.length, plaintext, 0);
return new String(plaintext, "UTF-8");
}
}
Counter mode does not require padding and is fully online, so you only have to call processBytes. For CBC mode you should look at PaddedBufferedBlockCipher. Still you would have slightly a tiny amount of buffer handling during decryption: before decryption you don't know the amount of padding that is present.
You could remove the IV code and the UTF-8 character decoding + exception handling, but you would be insecure and possibly incompatible. This code prefixes the IV to the ciphertext.
BouncyCastle implements the "normal Java API" so you can use Cipher.doFinal(String.getBytes()) you just have to specify the Provider "BC" when getting the Cipher: Cipher.getInstance("YourTransformation", "BC")
Use Bouncy Castle's CipherOutputStream. It's the closest thing to the Java API.
static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();
public static void main(String[] args) throws Exception {
KeyGenerator kg = KeyGenerator.getInstance("Threefish-1024", PROVIDER);
kg.init(1024);
KeyParameter key = new KeyParameter(kg.generateKey().getEncoded());
byte[] tweak = new byte[16];
TweakableBlockCipherParameters params = new TweakableBlockCipherParameters(key, tweak);
byte[] plaintext = "Hi! I'm cat!".getBytes();
byte[] ciphertext = encrypt(params, plaintext);
System.out.println(new String(decrypt(params, ciphertext)));
// prints "Hi! I'm cat!"
}
static byte[] encrypt(TweakableBlockCipherParameters params, byte[] plaintext) throws Exception {
return encryptOrDecrypt(true, params, plaintext);
}
static byte[] decrypt(TweakableBlockCipherParameters params, byte[] ciphertext) throws Exception {
return encryptOrDecrypt(false, params, ciphertext);
}
static byte[] encryptOrDecrypt(boolean encrypt, TweakableBlockCipherParameters params, byte[] bytes) throws Exception {
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(
new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024)), new PKCS7Padding());
cipher.init(encrypt, params);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
CipherOutputStream cos = new CipherOutputStream(baos, cipher);
cos.write(bytes);
// calling CipherOutputStream.close is mandatory
// it acts like Cipher.doFinal
cos.close();
return baos.toByteArray();
}
Link to my answer to a similar and related question.