<commit_before>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;

using Internal.Cryptography;
using Internal.Cryptography.Pal;

namespace System.Security.Cryptography.X509Certificates
{
    public class X509Certificate : IDisposable
    {
        public X509Certificate()
        {
        }

        public X509Certificate(byte[] data)
        {
            if (data != null && data.Length != 0)  // For compat reasons, this constructor treats passing a null or empty data set as the same as calling the nullary constructor.
                Pal = CertificatePal.FromBlob(data, null, X509KeyStorageFlags.DefaultKeySet);
        }

        public X509Certificate(byte[] rawData, string password)
            : this(rawData, password, X509KeyStorageFlags.DefaultKeySet)
        {
        }

        public X509Certificate(byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
        {
            if (rawData == null || rawData.Length == 0)
                throw new ArgumentException(SR.Arg_EmptyOrNullArray, "rawData");
            if ((keyStorageFlags & ~KeyStorageFlagsAll) != 0)
                throw new ArgumentException(SR.Argument_InvalidFlag, "keyStorageFlags");

            Pal = CertificatePal.FromBlob(rawData, password, keyStorageFlags);
        }

        public X509Certificate(IntPtr handle)
        {
            Pal = CertificatePal.FromHandle(handle);
        }

        internal X509Certificate(ICertificatePal pal)
        {
            Debug.Assert(pal != null);
            Pal = pal;
        }

        public X509Certificate(string fileName)
            : this(fileName, null, X509KeyStorageFlags.DefaultKeySet)
        {
        }

        public X509Certificate(string fileName, string password)
            : this(fileName, password, X509KeyStorageFlags.DefaultKeySet)
        {
        }

        public X509Certificate(string fileName, string password, X509KeyStorageFlags keyStorageFlags)
        {
            if (fileName == null)
                throw new ArgumentNullException("fileName");
            if ((keyStorageFlags & ~KeyStorageFlagsAll) != 0)
                throw new ArgumentException(SR.Argument_InvalidFlag, "keyStorageFlags");

            Pal = CertificatePal.FromFile(fileName, password, keyStorageFlags);
        }

        public IntPtr Handle
        {
            get
            {
                if (Pal == null)
                    return IntPtr.Zero;
                else
                    return Pal.Handle;
            }
        }

        public string Issuer
        {
            get
            {
                ThrowIfInvalid();

                string issuer = _lazyIssuer;
                if (issuer == null)
                    issuer = _lazyIssuer = Pal.Issuer;
                return issuer;
            }
        }

        public string Subject
        {
            get
            {
                ThrowIfInvalid();

                string subject = _lazySubject;
                if (subject == null)
                    subject = _lazySubject = Pal.Subject;
                return subject;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                ICertificatePal pal = Pal;
                Pal = null;
                if (pal != null)
                    pal.Dispose();
            }
        }

        public override bool Equals(object obj)
        {
            X509Certificate other = obj as X509Certificate;
            if (other == null)
                return false;
            return Equals(other);
        }

        public virtual bool Equals(X509Certificate other)
        {
            if (other == null)
                return false;

            if (Pal == null)
                return other.Pal == null;

            if (!Issuer.Equals(other.Issuer))
                return false;

            byte[] thisSerialNumber = GetSerialNumber();
            byte[] otherSerialNumber = other.GetSerialNumber();
            if (thisSerialNumber.Length != otherSerialNumber.Length)
                return false;
            for (int i = 0; i < thisSerialNumber.Length; i++)
            {
                if (thisSerialNumber[i] != otherSerialNumber[i])
                    return false;
            }

            return true;
        }

        public virtual byte[] Export(X509ContentType contentType)
        {
            return Export(contentType, null);
        }

        public virtual byte[] Export(X509ContentType contentType, string password)
        {
            if (!(contentType == X509ContentType.Cert || contentType == X509ContentType.SerializedCert || contentType == X509ContentType.Pkcs12))
                throw new CryptographicException(SR.Cryptography_X509_InvalidContentType);

            if (Pal == null)
                throw new CryptographicException(ErrorCode.E_POINTER);  // Not the greatest error, but needed for backward compat.

            using (IStorePal storePal = StorePal.FromCertificate(Pal))
            {
                return storePal.Export(contentType, password);
            }
        }

        public virtual byte[] GetCertHash()
        {
            ThrowIfInvalid();

            byte[] certHash = _lazyCertHash;
            if (certHash == null)
                _lazyCertHash = certHash = Pal.Thumbprint;

            return certHash.CloneByteArray();
        }

        public virtual string GetFormat()
        {
            return "X509";
        }

        public override int GetHashCode()
        {
            if (Pal == null)
                return 0;

            byte[] thumbPrint = GetCertHash();
            int value = 0;
            for (int i = 0; i < thumbPrint.Length && i < 4; ++i)
            {
                value = value << 8 | thumbPrint[i];
            }
            return value;
        }

        public virtual string GetKeyAlgorithm()
        {
            ThrowIfInvalid();

            string keyAlgorithm = _lazyKeyAlgorithm;
            if (keyAlgorithm == null)
                keyAlgorithm = _lazyKeyAlgorithm = Pal.KeyAlgorithm;
            return keyAlgorithm;
        }

        public virtual byte[] GetKeyAlgorithmParameters()
        {
            ThrowIfInvalid();

            byte[] keyAlgorithmParameters = _lazyKeyAlgorithmParameters;
            if (keyAlgorithmParameters == null)
                keyAlgorithmParameters = _lazyKeyAlgorithmParameters = Pal.KeyAlgorithmParameters;
            return keyAlgorithmParameters.CloneByteArray();
        }

        public virtual string GetKeyAlgorithmParametersString()
        {
            ThrowIfInvalid();

            byte[] keyAlgorithmParameters = GetKeyAlgorithmParameters();
            return keyAlgorithmParameters.ToHexStringUpper();
        }

        public virtual byte[] GetPublicKey()
        {
            ThrowIfInvalid();

            byte[] publicKey = _lazyPublicKey;
            if (publicKey == null)
                publicKey = _lazyPublicKey = Pal.PublicKeyValue;
            return publicKey.CloneByteArray();
        }

        public virtual byte[] GetSerialNumber()
        {
            ThrowIfInvalid();

            byte[] serialNumber = _lazySerialNumber;
            if (serialNumber == null)
                serialNumber = _lazySerialNumber = Pal.SerialNumber;
            return serialNumber.CloneByteArray();
        }

        public override string ToString()
        {
            return ToString(fVerbose: false);
        }

        public virtual string ToString(bool fVerbose)
        {
            if (fVerbose == false || Pal == null)
                return GetType().ToString();

            StringBuilder sb = new StringBuilder();

            // Subject
            sb.AppendLine("[Subject]");
            sb.Append("  ");
            sb.AppendLine(Subject);

            // Issuer
            sb.AppendLine();
            sb.AppendLine("[Issuer]");
            sb.Append("  ");
            sb.AppendLine(Issuer);

            // Serial Number
            sb.AppendLine();
            sb.AppendLine("[Serial Number]");
            sb.Append("  ");
            byte[] serialNumber = GetSerialNumber();
            Array.Reverse(serialNumber);
            sb.Append(serialNumber.ToHexArrayUpper());
            sb.AppendLine();

            // NotBefore
            sb.AppendLine();
            sb.AppendLine("[Not Before]");
            sb.Append("  ");
            sb.AppendLine(FormatDate(GetNotBefore()));

            // NotAfter
            sb.AppendLine();
            sb.AppendLine("[Not After]");
            sb.Append("  ");
            sb.AppendLine(FormatDate(GetNotAfter()));

            // Thumbprint
            sb.AppendLine();
            sb.AppendLine("[Thumbprint]");
            sb.Append("  ");
            sb.Append(GetCertHash().ToHexArrayUpper());
            sb.AppendLine();
<commit_msg>Improve perf of X509Certificate.GetHashCode/Equals<commit_after>// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;

using Internal.Cryptography;
using Internal.Cryptography.Pal;

namespace System.Security.Cryptography.X509Certificates
{
    public class X509Certificate : IDisposable
    {
        public X509Certificate()
        {
        }

        public X509Certificate(byte[] data)
        {
            if (data != null && data.Length != 0)  // For compat reasons, this constructor treats passing a null or empty data set as the same as calling the nullary constructor.
                Pal = CertificatePal.FromBlob(data, null, X509KeyStorageFlags.DefaultKeySet);
        }

        public X509Certificate(byte[] rawData, string password)
            : this(rawData, password, X509KeyStorageFlags.DefaultKeySet)
        {
        }

        public X509Certificate(byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
        {
            if (rawData == null || rawData.Length == 0)
                throw new ArgumentException(SR.Arg_EmptyOrNullArray, "rawData");
            if ((keyStorageFlags & ~KeyStorageFlagsAll) != 0)
                throw new ArgumentException(SR.Argument_InvalidFlag, "keyStorageFlags");

            Pal = CertificatePal.FromBlob(rawData, password, keyStorageFlags);
        }

        public X509Certificate(IntPtr handle)
        {
            Pal = CertificatePal.FromHandle(handle);
        }

        internal X509Certificate(ICertificatePal pal)
        {
            Debug.Assert(pal != null);
            Pal = pal;
        }

        public X509Certificate(string fileName)
            : this(fileName, null, X509KeyStorageFlags.DefaultKeySet)
        {
        }

        public X509Certificate(string fileName, string password)
            : this(fileName, password, X509KeyStorageFlags.DefaultKeySet)
        {
        }

        public X509Certificate(string fileName, string password, X509KeyStorageFlags keyStorageFlags)
        {
            if (fileName == null)
                throw new ArgumentNullException("fileName");
            if ((keyStorageFlags & ~KeyStorageFlagsAll) != 0)
                throw new ArgumentException(SR.Argument_InvalidFlag, "keyStorageFlags");

            Pal = CertificatePal.FromFile(fileName, password, keyStorageFlags);
        }

        public IntPtr Handle
        {
            get
            {
                if (Pal == null)
                    return IntPtr.Zero;
                else
                    return Pal.Handle;
            }
        }

        public string Issuer
        {
            get
            {
                ThrowIfInvalid();

                string issuer = _lazyIssuer;
                if (issuer == null)
                    issuer = _lazyIssuer = Pal.Issuer;
                return issuer;
            }
        }

        public string Subject
        {
            get
            {
                ThrowIfInvalid();

                string subject = _lazySubject;
                if (subject == null)
                    subject = _lazySubject = Pal.Subject;
                return subject;
            }
        }

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                ICertificatePal pal = Pal;
                Pal = null;
                if (pal != null)
                    pal.Dispose();
            }
        }

        public override bool Equals(object obj)
        {
            X509Certificate other = obj as X509Certificate;
            if (other == null)
                return false;
            return Equals(other);
        }

        public virtual bool Equals(X509Certificate other)
        {
            if (other == null)
                return false;

            if (Pal == null)
                return other.Pal == null;

            if (!Issuer.Equals(other.Issuer))
                return false;

            byte[] thisSerialNumber = GetRawSerialNumber();
            byte[] otherSerialNumber = other.GetRawSerialNumber();

            if (thisSerialNumber.Length != otherSerialNumber.Length)
                return false;
            for (int i = 0; i < thisSerialNumber.Length; i++)
            {
                if (thisSerialNumber[i] != otherSerialNumber[i])
                    return false;
            }

            return true;
        }

        public virtual byte[] Export(X509ContentType contentType)
        {
            return Export(contentType, null);
        }

        public virtual byte[] Export(X509ContentType contentType, string password)
        {
            if (!(contentType == X509ContentType.Cert || contentType == X509ContentType.SerializedCert || contentType == X509ContentType.Pkcs12))
                throw new CryptographicException(SR.Cryptography_X509_InvalidContentType);

            if (Pal == null)
                throw new CryptographicException(ErrorCode.E_POINTER);  // Not the greatest error, but needed for backward compat.

            using (IStorePal storePal = StorePal.FromCertificate(Pal))
            {
                return storePal.Export(contentType, password);
            }
        }

        public virtual byte[] GetCertHash()
        {
            ThrowIfInvalid();
            return GetRawCertHash().CloneByteArray();
        }

        // Only use for internal purposes when the returned byte[] will not be mutated
        private byte[] GetRawCertHash()
        {
            return _lazyCertHash ?? (_lazyCertHash = Pal.Thumbprint);
        }

        public virtual string GetFormat()
        {
            return "X509";
        }

        public override int GetHashCode()
        {
            if (Pal == null)
                return 0;

            byte[] thumbPrint = GetRawCertHash();
            int value = 0;
            for (int i = 0; i < thumbPrint.Length && i < 4; ++i)
            {
                value = value << 8 | thumbPrint[i];
            }
            return value;
        }

        public virtual string GetKeyAlgorithm()
        {
            ThrowIfInvalid();

            string keyAlgorithm = _lazyKeyAlgorithm;
            if (keyAlgorithm == null)
                keyAlgorithm = _lazyKeyAlgorithm = Pal.KeyAlgorithm;
            return keyAlgorithm;
        }

        public virtual byte[] GetKeyAlgorithmParameters()
        {
            ThrowIfInvalid();

            byte[] keyAlgorithmParameters = _lazyKeyAlgorithmParameters;
            if (keyAlgorithmParameters == null)
                keyAlgorithmParameters = _lazyKeyAlgorithmParameters = Pal.KeyAlgorithmParameters;
            return keyAlgorithmParameters.CloneByteArray();
        }

        public virtual string GetKeyAlgorithmParametersString()
        {
            ThrowIfInvalid();

            byte[] keyAlgorithmParameters = GetKeyAlgorithmParameters();
            return keyAlgorithmParameters.ToHexStringUpper();
        }

        public virtual byte[] GetPublicKey()
        {
            ThrowIfInvalid();

            byte[] publicKey = _lazyPublicKey;
            if (publicKey == null)
                publicKey = _lazyPublicKey = Pal.PublicKeyValue;
            return publicKey.CloneByteArray();
        }

        public virtual byte[] GetSerialNumber()
        {
            ThrowIfInvalid();

            return GetRawSerialNumber().CloneByteArray();
        }

        // Only use for internal purposes when the returned byte[] will not be mutated
        private byte[] GetRawSerialNumber()
        {
            return _lazySerialNumber ?? (_lazySerialNumber = Pal.SerialNumber);
        }

        public override string ToString()
        {
            return ToString(fVerbose: false);
        }

        public virtual string ToString(bool fVerbose)
        {
            if (fVerbose == false || Pal == null)
                return GetType().ToString();

            StringBuilder sb = new StringBuilder();

            // Subject
            sb.AppendLine("[Subject]");
            sb.Append("  ");
            sb.AppendLine(Subject);

            // Issuer
            sb.AppendLine();
            sb.AppendLine("[Issuer]");
            sb.Append("  ");
            sb.AppendLine(Issuer);

            // Serial Number
            sb.AppendLine();
            sb.AppendLine("[Serial Number]");
            sb.Append("  ");
            byte[] serialNumber = GetSerialNumber();
            Array.Reverse(serialNumber);
            sb.Append(serialNumber.ToHexArrayUpper());
            sb.AppendLine();

            // NotBefore
            sb.AppendLine();
            sb.AppendLine("[Not Before]");
            sb.Append("  ");
            sb.AppendLine(FormatDate(GetNotBefore()));

            // NotAfter
            sb.AppendLine();
            sb.AppendLine("[Not After]");
            sb.Append("  ");
            sb.AppendLine(FormatDate(GetNotAfter()));

            // Thumbprint
            sb.AppendLine();
            sb.AppendLine("[Thumbprint]");
            sb.Append("  ");
            sb.Append(GetRawCertHash().ToHexArrayUpper());
            sb.AppendLine();

{'fraction_non_alphanumeric': 0.08705380927011189, 'fraction_numerical': 0.010069259456579648, 'mean_word_length': 1.6016632016632018, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7397801', 'n_tokens_mistral': 4757, 'n_tokens_neox': 4450, 'n_words': 1103}