123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- using System;
- using Org.BouncyCastle.Crypto.Modes;
- using Org.BouncyCastle.Crypto.Parameters;
- using Org.BouncyCastle.Security;
- namespace Org.BouncyCastle.Crypto.Engines
- {
- /**
- * an implementation of the RFC 3211 Key Wrap
- * Specification.
- */
- public class Rfc3211WrapEngine
- : IWrapper
- {
- private CbcBlockCipher engine;
- private ParametersWithIV param;
- private bool forWrapping;
- private SecureRandom rand;
- public Rfc3211WrapEngine(
- IBlockCipher engine)
- {
- this.engine = new CbcBlockCipher(engine);
- }
- public virtual void Init(
- bool forWrapping,
- ICipherParameters param)
- {
- this.forWrapping = forWrapping;
- if (param is ParametersWithRandom)
- {
- ParametersWithRandom p = (ParametersWithRandom) param;
- this.rand = p.Random;
- this.param = (ParametersWithIV) p.Parameters;
- }
- else
- {
- if (forWrapping)
- {
- rand = new SecureRandom();
- }
- this.param = (ParametersWithIV) param;
- }
- }
- public virtual string AlgorithmName
- {
- get { return engine.GetUnderlyingCipher().AlgorithmName + "/RFC3211Wrap"; }
- }
- public virtual byte[] Wrap(
- byte[] inBytes,
- int inOff,
- int inLen)
- {
- if (!forWrapping)
- {
- throw new InvalidOperationException("not set for wrapping");
- }
- engine.Init(true, param);
- int blockSize = engine.GetBlockSize();
- byte[] cekBlock;
- if (inLen + 4 < blockSize * 2)
- {
- cekBlock = new byte[blockSize * 2];
- }
- else
- {
- cekBlock = new byte[(inLen + 4) % blockSize == 0 ? inLen + 4 : ((inLen + 4) / blockSize + 1) * blockSize];
- }
- cekBlock[0] = (byte)inLen;
- cekBlock[1] = (byte)~inBytes[inOff];
- cekBlock[2] = (byte)~inBytes[inOff + 1];
- cekBlock[3] = (byte)~inBytes[inOff + 2];
- Array.Copy(inBytes, inOff, cekBlock, 4, inLen);
- rand.NextBytes(cekBlock, inLen + 4, cekBlock.Length - inLen - 4);
- for (int i = 0; i < cekBlock.Length; i += blockSize)
- {
- engine.ProcessBlock(cekBlock, i, cekBlock, i);
- }
- for (int i = 0; i < cekBlock.Length; i += blockSize)
- {
- engine.ProcessBlock(cekBlock, i, cekBlock, i);
- }
- return cekBlock;
- }
- public virtual byte[] Unwrap(
- byte[] inBytes,
- int inOff,
- int inLen)
- {
- if (forWrapping)
- {
- throw new InvalidOperationException("not set for unwrapping");
- }
- int blockSize = engine.GetBlockSize();
- if (inLen < 2 * blockSize)
- {
- throw new InvalidCipherTextException("input too short");
- }
- byte[] cekBlock = new byte[inLen];
- byte[] iv = new byte[blockSize];
- Array.Copy(inBytes, inOff, cekBlock, 0, inLen);
- Array.Copy(inBytes, inOff, iv, 0, iv.Length);
- engine.Init(false, new ParametersWithIV(param.Parameters, iv));
- for (int i = blockSize; i < cekBlock.Length; i += blockSize)
- {
- engine.ProcessBlock(cekBlock, i, cekBlock, i);
- }
- Array.Copy(cekBlock, cekBlock.Length - iv.Length, iv, 0, iv.Length);
- engine.Init(false, new ParametersWithIV(param.Parameters, iv));
- engine.ProcessBlock(cekBlock, 0, cekBlock, 0);
- engine.Init(false, param);
- for (int i = 0; i < cekBlock.Length; i += blockSize)
- {
- engine.ProcessBlock(cekBlock, i, cekBlock, i);
- }
- if ((cekBlock[0] & 0xff) > cekBlock.Length - 4)
- {
- throw new InvalidCipherTextException("wrapped key corrupted");
- }
- byte[] key = new byte[cekBlock[0] & 0xff];
- Array.Copy(cekBlock, 4, key, 0, cekBlock[0]);
- // Note: Using constant time comparison
- int nonEqual = 0;
- for (int i = 0; i != 3; i++)
- {
- byte check = (byte)~cekBlock[1 + i];
- nonEqual |= (check ^ key[i]);
- }
- if (nonEqual != 0)
- throw new InvalidCipherTextException("wrapped key fails checksum");
- return key;
- }
- }
- }
- #endif
|