2 // PublicKey.cs - System.Security.Cryptography.PublicKey
5 // Sebastien Pouliot <sebastien@ximian.com>
6 // Tim Coleman (tim@timcoleman.com)
8 // (C) 2003 Motus Technologies Inc. (http://www.motus.com)
9 // Copyright (C) Tim Coleman, 2004
10 // Copyright (C) 2005 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #if NET_2_0 && SECURITY_DEP
35 using Mono
.Security
.Cryptography
;
36 using MSX
= Mono
.Security
.X509
;
38 namespace System
.Security
.Cryptography
.X509Certificates
{
40 public sealed class PublicKey
{
42 private const string rsaOid
= "1.2.840.113549.1.1.1";
43 private const string dsaOid
= "1.2.840.10040.4.1";
45 private AsymmetricAlgorithm _key
;
46 private AsnEncodedData _keyValue
;
47 private AsnEncodedData _params
;
50 public PublicKey (Oid oid
, AsnEncodedData parameters
, AsnEncodedData keyValue
)
53 throw new ArgumentNullException ("oid");
54 if (parameters
== null)
55 throw new ArgumentNullException ("parameters");
57 throw new ArgumentNullException ("keyValue");
60 _params
= new AsnEncodedData (parameters
);
61 _keyValue
= new AsnEncodedData (keyValue
);
64 internal PublicKey (MSX
.X509Certificate certificate
)
66 // note: _key MUSTonly contains the public part of the key
67 bool export_required
= true;
69 if (certificate
.KeyAlgorithm
== rsaOid
) {
70 // shortcut export/import in the case the private key isn't available
71 RSACryptoServiceProvider rcsp
= (certificate
.RSA
as RSACryptoServiceProvider
);
72 if ((rcsp
!= null) && rcsp
.PublicOnly
) {
73 _key
= certificate
.RSA
;
74 export_required
= false;
76 RSAManaged rsam
= (certificate
.RSA
as RSAManaged
);
77 if ((rsam
!= null) && rsam
.PublicOnly
) {
78 _key
= certificate
.RSA
;
79 export_required
= false;
83 if (export_required
) {
84 RSAParameters rsap
= certificate
.RSA
.ExportParameters (false);
86 (_key
as RSA
).ImportParameters (rsap
);
89 // shortcut export/import in the case the private key isn't available
90 DSACryptoServiceProvider dcsp
= (certificate
.DSA
as DSACryptoServiceProvider
);
91 if ((dcsp
!= null) && dcsp
.PublicOnly
) {
92 _key
= certificate
.DSA
;
93 export_required
= false;
95 // note: DSAManaged isn't availablt in Mono.Security due to a bug in Fx 1.x
97 if (export_required
) {
98 DSAParameters rsap
= certificate
.DSA
.ExportParameters (false);
100 (_key
as DSA
).ImportParameters (rsap
);
104 _oid
= new Oid (certificate
.KeyAlgorithm
);
105 _keyValue
= new AsnEncodedData (_oid
, certificate
.PublicKey
);
106 _params
= new AsnEncodedData (_oid
, certificate
.KeyAlgorithmParameters
);
111 public AsnEncodedData EncodedKeyValue
{
112 get { return _keyValue; }
115 public AsnEncodedData EncodedParameters
{
116 get { return _params; }
119 public AsymmetricAlgorithm Key
{
122 switch (_oid
.Value
) {
124 _key
= DecodeRSA (_keyValue
.RawData
);
127 _key
= DecodeDSA (_keyValue
.RawData
, _params
.RawData
);
130 string msg
= Locale
.GetText ("Cannot decode public key from unknown OID '{0}'.", _oid
.Value
);
131 throw new NotSupportedException (msg
);
144 static private byte[] GetUnsignedBigInteger (byte[] integer
)
146 if (integer
[0] != 0x00)
149 // this first byte is added so we're sure it's an unsigned integer
150 // however we can't feed it into RSAParameters or DSAParameters
151 int length
= integer
.Length
- 1;
152 byte[] uinteger
= new byte [length
];
153 Buffer
.BlockCopy (integer
, 1, uinteger
, 0, length
);
157 static internal DSA
DecodeDSA (byte[] rawPublicKey
, byte[] rawParameters
)
159 DSAParameters dsaParams
= new DSAParameters ();
161 // for DSA rawPublicKey contains 1 ASN.1 integer - Y
162 ASN1 pubkey
= new ASN1 (rawPublicKey
);
163 if (pubkey
.Tag
!= 0x02)
164 throw new CryptographicException (Locale
.GetText ("Missing DSA Y integer."));
165 dsaParams
.Y
= GetUnsignedBigInteger (pubkey
.Value
);
167 ASN1 param
= new ASN1 (rawParameters
);
168 if ((param
== null) || (param
.Tag
!= 0x30) || (param
.Count
< 3))
169 throw new CryptographicException (Locale
.GetText ("Missing DSA parameters."));
170 if ((param
[0].Tag
!= 0x02) || (param
[1].Tag
!= 0x02) || (param
[2].Tag
!= 0x02))
171 throw new CryptographicException (Locale
.GetText ("Invalid DSA parameters."));
173 dsaParams
.P
= GetUnsignedBigInteger (param
[0].Value
);
174 dsaParams
.Q
= GetUnsignedBigInteger (param
[1].Value
);
175 dsaParams
.G
= GetUnsignedBigInteger (param
[2].Value
);
177 catch (Exception e
) {
178 string msg
= Locale
.GetText ("Error decoding the ASN.1 structure.");
179 throw new CryptographicException (msg
, e
);
182 DSA dsa
= (DSA
) new DSACryptoServiceProvider (dsaParams
.Y
.Length
<< 3);
183 dsa
.ImportParameters (dsaParams
);
187 static internal RSA
DecodeRSA (byte[] rawPublicKey
)
189 RSAParameters rsaParams
= new RSAParameters ();
191 // for RSA rawPublicKey contains 2 ASN.1 integers
192 // the modulus and the public exponent
193 ASN1 pubkey
= new ASN1 (rawPublicKey
);
194 if (pubkey
.Count
== 0)
195 throw new CryptographicException (Locale
.GetText ("Missing RSA modulus and exponent."));
196 ASN1 modulus
= pubkey
[0];
197 if ((modulus
== null) || (modulus
.Tag
!= 0x02))
198 throw new CryptographicException (Locale
.GetText ("Missing RSA modulus."));
199 ASN1 exponent
= pubkey
[1];
200 if (exponent
.Tag
!= 0x02)
201 throw new CryptographicException (Locale
.GetText ("Missing RSA public exponent."));
203 rsaParams
.Modulus
= GetUnsignedBigInteger (modulus
.Value
);
204 rsaParams
.Exponent
= exponent
.Value
;
206 catch (Exception e
) {
207 string msg
= Locale
.GetText ("Error decoding the ASN.1 structure.");
208 throw new CryptographicException (msg
, e
);
211 int keySize
= (rsaParams
.Modulus
.Length
<< 3);
212 RSA rsa
= (RSA
) new RSACryptoServiceProvider (keySize
);
213 rsa
.ImportParameters (rsaParams
);