static public string ToString (ASN1 seq, bool reversed, string separator, bool quotes) { StringBuilder sb = new StringBuilder (); if (reversed) { for (int i = seq.Count - 1; i >= 0; i--) { ASN1 entry = seq [i]; AppendEntry (sb, entry, quotes); // separator (not on last iteration) if (i > 0) sb.Append (separator); } } else { for (int i = 0; i < seq.Count; i++) { ASN1 entry = seq [i]; AppendEntry (sb, entry, quotes); // separator (not on last iteration) if (i < seq.Count - 1) sb.Append (separator); } } return sb.ToString (); }
static public KeyInfo GetType (byte[] data) { if (data == null) throw new ArgumentNullException ("data"); KeyInfo ki = KeyInfo.Unknown; try { ASN1 top = new ASN1 (data); if ((top.Tag == 0x30) && (top.Count > 0)) { ASN1 firstLevel = top [0]; switch (firstLevel.Tag) { case 0x02: ki = KeyInfo.PrivateKey; break; case 0x30: ki = KeyInfo.EncryptedPrivateKey; break; } } } catch { throw new CryptographicException ("invalid ASN.1 data"); } return ki; }
public X509ExtensionCollection (ASN1 asn1) : this () { readOnly = true; if (asn1 == null) return; if (asn1.Tag != 0x30) throw new Exception ("Invalid extensions format"); for (int i=0; i < asn1.Count; i++) { X509Extension extension = new X509Extension (asn1 [i]); InnerList.Add (extension); } }
static public string ToString (ASN1 seq) { StringBuilder sb = new StringBuilder (); for (int i = 0; i < seq.Count; i++) { ASN1 entry = seq [i]; AppendEntry (sb, entry, true); // separator (not on last iteration) if (i < seq.Count - 1) sb.Append (", "); } return sb.ToString (); }
static public ASN1 FromInt32 (Int32 value) { byte[] integer = BitConverterLE.GetBytes (value); Array.Reverse (integer); int x = 0; while ((x < integer.Length) && (integer [x] == 0x00)) x++; ASN1 asn1 = new ASN1 (0x02); switch (x) { case 0: asn1.Value = integer; break; case 4: asn1.Value = new byte [1]; break; default: byte[] smallerInt = new byte [4 - x]; Buffer.BlockCopy (integer, x, smallerInt, 0, smallerInt.Length); asn1.Value = smallerInt; break; } return asn1; }
static private void AppendEntry (StringBuilder sb, ASN1 entry, bool quotes) { // multiple entries are valid for (int k = 0; k < entry.Count; k++) { ASN1 pair = entry [k]; ASN1 s = pair [1]; if (s == null) continue; ASN1 poid = pair [0]; if (poid == null) continue; if (poid.CompareValue (countryName)) sb.Append ("C="); else if (poid.CompareValue (organizationName)) sb.Append ("O="); else if (poid.CompareValue (organizationalUnitName)) sb.Append ("OU="); else if (poid.CompareValue (commonName)) sb.Append ("CN="); else if (poid.CompareValue (localityName)) sb.Append ("L="); else if (poid.CompareValue (stateOrProvinceName)) sb.Append ("S="); // NOTE: RFC2253 uses ST= else if (poid.CompareValue (streetAddress)) sb.Append ("STREET="); else if (poid.CompareValue (domainComponent)) sb.Append ("DC="); else if (poid.CompareValue (userid)) sb.Append ("UID="); else if (poid.CompareValue (email)) sb.Append ("E="); // NOTE: Not part of RFC2253 else if (poid.CompareValue (dnQualifier)) sb.Append ("dnQualifier="); else if (poid.CompareValue (title)) sb.Append ("T="); else if (poid.CompareValue (surname)) sb.Append ("SN="); else if (poid.CompareValue (givenName)) sb.Append ("G="); else if (poid.CompareValue (initial)) sb.Append ("I="); else { // unknown OID sb.Append ("OID."); // NOTE: Not present as RFC2253 sb.Append (ASN1Convert.ToOid (poid)); sb.Append ("="); } string sValue = null; // 16bits or 8bits string ? TODO not complete (+special chars!) if (s.Tag == 0x1E) { // BMPSTRING StringBuilder sb2 = new StringBuilder (); for (int j = 1; j < s.Value.Length; j += 2) sb2.Append ((char)s.Value[j]); sValue = sb2.ToString (); } else { if (s.Tag == 0x14) sValue = Encoding.UTF7.GetString (s.Value); else sValue = Encoding.UTF8.GetString (s.Value); // in some cases we must quote (") the value // Note: this doesn't seems to conform to RFC2253 char[] specials = { ',', '+', '"', '\\', '<', '>', ';' }; if (quotes) { if ((sValue.IndexOfAny (specials, 0, sValue.Length) > 0) || sValue.StartsWith (" ") || (sValue.EndsWith (" "))) sValue = "\"" + sValue + "\""; } } sb.Append (sValue); // separator (not on last iteration) if (k < entry.Count - 1) sb.Append (", "); } }
public ASN1 Add (ASN1 asn1) { if (asn1 != null) { if (elist == null) elist = new ArrayList (); elist.Add (asn1); } return asn1; }
private byte[] UniqueIdentifier (byte[] id) { // UniqueIdentifier ::= BIT STRING ASN1 uid = new ASN1 (0x03); // first byte in a BITSTRING is the number of unused bits in the first byte byte[] v = new byte [id.Length + 1]; Buffer.BlockCopy (id, 0, v, 1, id.Length); uid.Value = v; return uid.GetBytes (); }
// DSA only encode it's X private key inside an ASN.1 INTEGER (Hint: Tag == 0x02) // which isn't enough for rebuilding the keypair. The other parameters // can be found (98% of the time) in the X.509 certificate associated // with the private key or (2% of the time) the parameters are in it's // issuer X.509 certificate (not supported in the .NET framework). static public DSA DecodeDSA (byte[] privateKey, DSAParameters dsaParameters) { ASN1 pvk = new ASN1 (privateKey); if (pvk.Tag != 0x02) throw new CryptographicException ("invalid private key format"); // X is ALWAYS 20 bytes (no matter if the key length is 512 or 1024 bits) dsaParameters.X = Normalize (pvk.Value, 20); DSA dsa = DSA.Create (); dsa.ImportParameters (dsaParameters); return dsa; }
/* * RSAPrivateKey ::= SEQUENCE { * version Version, * modulus INTEGER, -- n * publicExponent INTEGER, -- e * privateExponent INTEGER, -- d * prime1 INTEGER, -- p * prime2 INTEGER, -- q * exponent1 INTEGER, -- d mod (p-1) * exponent2 INTEGER, -- d mod (q-1) * coefficient INTEGER, -- (inverse of q) mod p * otherPrimeInfos OtherPrimeInfos OPTIONAL * } */ static public RSA DecodeRSA (byte[] keypair) { ASN1 privateKey = new ASN1 (keypair); if (privateKey.Tag != 0x30) throw new CryptographicException ("invalid private key format"); ASN1 version = privateKey [0]; if (version.Tag != 0x02) throw new CryptographicException ("missing version"); if (privateKey.Count < 9) throw new CryptographicException ("not enough key parameters"); RSAParameters param = new RSAParameters (); // note: MUST remove leading 0 - else MS wont import the key param.Modulus = RemoveLeadingZero (privateKey [1].Value); int keysize = param.Modulus.Length; int keysize2 = (keysize >> 1); // half-size // size must be normalized - else MS wont import the key param.D = Normalize (privateKey [3].Value, keysize); param.DP = Normalize (privateKey [6].Value, keysize2); param.DQ = Normalize (privateKey [7].Value, keysize2); param.Exponent = RemoveLeadingZero (privateKey [2].Value); param.InverseQ = Normalize (privateKey [8].Value, keysize2); param.P = Normalize (privateKey [4].Value, keysize2); param.Q = Normalize (privateKey [5].Value, keysize2); RSA rsa = null; try { rsa = RSA.Create (); rsa.ImportParameters (param); } catch (CryptographicException) { // this may cause problem when this code is run under // the SYSTEM identity on Windows (e.g. ASP.NET). See // http://bugzilla.ximian.com/show_bug.cgi?id=77559 CspParameters csp = new CspParameters(); csp.Flags = CspProviderFlags.UseMachineKeyStore; rsa = new RSACryptoServiceProvider(csp); rsa.ImportParameters(param); } return rsa; }
// methods private void Decode (byte[] data) { ASN1 privateKeyInfo = new ASN1 (data); if (privateKeyInfo.Tag != 0x30) throw new CryptographicException ("invalid PrivateKeyInfo"); ASN1 version = privateKeyInfo [0]; if (version.Tag != 0x02) throw new CryptographicException ("invalid version"); _version = version.Value [0]; ASN1 privateKeyAlgorithm = privateKeyInfo [1]; if (privateKeyAlgorithm.Tag != 0x30) throw new CryptographicException ("invalid algorithm"); ASN1 algorithm = privateKeyAlgorithm [0]; if (algorithm.Tag != 0x06) throw new CryptographicException ("missing algorithm OID"); _algorithm = ASN1Convert.ToOid (algorithm); ASN1 privateKey = privateKeyInfo [2]; _key = privateKey.Value; // attributes [0] IMPLICIT Attributes OPTIONAL if (privateKeyInfo.Count > 3) { ASN1 attributes = privateKeyInfo [3]; for (int i=0; i < attributes.Count; i++) { _list.Add (attributes [i]); } } }
private ASN1 SecretBagSafeBag (byte[] secret, IDictionary attributes) { ASN1 safeBag = new ASN1 (0x30); safeBag.Add (ASN1Convert.FromOid (secretBag)); ASN1 bagValue = new ASN1 (0x80, secret); safeBag.Add (bagValue); if (attributes != null) { ASN1 bagAttributes = new ASN1 (0x31); IDictionaryEnumerator de = attributes.GetEnumerator (); while (de.MoveNext ()) { string oid = (string)de.Key; switch (oid) { case PKCS9.friendlyName: ArrayList names = (ArrayList)de.Value; if (names.Count > 0) { ASN1 pkcs12Attribute = new ASN1 (0x30); pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName)); ASN1 attrValues = new ASN1 (0x31); foreach (byte[] name in names) { ASN1 attrValue = new ASN1 (0x1e); attrValue.Value = name; attrValues.Add (attrValue); } pkcs12Attribute.Add (attrValues); bagAttributes.Add (pkcs12Attribute); } break; case PKCS9.localKeyId: ArrayList keys = (ArrayList)de.Value; if (keys.Count > 0) { ASN1 pkcs12Attribute = new ASN1 (0x30); pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId)); ASN1 attrValues = new ASN1 (0x31); foreach (byte[] key in keys) { ASN1 attrValue = new ASN1 (0x04); attrValue.Value = key; attrValues.Add (attrValue); } pkcs12Attribute.Add (attrValues); bagAttributes.Add (pkcs12Attribute); } break; default: break; } } if (bagAttributes.Count > 0) { safeBag.Add (bagAttributes); } } return safeBag; }
public virtual byte[] Sign (DSA key) { string oid = "1.2.840.10040.4.3"; ASN1 tbs = ToBeSigned (oid); HashAlgorithm ha = HashAlgorithm.Create (hashName); if (!(ha is SHA1)) throw new NotSupportedException ("Only SHA-1 is supported for DSA"); byte[] hash = ha.ComputeHash (tbs.GetBytes ()); DSASignatureFormatter dsa = new DSASignatureFormatter (key); dsa.SetHashAlgorithm (hashName); byte[] rs = dsa.CreateSignature (hash); // split R and S byte[] r = new byte [20]; Buffer.BlockCopy (rs, 0, r, 0, 20); byte[] s = new byte [20]; Buffer.BlockCopy (rs, 20, s, 0, 20); ASN1 signature = new ASN1 (0x30); signature.Add (new ASN1 (0x02, r)); signature.Add (new ASN1 (0x02, s)); // dsaWithSha1 (1 2 840 10040 4 3) return Build (tbs, oid, signature.GetBytes ()); }
static public DateTime ToDateTime (ASN1 time) { if (time == null) throw new ArgumentNullException ("time"); string t = Encoding.ASCII.GetString (time.Value); // to support both UTCTime and GeneralizedTime (and not so common format) string mask = null; int year; switch (t.Length) { case 11: // illegal format, still it's supported for compatibility mask = "yyMMddHHmmZ"; break; case 13: // RFC3280: 4.1.2.5.1 UTCTime year = Convert.ToInt16 (t.Substring (0, 2), CultureInfo.InvariantCulture); // Where YY is greater than or equal to 50, the // year SHALL be interpreted as 19YY; and // Where YY is less than 50, the year SHALL be // interpreted as 20YY. if (year >= 50) t = "19" + t; else t = "20" + t; mask = "yyyyMMddHHmmssZ"; break; case 15: mask = "yyyyMMddHHmmssZ"; // GeneralizedTime break; case 17: // another illegal format (990630000000+1000), again supported for compatibility year = Convert.ToInt16 (t.Substring (0, 2), CultureInfo.InvariantCulture); string century = (year >= 50) ? "19" : "20"; // ASN.1 (see ITU X.680 section 43.3) deals with offset differently than .NET char sign = (t[12] == '+') ? '-' : '+'; t = String.Format ("{0}{1}{2}{3}{4}:{5}{6}", century, t.Substring (0, 12), sign, t[13], t[14], t[15], t[16]); mask = "yyyyMMddHHmmsszzz"; break; } return DateTime.ParseExact (t, mask, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal); }
// Convert a binary encoded OID to human readable string representation of // an OID (IETF style). Based on DUMPASN1.C from Peter Gutmann. static public string ToOid (ASN1 asn1) { if (asn1 == null) throw new ArgumentNullException ("asn1"); byte[] aOID = asn1.Value; StringBuilder sb = new StringBuilder (); // Pick apart the OID byte x = (byte) (aOID[0] / 40); byte y = (byte) (aOID[0] % 40); if (x > 2) { // Handle special case for large y if x = 2 y += (byte) ((x - 2) * 40); x = 2; } sb.Append (x.ToString (CultureInfo.InvariantCulture)); sb.Append ("."); sb.Append (y.ToString (CultureInfo.InvariantCulture)); ulong val = 0; for (x = 1; x < aOID.Length; x++) { val = ((val << 7) | ((byte) (aOID [x] & 0x7F))); if ( !((aOID [x] & 0x80) == 0x80)) { sb.Append ("."); sb.Append (val.ToString (CultureInfo.InvariantCulture)); val = 0; } } return sb.ToString (); }
static public int ToInt32 (ASN1 asn1) { if (asn1 == null) throw new ArgumentNullException ("asn1"); if (asn1.Tag != 0x02) throw new FormatException ("Only integer can be converted"); int x = 0; for (int i=0; i < asn1.Value.Length; i++) x = (x << 8) + asn1.Value [i]; return x; }
protected override ASN1 ToBeSigned (string oid) { // TBSCertificate ASN1 tbsCert = new ASN1 (0x30); if (version > 1) { // TBSCertificate / [0] Version DEFAULT v1, byte[] ver = { (byte)(version - 1) }; ASN1 v = tbsCert.Add (new ASN1 (0xA0)); v.Add (new ASN1 (0x02, ver)); } // TBSCertificate / CertificateSerialNumber, tbsCert.Add (new ASN1 (0x02, sn)); // TBSCertificate / AlgorithmIdentifier, tbsCert.Add (PKCS7.AlgorithmIdentifier (oid)); // TBSCertificate / Name tbsCert.Add (X501.FromString (issuer)); // TBSCertificate / Validity ASN1 validity = tbsCert.Add (new ASN1 (0x30)); // TBSCertificate / Validity / Time validity.Add (ASN1Convert.FromDateTime (notBefore)); // TBSCertificate / Validity / Time validity.Add (ASN1Convert.FromDateTime (notAfter)); // TBSCertificate / Name tbsCert.Add (X501.FromString (subject)); // TBSCertificate / SubjectPublicKeyInfo tbsCert.Add (SubjectPublicKeyInfo ()); if (version > 1) { // TBSCertificate / [1] IMPLICIT UniqueIdentifier OPTIONAL if (issuerUniqueID != null) tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (issuerUniqueID))); // TBSCertificate / [2] IMPLICIT UniqueIdentifier OPTIONAL if (subjectUniqueID != null) tbsCert.Add (new ASN1 (0xA1, UniqueIdentifier (subjectUniqueID))); // TBSCertificate / [3] Extensions OPTIONAL if ((version > 2) && (extensions.Count > 0)) tbsCert.Add (new ASN1 (0xA3, extensions.GetBytes ())); } return tbsCert; }
static public ASN1 FromString (string rdn) { if (rdn == null) throw new ArgumentNullException ("rdn"); int pos = 0; ASN1 asn1 = new ASN1 (0x30); while (pos < rdn.Length) { X520.AttributeTypeAndValue atv = ReadAttribute (rdn, ref pos); atv.Value = ReadValue (rdn, ref pos); ASN1 sequence = new ASN1 (0x31); sequence.Add (atv.GetASN1 ()); asn1.Add (sequence); } return asn1; }
private byte[] Build (ASN1 tbs, string hashoid, byte[] signature) { ASN1 builder = new ASN1 (0x30); builder.Add (tbs); builder.Add (PKCS7.AlgorithmIdentifier (hashoid)); // first byte of BITSTRING is the number of unused bits in the first byte byte[] bitstring = new byte [signature.Length + 1]; Buffer.BlockCopy (signature, 0, bitstring, 1, signature.Length); builder.Add (new ASN1 (0x03, bitstring)); return builder.GetBytes (); }
internal ASN1 GetASN1 (byte encoding) { byte encode = encoding; if (encode == 0xFF) encode = SelectBestEncoding (); ASN1 asn1 = new ASN1 (0x30); asn1.Add (ASN1Convert.FromOid (oid)); switch (encode) { case 0x13: // PRINTABLESTRING asn1.Add (new ASN1 (0x13, Encoding.ASCII.GetBytes (attrValue))); break; case 0x16: // IA5STRING asn1.Add (new ASN1 (0x16, Encoding.ASCII.GetBytes (attrValue))); break; case 0x1E: // BMPSTRING asn1.Add (new ASN1 (0x1E, Encoding.BigEndianUnicode.GetBytes (attrValue))); break; } return asn1; }
// that's were the real job is! private void Parse (byte[] data) { try { decoder = new ASN1 (data); // Certificate if (decoder.Tag != 0x30) throw new CryptographicException (encoding_error); // Certificate / TBSCertificate if (decoder [0].Tag != 0x30) throw new CryptographicException (encoding_error); ASN1 tbsCertificate = decoder [0]; int tbs = 0; // Certificate / TBSCertificate / Version ASN1 v = decoder [0][tbs]; version = 1; // DEFAULT v1 if ((v.Tag == 0xA0) && (v.Count > 0)) { // version (optional) is present only in v2+ certs version += v [0].Value [0]; // zero based tbs++; } // Certificate / TBSCertificate / CertificateSerialNumber ASN1 sn = decoder [0][tbs++]; if (sn.Tag != 0x02) throw new CryptographicException (encoding_error); serialnumber = sn.Value; Array.Reverse (serialnumber, 0, serialnumber.Length); // Certificate / TBSCertificate / AlgorithmIdentifier tbs++; // ASN1 signatureAlgo = tbsCertificate.Element (tbs++, 0x30); issuer = tbsCertificate.Element (tbs++, 0x30); m_issuername = X501.ToString (issuer); ASN1 validity = tbsCertificate.Element (tbs++, 0x30); ASN1 notBefore = validity [0]; m_from = ASN1Convert.ToDateTime (notBefore); ASN1 notAfter = validity [1]; m_until = ASN1Convert.ToDateTime (notAfter); subject = tbsCertificate.Element (tbs++, 0x30); m_subject = X501.ToString (subject); ASN1 subjectPublicKeyInfo = tbsCertificate.Element (tbs++, 0x30); ASN1 algorithm = subjectPublicKeyInfo.Element (0, 0x30); ASN1 algo = algorithm.Element (0, 0x06); m_keyalgo = ASN1Convert.ToOid (algo); // parameters ANY DEFINED BY algorithm OPTIONAL // so we dont ask for a specific (Element) type and return DER ASN1 parameters = algorithm [1]; m_keyalgoparams = ((algorithm.Count > 1) ? parameters.GetBytes () : null); ASN1 subjectPublicKey = subjectPublicKeyInfo.Element (1, 0x03); // we must drop th first byte (which is the number of unused bits // in the BITSTRING) int n = subjectPublicKey.Length - 1; m_publickey = new byte [n]; Buffer.BlockCopy (subjectPublicKey.Value, 1, m_publickey, 0, n); // signature processing byte[] bitstring = decoder [2].Value; // first byte contains unused bits in first byte signature = new byte [bitstring.Length - 1]; Buffer.BlockCopy (bitstring, 1, signature, 0, signature.Length); algorithm = decoder [1]; algo = algorithm.Element (0, 0x06); m_signaturealgo = ASN1Convert.ToOid (algo); parameters = algorithm [1]; if (parameters != null) m_signaturealgoparams = parameters.GetBytes (); else m_signaturealgoparams = null; // Certificate / TBSCertificate / issuerUniqueID ASN1 issuerUID = tbsCertificate.Element (tbs, 0x81); if (issuerUID != null) { tbs++; issuerUniqueID = issuerUID.Value; } // Certificate / TBSCertificate / subjectUniqueID ASN1 subjectUID = tbsCertificate.Element (tbs, 0x82); if (subjectUID != null) { tbs++; subjectUniqueID = subjectUID.Value; } // Certificate / TBSCertificate / Extensions ASN1 extns = tbsCertificate.Element (tbs, 0xA3); if ((extns != null) && (extns.Count == 1)) extensions = new X509ExtensionCollection (extns [0]); else extensions = new X509ExtensionCollection (null); // keep a copy of the original data m_encodedcert = (byte[]) data.Clone (); } catch (Exception ex) { throw new CryptographicException (encoding_error, ex); } }
public byte[] GetBytes () { if (InnerList.Count < 1) return null; ASN1 sequence = new ASN1 (0x30); for (int i=0; i < InnerList.Count; i++) { X509Extension x = (X509Extension) InnerList [i]; sequence.Add (x.ASN1); } return sequence.GetBytes (); }
public byte[] GetBytes () { ASN1 privateKeyAlgorithm = new ASN1 (0x30); privateKeyAlgorithm.Add (ASN1Convert.FromOid (_algorithm)); privateKeyAlgorithm.Add (new ASN1 (0x05)); // ASN.1 NULL ASN1 pki = new ASN1 (0x30); pki.Add (new ASN1 (0x02, new byte [1] { (byte) _version })); pki.Add (privateKeyAlgorithm); pki.Add (new ASN1 (0x04, _key)); if (_list.Count > 0) { ASN1 attributes = new ASN1 (0xA0); foreach (ASN1 attribute in _list) { attributes.Add (attribute); } pki.Add (attributes); } return pki.GetBytes (); }
// Note: PKCS#8 doesn't define how to generate the key required for encryption // so you're on your own. Just don't try to copy the big guys too much ;) // Netscape: http://www.cs.auckland.ac.nz/~pgut001/pubs/netscape.txt // Microsoft: http://www.cs.auckland.ac.nz/~pgut001/pubs/breakms.txt public byte[] GetBytes () { if (_algorithm == null) throw new CryptographicException ("No algorithm OID specified"); ASN1 encryptionAlgorithm = new ASN1 (0x30); encryptionAlgorithm.Add (ASN1Convert.FromOid (_algorithm)); // parameters ANY DEFINED BY algorithm OPTIONAL if ((_iterations > 0) || (_salt != null)) { ASN1 salt = new ASN1 (0x04, _salt); ASN1 iterations = ASN1Convert.FromInt32 (_iterations); ASN1 parameters = new ASN1 (0x30); parameters.Add (salt); parameters.Add (iterations); encryptionAlgorithm.Add (parameters); } // encapsulates EncryptedData into an OCTET STRING ASN1 encryptedData = new ASN1 (0x04, _data); ASN1 encryptedPrivateKeyInfo = new ASN1 (0x30); encryptedPrivateKeyInfo.Add (encryptionAlgorithm); encryptedPrivateKeyInfo.Add (encryptedData); return encryptedPrivateKeyInfo.GetBytes (); }
/* * RSAPrivateKey ::= SEQUENCE { * version Version, * modulus INTEGER, -- n * publicExponent INTEGER, -- e * privateExponent INTEGER, -- d * prime1 INTEGER, -- p * prime2 INTEGER, -- q * exponent1 INTEGER, -- d mod (p-1) * exponent2 INTEGER, -- d mod (q-1) * coefficient INTEGER, -- (inverse of q) mod p * otherPrimeInfos OtherPrimeInfos OPTIONAL * } */ static public byte[] Encode (RSA rsa) { RSAParameters param = rsa.ExportParameters (true); ASN1 rsaPrivateKey = new ASN1 (0x30); rsaPrivateKey.Add (new ASN1 (0x02, new byte [1] { 0x00 })); rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.Modulus)); rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.Exponent)); rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.D)); rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.P)); rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.Q)); rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.DP)); rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.DQ)); rsaPrivateKey.Add (ASN1Convert.FromUnsignedBigInteger (param.InverseQ)); return rsaPrivateKey.GetBytes (); }
private ASN1 KeyBagSafeBag (AsymmetricAlgorithm aa, IDictionary attributes) { PKCS8.PrivateKeyInfo pki = new PKCS8.PrivateKeyInfo (); if (aa is RSA) { pki.Algorithm = "1.2.840.113549.1.1.1"; pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((RSA)aa); } else if (aa is DSA) { pki.Algorithm = null; pki.PrivateKey = PKCS8.PrivateKeyInfo.Encode ((DSA)aa); } else throw new CryptographicException ("Unknown asymmetric algorithm {0}", aa.ToString ()); ASN1 safeBag = new ASN1 (0x30); safeBag.Add (ASN1Convert.FromOid (keyBag)); ASN1 bagValue = new ASN1 (0xA0); bagValue.Add (new ASN1 (pki.GetBytes ())); safeBag.Add (bagValue); if (attributes != null) { ASN1 bagAttributes = new ASN1 (0x31); IDictionaryEnumerator de = attributes.GetEnumerator (); while (de.MoveNext ()) { string oid = (string)de.Key; switch (oid) { case PKCS9.friendlyName: ArrayList names = (ArrayList)de.Value; if (names.Count > 0) { ASN1 pkcs12Attribute = new ASN1 (0x30); pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.friendlyName)); ASN1 attrValues = new ASN1 (0x31); foreach (byte[] name in names) { ASN1 attrValue = new ASN1 (0x1e); attrValue.Value = name; attrValues.Add (attrValue); } pkcs12Attribute.Add (attrValues); bagAttributes.Add (pkcs12Attribute); } break; case PKCS9.localKeyId: ArrayList keys = (ArrayList)de.Value; if (keys.Count > 0) { ASN1 pkcs12Attribute = new ASN1 (0x30); pkcs12Attribute.Add (ASN1Convert.FromOid (PKCS9.localKeyId)); ASN1 attrValues = new ASN1 (0x31); foreach (byte[] key in keys) { ASN1 attrValue = new ASN1 (0x04); attrValue.Value = key; attrValues.Add (attrValue); } pkcs12Attribute.Add (attrValues); bagAttributes.Add (pkcs12Attribute); } break; default: break; } } if (bagAttributes.Count > 0) { safeBag.Add (bagAttributes); } } return safeBag; }
// methods private void Decode (byte[] data) { ASN1 encryptedPrivateKeyInfo = new ASN1 (data); if (encryptedPrivateKeyInfo.Tag != 0x30) throw new CryptographicException ("invalid EncryptedPrivateKeyInfo"); ASN1 encryptionAlgorithm = encryptedPrivateKeyInfo [0]; if (encryptionAlgorithm.Tag != 0x30) throw new CryptographicException ("invalid encryptionAlgorithm"); ASN1 algorithm = encryptionAlgorithm [0]; if (algorithm.Tag != 0x06) throw new CryptographicException ("invalid algorithm"); _algorithm = ASN1Convert.ToOid (algorithm); // parameters ANY DEFINED BY algorithm OPTIONAL if (encryptionAlgorithm.Count > 1) { ASN1 parameters = encryptionAlgorithm [1]; if (parameters.Tag != 0x30) throw new CryptographicException ("invalid parameters"); ASN1 salt = parameters [0]; if (salt.Tag != 0x04) throw new CryptographicException ("invalid salt"); _salt = salt.Value; ASN1 iterationCount = parameters [1]; if (iterationCount.Tag != 0x02) throw new CryptographicException ("invalid iterationCount"); _iterations = ASN1Convert.ToInt32 (iterationCount); } ASN1 encryptedData = encryptedPrivateKeyInfo [1]; if (encryptedData.Tag != 0x04) throw new CryptographicException ("invalid EncryptedData"); _data = encryptedData.Value; }
/* SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING } */ private ASN1 SubjectPublicKeyInfo () { ASN1 keyInfo = new ASN1 (0x30); if (aa is RSA) { keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.113549.1.1.1")); RSAParameters p = (aa as RSA).ExportParameters (false); /* RSAPublicKey ::= SEQUENCE { * modulus INTEGER, -- n * publicExponent INTEGER } -- e */ ASN1 key = new ASN1 (0x30); key.Add (ASN1Convert.FromUnsignedBigInteger (p.Modulus)); key.Add (ASN1Convert.FromUnsignedBigInteger (p.Exponent)); keyInfo.Add (new ASN1 (UniqueIdentifier (key.GetBytes ()))); } else if (aa is DSA) { DSAParameters p = (aa as DSA).ExportParameters (false); /* Dss-Parms ::= SEQUENCE { * p INTEGER, * q INTEGER, * g INTEGER } */ ASN1 param = new ASN1 (0x30); param.Add (ASN1Convert.FromUnsignedBigInteger (p.P)); param.Add (ASN1Convert.FromUnsignedBigInteger (p.Q)); param.Add (ASN1Convert.FromUnsignedBigInteger (p.G)); keyInfo.Add (PKCS7.AlgorithmIdentifier ("1.2.840.10040.4.1", param)); ASN1 key = keyInfo.Add (new ASN1 (0x03)); // DSAPublicKey ::= INTEGER -- public key, y key.Add (ASN1Convert.FromUnsignedBigInteger (p.Y)); } else throw new NotSupportedException ("Unknown Asymmetric Algorithm " + aa.ToString ()); return keyInfo; }
// PKCS #1 v.2.1, Section 9.2 // EMSA-PKCS1-v1_5-Encode public static byte[] Encode_v15 (HashAlgorithm hash, byte[] hashValue, int emLength) { if (hashValue.Length != (hash.HashSize >> 3)) throw new CryptographicException ("bad hash length for " + hash.ToString ()); // DigestInfo ::= SEQUENCE { // digestAlgorithm AlgorithmIdentifier, // digest OCTET STRING // } byte[] t = null; string oid = CryptoConfig.MapNameToOID (hash.ToString ()); if (oid != null) { ASN1 digestAlgorithm = new ASN1 (0x30); digestAlgorithm.Add (new ASN1 (CryptoConfig.EncodeOID (oid))); digestAlgorithm.Add (new ASN1 (0x05)); // NULL ASN1 digest = new ASN1 (0x04, hashValue); ASN1 digestInfo = new ASN1 (0x30); digestInfo.Add (digestAlgorithm); digestInfo.Add (digest); t = digestInfo.GetBytes (); } else { // There are no valid OID, in this case t = hashValue // This is the case of the MD5SHA hash algorithm t = hashValue; } Buffer.BlockCopy (hashValue, 0, t, t.Length - hashValue.Length, hashValue.Length); int PSLength = System.Math.Max (8, emLength - t.Length - 3); // PS = PSLength of 0xff // EM = 0x00 | 0x01 | PS | 0x00 | T byte[] EM = new byte [PSLength + t.Length + 3]; EM [1] = 0x01; for (int i=2; i < PSLength + 2; i++) EM[i] = 0xff; Buffer.BlockCopy (t, 0, EM, PSLength + 3, t.Length); return EM; }
private void ReadSafeBag (ASN1 safeBag) { if (safeBag.Tag != 0x30) throw new ArgumentException ("invalid safeBag"); ASN1 bagId = safeBag [0]; if (bagId.Tag != 0x06) throw new ArgumentException ("invalid safeBag id"); ASN1 bagValue = safeBag [1]; string oid = ASN1Convert.ToOid (bagId); switch (oid) { case keyBag: // NEED UNIT TEST AddPrivateKey (new PKCS8.PrivateKeyInfo (bagValue.Value)); break; case pkcs8ShroudedKeyBag: PKCS8.EncryptedPrivateKeyInfo epki = new PKCS8.EncryptedPrivateKeyInfo (bagValue.Value); byte[] decrypted = Decrypt (epki.Algorithm, epki.Salt, epki.IterationCount, epki.EncryptedData); AddPrivateKey (new PKCS8.PrivateKeyInfo (decrypted)); Array.Clear (decrypted, 0, decrypted.Length); break; case certBag: PKCS7.ContentInfo cert = new PKCS7.ContentInfo (bagValue.Value); if (cert.ContentType != x509Certificate) throw new NotSupportedException ("unsupport certificate type"); X509Certificate x509 = new X509Certificate (cert.Content [0].Value); _certs.Add (x509); break; case crlBag: // TODO break; case secretBag: byte[] secret = bagValue.Value; _secretBags.Add(secret); break; case safeContentsBag: // TODO - ? recurse ? break; default: throw new ArgumentException ("unknown safeBag oid"); } if (safeBag.Count > 2) { ASN1 bagAttributes = safeBag [2]; if (bagAttributes.Tag != 0x31) throw new ArgumentException ("invalid safeBag attributes id"); for (int i = 0; i < bagAttributes.Count; i++) { ASN1 pkcs12Attribute = bagAttributes[i]; if (pkcs12Attribute.Tag != 0x30) throw new ArgumentException ("invalid PKCS12 attributes id"); ASN1 attrId = pkcs12Attribute [0]; if (attrId.Tag != 0x06) throw new ArgumentException ("invalid attribute id"); string attrOid = ASN1Convert.ToOid (attrId); ASN1 attrValues = pkcs12Attribute[1]; for (int j = 0; j < attrValues.Count; j++) { ASN1 attrValue = attrValues[j]; switch (attrOid) { case PKCS9.friendlyName: if (attrValue.Tag != 0x1e) throw new ArgumentException ("invalid attribute value id"); break; case PKCS9.localKeyId: if (attrValue.Tag != 0x04) throw new ArgumentException ("invalid attribute value id"); break; default: // Unknown OID -- don't check Tag break; } } } } _safeBags.Add (new SafeBag(oid, safeBag)); }