0

I'm trying to encrypt with bounycastle using CBC blowfish encryption. It is a requirement I cannot change so I need to figure out how this works. I am rather new with encryption altogether so any help would be really appreciated as I have a deadline to meet.

Here is what I have so far:

public void Test() {
    var value = "My Test Value";
    var key = "some key"; //56 characters long
    var iv = Encoding.GetBytes("some iv");
    var encryptedValue = CbcBlowfishEncrypt(encryptedText, key, iv);
}

private string CbcBlowfishEncrypt(string strValue, string key, byte[] iv)
{
    byte[] inputBytes = Encoding.UTF8.GetBytes(strValue);
    BlowfishEngine engine = new BlowfishEngine();
    CbcBlockCipher blockCipher = new CbcBlockCipher(engine); //CBC
    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher); //Default scheme is PKCS5/PKCS7
    KeyParameter keyParam = new KeyParameter(Convert.FromBase64String(key));
    ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv, 0, 8);

    cipher.Init(true, keyParamWithIV);
    byte[] outputBytes = new byte[cipher.GetOutputSize(inputBytes.Length)];
    int length = cipher.ProcessBytes(inputBytes, outputBytes, 0);
    cipher.DoFinal(outputBytes, length);
    var result = BitConverter.ToString(outputBytes).Replace("-", "");
    return result;
}

public static byte[] StringToByteArray(string hex)
{
    return Enumerable.Range(0, hex.Length)
        .Where(x => x % 2 == 0)
        .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
        .ToArray();
}

Here is the error I get:

'initialisation vector must be the same length as block size'

As I've mentioned above, I am rather new to this with a deadline for a client and doing my best to read up on a lot of this and understand it, but I've really hit a wall here and not sure where to go from here. This is probably an obvious thing for some of you so please have some mercy :)

Edit: One thing to mention is that I tried changing 16 to 8 for ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv, 0, 16); and it seems to let it through. But what I'm confused on that is my byte is 16 bytes long, not 8. Is this because each character takes up 2 bytes and that value represents characters, not bytes?

Bagzli
  • 6,254
  • 17
  • 80
  • 163
  • 2
    As you can already see from the error message, the length of the IV must be equal to the block size, i.e. 8 bytes for Blowfish. Your IV seems to be hex encoded, so it must be hex decoded, e.g. with [`StringToByteArray()`](https://stackoverflow.com/a/321404), which results in an 8 bytes IV (additionally the length must be fixed in the `ParametersWithIV` instantiation). The ciphertext is `F7OS9ONj15ah7h/CS2T3DQ==`. – Topaco Feb 02 '21 at 07:36
  • @Topaco what do you mean by "ciphertext is `F7OS9ONj15ah7h/CS2T3DQ==`" I did not understand that reference – Bagzli Feb 02 '21 at 15:18
  • This is the ciphertext that `CbcBlowfishEncrypt()` returns for your plaintext, key and IV when the IV is hex decoded. – Topaco Feb 02 '21 at 15:28
  • @Topaco gotcha. The value that I get is `874393536ACDF63B24078A9E6D3EA30C` Any chance you could post in an answer code that you ran so I can compare? – Bagzli Feb 02 '21 at 15:33
  • Your ciphertext is hex encoded, while `CbcBlowfishEncrypt()` returns a base64 encoded result. It seems you are not using the posted code. Please post an MCVE that produces your result `8743...`. – Topaco Feb 02 '21 at 15:50
  • @Topaco My apologies, I've been running so many different examples I've found online. I updated the question to reflect code which gives me different results. My problem is that I'm not really understanding which is the correct one. One IV uses `Encoding.GetBytes`, the other `StringToByteArray` and they give different results. However, neither matches yours. Is the problem with IV or is the problem with my code? – Bagzli Feb 02 '21 at 16:00
  • @Topaco Ah, I figured out the difference. It was as you said, the .ToBase64String(). – Bagzli Feb 02 '21 at 16:11
  • _But what I'm confused on that is my byte is 16 bytes long, not 8. Is this because each character takes up 2 bytes and that value represents characters, not bytes?_ Yes. You need to hex digits to make a byte. One hex digit is 4 bits, one byte is 8 bits. – xanatos Feb 02 '21 at 16:25

1 Answers1

0

Nobody officially posted an answer, so I just wanted to close of the question to help anyone else trying to do the same. Below is the code I used to encrypt and decrypt the value:

function Run()
{
    var key = "enter your key";
    var value = "Enter your test value";
    var iv = StringToByteArray("enter your 16 char hex value");

    var encryptedValue = CbcBlowfishEncrypt(value, key, iv);
    var decryptedValue = CbcBlowfishDecrypt(encryptedValue, key, iv);
}

private string CbcBlowfishEncrypt(string strValue, string key, byte[] iv)
{
    byte[] inputBytes = Encoding.UTF8.GetBytes(strValue);
    BlowfishEngine engine = new BlowfishEngine();
    CbcBlockCipher blockCipher = new CbcBlockCipher(engine);
    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher);
    KeyParameter keyParam = new KeyParameter(Convert.FromBase64String(key));
    ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv, 0, 8);

    cipher.Init(true, keyParamWithIV);
    byte[] outputBytes = new byte[cipher.GetOutputSize(inputBytes.Length)];
    int length = cipher.ProcessBytes(inputBytes, outputBytes, 0);
    cipher.DoFinal(outputBytes, length); //Do the final block
    var c = BitConverter.ToString(outputBytes);
    string encryptedInput = Convert.ToBase64String(outputBytes);
    var result = BitConverter.ToString(outputBytes).Replace("-", "");
    return result;
}

private string CbcBlowfishDecrypt(string strValue, string key, byte[] iv)
{
    BlowfishEngine engine = new BlowfishEngine();
    CbcBlockCipher blockCipher = new CbcBlockCipher(engine);
    PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(blockCipher);
    StringBuilder result = new StringBuilder();
    KeyParameter keyParam = new KeyParameter(Convert.FromBase64String(key));
    ParametersWithIV keyParamWithIV = new ParametersWithIV(keyParam, iv, 0, 8);

    cipher.Init(false, keyParamWithIV);
    byte[] out1 = Hex.Decode(strValue);
    byte[] out2 = new byte[cipher.GetOutputSize(out1.Length)];
    int len2 = cipher.ProcessBytes(out1, 0, out1.Length, out2, 0);
    cipher.DoFinal(out2, len2);
    return Encoding.UTF8.GetString(out2);
}

public static byte[] StringToByteArray(string hex)
{
    return Enumerable.Range(0, hex.Length)
        .Where(x => x % 2 == 0)
        .Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
        .ToArray();
}
Bagzli
  • 6,254
  • 17
  • 80
  • 163