You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
130
mcs/class/corlib/CommonCrypto/CommonCrypto.cs
Normal file
130
mcs/class/corlib/CommonCrypto/CommonCrypto.cs
Normal 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
|
||||
}
|
||||
24
mcs/class/corlib/CommonCrypto/CorlibExtras.cs
Normal file
24
mcs/class/corlib/CommonCrypto/CorlibExtras.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
mcs/class/corlib/CommonCrypto/CryptorTransform.cs
Normal file
60
mcs/class/corlib/CommonCrypto/CryptorTransform.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
348
mcs/class/corlib/CommonCrypto/FastCryptorTransform.cs
Normal file
348
mcs/class/corlib/CommonCrypto/FastCryptorTransform.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
212
mcs/class/corlib/CommonCrypto/RC4CommonCrypto.cs
Normal file
212
mcs/class/corlib/CommonCrypto/RC4CommonCrypto.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
119
mcs/class/corlib/CommonCrypto/RijndaelManaged.cs
Normal file
119
mcs/class/corlib/CommonCrypto/RijndaelManaged.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
81
mcs/class/corlib/CommonCrypto/SecRandom.cs
Normal file
81
mcs/class/corlib/CommonCrypto/SecRandom.cs
Normal 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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user