123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
- using System;
- using Org.BouncyCastle.Crypto.Parameters;
- using Org.BouncyCastle.Crypto.Digests;
- using Org.BouncyCastle.Security;
- using Org.BouncyCastle.Utilities;
- namespace Org.BouncyCastle.Crypto.Encodings
- {
-
- public class Pkcs1Encoding
- : IAsymmetricBlockCipher
- {
-
- public const string StrictLengthEnabledProperty = "Org.BouncyCastle.Pkcs1.Strict";
- private const int HeaderLength = 10;
-
- public static bool StrictLengthEnabled
- {
- get { return strictLengthEnabled[0]; }
- set { strictLengthEnabled[0] = value; }
- }
- private static readonly bool[] strictLengthEnabled;
- static Pkcs1Encoding()
- {
- string strictProperty = Org.BouncyCastle.Utilities.Platform.GetEnvironmentVariable(StrictLengthEnabledProperty);
- strictLengthEnabled = new bool[]{ strictProperty == null || strictProperty.Equals("true")};
- }
- private SecureRandom random;
- private IAsymmetricBlockCipher engine;
- private bool forEncryption;
- private bool forPrivateKey;
- private bool useStrictLength;
- private int pLen = -1;
- private byte[] fallback = null;
-
- public Pkcs1Encoding(
- IAsymmetricBlockCipher cipher)
- {
- this.engine = cipher;
- this.useStrictLength = StrictLengthEnabled;
- }
-
- public Pkcs1Encoding(IAsymmetricBlockCipher cipher, int pLen)
- {
- this.engine = cipher;
- this.useStrictLength = StrictLengthEnabled;
- this.pLen = pLen;
- }
-
- public Pkcs1Encoding(IAsymmetricBlockCipher cipher, byte[] fallback)
- {
- this.engine = cipher;
- this.useStrictLength = StrictLengthEnabled;
- this.fallback = fallback;
- this.pLen = fallback.Length;
- }
- public IAsymmetricBlockCipher GetUnderlyingCipher()
- {
- return engine;
- }
- public string AlgorithmName
- {
- get { return engine.AlgorithmName + "/PKCS1Padding"; }
- }
- public void Init(
- bool forEncryption,
- ICipherParameters parameters)
- {
- AsymmetricKeyParameter kParam;
- if (parameters is ParametersWithRandom)
- {
- ParametersWithRandom rParam = (ParametersWithRandom)parameters;
- this.random = rParam.Random;
- kParam = (AsymmetricKeyParameter)rParam.Parameters;
- }
- else
- {
- this.random = new SecureRandom();
- kParam = (AsymmetricKeyParameter)parameters;
- }
- engine.Init(forEncryption, parameters);
- this.forPrivateKey = kParam.IsPrivate;
- this.forEncryption = forEncryption;
- }
- public int GetInputBlockSize()
- {
- int baseBlockSize = engine.GetInputBlockSize();
- return forEncryption
- ? baseBlockSize - HeaderLength
- : baseBlockSize;
- }
- public int GetOutputBlockSize()
- {
- int baseBlockSize = engine.GetOutputBlockSize();
- return forEncryption
- ? baseBlockSize
- : baseBlockSize - HeaderLength;
- }
- public byte[] ProcessBlock(
- byte[] input,
- int inOff,
- int length)
- {
- return forEncryption
- ? EncodeBlock(input, inOff, length)
- : DecodeBlock(input, inOff, length);
- }
- private byte[] EncodeBlock(
- byte[] input,
- int inOff,
- int inLen)
- {
- if (inLen > GetInputBlockSize())
- throw new ArgumentException("input data too large", "inLen");
- byte[] block = new byte[engine.GetInputBlockSize()];
- if (forPrivateKey)
- {
- block[0] = 0x01;
- for (int i = 1; i != block.Length - inLen - 1; i++)
- {
- block[i] = (byte)0xFF;
- }
- }
- else
- {
- random.NextBytes(block);
- block[0] = 0x02;
-
-
-
-
- for (int i = 1; i != block.Length - inLen - 1; i++)
- {
- while (block[i] == 0)
- {
- block[i] = (byte)random.NextInt();
- }
- }
- }
- block[block.Length - inLen - 1] = 0x00;
- Array.Copy(input, inOff, block, block.Length - inLen, inLen);
- return engine.ProcessBlock(block, 0, block.Length);
- }
-
- private static int CheckPkcs1Encoding(byte[] encoded, int pLen)
- {
- int correct = 0;
-
- correct |= (encoded[0] ^ 2);
-
- int plen = encoded.Length - (
- pLen
- + 1
- );
- for (int i = 1; i < plen; i++)
- {
- int tmp = encoded[i];
- tmp |= tmp >> 1;
- tmp |= tmp >> 2;
- tmp |= tmp >> 4;
- correct |= (tmp & 1) - 1;
- }
-
- correct |= encoded[encoded.Length - (pLen + 1)];
-
- correct |= correct >> 1;
- correct |= correct >> 2;
- correct |= correct >> 4;
- return ~((correct & 1) - 1);
- }
-
- private byte[] DecodeBlockOrRandom(byte[] input, int inOff, int inLen)
- {
- if (!forPrivateKey)
- throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing");
- byte[] block = engine.ProcessBlock(input, inOff, inLen);
- byte[] random = null;
- if (this.fallback == null)
- {
- random = new byte[this.pLen];
- this.random.NextBytes(random);
- }
- else
- {
- random = fallback;
- }
-
- if (block.Length < GetOutputBlockSize())
- throw new InvalidCipherTextException("block truncated");
-
- if (useStrictLength && block.Length != engine.GetOutputBlockSize())
- throw new InvalidCipherTextException("block incorrect size");
-
- int correct = Pkcs1Encoding.CheckPkcs1Encoding(block, this.pLen);
-
- byte[] result = new byte[this.pLen];
- for (int i = 0; i < this.pLen; i++)
- {
- result[i] = (byte)((block[i+(block.Length-pLen)]&(~correct)) | (random[i]&correct));
- }
- return result;
- }
-
- private byte[] DecodeBlock(
- byte[] input,
- int inOff,
- int inLen)
- {
-
- if (this.pLen != -1)
- {
- return this.DecodeBlockOrRandom(input, inOff, inLen);
- }
- byte[] block = engine.ProcessBlock(input, inOff, inLen);
- if (block.Length < GetOutputBlockSize())
- {
- throw new InvalidCipherTextException("block truncated");
- }
- byte type = block[0];
- if (type != 1 && type != 2)
- {
- throw new InvalidCipherTextException("unknown block type");
- }
- if (useStrictLength && block.Length != engine.GetOutputBlockSize())
- {
- throw new InvalidCipherTextException("block incorrect size");
- }
-
-
-
- int start;
- for (start = 1; start != block.Length; start++)
- {
- byte pad = block[start];
- if (pad == 0)
- {
- break;
- }
- if (type == 1 && pad != (byte)0xff)
- {
- throw new InvalidCipherTextException("block padding incorrect");
- }
- }
- start++;
- if (start > block.Length || start < HeaderLength)
- {
- throw new InvalidCipherTextException("no data in block");
- }
- byte[] result = new byte[block.Length - start];
- Array.Copy(block, start, result, 0, result.Length);
- return result;
- }
- }
- }
- #endif
|