Merge pull request #3213 from henricm/fix-for-win-securestring-to-bstr
[mono.git] / mcs / class / referencesource / mscorlib / system / security / cryptography / rsapkcs1keyexchangeformatter.cs
1 // ==++==
2 // 
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 // 
5 // ==--==
6 // <OWNER>[....]</OWNER>
7 // 
8
9 namespace System.Security.Cryptography {
10     using System.Globalization;
11     using System.Diagnostics.Contracts;
12
13     [System.Runtime.InteropServices.ComVisible(true)]
14     public class RSAPKCS1KeyExchangeFormatter : AsymmetricKeyExchangeFormatter {
15         RandomNumberGenerator RngValue;
16         RSA _rsaKey;
17         bool?  _rsaOverridesEncrypt;
18
19         //
20         // public constructors
21         //
22
23         public RSAPKCS1KeyExchangeFormatter() {}
24
25         public RSAPKCS1KeyExchangeFormatter(AsymmetricAlgorithm key) {
26             if (key == null) 
27                 throw new ArgumentNullException("key");
28             Contract.EndContractBlock();
29             _rsaKey = (RSA) key;
30         }
31
32         //
33         // public properties
34         //
35
36         public override String Parameters {
37             get { return "<enc:KeyEncryptionMethod enc:Algorithm=\"http://www.microsoft.com/xml/security/algorithm/PKCS1-v1.5-KeyEx\" xmlns:enc=\"http://www.microsoft.com/xml/security/encryption/v1.0\" />"; }
38         }
39
40         public RandomNumberGenerator Rng {
41             get { return RngValue; }
42             set { RngValue = value; }
43         }
44         
45         //
46         // public methods
47         //
48
49         public override void SetKey(AsymmetricAlgorithm key) {
50             if (key == null) 
51                 throw new ArgumentNullException("key");
52             Contract.EndContractBlock();
53             _rsaKey = (RSA) key;
54             _rsaOverridesEncrypt = default(bool?);
55         }
56
57         public override byte[] CreateKeyExchange(byte[] rgbData) {
58 #if MONO
59                         if (rgbData == null)
60                                 throw new ArgumentNullException ("rgbData");
61 #endif
62
63             if (_rsaKey == null)
64                 throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_MissingKey"));
65
66             byte[] rgbKeyEx;
67             if (OverridesEncrypt) {
68                 rgbKeyEx = _rsaKey.Encrypt(rgbData, RSAEncryptionPadding.Pkcs1);
69             }
70             else {
71                 int cb = _rsaKey.KeySize/8;
72                 if ((rgbData.Length + 11) > cb)
73                     throw new CryptographicException(Environment.GetResourceString("Cryptography_Padding_EncDataTooBig", cb-11));
74                 byte[]  rgbInput = new byte[cb];
75
76                 //
77                 //  We want to pad to the following format:
78                 //      00 || 02 || PS || 00 || D
79                 //
80                 //      PS - pseudorandom non zero bytes
81                 //      D - data
82                 //
83
84                 if (RngValue == null) {
85                     RngValue = RandomNumberGenerator.Create();
86                 }
87                 
88                 Rng.GetNonZeroBytes(rgbInput);
89                 rgbInput[0] = 0;
90                 rgbInput[1] = 2;
91                 rgbInput[cb-rgbData.Length-1] = 0;
92                 Buffer.InternalBlockCopy(rgbData, 0, rgbInput, cb-rgbData.Length, rgbData.Length);
93
94                 //
95                 //  Now encrypt the value and return it. (apply public key)
96                 //
97
98                 rgbKeyEx = _rsaKey.EncryptValue(rgbInput);
99             }
100             return rgbKeyEx;
101         }
102
103         public override byte[] CreateKeyExchange(byte[] rgbData, Type symAlgType) {
104             return CreateKeyExchange(rgbData);
105         }
106
107         private bool OverridesEncrypt {
108             get {
109                 if (!_rsaOverridesEncrypt.HasValue) {
110                     _rsaOverridesEncrypt = Utils.DoesRsaKeyOverride(_rsaKey, "Encrypt", new Type[] { typeof(byte[]), typeof(RSAEncryptionPadding) });
111                 }
112                 return _rsaOverridesEncrypt.Value;
113             }
114         }
115     }
116 }