Closed firepacket closed 2 years ago
I'm unclear what you're asking. OCB doesn't need padding (and our implementation doesn't add any). However prior to DoFinal partial block input is buffered internally. ProcessByte
, ProcessBytes
and DoFinal
all return a value indicating how much output was written by that call. Finally we add the tag to the output for encryption and expect it in the input for decryption.
If pain persists, please include sample code that you think is misbehaving.
But I can't encrypt 1 character with OCB, right? It has to match the blocksize? If I try encrypting text under 16 bytes it returns nothing and a length of 0 is returned. So it actually NEEDS padding, it's just not being used?
Of course you can encrypt 1 byte with OCB. Are you calling DoFinal
to get the final output (and checking the return value)?
If I try encrypting text under 16 bytes it returns nothing and a length of 0 is returned.
If you will just show the code you are trying to use, I'm sure we can quickly clear this up.
private void EncBTN_Click(object sender, EventArgs e)
{
string k = keyTxt.Text.Substring(0, 32);
byte[] key = k.ToByteArray();
KeyParameter kp = new KeyParameter(key);
ocb = new OcbBlockCipher(new AesLightEngine(), new AesLightEngine());
Rfc2898DeriveBytes pk = new Rfc2898DeriveBytes(k + ":" + encTxt.Text, data, 10000);
byte[] ad = pk.GetBytes(32);
encADtxt.Text = ad.ToBase32k();
decADtxt.Text = encADtxt.Text;
ocb.Init(true, new AeadParameters(kp, 128, NewNonce().ToByteArray(), ad));
byte[] input = encTxt.Text.ToByteArray();
byte[] o = new byte[64];
ocb.Init(true, new AeadParameters(kp, 128, NewNonce().ToByteArray(), ad));
int len = ocb.ProcessBytes(input, 0, input.Length, o, 0);
if (len >= o.Length)
Array.Resize<byte>(ref o, o.Length + len);
ocb.Init(true, new AeadParameters(kp, 128, NewNonce().ToByteArray(), ad));
len = ocb.DoFinal(o, len);
encMacTxt.Text = ocb.GetMac().ToByteString();
decMacTxt.Text = encMacTxt.Text;
decTxt.Text = o.ToByteString();
}
private void DecBtn_Click(object sender, EventArgs e)
{
string k = keyTxt.Text.Substring(0, 32);
byte[] key = k.ToByteArray();
KeyParameter kp = new KeyParameter(key);
ocb = new OcbBlockCipher(new AesLightEngine(), new AesLightEngine());
byte[] ad = decADtxt.Text.FromBase32k();
ocb.Init(false, new AeadParameters(kp, 128, NewNonce().ToByteArray(), ad));
byte[] inp = decTxt.Text.ToByteArray();
int len = ocb.GetUpdateOutputSize(inp.Length);
byte[] o = new byte[128]; // bigger just in case
len = ocb.ProcessBytes(inp, 0, inp.Length, o, len);
string s = o.ToByteString();
ocb.Init(false, new AeadParameters(kp, 128, NewNonce().ToByteArray(), ad));
if (len >= o.Length)
Array.Resize<byte>(ref o, o.Length + len);
len = ocb.DoFinal(o, 0); // #ERROR: 'mac check in OCB failed'
// I also sometimes get ERROR: 'data too short' (o = 128.Length, len = 112)??
s = o.ToByteString();
ocb.Init(false, new AeadParameters(kp, 128, NewNonce().ToByteArray(), ad));
string mac = ocb.GetMac().ToByteString();
if (mac.SequenceEqual(decMacTxt.Text.AsEnumerable()))
decMacTxt.BackColor = Color.FromArgb(3, 60, 0);
decMacTxt.Text = mac;
encTxt.Text = o.FromByteArray();
//encTxt.Text = len.ToString();
}
If I pad the plaintext it seems to work but, the mac matches the last part of the output, there appears to be cipher text for 1 block if I pad, but I cant get decrypt to work using the same values. There appears to be no ciphertext (unless plaintex=blocksize). Its all 0s as you can see in pic where I'm not padding.
If I pad the plain text, I get a full 128 byte string with the mac at the end but it doesn't decrypt.
Also, am I reseeding the nonce at the right times? I was never sure.
Even when I'm padding, I'm not getting it to decrypt and the MAC never matches. Something else must be wrong? I feel like it's encrypting because when I add encrypted text I see it in front of the mac, There's just a lot of zeros at the end. Should I cut them off? Even when I give DoFinal() 256 byte output it says "Data too short?" Is it really meaning to say "Array too big?"
Of course you can encrypt 1 byte with OCB. Are you calling
DoFinal
to get the final outputvalue)?Yes I am. If I do that I get Just a MAC at the beginning the rest zeros. (Assuming ocb.ProcessByte is under the blocksize)
(and checking the return value? If you will just show the code you are trying to use, I'm sure we can quickly clear this up.
What am I supposed to do with the return value of DoFinal? It's usually 16, the size of the mac which is what was written. So it's just telling me it wrote the mac.... but the ciphertext might be at the beginning, but I am confused as to what to do with all the zeros. I can't seem to decrypt the output, do I trim the zeros? If everything matches the blocksize there are no zeros but it still wont decrypt I am passing in the MAC and all the zeros in ocb.ProcessBlock().
Here's an example. Notice when the plaintext is under the blocksize (16) I get no cipher text, just a mac, but when it is exactly the blocksize I get ciphertext:
(I trimmed the zeros here)
I can get 16 bytes from processbyte if length=blocksize but I always get:
"Org.BouncyCastle.Crypto.InvalidCipherTextException: 'mac check in OCB failed'"
Here: int len = ocb.ProcessBytes(inp, 0, 32, o, 0); // I get 16 byes in byte[] o Great! (If I don't pass the WHOLE input with the mac o=all zeros) now... len = ocb.DoFinal(inp, 0); // ERROR: 'mac check in OCB failed' len = ocb.DoFinal(inp, 32); // ERROR: 'mac check in OCB failed' len = ocb.DoFinal(inp, 31); // ERROR: 'mac check in OCB failed' len = ocb.DoFinal(inp, 33); // ERROR: 'mac check in OCB failed' len = ocb.DoFinal(inp, 16); // ERROR: 'mac check in OCB failed' len = ocb.DoFinal(inp, 15); // ERROR: 'mac check in OCB failed' len = ocb.DoFinal(inp, 17); // ERROR: 'mac check in OCB failed' len = ocb.DoFinal(decMacTxt.Text.ToByteArray(), 0); // ERROR: 'mac check in OCB failed'
If I add an Init() before DoFinal() I get another error:
byte[] o = new byte[64]; int len = ocb.ProcessBytes(inp, 0, 32, o, 0); ocb.Init(false, new AeadParameters(kp, 128, NewNonce().ToByteArray())); len = ocb.DoFinal(o, 16);
I get Error: 'data too short' And keep in mind I only get this far if the plaintext is exactly 16 bytes. Otherwise I get nothing but a MAC.
I posted all my work because you made it seem as if you were willing to help me.
Hello it's been days. Have I done something wrong? Are you no longer allowed to help me? Have I triggered something? You seemed to eager to help me so I posted everything and now I'm being stonewalled.
The main problem seems to be that your are calling Init repeatedly. There only needs to be one call to Init for the entire encryption (or decryption). Here is sample code for encrypting a single byte plaintext:
KeyParameter keyParameter = new KeyParameter(new byte[16]);
AeadParameters aeadParameters = new AeadParameters(keyParameter, 128, new byte[15], null);
OcbBlockCipher c = new OcbBlockCipher(new AesEngine(), new AesEngine());
c.Init(true, aeadParameters);
int outputSize = c.GetOutputSize(1);
byte[] output = new byte[outputSize];
int outputPos = 0;
outputPos += c.ProcessByte(0, output, outputPos);
outputPos += c.DoFinal(output, outputPos);
Console.WriteLine(outputPos);
Console.WriteLine(Hex.ToHexString(output));
There has to be a single call to Init
at the beginning, and a single call to DoFinal
at the end. There can be 0 or more calls to ProcessByte(s)
in between, each of which supplies some input. Each call to ProcessByte(s)
and DoFinal
returns a value indicating how much output that call produced. After the DoFinal
call, all output will have been written.
GetOutputSize
is used to get the maximum possible size of output for the given total amount of input. For OCB, it will actually be an exact prediction, but it is good practice to use the calculated output length (outputPos in the above example) to tell how much total output you got.
I suggest that you separate out your encryption/decryption code and get it working apart from all the other stuff first. Then include the AAD and check that things work. Then add the key derivation and check again, and so on.
Thank you for your reply. In my research of OCB mode I read that the nonce was only supposed to be 12 bytes, I noticed you have it set to 15, that clears up some confusion for me.
I also read that OCB can accept 32 byte keys, but I tried the following code with 16 byte keys and a 15 byte nonce but still got the error while trying to encrypt 3 characters (xxx) "Output buffer too short" on DoFinal()
The ToByteArray() function I am using is straight out of Org.BouncyCastle.Utilities.Strings I just made it into an extension method.
string k = keyTxt.Text.Substring(0, 16);
byte[] key = Hex.DecodeStrict(k);
KeyParameter kp = new KeyParameter(key);
ocb = new OcbBlockCipher(new AesEngine(), new AesEngine());
ocb.Init(true, new AeadParameters(kp, 128, NewNonce(15).ToByteArray()));
byte[] input = encTxt.Text.ToByteArray(); // xxx
int len = ocb.GetOutputSize(input.Length);
byte[] o = new byte[len];
len += ocb.ProcessBytes(input, 0, input.Length, o, 0);
len += ocb.DoFinal(o, len); // Org.BouncyCastle.Crypto.OutputLengthException: 'Output buffer too short'
byte [] o = o[19] (all zeros) len = 19
I don't know what I am doing wrong here, but I need to encrypt more than one character and I need to use a real key. I tried Hex.DecodeStrict(k) to no avail. Switched to AesEngine.
I don't understand what could be going wrong here. Should I just be encrypting one byte at a time in a loop?
Do you happen to know the difference between GetOutputSize() and GetUpdateOutputSize()?
Here's some screenshots of the objects if it helps any:
Thanks I would appreciate any continued help.
In my research of OCB mode I read that the nonce was only supposed to be 12 bytes, I noticed you have it set to 15, that clears up some confusion for me.
15 is the maximum length of the nonce. The actual length to use should be specified in the particular context you are using it.
I also read that OCB can accept 32 byte keys
Yes, it can be used with any key permitted by the underlying cipher (in your case AES), so 256 bit key is fine too.
I don't know what I am doing wrong here
This code is wrong because you didn't reset len
to 0 after using it to get the output size. Just change the ProcessBytes
line to:
len = ocb.ProcessBytes(input, 0, input.Length, o, 0);
Do you happen to know the difference between GetOutputSize() and Get_Update_OutputSize()?
GetOutputSize
returns the total length of output for a total input length (possibly across multiple ProcessByte(s)
calls). This is usually the only one needed. GetUpdateOutputSize
tells you how much output (maximum) would be generated by the next call to ProcessBytes
with the given length. It can sometimes be useful in streaming large contents, but I doubt you need it here.
YESS!!!!!! THANKYOU!!
len = ocb.ProcessBytes(input, 0, input.Length, o, 0);
That was it!! Thank you, AGAIN! You were using += because you were just doing one byte at a time and I didn't change it. Encryption appears to be working perfectly now!!
It looks like if the KeyParameter is only 16 bytes then the Init line causes an exception: (Key length not 128/192/256 bits):
ocb.Init(true, new AeadParameters(kp, 128, NewNonce(15).ToByteArray()));
So I changed back to a 32 byte key and everything worked! I am so grateful, but unfortunately now I am now having trouble decrypting :-(
I am getting the error "'mac check in OCB failed", even though it finds the correct output length and attempts a decryption (that is incorrect).
I resolved the problem. Answer:
I read really some bad information... (There's a lot of junk on OCB out there). Thanks for your help. Now if anyone would like to answer before I close this, is it better to use a RANDOM IV or a INCREMENTING NUMERICAL NONCE?
And WHY?
Thanks again for all your help.
I have answered my own question:
A nonce is good for when two parties have a communication channel and can predictably derive the same nonce reliably and independently, by themselves, each time a message is sent or received. This avoids having to send it with the cipher text. OCB was designed to allow this without weakening its function.
Thanks everyone, sorry for taking so much space.
As you can see from this whitepaper describing OCB mode , it says the following:
Unfortunately this is not true in this current version of bc-sharp.
If you try to encrypt any text less than the blocksize, the function will return all zeros all the way up to DoFinal(). If you stretch the array to meet the the size of the blocksize length, a portion of that array will contain random looking data, but the rest will be zeros.
Is this class supposed to be used differently? Or is this a bug?
I shouldn't have to pad plaintext in this mode. Something must be wrong?