summary refs log tree commit diff
path: root/crypto/src/crypto/encodings/OaepEncoding.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/crypto/encodings/OaepEncoding.cs')
-rw-r--r--crypto/src/crypto/encodings/OaepEncoding.cs674
1 files changed, 339 insertions, 335 deletions
diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs

index 81561e7f5..a4d2f0e36 100644 --- a/crypto/src/crypto/encodings/OaepEncoding.cs +++ b/crypto/src/crypto/encodings/OaepEncoding.cs
@@ -6,340 +6,344 @@ using Org.BouncyCastle.Security; namespace Org.BouncyCastle.Crypto.Encodings { - /** - * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2. - */ - public class OaepEncoding - : IAsymmetricBlockCipher - { - private byte[] defHash; - private IDigest hash; - private IDigest mgf1Hash; - - private IAsymmetricBlockCipher engine; - private SecureRandom random; - private bool forEncryption; - - public OaepEncoding( - IAsymmetricBlockCipher cipher) - : this(cipher, new Sha1Digest(), null) - { - } - - public OaepEncoding( - IAsymmetricBlockCipher cipher, - IDigest hash) - : this(cipher, hash, null) - { - } - - public OaepEncoding( - IAsymmetricBlockCipher cipher, - IDigest hash, - byte[] encodingParams) - : this(cipher, hash, hash, encodingParams) - { - } - - public OaepEncoding( - IAsymmetricBlockCipher cipher, - IDigest hash, - IDigest mgf1Hash, - byte[] encodingParams) - { - this.engine = cipher; - this.hash = hash; - this.mgf1Hash = mgf1Hash; - this.defHash = new byte[hash.GetDigestSize()]; - - if (encodingParams != null) - { - hash.BlockUpdate(encodingParams, 0, encodingParams.Length); - } - - hash.DoFinal(defHash, 0); - } - - public IAsymmetricBlockCipher GetUnderlyingCipher() - { - return engine; - } - - public string AlgorithmName - { - get { return engine.AlgorithmName + "/OAEPPadding"; } - } - - public void Init( - bool forEncryption, - ICipherParameters param) - { - if (param is ParametersWithRandom) - { - ParametersWithRandom rParam = (ParametersWithRandom)param; - this.random = rParam.Random; - } - else - { - this.random = new SecureRandom(); - } - - engine.Init(forEncryption, param); - - this.forEncryption = forEncryption; - } - - public int GetInputBlockSize() - { - int baseBlockSize = engine.GetInputBlockSize(); - - if (forEncryption) - { - return baseBlockSize - 1 - 2 * defHash.Length; - } - else - { - return baseBlockSize; - } - } - - public int GetOutputBlockSize() - { - int baseBlockSize = engine.GetOutputBlockSize(); - - if (forEncryption) - { - return baseBlockSize; - } - else - { - return baseBlockSize - 1 - 2 * defHash.Length; - } - } - - public byte[] ProcessBlock( - byte[] inBytes, - int inOff, - int inLen) - { - if (forEncryption) - { - return encodeBlock(inBytes, inOff, inLen); - } - else - { - return decodeBlock(inBytes, inOff, inLen); - } - } - - private byte[] encodeBlock( - byte[] inBytes, - int inOff, - int inLen) - { - byte[] block = new byte[GetInputBlockSize() + 1 + 2 * defHash.Length]; - - // - // copy in the message - // - Array.Copy(inBytes, inOff, block, block.Length - inLen, inLen); - - // - // add sentinel - // - block[block.Length - inLen - 1] = 0x01; - - // - // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0) - // - - // - // add the hash of the encoding params. - // - Array.Copy(defHash, 0, block, defHash.Length, defHash.Length); - - // - // generate the seed. - // - byte[] seed = random.GenerateSeed(defHash.Length); - - // - // mask the message block. - // - byte[] mask = maskGeneratorFunction1(seed, 0, seed.Length, block.Length - defHash.Length); - - for (int i = defHash.Length; i != block.Length; i++) - { - block[i] ^= mask[i - defHash.Length]; - } - - // - // add in the seed - // - Array.Copy(seed, 0, block, 0, defHash.Length); - - // - // mask the seed. - // - mask = maskGeneratorFunction1( - block, defHash.Length, block.Length - defHash.Length, defHash.Length); - - for (int i = 0; i != defHash.Length; i++) - { - block[i] ^= mask[i]; - } - - return engine.ProcessBlock(block, 0, block.Length); - } - - /** - * @exception InvalidCipherTextException if the decrypted block turns out to - * be badly formatted. - */ - private byte[] decodeBlock( - byte[] inBytes, - int inOff, - int inLen) - { - byte[] data = engine.ProcessBlock(inBytes, inOff, inLen); - byte[] block; - - // - // as we may have zeros in our leading bytes for the block we produced - // on encryption, we need to make sure our decrypted block comes back - // the same size. - // - if (data.Length < engine.GetOutputBlockSize()) - { - block = new byte[engine.GetOutputBlockSize()]; - - Array.Copy(data, 0, block, block.Length - data.Length, data.Length); - } - else - { - block = data; - } - - if (block.Length < (2 * defHash.Length) + 1) - { - throw new InvalidCipherTextException("data too short"); - } - - // - // unmask the seed. - // - byte[] mask = maskGeneratorFunction1( - block, defHash.Length, block.Length - defHash.Length, defHash.Length); - - for (int i = 0; i != defHash.Length; i++) - { - block[i] ^= mask[i]; - } - - // - // unmask the message block. - // - mask = maskGeneratorFunction1(block, 0, defHash.Length, block.Length - defHash.Length); - - for (int i = defHash.Length; i != block.Length; i++) - { - block[i] ^= mask[i - defHash.Length]; - } - - // - // check the hash of the encoding params. - // - for (int i = 0; i != defHash.Length; i++) - { - if (defHash[i] != block[defHash.Length + i]) - { - throw new InvalidCipherTextException("data hash wrong"); - } - } - - // - // find the data block - // - int start; - for (start = 2 * defHash.Length; start != block.Length; start++) - { - if (block[start] != 0) - { - break; - } - } - - if (start >= (block.Length - 1) || block[start] != 1) - { - throw new InvalidCipherTextException("data start wrong " + start); - } - - start++; - - // - // extract the data block - // - byte[] output = new byte[block.Length - start]; - - Array.Copy(block, start, output, 0, output.Length); - - return output; - } - - /** - * int to octet string. - */ - private void ItoOSP( - int i, - byte[] sp) - { - sp[0] = (byte)((uint)i >> 24); - sp[1] = (byte)((uint)i >> 16); - sp[2] = (byte)((uint)i >> 8); - sp[3] = (byte)((uint)i >> 0); - } - - /** - * mask generator function, as described in PKCS1v2. - */ - private byte[] maskGeneratorFunction1( - byte[] Z, - int zOff, - int zLen, - int length) - { - byte[] mask = new byte[length]; - byte[] hashBuf = new byte[mgf1Hash.GetDigestSize()]; - byte[] C = new byte[4]; - int counter = 0; - - hash.Reset(); - - do - { - ItoOSP(counter, C); - - mgf1Hash.BlockUpdate(Z, zOff, zLen); - mgf1Hash.BlockUpdate(C, 0, C.Length); - mgf1Hash.DoFinal(hashBuf, 0); - - Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, hashBuf.Length); - } - while (++counter < (length / hashBuf.Length)); - - if ((counter * hashBuf.Length) < length) - { - ItoOSP(counter, C); - - mgf1Hash.BlockUpdate(Z, zOff, zLen); - mgf1Hash.BlockUpdate(C, 0, C.Length); - mgf1Hash.DoFinal(hashBuf, 0); - - Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, mask.Length - (counter * hashBuf.Length)); - } - - return mask; - } - } + /** + * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2. + */ + public class OaepEncoding + : IAsymmetricBlockCipher + { + private byte[] defHash; + private IDigest hash; + private IDigest mgf1Hash; + + private IAsymmetricBlockCipher engine; + private SecureRandom random; + private bool forEncryption; + + public OaepEncoding( + IAsymmetricBlockCipher cipher) + : this(cipher, new Sha1Digest(), null) + { + } + + public OaepEncoding( + IAsymmetricBlockCipher cipher, + IDigest hash) + : this(cipher, hash, null) + { + } + + public OaepEncoding( + IAsymmetricBlockCipher cipher, + IDigest hash, + byte[] encodingParams) + : this(cipher, hash, hash, encodingParams) + { + } + + public OaepEncoding( + IAsymmetricBlockCipher cipher, + IDigest hash, + IDigest mgf1Hash, + byte[] encodingParams) + { + this.engine = cipher; + this.hash = hash; + this.mgf1Hash = mgf1Hash; + this.defHash = new byte[hash.GetDigestSize()]; + + if (encodingParams != null) + { + hash.BlockUpdate(encodingParams, 0, encodingParams.Length); + } + + hash.DoFinal(defHash, 0); + } + + public IAsymmetricBlockCipher GetUnderlyingCipher() + { + return engine; + } + + public string AlgorithmName + { + get { return engine.AlgorithmName + "/OAEPPadding"; } + } + + public void Init( + bool forEncryption, + ICipherParameters param) + { + if (param is ParametersWithRandom) + { + ParametersWithRandom rParam = (ParametersWithRandom)param; + this.random = rParam.Random; + } + else + { + this.random = new SecureRandom(); + } + + engine.Init(forEncryption, param); + + this.forEncryption = forEncryption; + } + + public int GetInputBlockSize() + { + int baseBlockSize = engine.GetInputBlockSize(); + + if (forEncryption) + { + return baseBlockSize - 1 - 2 * defHash.Length; + } + else + { + return baseBlockSize; + } + } + + public int GetOutputBlockSize() + { + int baseBlockSize = engine.GetOutputBlockSize(); + + if (forEncryption) + { + return baseBlockSize; + } + else + { + return baseBlockSize - 1 - 2 * defHash.Length; + } + } + + public byte[] ProcessBlock( + byte[] inBytes, + int inOff, + int inLen) + { + if (forEncryption) + { + return EncodeBlock(inBytes, inOff, inLen); + } + else + { + return DecodeBlock(inBytes, inOff, inLen); + } + } + + private byte[] EncodeBlock( + byte[] inBytes, + int inOff, + int inLen) + { + byte[] block = new byte[GetInputBlockSize() + 1 + 2 * defHash.Length]; + + // + // copy in the message + // + Array.Copy(inBytes, inOff, block, block.Length - inLen, inLen); + + // + // add sentinel + // + block[block.Length - inLen - 1] = 0x01; + + // + // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0) + // + + // + // add the hash of the encoding params. + // + Array.Copy(defHash, 0, block, defHash.Length, defHash.Length); + + // + // generate the seed. + // + byte[] seed = random.GenerateSeed(defHash.Length); + + // + // mask the message block. + // + byte[] mask = maskGeneratorFunction1(seed, 0, seed.Length, block.Length - defHash.Length); + + for (int i = defHash.Length; i != block.Length; i++) + { + block[i] ^= mask[i - defHash.Length]; + } + + // + // add in the seed + // + Array.Copy(seed, 0, block, 0, defHash.Length); + + // + // mask the seed. + // + mask = maskGeneratorFunction1( + block, defHash.Length, block.Length - defHash.Length, defHash.Length); + + for (int i = 0; i != defHash.Length; i++) + { + block[i] ^= mask[i]; + } + + return engine.ProcessBlock(block, 0, block.Length); + } + + /** + * @exception InvalidCipherTextException if the decrypted block turns out to + * be badly formatted. + */ + private byte[] DecodeBlock( + byte[] inBytes, + int inOff, + int inLen) + { + byte[] data = engine.ProcessBlock(inBytes, inOff, inLen); + byte[] block; + + // + // as we may have zeros in our leading bytes for the block we produced + // on encryption, we need to make sure our decrypted block comes back + // the same size. + // + if (data.Length < engine.GetOutputBlockSize()) + { + block = new byte[engine.GetOutputBlockSize()]; + + Array.Copy(data, 0, block, block.Length - data.Length, data.Length); + } + else + { + block = data; + } + + if (block.Length < (2 * defHash.Length) + 1) + { + throw new InvalidCipherTextException("data too short"); + } + + // + // unmask the seed. + // + byte[] mask = maskGeneratorFunction1( + block, defHash.Length, block.Length - defHash.Length, defHash.Length); + + for (int i = 0; i != defHash.Length; i++) + { + block[i] ^= mask[i]; + } + + // + // unmask the message block. + // + mask = maskGeneratorFunction1(block, 0, defHash.Length, block.Length - defHash.Length); + + for (int i = defHash.Length; i != block.Length; i++) + { + block[i] ^= mask[i - defHash.Length]; + } + + // + // check the hash of the encoding params. + // long check to try to avoid this been a source of a timing attack. + // + { + int diff = 0; + for (int i = 0; i < defHash.Length; ++i) + { + diff |= (byte)(defHash[i] ^ block[defHash.Length + i]); + } + + if (diff != 0) + throw new InvalidCipherTextException("data hash wrong"); + } + + // + // find the data block + // + int start; + for (start = 2 * defHash.Length; start != block.Length; start++) + { + if (block[start] != 0) + { + break; + } + } + + if (start >= (block.Length - 1) || block[start] != 1) + { + throw new InvalidCipherTextException("data start wrong " + start); + } + + start++; + + // + // extract the data block + // + byte[] output = new byte[block.Length - start]; + + Array.Copy(block, start, output, 0, output.Length); + + return output; + } + + /** + * int to octet string. + */ + private void ItoOSP( + int i, + byte[] sp) + { + sp[0] = (byte)((uint)i >> 24); + sp[1] = (byte)((uint)i >> 16); + sp[2] = (byte)((uint)i >> 8); + sp[3] = (byte)((uint)i >> 0); + } + + /** + * mask generator function, as described in PKCS1v2. + */ + private byte[] maskGeneratorFunction1( + byte[] Z, + int zOff, + int zLen, + int length) + { + byte[] mask = new byte[length]; + byte[] hashBuf = new byte[mgf1Hash.GetDigestSize()]; + byte[] C = new byte[4]; + int counter = 0; + + hash.Reset(); + + do + { + ItoOSP(counter, C); + + mgf1Hash.BlockUpdate(Z, zOff, zLen); + mgf1Hash.BlockUpdate(C, 0, C.Length); + mgf1Hash.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, hashBuf.Length); + } + while (++counter < (length / hashBuf.Length)); + + if ((counter * hashBuf.Length) < length) + { + ItoOSP(counter, C); + + mgf1Hash.BlockUpdate(Z, zOff, zLen); + mgf1Hash.BlockUpdate(C, 0, C.Length); + mgf1Hash.DoFinal(hashBuf, 0); + + Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, mask.Length - (counter * hashBuf.Length)); + } + + return mask; + } + } }