Imported Upstream version 4.6.0.125

Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2016-08-03 10:59:49 +00:00
parent a569aebcfd
commit e79aa3c0ed
17047 changed files with 3137615 additions and 392334 deletions

View File

@@ -0,0 +1,130 @@
// CommonCrypto bindings for MonoMac and MonoTouch
//
// Authors:
// Sebastien Pouliot <sebastien@xamarin.com>
//
// Copyright 2012-2014 Xamarin Inc.
using System;
using System.Security.Cryptography;
using System.Runtime.InteropServices;
namespace Crimson.CommonCrypto {
// int32_t -> CommonCryptor.h
enum CCCryptorStatus {
Success = 0,
ParamError = -4300,
BufferTooSmall = -4301,
MemoryFailure = -4302,
AlignmentError = -4303,
DecodeError = -4304,
Unimplemented = -4305
}
// uint32_t -> CommonCryptor.h
// note: not exposed publicly so it can stay signed
enum CCOperation {
Encrypt = 0,
Decrypt,
}
// uint32_t -> CommonCryptor.h
// note: not exposed publicly so it can stay signed
enum CCAlgorithm {
AES128 = 0,
DES,
TripleDES,
CAST,
RC4,
RC2,
Blowfish
}
// uint32_t -> CommonCryptor.h
// note: not exposed publicly so it can stay signed
[Flags]
enum CCOptions {
None = 0,
PKCS7Padding = 1,
ECBMode = 2
}
static class Cryptor {
const string libSystem = "/usr/lib/libSystem.dylib";
// size_t was changed to IntPtr for 32/64 bits size difference - even if mono is (moslty) used in 32bits only on OSX today
// not using `nint` to be able to resue this outside (if needed)
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorCreate (CCOperation op, CCAlgorithm alg, CCOptions options, /* const void* */ byte[] key, /* size_t */ IntPtr keyLength, /* const void* */ byte[] iv, /* CCCryptorRef* */ ref IntPtr cryptorRef);
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorRelease (/* CCCryptorRef */ IntPtr cryptorRef);
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorUpdate (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ byte[] dataIn, /* size_t */ IntPtr dataInLength, /* void* */ byte[] dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorUpdate (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ IntPtr dataIn, /* size_t */ IntPtr dataInLength, /* void* */ IntPtr dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorFinal (/* CCCryptorRef */ IntPtr cryptorRef, /* void* */ byte[] dataOut, /* size_t */ IntPtr dataOutAvailable, /* size_t* */ ref IntPtr dataOutMoved);
[DllImport (libSystem)]
extern internal static int CCCryptorGetOutputLength (/* CCCryptorRef */ IntPtr cryptorRef, /* size_t */ IntPtr inputLength, bool final);
[DllImport (libSystem)]
extern internal static CCCryptorStatus CCCryptorReset (/* CCCryptorRef */ IntPtr cryptorRef, /* const void* */ IntPtr iv);
// helper method to reduce the amount of generate code for each cipher algorithm
static internal IntPtr Create (CCOperation operation, CCAlgorithm algorithm, CCOptions options, byte[] key, byte[] iv)
{
if (key == null)
throw new CryptographicException ("A null key was provided");
// unlike the .NET framework CommonCrypto does not support two-keys triple-des (128 bits) ref: #6967
if ((algorithm == CCAlgorithm.TripleDES) && (key.Length == 16)) {
byte[] key3 = new byte [24];
Buffer.BlockCopy (key, 0, key3, 0, 16);
Buffer.BlockCopy (key, 0, key3, 16, 8);
key = key3;
}
IntPtr cryptor = IntPtr.Zero;
CCCryptorStatus status = Cryptor.CCCryptorCreate (operation, algorithm, options, key, (IntPtr) key.Length, iv, ref cryptor);
if (status != CCCryptorStatus.Success)
throw new CryptographicUnexpectedOperationException ();
return cryptor;
}
// size_t was changed to IntPtr for 32/64 bits size difference - even if mono is (moslty) used in 32bits only on OSX today
[DllImport ("/System/Library/Frameworks/Security.framework/Security")]
extern internal static /* int */ int SecRandomCopyBytes (/* SecRandomRef */ IntPtr rnd, /* size_t */ IntPtr count, /* uint8_t* */ byte[] bytes);
static internal void GetRandom (byte[] buffer)
{
if (SecRandomCopyBytes (IntPtr.Zero, (IntPtr) buffer.Length, buffer) != 0)
throw new CryptographicException (Marshal.GetLastWin32Error ()); // errno
}
}
#if !MONOTOUCH && !XAMMAC
static class KeyBuilder {
static public byte[] Key (int size)
{
byte[] buffer = new byte [size];
Cryptor.GetRandom (buffer);
return buffer;
}
static public byte[] IV (int size)
{
byte[] buffer = new byte [size];
Cryptor.GetRandom (buffer);
return buffer;
}
}
#endif
}

View File

@@ -0,0 +1,24 @@
//
// CorlibExtras.cs: additional stuff not provided by autogenerated code
//
// Authors:
// Sebastien Pouliot (sebastien@xamarun.com)
//
// Copyright (C) 2012 Xamarin Inc. All rights reserved.
//
namespace System.Security.Cryptography {
// required to ensure compatibility with MS implementation
public sealed partial class RC2CryptoServiceProvider : RC2 {
public override int EffectiveKeySize {
get { return base.EffectiveKeySize; }
set {
if (value != KeySizeValue)
throw new CryptographicUnexpectedOperationException ("Effective key size must match key size for compatibility");
base.EffectiveKeySize = value;
}
}
}
}

View File

@@ -0,0 +1,60 @@
// ICryptoTransform implementation on top of CommonCrypto and SymmetricTransform
//
// Authors:
// Sebastien Pouliot <sebastien@xamarin.com>
//
// Copyright 2012 Xamarin Inc.
using System;
using System.Security.Cryptography;
using Mono.Security.Cryptography;
namespace Crimson.CommonCrypto {
class CryptorTransform : SymmetricTransform {
IntPtr handle;
IntPtr handle_e;
bool encryption;
public CryptorTransform (IntPtr cryptor, IntPtr special, SymmetricAlgorithm algo, bool encryption, byte[] iv)
: base (algo, encryption, iv)
{
handle = cryptor;
// for CFB we need to encrypt data while decrypting
handle_e = special;
this.encryption = encryption;
}
~CryptorTransform ()
{
Dispose (false);
}
// PRO: doing this ensure all cipher modes and padding modes supported by .NET will be available with CommonCrypto (drop-in replacements)
// CON: doing this will only process one block at the time, so it's not ideal for performance, but still a lot better than managed
protected override void ECB (byte[] input, byte[] output)
{
IntPtr len = IntPtr.Zero;
CCCryptorStatus s = Cryptor.CCCryptorUpdate ((encrypt == encryption) ? handle : handle_e,
input, (IntPtr) input.Length, output, (IntPtr) output.Length, ref len);
if (((int) len != output.Length) || (s != CCCryptorStatus.Success))
throw new CryptographicUnexpectedOperationException (s.ToString ());
}
protected override void Dispose (bool disposing)
{
if (handle != IntPtr.Zero) {
Cryptor.CCCryptorRelease (handle);
handle = IntPtr.Zero;
}
if (handle_e != IntPtr.Zero) {
Cryptor.CCCryptorRelease (handle_e);
handle_e = IntPtr.Zero;
}
base.Dispose (disposing);
GC.SuppressFinalize (this);
}
}
}

View File

@@ -0,0 +1,348 @@
// Fast, multi-block, ICryptoTransform implementation on top of CommonCrypto
//
// Authors:
// Sebastien Pouliot <sebastien@xamarin.com>
//
// Copyright 2012 Xamarin Inc.
using System;
using System.Security.Cryptography;
using Mono.Security.Cryptography;
namespace Crimson.CommonCrypto {
unsafe class FastCryptorTransform : ICryptoTransform {
IntPtr handle;
bool encrypt;
int BlockSizeByte;
byte[] workBuff;
bool lastBlock;
PaddingMode padding;
public FastCryptorTransform (IntPtr cryptor, SymmetricAlgorithm algo, bool encryption, byte[] iv)
{
BlockSizeByte = (algo.BlockSize >> 3);
if (iv == null) {
iv = KeyBuilder.IV (BlockSizeByte);
} else if (iv.Length < BlockSizeByte) {
string msg = String.Format ("IV is too small ({0} bytes), it should be {1} bytes long.",
iv.Length, BlockSizeByte);
throw new CryptographicException (msg);
}
handle = cryptor;
encrypt = encryption;
padding = algo.Padding;
// transform buffer
workBuff = new byte [BlockSizeByte];
}
~FastCryptorTransform ()
{
Dispose (false);
}
public void Dispose ()
{
Dispose (true);
}
protected virtual void Dispose (bool disposing)
{
if (handle != IntPtr.Zero) {
Cryptor.CCCryptorRelease (handle);
handle = IntPtr.Zero;
}
GC.SuppressFinalize (this);
}
public virtual bool CanTransformMultipleBlocks {
get { return true; }
}
public virtual bool CanReuseTransform {
get { return false; }
}
public virtual int InputBlockSize {
get { return BlockSizeByte; }
}
public virtual int OutputBlockSize {
get { return BlockSizeByte; }
}
int Transform (byte[] input, int inputOffset, byte[] output, int outputOffset, int length)
{
IntPtr len = IntPtr.Zero;
IntPtr in_len = (IntPtr) length;
IntPtr out_len = (IntPtr) (output.Length - outputOffset);
fixed (byte* inputBuffer = &input [0])
fixed (byte* outputBuffer = &output [0]) {
CCCryptorStatus s = Cryptor.CCCryptorUpdate (handle, (IntPtr) (inputBuffer + inputOffset), in_len, (IntPtr) (outputBuffer + outputOffset), out_len, ref len);
if (s != CCCryptorStatus.Success)
throw new CryptographicException (s.ToString ());
}
return (int) len;
}
private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputBuffer == null)
throw new ArgumentNullException ("inputBuffer");
if (inputOffset < 0)
throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
if (inputCount < 0)
throw new ArgumentOutOfRangeException ("inputCount", "< 0");
// ordered to avoid possible integer overflow
if (inputOffset > inputBuffer.Length - inputCount)
throw new ArgumentException ("inputBuffer", "Overflow");
}
// this method may get called MANY times so this is the one to optimize
public virtual int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
CheckInput (inputBuffer, inputOffset, inputCount);
// check output parameters
if (outputBuffer == null)
throw new ArgumentNullException ("outputBuffer");
if (outputOffset < 0)
throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
// ordered to avoid possible integer overflow
int len = outputBuffer.Length - inputCount - outputOffset;
if (!encrypt && (0 > len) && ((padding == PaddingMode.None) || (padding == PaddingMode.Zeros))) {
throw new CryptographicException ("outputBuffer", "Overflow");
} else if (KeepLastBlock) {
if (0 > len + BlockSizeByte) {
throw new CryptographicException ("outputBuffer", "Overflow");
}
} else {
if (0 > len) {
// there's a special case if this is the end of the decryption process
if (inputBuffer.Length - inputOffset - outputBuffer.Length == BlockSizeByte)
inputCount = outputBuffer.Length - outputOffset;
else
throw new CryptographicException ("outputBuffer", "Overflow");
}
}
return InternalTransformBlock (inputBuffer, inputOffset, inputCount, outputBuffer, outputOffset);
}
private bool KeepLastBlock {
get {
return ((!encrypt) && (padding != PaddingMode.None) && (padding != PaddingMode.Zeros));
}
}
private int InternalTransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
int offs = inputOffset;
int full;
// this way we don't do a modulo every time we're called
// and we may save a division
if (inputCount != BlockSizeByte) {
if ((inputCount % BlockSizeByte) != 0)
throw new CryptographicException ("Invalid input block size.");
full = inputCount / BlockSizeByte;
} else
full = 1;
if (KeepLastBlock)
full--;
int total = 0;
if (lastBlock) {
Transform (workBuff, 0, outputBuffer, outputOffset, BlockSizeByte);
outputOffset += BlockSizeByte;
total += BlockSizeByte;
lastBlock = false;
}
if (full > 0) {
int length = full * BlockSizeByte;
Transform (inputBuffer, offs, outputBuffer, outputOffset, length);
offs += length;
outputOffset += length;
total += length;
}
if (KeepLastBlock) {
Buffer.BlockCopy (inputBuffer, offs, workBuff, 0, BlockSizeByte);
lastBlock = true;
}
return total;
}
private void Random (byte[] buffer, int start, int length)
{
byte[] random = new byte [length];
Cryptor.GetRandom (random);
Buffer.BlockCopy (random, 0, buffer, start, length);
}
private void ThrowBadPaddingException (PaddingMode padding, int length, int position)
{
string msg = String.Format ("Bad {0} padding.", padding);
if (length >= 0)
msg += String.Format (" Invalid length {0}.", length);
if (position >= 0)
msg += String.Format (" Error found at position {0}.", position);
throw new CryptographicException (msg);
}
private byte[] FinalEncrypt (byte[] inputBuffer, int inputOffset, int inputCount)
{
// are there still full block to process ?
int full = (inputCount / BlockSizeByte) * BlockSizeByte;
int rem = inputCount - full;
int total = full;
switch (padding) {
case PaddingMode.ANSIX923:
case PaddingMode.ISO10126:
case PaddingMode.PKCS7:
// we need to add an extra block for padding
total += BlockSizeByte;
break;
default:
if (inputCount == 0)
return new byte [0];
if (rem != 0) {
if (padding == PaddingMode.None)
throw new CryptographicException ("invalid block length");
// zero padding the input (by adding a block for the partial data)
byte[] paddedInput = new byte [full + BlockSizeByte];
Buffer.BlockCopy (inputBuffer, inputOffset, paddedInput, 0, inputCount);
inputBuffer = paddedInput;
inputOffset = 0;
inputCount = paddedInput.Length;
total = inputCount;
}
break;
}
byte[] res = new byte [total];
int outputOffset = 0;
// process all blocks except the last (final) block
if (total > BlockSizeByte) {
outputOffset = InternalTransformBlock (inputBuffer, inputOffset, total - BlockSizeByte, res, 0);
inputOffset += outputOffset;
}
// now we only have a single last block to encrypt
byte pad = (byte) (BlockSizeByte - rem);
switch (padding) {
case PaddingMode.ANSIX923:
// XX 00 00 00 00 00 00 07 (zero + padding length)
res [res.Length - 1] = pad;
Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
// the last padded block will be transformed in-place
InternalTransformBlock (res, full, BlockSizeByte, res, full);
break;
case PaddingMode.ISO10126:
// XX 3F 52 2A 81 AB F7 07 (random + padding length)
Random (res, res.Length - pad, pad - 1);
res [res.Length - 1] = pad;
Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
// the last padded block will be transformed in-place
InternalTransformBlock (res, full, BlockSizeByte, res, full);
break;
case PaddingMode.PKCS7:
// XX 07 07 07 07 07 07 07 (padding length)
for (int i = res.Length; --i >= (res.Length - pad);)
res [i] = pad;
Buffer.BlockCopy (inputBuffer, inputOffset, res, full, rem);
// the last padded block will be transformed in-place
InternalTransformBlock (res, full, BlockSizeByte, res, full);
break;
default:
InternalTransformBlock (inputBuffer, inputOffset, BlockSizeByte, res, outputOffset);
break;
}
return res;
}
private byte[] FinalDecrypt (byte[] inputBuffer, int inputOffset, int inputCount)
{
if ((inputCount % BlockSizeByte) > 0)
throw new CryptographicException ("Invalid input block size.");
int total = inputCount;
if (lastBlock)
total += BlockSizeByte;
byte[] res = new byte [total];
int outputOffset = 0;
if (inputCount > 0)
outputOffset = InternalTransformBlock (inputBuffer, inputOffset, inputCount, res, 0);
if (lastBlock) {
Transform (workBuff, 0, res, outputOffset, BlockSizeByte);
outputOffset += BlockSizeByte;
lastBlock = false;
}
// total may be 0 (e.g. PaddingMode.None)
byte pad = ((total > 0) ? res [total - 1] : (byte) 0);
switch (padding) {
case PaddingMode.ANSIX923:
if ((pad == 0) || (pad > BlockSizeByte))
ThrowBadPaddingException (padding, pad, -1);
for (int i = pad - 1; i > 0; i--) {
if (res [total - 1 - i] != 0x00)
ThrowBadPaddingException (padding, -1, i);
}
total -= pad;
break;
case PaddingMode.ISO10126:
if ((pad == 0) || (pad > BlockSizeByte))
ThrowBadPaddingException (padding, pad, -1);
total -= pad;
break;
case PaddingMode.PKCS7:
if ((pad == 0) || (pad > BlockSizeByte))
ThrowBadPaddingException (padding, pad, -1);
for (int i = pad - 1; i > 0; i--) {
if (res [total - 1 - i] != pad)
ThrowBadPaddingException (padding, -1, i);
}
total -= pad;
break;
case PaddingMode.None: // nothing to do - it's a multiple of block size
case PaddingMode.Zeros: // nothing to do - user must unpad himself
break;
}
// return output without padding
if (total > 0) {
byte[] data = new byte [total];
Buffer.BlockCopy (res, 0, data, 0, total);
// zeroize decrypted data (copy with padding)
Array.Clear (res, 0, res.Length);
return data;
}
else
return new byte [0];
}
public virtual byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
{
CheckInput (inputBuffer, inputOffset, inputCount);
if (encrypt)
return FinalEncrypt (inputBuffer, inputOffset, inputCount);
else
return FinalDecrypt (inputBuffer, inputOffset, inputCount);
}
}
}

View File

@@ -0,0 +1,212 @@
// A CommonCrypto-based implementation of RC4(tm)
//
// Authors:
// Sebastien Pouliot <sebastien@xamarin.com>
//
// (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Copyright 2012-2014 Xamarin Inc.
using System;
using System.Security.Cryptography;
using Crimson.CommonCrypto;
#if MONOTOUCH || XAMMAC
using Mono.Security.Cryptography;
namespace Mono.Security.Cryptography {
#if !INSIDE_CORLIB
public
#endif
sealed partial class ARC4Managed : RC4, ICryptoTransform {
IntPtr handle;
public ARC4Managed ()
{
}
~ARC4Managed ()
{
Dispose (false);
}
#else
namespace Crimson.Security.Cryptography {
public abstract class RC4 : SymmetricAlgorithm {
private static KeySizes[] s_legalBlockSizes = {
new KeySizes (64, 64, 0)
};
private static KeySizes[] s_legalKeySizes = {
new KeySizes (40, 512, 8)
};
public RC4 ()
{
KeySizeValue = 128;
BlockSizeValue = 64;
FeedbackSizeValue = BlockSizeValue;
LegalBlockSizesValue = s_legalBlockSizes;
LegalKeySizesValue = s_legalKeySizes;
}
// required for compatibility with .NET 2.0
public override byte[] IV {
get { return new byte [0]; }
set { ; }
}
new static public RC4 Create()
{
return Create ("RC4");
}
new static public RC4 Create (string algName)
{
object o = CryptoConfig.CreateFromName (algName);
return (RC4) o ?? new RC4CommonCrypto ();
}
}
public sealed class RC4CommonCrypto : RC4, ICryptoTransform {
IntPtr handle;
public RC4CommonCrypto ()
{
}
~RC4CommonCrypto ()
{
Dispose (false);
}
#endif
public bool CanReuseTransform {
get { return false; }
}
public bool CanTransformMultipleBlocks {
get { return true; }
}
public int InputBlockSize {
get { return 1; }
}
public int OutputBlockSize {
get { return 1; }
}
public override byte[] Key {
get {
return base.Key;
}
set {
if (value == null)
throw new ArgumentNullException ("Key");
int length = (value.Length << 3);
KeySizeValue = length;
KeyValue = (byte[]) value.Clone ();
}
}
protected override void Dispose (bool disposing)
{
if (handle != IntPtr.Zero) {
Cryptor.CCCryptorRelease (handle);
handle = IntPtr.Zero;
}
base.Dispose (disposing);
GC.SuppressFinalize (this);
}
public override void GenerateIV ()
{
// not used for a stream cipher
IVValue = new byte [0];
}
public override void GenerateKey ()
{
KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
}
public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
{
KeyValue = rgbKey;
IVValue = rgbIV;
return this;
}
public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
{
KeyValue = rgbKey;
IVValue = rgbIV;
return this;
}
private void CheckInput (byte[] inputBuffer, int inputOffset, int inputCount)
{
if (inputBuffer == null)
throw new ArgumentNullException ("inputBuffer");
if (inputOffset < 0)
throw new ArgumentOutOfRangeException ("inputOffset", "< 0");
if (inputCount < 0)
throw new ArgumentOutOfRangeException ("inputCount", "< 0");
// ordered to avoid possible integer overflow
if (inputOffset > inputBuffer.Length - inputCount)
throw new ArgumentException ("inputBuffer", "Overflow");
}
public unsafe int TransformBlock (byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
{
CheckInput (inputBuffer, inputOffset, inputCount);
if (inputCount == 0)
return 0;
// check output parameters
if (outputBuffer == null)
throw new ArgumentNullException ("outputBuffer");
if (outputOffset < 0)
throw new ArgumentOutOfRangeException ("outputOffset", "< 0");
// ordered to avoid possible integer overflow
if (outputOffset > outputBuffer.Length - inputCount)
throw new ArgumentException ("outputBuffer", "Overflow");
if (outputBuffer.Length == 0)
throw new CryptographicException ("output buffer too small");
if (handle == IntPtr.Zero)
handle = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.RC4, CCOptions.None, KeyValue, IVValue);
IntPtr len = IntPtr.Zero;
IntPtr in_len = (IntPtr) (inputBuffer.Length - inputOffset);
IntPtr out_len = (IntPtr) (outputBuffer.Length - outputOffset);
fixed (byte* input = &inputBuffer [0])
fixed (byte* output = &outputBuffer [0]) {
CCCryptorStatus s = Cryptor.CCCryptorUpdate (handle, (IntPtr) (input + inputOffset), in_len, (IntPtr) (output + outputOffset), out_len, ref len);
if ((len != out_len) || (s != CCCryptorStatus.Success))
throw new CryptographicUnexpectedOperationException (s.ToString ());
}
return (int) out_len;
}
public byte[] TransformFinalBlock (byte[] inputBuffer, int inputOffset, int inputCount)
{
CheckInput (inputBuffer, inputOffset, inputCount);
try {
byte[] output = new byte [inputCount];
TransformBlock (inputBuffer, inputOffset, inputCount, output, 0);
return output;
}
finally {
Cryptor.CCCryptorRelease (handle);
handle = IntPtr.Zero;
}
}
}
}

View File

@@ -0,0 +1,119 @@
//
// RijndaelManaged.cs: Use CommonCrypto AES when possible,
// fallback on RijndaelManagedTransform otherwise
//
// Authors:
// Sebastien Pouliot <sebastien@xamarin.com>
//
// Copyright 2012 Xamarin Inc.
//
using System;
using System.Security.Cryptography;
using Mono.Security.Cryptography;
using Crimson.CommonCrypto;
namespace System.Security.Cryptography {
public sealed class RijndaelManaged : Rijndael {
public RijndaelManaged ()
{
}
public override void GenerateIV ()
{
IVValue = KeyBuilder.IV (BlockSizeValue >> 3);
}
public override void GenerateKey ()
{
KeyValue = KeyBuilder.Key (KeySizeValue >> 3);
}
public override ICryptoTransform CreateDecryptor (byte[] rgbKey, byte[] rgbIV)
{
// AES is Rijndael with a 128 bits block size, so we can use CommonCrypto in this case
if (BlockSize == 128) {
IntPtr decryptor = IntPtr.Zero;
switch (Mode) {
case CipherMode.CBC:
decryptor = Cryptor.Create (CCOperation.Decrypt, CCAlgorithm.AES128, CCOptions.None, rgbKey, rgbIV);
return new FastCryptorTransform (decryptor, this, false, rgbIV);
case CipherMode.ECB:
decryptor = Cryptor.Create (CCOperation.Decrypt, CCAlgorithm.AES128, CCOptions.ECBMode, rgbKey, rgbIV);
return new FastCryptorTransform (decryptor, this, false, rgbIV);
default:
// CFB cipher mode is not supported by the (old) API we used (for compatibility) so we fallback for them
// FIXME: benchmark if we're better with RijndaelManagedTransform or CryptorTransform for CFB mode
break;
}
}
return NewEncryptor(rgbKey,
ModeValue,
rgbIV,
FeedbackSizeValue,
RijndaelManagedTransformMode.Decrypt);
}
public override ICryptoTransform CreateEncryptor (byte[] rgbKey, byte[] rgbIV)
{
if (BlockSize == 128) {
IntPtr encryptor = IntPtr.Zero;
switch (Mode) {
case CipherMode.CBC:
encryptor = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.AES128, CCOptions.None, rgbKey, rgbIV);
return new FastCryptorTransform (encryptor, this, true, rgbIV);
case CipherMode.ECB:
encryptor = Cryptor.Create (CCOperation.Encrypt, CCAlgorithm.AES128, CCOptions.ECBMode, rgbKey, rgbIV);
return new FastCryptorTransform (encryptor, this, true, rgbIV);
default:
// CFB cipher mode is not supported by the (old) API we used (for compatibility) so we fallback for them
// FIXME: benchmark if we're better with RijndaelManagedTransform or CryptorTransform for CFB mode
break;
}
}
return NewEncryptor(rgbKey,
ModeValue,
rgbIV,
FeedbackSizeValue,
RijndaelManagedTransformMode.Encrypt);
}
private ICryptoTransform NewEncryptor (byte[] rgbKey,
CipherMode mode,
byte[] rgbIV,
int feedbackSize,
RijndaelManagedTransformMode encryptMode) {
// Build the key if one does not already exist
if (rgbKey == null) {
rgbKey = Utils.GenerateRandom(KeySizeValue / 8);
}
// If not ECB mode, make sure we have an IV. In CoreCLR we do not support ECB, so we must have
// an IV in all cases.
#if !FEATURE_CRYPTO
if (mode != CipherMode.ECB) {
#endif // !FEATURE_CRYPTO
if (rgbIV == null) {
rgbIV = Utils.GenerateRandom(BlockSizeValue / 8);
}
#if !FEATURE_CRYPTO
}
#endif // !FEATURE_CRYPTO
// Create the encryptor/decryptor object
return new RijndaelManagedTransform (rgbKey,
mode,
rgbIV,
BlockSizeValue,
feedbackSize,
PaddingValue,
encryptMode);
}
}
}

View File

@@ -0,0 +1,81 @@
//
// SecRandom.cs: based on Mono's System.Security.Cryptography.RNGCryptoServiceProvider
//
// Authors:
// Mark Crichton (crichton@gimp.org)
// Sebastien Pouliot (sebastien@xamarun.com)
//
// (C) 2002
// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
// Copyright (C) 2012-2014 Xamarin Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using Crimson.CommonCrypto;
// http://developer.apple.com/library/ios/#DOCUMENTATION/Security/Reference/RandomizationReference/Reference/reference.html
#if MONOTOUCH || XAMMAC
namespace System.Security.Cryptography {
public class RNGCryptoServiceProvider : RandomNumberGenerator {
public RNGCryptoServiceProvider ()
{
}
~RNGCryptoServiceProvider ()
{
}
#else
using System;
using System.Security.Cryptography;
namespace Crimson.Security.Cryptography {
public class SecRandom : RandomNumberGenerator {
#endif
public override void GetBytes (byte[] data)
{
if (data == null)
throw new ArgumentNullException ("data");
Cryptor.GetRandom (data);
}
public override void GetNonZeroBytes (byte[] data)
{
if (data == null)
throw new ArgumentNullException ("data");
byte[] random = new byte [data.Length * 2];
int i = 0;
// one pass should be enough but hey this is random ;-)
while (i < data.Length) {
Cryptor.GetRandom (random);
for (int j=0; j < random.Length; j++) {
if (i == data.Length)
break;
if (random [j] != 0)
data [i++] = random [j];
}
}
}
}
}