DELPHI 利用OpenSSL实现加解密,证书(X.509)等功能

基于OpenSSL 1.1.1,主要有RSA,X,509,ECC,SM,AES,GCM,HAMC,ENC等测试

DELPHI版本是11.X

Delphi 复制代码
主要功能类:

//*
//* Janker Changed FROM Grijjy Demo
//* OpenSSL 1.1.1

unit JkSoft.Crypto.OpenSSL11;

interface

uses
  System.SysUtils, System.Classes, System.NetEncoding, System.Generics.Collections,
  System.JSON, {为了处理CreatePublicJWKFromPEM()和CreatePublicPEMFromJWK()添加,直接是使用了Json字符串}
  JkSoft.Crypto.OpenSSL11.API;

const
  { Default bits for RSA}
  RSA_KEY_BITS = 2048;
  // Auth tag size
  AUTH_TAG_LEN = 16;

  //AES
  CTX_AES_KEY_LEN128  = 16;
  CTX_AES_KEY_LEN192  = 24;
  CTX_AES_KEY_LEN256  = 32;
  CTX_AES_IV_LEN      = 16;
  //DES
  CTX_DES_KEY_LEN     = 8;
  CTX_DES3_KEY_LEN    = 24;
  CTX_DES_IV_LEN      = 8;

  //CCM
  CTX_AES_CCM_IV_LEN  = 7;
  CTX_AES_CCM_TAG_LEN = 14;
  //GCM
  CTX_AES_GCM_IV_LEN  = 12;
  CTX_AES_GCM_TAG_LEN = 16;

type
  {
    摘要长度:
    MD5:          16
    SHA1:         20
    SHA224:       28
    SHA256:       32
    SHA384:       48
    SHA512:       64
    SHA512-224:   28
    SHA512-256:   32
  }
  THashMDKind  = (MD5, SHA1, SHA224, SHA256, SHA384, SHA512, SHA512_224, SHA512_256, SM3);
  TCertPKCS    = (PKCS1, {PKCS2, PKCS3, PKCS4, PKCS5, PKCS6, PKCS7,} PKCS8, {PKCS9, PKCS10, PKCS11,} PKCS12);

  //subject/issuer名称类型
  TX509NameType = (ntSubject, ntIssuer);
//    subject/issuer Entry 主体/颁布者名称词条默认结构 (可以用长名称LN, 短名称SN, 或NID(序号) 来表示各个项
//    CN: string;   //commonName 公用名称   open -> NID_commonName = 13
//    C: string;    //countryName 国家      open -> NID_countryName = 14; 国家名称要符合规定,不然错误
//    L: string;    //localityName 城市或者区域       open -> NID_localityName = 15
//    ST: string;   //stateOrProvinceName (州名)省份  open -> NID_stateOrProvinceName = 16
//    O: string;    //organizationName 组织名称       open -> NID_organizationName = 17
//    OU: string;   //organizationalUnitName 组织单位名称  open -> NID_organizationalUnitName = 18
  {
    (NID_commonName, NID_countryName,
     NID_localityName, NID_stateOrProvinceName,
     NID_organizationName, NID_organizationalUnitName);
  }
  //名称实体项 Entry
  TX509NameEntryType = (necommonName = NID_commonName, necountryName = NID_countryName, nelocalityName = NID_localityName,
          nestateOrProvinceName = NID_stateOrProvinceName, neorganizationName = NID_organizationName,
          neorganizationalUnitName = NID_organizationalUnitName);
  //subject/issuer Entry 主体/颁布者 名称词条列表,  (Key = TX509NameEntryType; Value = EntryValue)
  TX509NameEntrys = TDictionary<TX509NameEntryType, string>;

  //Extension Types (Parts)
  TX509ExtensionType = (etKeyUsage = NID_key_usage, etSubjectAltName = NID_subject_alt_name,
          etIssuerAltName = NID_issuer_alt_name, etBasicConstraints = NID_basic_constraints,
          etExtensionKeyUsage = NID_ext_key_usage, etAnyPolicy = NID_any_policy);

  //SubjectAltName and IssuerAltName Entry

//    id-ce-subjectAltName OBJECT IDENTIFIER ::=  { id-ce 17 }
//
//       SubjectAltName ::= GeneralNames
//
//       GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
//
//       GeneralName ::= CHOICE {
//          otherName          [0]     OtherName,
//          rfc822Name          [1]     IA5String,   //Email
//          dNSName          [2]     IA5String,
//          x400Address          [3]     ORAddress,
//          directoryName          [4]     Name,
//          ediPartyName          [5]     EDIPartyName,
//          uniformResourceIdentifier       [6]     IA5String,
//          iPAddress          [7]     OCTET STRING,
//          registeredID          [8]     OBJECT IDENTIFIER }
//
//       OtherName ::= SEQUENCE {
//          type-id    OBJECT IDENTIFIER,
//          value      [0] EXPLICIT ANY DEFINED BY type-id }
//
//       EDIPartyName ::= SEQUENCE {
//          nameAssigner          [0]     DirectoryString OPTIONAL,
//          partyName          [1]     DirectoryString }


  {
    GEN_OTHERNAME = 0;
    GEN_EMAIL = 1;
    GEN_DNS = 2;
    GEN_X400 = 3;
    GEN_DIRNAME = 4;
    GEN_EDIPARTY = 5;
    GEN_URI = 6;
    GEN_IPADD = 7;
    GEN_RID = 8;
  }
  TX509ExtAltNameType = (antSubject = NID_subject_alt_name, antIssuer = NID_issuer_alt_name);
  {
    (GEN_OTHERNAME, GEN_EMAIL, GEN_DNS, GEN_X400, GEN_DIRNAME, GEN_EDIPARTY, GEN_URI, GEN_IPADD, GEN_RID);
  }
  //SAN Item Type
  TX509SANItemType = (sanOtherName = GEN_OTHERNAME, sanEMAIL = GEN_EMAIL, sanDNS = GEN_DNS, sanX400 = GEN_X400,
          sanDIRNAME = GEN_DIRNAME, sanEDIPARTY = GEN_EDIPARTY, sanURI = GEN_URI,
          sanIPADD = GEN_IPADD, sanRID = GEN_RID);

  //SubjectAltName(IssuerAltName) Entry  (Key = TX509SANItemType, Value = EntryData)
  TX509SANEntrys = TDictionary<TX509SANItemType, string>;

  TX509NameEntryAlias = record
    SN: string;   //短名称
    LN: string;   //长名称
  end;

  //证书标准扩展
  TX509Extensions = record
    AuthorityKeyIdentifier: PX509_EXTENSION;
    SubjectKeyIdentifier: PX509_EXTENSION;
    KeyUsage: PX509_EXTENSION;
    AnyPolicy: PX509_EXTENSION;
    PolicyMappings: PX509_EXTENSION;
    SubjectAltName: PX509_EXTENSION;
    IssuerAltName: PX509_EXTENSION;
    SubjectDirectoryAttributes: PX509_EXTENSION;
    BasicConstraints: PX509_EXTENSION;
    NameConstraints: PX509_EXTENSION;
    PolicyConstraints: PX509_EXTENSION;
    ExtKeyUsage: PX509_EXTENSION;
    CrlDistributionPoints: PX509_EXTENSION;
    InhibitAnyPolicy: PX509_EXTENSION;
    FreshestCrl: PX509_EXTENSION;
  end;
  //证书主体信息结构  openssl -> TX509_CINF
  TX509CertInfo = record
    Version: string;          //版本
    SerialNumber: string;     //序列号
    SignAlgorithm: string;    //签名算法
    Subject: TX509NameEntrys; //主体(持有者)
    Issuer: TX509NameEntrys;  //颁布者
    ValidTime: Int64;         //有效期(ISO-8601 TimeStamp)
    PubliKkey: TBytes;        //公钥
    SubjectUID: string;       //主体ID
    IssuerUID: string;        //颁布者ID
    Extensions: TX509Extensions;       //扩展(默认=nil)
  end;
  //证书结构
  TX509Info = record
    CertInfo: TX509CertInfo; //证书主体信息
    SignAlgorithm: string;   //签名算法,
    signValue: TBytes;       //签名值
    IsValid: Boolean;        //是否有效
    RefCount: Integer;       //引用次数
    Name: string;          //证书名称
  end;

  // ========= ENC 对称加密 ==========
  //IDEA 类似DES 瑞士
  //BF(Blowfish) 用于代替DES,但是没有版权限制(AES有版权限制) 升级版本是 Twofish, OpenSSL 没有实现
  //CAST5 类似AES  加拿大
  //ARIA 韩国标准 类似AES
  //CAMELLIA 欧洲标准 作为欧洲新一代的加密标准,它具有较强的安全性,能够抵抗差分" title="差分">差分和线性密码分析等已知的攻击。
  //与AES算法性能相当,针对小规模硬件平台的设计
  //SM4 国标 类似AES
  TENCCryptType = (ctAES128, ctAES192, ctAES256, ctDES, ctDES3, ctRC2, ctRC4, ctIDEA, ctBF,
          ctCAST5, ctARIA, ctCAMELLIA128, ctCAMELLIA192, ctCAMELLIA256, ctSM4);
  TENCCryptMode = (
    // 电子密码本模式(最古老的模式,不推荐。key相同时,
    //相同的明文在不同的时候产生相同的明文,容易遭到字典攻击)
    cmECB,
    // 加密块链模式(Windows默认)。加入了向量参数,一定程度上抵御了字典工具,
    //但缺点也随之而来,一旦中间一个数据出错或丢失,后面的数据将受到影响
    cmCBC,
    // 加密反馈模式。与CBC类似,好处是明文和密文不用是8bit的整数倍,中间一个数据出错,
    //只影响后面的几个块的数据
    cmCFB,
    // 输出反馈模式。类似CFB,一旦一个数据出错,不会影响后面的数据,但安全性降低
    cmOFB,
    // 计数器模式。CTR模式的加密和解密使用了完全相同的模式,因此在程序上实现上比较容易。
    //能够以任意顺序处理分组,意味着能够实现并行计算。CTR模式的速度是非常快的。
    cmCTR,
    //XTS即基于XEX(XOR-ENCRYPT-XOR)的密文窃取算法的可调整的密码本模式(Tweakable Codebook mode),
    //该算法主要用于以数据单元(包括扇区、逻辑磁盘块等)为基础结构的存储设备中静止状态数据的加密。
    cmXTS,
    // Key Wrapping 密钥封装模式:保密防篡改、适用于加密少量数据,比如密钥;分为填充模式和非填充模式
    cmWRAP,
    cmWARP_PAD,
    //CCM(Counter with CBC-MAC)是Cipher Block Chaining Message Authentication Code (CBC-MAC)和Counter模式(CTR)的组合。
    //可以同时生成认证信息和对数据加密。CCM广泛用于互联网和物联网中对传输数据进行保护。
    //而且很多MCU中都实现了对CCM的硬件支持,使用也比较方便。比如WiFi安全中的WPE协议,它就使用了AES-CCM模式。
    cmCCM,
    //MAC 全称是 Message Authentication Code,中文名称为消息认证码,一串由密钥和密文生成的固定值,有时也称 Auth Tag。
    //GMAC 全称是 Galois Message Authentication Code,中文名称为伽罗瓦消息验证码。
    //GMAC 就是利用伽罗华域(Galois Field,GF,有限域)乘法运算来计算消息的 MAC 值。
    //GCM 全称为 Galois/Counter Mode,可以看出 G 是指 GMAC,C 是指 CTR。它在 CTR 加密的基础上增加 GMAC 的特性,
    //解决了 CTR 不能对加密消息进行完整性校验的问题。
    cmGCM
    );

const
  DefAttcherKeyLen: array [THashMDKind] of Integer = (16, 20, 28, 32, 48, 64, 28, 32, 32);

  DefSANItemName: array [TX509SANItemType] of string = ('Orther:', 'EMAIL:', 'DNS:', 'X400:',
          'DIR:', 'EDI:', 'URI:', 'IP:', 'RID:');

  DefASN1_TIME_GENERALIZED_Format = 'YYYYMMDDHHMMSS'; //+Z

type
  TJkOpenSSLUtils = class
  protected
    class function ASN1_STRING2Str(const AData: PASN1_STRING; const AEncoding: TEncoding = nil): string;
    class function X509PublicKeyEVPToDer(const AEVP: PEVP_PKEY; out ADerData: TBytes): Boolean;
    class function ASN1_Time2DateTime(const AASN1Time: PASN1_TIME; out ADateTime: TDateTime): Boolean;

    class function CertToPEM(const ACertificates: array of PX509; const APrivateKey: PEVP_PKEY;
      out ACertificatePEM, APrivateKeyPEM: TBytes): Boolean; static;
    class function ECCertToPEM(const ACertificates: array of PX509; const APrivateKey: PEVP_PKEY;
      out ACertificatePEM, APrivateKeyPEM: TBytes): Boolean; static;

    class function CreateCertRequestWithSha256(const ACountry, AState, ALocality, AOrganization, AOrgUnit, ACommonName: String;
      out ARSA: PRSA; out ACertRequest: PX509_REQ; out APrivateKey: PEVP_PKEY): Boolean; static;

    class function SetRandomSerial(const ACertificate: PX509; out ARandomSerial: TBytes): Boolean; static;

    class function CreateKeyPair_CA(const ACertificateCA: PX509; const APrivateKeyCA: PEVP_PKEY;
      const ACountry, AState, ALocality, AOrganization, AOrgUnit, ACommonName: String;
      const AServerName: String; const AExpiresDays: Integer;
      out ARSA: PRSA; out ACertificate: PX509; out APrivateKey: PEVP_PKEY;
      out ARandomSerial: TBytes): Boolean; static;

    // Create Cert
    class function CreateCertDescribe(const AEntryOVList: TX509NameEntrys;
      const ANotBeforeTime, ANotAfterTime: TDateTime; const ASubjetAltNameType: TX509SANItemType;
      const ASubjetAltNameValue: String; var ACertificate: PX509;
      var ASerialNumber: TBytes): Boolean; static;
  public
    { Generates a crypto-safe random buffer of bytes

      Parameters:
        ASize: the length in bytes

      Returns:
        Bytes of random data }
    class function RandomBytes(const ASize: Integer): TBytes; static;

    { Generates a crypto-safe random string

      Parameters:
        ACharset: a string of approved characters
        ASize: the length in bytes

      Returns:
        String of random data }
    class function RandomString(const ACharset: String; const ASize: Integer): String; overload; static;

    { Generates a crypto-safe random string

      Parameters:
        ASize: the length in bytes

      Returns:
        String of random data }
    class function RandomString(const ASize: Integer; const IsContainedZero: Boolean = True): String; overload; static;

    class function RandomStringExt(const ASize: Integer): string;

    class function RandomPrintableString(const ASize: Integer): string;

    { Generates a crypto-safe random string of characters only

      Parameters:
        ASize: the length in bytes

      Returns:
        String of random data }
    class function RandomChars(const ASize: Integer): String; static;

    { Generates a crypto-safe lowercase random string

      Parameters:
        ASize: the length in bytes

      Returns:
        String of random data }
    class function RandomLowerString(const ASize: Integer; const IsContainedZero: Boolean = True): String; static;

    { Generates a crypto-safe random string of lowercase characters only

      Parameters:
        ASize: the length in bytes

      Returns:
        String of random data }
    class function RandomLowerChars(const ASize: Integer): String; static;

    { Generates a crypto-safe random string of numbers

      Parameters:
        ASize: the length in bytes

      Returns:
        String of random data }
    class function RandomDigits(const ASize: Integer; const IsContainedZero: Boolean = True): String; static;

    {
      BinToHexString
    }
    class function ByteToHexString(const ABytes: TBytes): string;

    {
      HexStringToByte
    }
    class function HexStringToByte(const AHexString: string): TBytes;

    {
      Der binary Data To PEM Data
    }
    class function DerToPEM(const ADerData: TBytes; out APEMData: TBytes;
      const ACertPKCS: TCertPKCS = TCertPKCS.PKCS1): Boolean;
    class function ECCDerToPEM(const ADerData: TBytes; out APEMData: TBytes): Boolean;
  public
    { CreateKeyPair //janker
      Parameters:
        APKCSFormat: PKCS Format; 1- PKCS1; 2- PKCS2; 8- PKCS8 , Only for 1 and 8, Default = 1

        APrivateKey: RSA Private Key
        APublicKey: RSA PUblic Key

      Return:
        True if the Create Succeed, False otherwise }
    class function CreateRSAPairKey(const APKCSFormat: TCertPKCS; out APrivateKey, APublicKey: TBytes): Boolean; static;
    { Signs data using a private key to produce a signature

      Parameters:
        AData: the data that the signature is based upon
        APrivateKey: the private key  //PKCS#1 or PKCS#8
        ASignature: the resulting signature

      Returns:
        True if the signature was created, False otherwise }
    class function Sign_RSASHA256(const AData: TBytes; const APrivateKey: TBytes;
      out ASignature: TBytes): Boolean; static;

    { Verifies data using a public key and a signature

      Parameters:
        AData: the data that the signature is based upon
        ASignature: the resulting signature
        APublicKey: the public key

      Returns:
        True if the signature was verified, False otherwise }
    class function Verify_RSASHA256(const AHeader, APayload, ASignature: TBytes; const APublicKey: TBytes): Boolean; overload; static;

    { Verifies data using a public key and a signature

      Parameters:
        AData: the data that the signature is based upon
        ASignature: the resulting signature
        APublicKey: the public key

      Returns:
        True if the signature was verified, False otherwise }
    class function Verify_RSASHA256(const AData, ASignature: TBytes; const APublicKey: TBytes): Boolean; overload; static;

    { General Signs data using a private key to produce a signature

      Parameters:
        AData: the data that the signature is based upon
        APrivateKey: the private key  //PKCS#1 or PKCS#8
        AHashKind: MD Kind
        ASignature: the resulting signature

      Returns:
        True if the signature was created, False otherwise }
    class function Sign_RSA_Ex(const AData, APrivateKey: TBytes; const AHashKind: THashMDKind;
      out ASignature: TBytes): Boolean; static;
    { General Verifies data using a public key and a signature

      Parameters:
        AData: the data that the signature is based upon
        ASignature: the resulting signature
        APublicKey: the public key
        AHashKind: MD Kind

      Returns:
        True if the signature was verified, False otherwise }
    class function Verify_RSA_Ex(const AData, ASignData: TBytes; const APublicKey: TBytes;
      const AHashKind: THashMDKind): Boolean; static;

    { Signs data using a private key to produce a signature,  function RSA_sign()

      Parameters:
        AData: the data that the signature is based upon
        APrivateKey: the private key  //PKCS#1 or PKCS#8
        ASignature: the resulting signature
        AHashKind: the MD Kind

      Returns:
        True if the signature was created, False otherwise }
    class function Sign_RSA(const AData: TBytes; const APrivateKey: TBytes; const AHashKind: THashMDKind;
      out ASignature: TBytes): Boolean; static;

    { Verify Signs data using a public key to Verify a signature, function RSA_verify()

      Parameters:
        AData: the data that the signature is based upon
        ASignData: the resulting signature
        APublicKey: the public key  //PKCS#1 or PKCS#8
        AHashKind: the MD Kind

      Returns:
        True if the signature was created, False otherwise }
    class function Verify_RSA(const AData, ASignData: TBytes; const APublicKey: TBytes;
      const AHashKind: THashMDKind): Boolean; static;

    { RSA-PSS Signature Data using a private key

      Parameters:
        AData: the data that the signature is based upon
        APrivateKey: the private key  //PKCS#1 or PKCS#8
        AHashKind: the MD Kind
        [out] ASignature: the resulting signature
        IsWithMFG1: Is Use MGF1 function

      Returns:
        True if the signature was created, False otherwise }
    class function Sign_RSA_PSS(const AData: TBytes; const APrivateKey: TBytes;
      const ASignMDKind, AMGF1MDKind: THashMDKind; out ASignature: TBytes): Boolean; static;

    { RSA-PSS Verify Signs data using a public key to Verify a signature

      Parameters:
        AData: the data that the signature is based upon
        ASignature: the resulting signature
        APrivateKey: the private key  //PKCS#1 or PKCS#8
        AHashKind: the MD Kind
        IsWithMFG1: Is Use MGF1 function

      Returns:
        True if the Verify OK, False otherwise }
    class function Verify_RSA_PSS(const AData, ASignData: TBytes; const APublicKey: TBytes;
      const ASignMDKind, AMGF1MDKind: THashMDKind): Boolean; static;

    { RSA-PSS Signature Data using a private key with EVP interface

      Parameters:
        AData: the data that the signature is based upon
        APrivateKey: the private key  //PKCS#1 or PKCS#8
        ASignMDKind: the Signature MD Kind
        AMGF1MDKind: the MGF1 MD Kind
        [out] ASignature: the resulting signature

      Returns:
        True if the signature was created, False otherwise }
    class function Sign_RSA_PSS_Ex(const AData: TBytes; const APrivateKey: TBytes;
      const ASignMDKind, AMGF1MDKind: THashMDKind; out ASignature: TBytes): Boolean; static;

    { RSA-PSS Verify Signs data using a public key to Verify a signature with EVP interface

      Parameters:
        AData: the data that the signature is based upon
        ASignature: the resulting signature
        APrivateKey: the private key  //PKCS#1 or PKCS#8
        AHashKind: the MD Kind
        IsWithMFG1: Is Use MGF1 function

      Returns:
        True if the Verify OK, False otherwise }
    class function Verify_RSA_PSS_Ex(const AData, ASignData: TBytes; const APublicKey: TBytes;
      const ASignMDKind, AMGF1MDKind: THashMDKind): Boolean; static;

  public
    { Creates a X.509 self-signed certificate

      CN=公用名称
      C=国家
      ST=省份
      L =城市或者区域
      O=组织名称
      OU=组织单位名称

      Parameters:
        ACountry: the country value of the certificate
        AState: the state value of the certificate
        ALocality: the locality value of the certificate
        AOrganization: the org value of the certificate
        AOrgUnit: the org unit value of the certificate
        ACommonName: the common name value of the certificate
        AServerName: the given DNS name for the certificate (optional)
        AExpiresDays: the number of days before the certificate will expire
        ACertificate: the resulting X.509 certificate
        APrivateKey: the resulting private key

      Returns:
        True if the certificate pair was created, False otherwise }
    class function CreateSelfSignedCert_X509(const AEntryOVList: TX509NameEntrys;
      const ANotBeforeTime: TDateTime; const ANotAfterTime: TDateTime; const ASubjetAltNameType: TX509SANItemType;
      const ASubjetAltNameValue: String; out ACertificate, APrivateKey, ASerialNumber: TBytes;
      const AHashKind: THashMDKind = THashMDKind.SHA256; const AWithRSAPSS: Boolean = False): Boolean; static;

    { Creates a X.509 certificate signed by the provided CA

      Parameters:
        ACertificateCA: the certificate authority certificate
        APrivateKeyCA: the certificate authority private key
        APassword: the password for the private key (optional)
        ACountry: the country value of the certificate
        AState: the state value of the certificate
        ALocality: the locality value of the certificate
        AOrganization: the org value of the certificate
        AOrgUnit: the org unit value of the certificate
        ACommonName: the common name value of the certificate
        AServerName: the given DNS name for the certificate (optional)
        AExpiresDays: the number of days before the certificate will expire
        ACertificate: the resulting X.509 certificate
        APrivateKey: the resulting private key

      Returns:
        True if the certificate pair was created, False otherwise }
    class function CreateSelfSignedCert_X509CA(const ACertificateCA, APrivateKeyCA: TBytes; const APassword: String;
      const ACountry, AState, ALocality, AOrganization, AOrgUnit, ACommonName: String;
      const AServerName: String; const AExpiresDays: Integer;
      out ACertificate, APrivateKey, ASerialNumber: TBytes): Boolean; static;

    { ECC Cert

    }
    class function CreateECCSelfSignedCert_X509(const AEntryOVList: TX509NameEntrys;
      const ANotBeforeTime: TDateTime; const ANotAfterTime: TDateTime; const ASubjetAltNameType: TX509SANItemType;
      const ASubjetAltNameValue: String; out ACertificate, APrivateKey, ASerialNumber: TBytes;
      const ACurveName: string = 'prime256v1';
      const AHashKind: THashMDKind = THashMDKind.SHA256): Boolean; static;

    {
      Parse x509
      read base64 file cert: 从文件取证书(base64编码)
      function PEM_read_X509(fp: PPointer; x: PPX509; cb: Ppem_password_cb; u: Pointer): PX509;
      read base64 memory cert: 从内存取证书(base64编码)
      function PEM_read_bio_X509(bp: PBIO; x: PPX509; cb: Ppem_password_cb; u: Pointer): PX509;
    }
    class function GetCertX509FromFile(const APEMFileName: string): PX509; static;
    class function GetCertX509FromMem(const APEMCert: string): PX509; static;
    class function GetCertX509FromDerData(const ADerData: TBytes): PX509; static;

    class function CheckCertX509CAStatus(const AX509: PX509): Boolean;
    class function VelidateCertX509CAStatus(const AX509: PX509): Integer;
    class function GetCertX509SerialNumber(const AX509: PX509): string;
    class function GetCertX509Name(const AX509: PX509; const ANameType: TX509NameType;
      out ANameEntrys: TX509NameEntrys): Boolean;
    class function GetCertX509PublicKey(const AX509: PX509; out AKey: TBytes): Boolean; overload;
    class function GetCertX509PublicKey(const APemX509Cert: string; out AKey: TBytes): Boolean; overload;
    class function GetCertX509PublicKey(const AX509: PX509; out AAlgOID: Integer; out AAlgorithm: string;
      out AKey: TBytes): Boolean; overload;
    class function GetCertX509Validity(const AX509: PX509; out AValidityStart, AValidityEnd: TDateTime): Boolean;
    class function GetCertX509Version(const AX509: PX509): string;
    class function GetCertX509Signature(const AX509: PX509; out AAlgOID: Integer; out AAlgorithm: string;
      out ASignature: TBytes): Boolean;
    //取外部扩展,各个扩展需单独处理,每个扩展类型不一样
    class function GetCertX509Extensions(const AX509: PX509; const AExtType: TX509ExtensionType;
      out AValue: TX509SANEntrys): Boolean;
    //subjectAltName 和 IssuerAltName, 一般subjectAltName比较重要,参与了证书签名和证书链,但IssuerAltName不参与
    class function GetCertX509AltName(const AX509: PX509; const AAltNameType: TX509ExtAltNameType;
      out AValue: TX509SANEntrys): Boolean;
  public
  { TODO -ojanker -c : ADD 2021-06-11 16:07:29 }

    {
      Get EC Curves Name
    }
    class function GetECCurveNameAndID(const AList: TStrings): Boolean; static;
    class function GetECCurveName(const AList: TStrings): Boolean; static;

    { CreateECKeyPair

    }
    class function CreateECCPairKey(out APrivateKey, APublicKey: TBytes; const ACurveName: string = 'prime256v1'): Boolean; overload; static;
    class function CreateECCPairKey(out APrivateKey, APublicKey: TBytes; const ACurveID: Integer): Boolean; overload; static;
    { ECDSA Sign

    }
    class function Sign_ECDSA(const AData: TBytes; const APrivateKey: TBytes; const AHashKind: THashMDKind;
      out ASignData: TBytes): Boolean; static;
    class function Sign_ECDSA_Ex(const AData: TBytes; const APrivateKey: TBytes; const AHashKind: THashMDKind;
      out ASignData: TBytes): Boolean; static;

    { ECDSA verify Sign

    }
    class function Verify_ECDSA(const AData, ASignData: TBytes; const APublicKey: TBytes;
      const AHashKind: THashMDKind): Boolean; static;
    class function Verify_ECDSA_Ex(const AData, ASignData: TBytes; const APublicKey: TBytes;
      const AHashKind: THashMDKind): Boolean; static;

    { CreateSM2KeyPair

    }
    class function CreateSM2PairKey(out APrivateKey, APublicKey: TBytes): Boolean; static;

    { SM2 Sign

    }
    class function Sign_SM2(const AData: TBytes; const APrivateKey: TBytes; const AHashKind: THashMDKind;
      out ASignData: TBytes): Boolean; static;
    class function Sign_SM2_Ex(const AData: TBytes; const APrivateKey: TBytes; const AHashKind: THashMDKind;
      out ASignData: TBytes): Boolean; static;
    class function Sign_SM2WithSM3(const AData: TBytes; const APrivateKey: TBytes;
      out ASignData: TBytes): Boolean; static;

    { SM2 verify Sign

    }
    class function Verify_SM2(const AData, ASignData: TBytes; const APublicKey: TBytes;
      const AHashKind: THashMDKind): Boolean; static;
    class function Verify_SM2_Ex(const AData, ASignData: TBytes; const APublicKey: TBytes;
      const AHashKind: THashMDKind): Boolean; static;
    class function Verify_SM2WithSM3(const AData, ASignData: TBytes; const APublicKey: TBytes): Boolean; static;

    { SM2 Encrypt
      //SM2 只能公钥加密私钥解密,没有私钥加密公钥解密的处理
    }
    class function EncrytByPublicKey_SM2(const APlainData, APublicKey: TBytes;
      out ACipherData: TBytes): Boolean; static;
//    class function EncrytByPrivateKey_SM2(const APlainData, APrivateKey: TBytes;
//      out ACipherData: TBytes): Boolean; static;
    { SM2 Decrypt

    }
//    class function DecrytByPublicKey_SM2(const ACipherData, APublicKey: TBytes;
//      out APlainData: TBytes): Boolean; static;
    class function DecrytByPrivateKey_SM2(const ACipherData, APrivateKey: TBytes;
      out APlainData: TBytes): Boolean; static;

    { Encrypt data using a key with AEAD_AES_256_GCM

      Parameters:
        AData: the data want to Encrypt
        AKey: the Encrypt Key
        AIV: IV(Initialisation Vector):初始向量,它的选取必须随机。通常以明文的形式和密文一起传送。
          它的作用和HASH的"加盐"有些类似,目的是防止同样的明文块,始终加密成同样的密文块。
          //注: 微信接口里的随机串用这个参数
        AAD: AAD(Additional Authenticated Data):附加身份验证数据。AAD数据不需要加密,通常以明文形式与密文一起传递给接收者。
        AEnCryptData: the data Encrypted
        ATag: Get Tag for Decrypt,  Works in OpenSSL 1.0.1d and later.
          The tag is subsequently used during the decryption operation to ensure that the ciphertext and AAD
          have not been tampered with.
          //注,这个authentication tag值,如果不单独提供,则附加到密文中最后的16字节
          //注:这个函数和ENCEncryptCM()的 aes-256-gcm一样
      Returns:
        True if the Encrypt was Succeed, False otherwise }
    class function Encrypt_AEAD_AES_256_GCM(const APlainData, AKey, AIV, AAD: TBytes;
      out ACipherData, ATag: TBytes): Boolean; overload; static;
    class function Encrypt_AEAD_AES_256_GCM(const APlainData, AKey, AIV, AAD: TBytes;
      out ACipherDataWithTag: TBytes): Boolean; overload; static;

    { Decrypt data using a key with AEAD_AES_256_GCM

      Parameters:
        AData: the data want to Decrypt
        AKey: the Decrypt Key
        AIV: IV(Initialisation Vector):初始向量,它的选取必须随机。通常以明文的形式和密文一起传送。
          它的作用和MD5的"加盐"有些类似,目的是防止同样的明文块,始终加密成同样的密文块。
          //注: 微信接口里的随机串用这个参数
        AAD: AAD(Additional Authenticated Data):附加身份验证数据。AAD数据不需要加密,通常以明文形式与密文一起传递给接收者。
        ATag: Set Tag From Encrypt,  Works in OpenSSL 1.0.1d and later.
          ADeCryptData: the data Decrypted
          //注,这个authentication tag值,如果未单独提供,则包含在密文中最后的16字节
          //注:这个函数和ENCDecryptCM()的 aes-256-gcm一样
      Returns:
        True if the Decrypt was Succeed, False otherwise}
    class function Decrypt_AEAD_AES_256_GCM(const ACipherData, AKey, AIV, AAD, ATag: TBytes; out APlainData: TBytes): Boolean; overload; static;
    class function Decrypt_AEAD_AES_256_GCM(const ACipherDataWithTag, AKey, AIV, AAD: TBytes; out APlainData: TBytes): Boolean; overload; static;

    { Encrypt data using public.private key
      Parameters:
        AData: the data want to Encrypt
        APublicKey: the Encrypt Key
        AEnCryptData: the data Encrypted
        //* note using RSA_PKCS1_OAEP_PADDING Padding
        //* Length(AData) <= Length(Key) - 2 * Length(HashData) - 2 (Byte)

      Returns:
        True if the Encrypt was Succeed, False otherwise }
    class function EncrytByPublicKey_RSA_OAEP(const APlainData, APublicKey: TBytes;
      out ACipherData: TBytes): Boolean; static;
    class function EncrytByPrivateKey_RSA_OAEP(const APlainData, APrivateKey: TBytes;
      out ACipherData: TBytes): Boolean; static;
    { Decrypt data using public/private key
      Parameters:
        AData: the data want to Decrypt
        APrivateKey: the Decrypt Key
        ADeCryptData: the data Decrypted
        //* note using RSA_PKCS1_OAEP_PADDING Padding

      Returns:
        True if the Decrypt was Succeed, False otherwise }
    class function DecrytByPrivateKey_RSA_OAEP(const ACipherData, APrivateKey: TBytes;
      out APlainData: TBytes): Boolean; static;
    class function DecrytByPublicKey_RSA_OAEP(const ACipherData, APublicKey: TBytes;
      out APlainData: TBytes): Boolean; static;
    { 参考 https://github.com/grijjy/DelphiOpenSsl/issues/1,
      其中需要的几个库API, Grijjy的OpenSSL.Api_11.pas 已经包含了 }
    class function CreatePublicJWKFromPEM(PEMString: AnsiString): string; static;
    class function CreatePublicPEMFromJWK(json: TJSONObject): string; static;
  public
    {
      HASh不能直接调用OpenSSL库的md5(),sha1(), sha256等函数,这些函数是库的内部函数,用以下3个摘要算法函数实现
      int EVP_DigestInit(EVP_MD_CTX *ctx, const EVP_MD *type)  //EVP_DigestInit_ex
      int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count)
      int EVP_DigestFinal(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size) //EVP_DigestFinal_ex
    }
    class function Hash(const MDKind: THashMDKind; const AData: TBytes; out AHashData: TBytes): Boolean; overload; static;
    class function Hash(const MDKind: THashMDKind; const AData: string; out AHashData: TBytes): Boolean; overload; static;

    {
      //hash后的值大小 KenLen
      MD5      16
      SHA1    20
      SHA224  28
      SHA256  32
      SHA384  48
      SHA512  64

      APasswordData: utf8 bytes
    }
    class function PBKDF2_HMAC_SHA(const APasswordData: TBytes; const ASalt: TBytes; const AIterationsCount: Integer;
        const MDKind: THashMDKind; out AHashData: TBytes): Boolean; overload; static;
    class function PBKDF2_HMAC_SHA(const APassword: string; const ASalt: TBytes; const AIterationsCount: Integer;
        const MDKind: THashMDKind; out AHashData: TBytes): Boolean; overload; static;

    //PBE_Scrypt
    {
      Parameters

      APassword:  pass.
      APasswordData: utf8 bytes
      ASalt:  Salt.
      ACost(N):     CPU/memory cost parameter. The power of 2.  // = 14  ; N = 2^ACost
      ABlockSize(r):   Block size parameter.  // = 8
      AParallelization(p):  Parallelization parameter. // = 1
      Maxmem: Max Memory Size.      // = N*r = 2^ACost*ABlockSize
      AKeyLen: Desired Key Length.  ByteLength
      AKey:  the derived key.
    }
    class function PBE_Scrypt(const APasswordData: TBytes; const ASalt: TBytes; const AKeyLen: Integer;
        out AKey: TBytes; const ACost: Integer = 14; const ABlockSize: Integer = 8;
        const AParallelization: Integer = 2): Boolean; overload; static;
    class function PBE_Scrypt(const APassword: string; const ASalt: TBytes; const AKeyLen: Integer;
        out AKey: TBytes; const ACost: Integer = 14; const ABlockSize: Integer = 8;
        const AParallelization: Integer = 2): Boolean; overload; static;

    {
      HMAC Message Sign with MDKind
    }
    class function HMACSign(const AData, AKey: TBytes; const MDKind: THashMDKind; out ASignData: TBytes): Boolean; {overload;} static;
    //class function HMACSign(const AData, AKey: RawByteString; const MDKind: THashMDKind): TBytes; overload; static;
    //class function HMACSignHex(const AData, AKey: RawByteString; const MDKind: THashMDKind): string; overload; static;
    class function HMACSignHex(const AData, AKey: string; const MDKind: THashMDKind; out ASignData: string): Boolean; {overload;} static;
    //class function HMACSignBase64(const AData, AKey: RawByteString; const MDKind: THashMDKind): string; overload; static;
    class function HMACSignBase64(const AData, AKey: string; const MDKind: THashMDKind; out ASignData: string): Boolean; static;
    class function HMACSignBase64URL(const AData, AKey: string; const MDKind: THashMDKind; out ASignData: string): Boolean; static;
    class function HMACVerify(const AData, ASignData, AKey: TBytes; const MDKind: THashMDKind): Boolean; static;
    class function HMACVerifyHex(const AData, ASignData, AKey: string; const MDKind: THashMDKind): Boolean; static;
    class function HMACVerifyBase64(const AData, ASignData, AKey: string; const MDKind: THashMDKind): Boolean; static;
    class function HMACVerifyBase64URL(const AData, ASignData, AKey: string; const MDKind: THashMDKind): Boolean; static;

    //OpenSSL ENC
    class function GetEncType(const ACryptType: TENCCryptType; const ACryptMode: TENCCryptMode;
      var ALenKey, ALenIV: Integer): PEVP_CIPHER;
    //General
    //IV系列附加在Cipher后面,最后一个字节表示IV长度
    class function ENCEncrypt(const APlainData, AKey: TBytes; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out ACipherDataIV: TBytes): Boolean; overload; static;
    class function ENCEncrypt(const APlainData, AKey: TBytes; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out ACipherData, AIV: TBytes): Boolean; overload; static;
    //IV系列附加在Cipher后面,最后一个字节表示IV长度
    class function ENCDecrypt(const ACipherDataIV, AKey: TBytes; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out APlainData: TBytes): Boolean; overload; static;
    class function ENCDecrypt(const ACipherData, AKey, AIV: TBytes; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out APlainData: TBytes): Boolean; overload; static;
    class function ENCEncryptToHEX(const APlainText, AKey: string; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out ACipherTextHex: string): Boolean; static;
    class function ENCDecryptFromHEX(const ACipherTextHex, AKey: string; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out APlainText: string): Boolean; static;
    class function ENCEncryptToBase64(const APlainText, AKey: string; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out ACipherText: string; const IsLineSplit: Boolean = True): Boolean; static;
    class function ENCDecryptFromBase64(const APlainTextBase64, AKey: string; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out APlainText: string): Boolean; static;

    //File
    //加密和解密文件不同名 IV=固定系列 加密模式 AES256_CTR
    class function ENCCryptFile(const AFileIn, AFileOut: string; const AKey: string;
      const IsEncrypt: Boolean = True): Boolean; overload; static;
    //加密和解密对同一个文件名 IV=固定系列 加密模式 AES256_CTR
    class function ENCCryptFile(const AFileName: string; const AKey: string;
      const IsEncrypt: Boolean = True): Boolean; overload; static;

    //CCM GCM
    class function ENCEncryptCM(const APlainData, AKey: TBytes; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out ACipherData, AIV, AADD, ATag: TBytes): Boolean; overload; static;
    // 第一字节为IV长度,然后IV系列;接着放置一个字节ADD长度,然后ADD系列;接着放置CipherData;接着放置Tag,最后一个字节为TAG长度
    // [IVLen] + IV + [ADDLen] + ADD+ CipherData + Tag + [TagLen] (Len = 1 Byte)
    class function ENCEncryptCM(const APlainData, AKey: TBytes; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out ACipherDataAddIvTag: TBytes): Boolean; overload; static;
    class function ENCDecryptCM(const ACipherData, AKey, AIV, AADD, ATag: TBytes; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out APlainData: TBytes): Boolean; overload; static;
    // 第一字节为IV长度,然后IV系列;接着放置一个字节ADD长度,然后ADD系列;接着放置CipherData;接着放置Tag,最后一个字节为TAG长度
    // [IVLen] + IV + [ADDLen] + ADD+ CipherData + Tag + [TagLen] (Len = 1 Byte)
    class function ENCDecryptCM(const ACipherDataAddIvTag, AKey: TBytes;  const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out APlainData: TBytes): Boolean; overload; static;
    class function ENCEncryptCMToHEX(const APlainText, AKey: string; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out ACipherTextHex: string): Boolean; static;
    class function ENCDecryptCMFromHEX(const ACipherTextHex, AKey: string; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out APlainText: string): Boolean; static;
    class function ENCEncryptCMToBase64(const APlainText, AKey: string; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out ACipherText: string; const IsLineSplit: Boolean = True): Boolean; static;
    class function ENCDecryptCMFromBase64(const APlainTextBase64, AKey: string; const ACryptType: TENCCryptType;
      const ACryptMode: TENCCryptMode; out APlainText: string): Boolean; static;

    //File
    //加密文件 加密模式 AES256_GCM
    //第一个字节为随机系列长度,然后随机系列,IV长度字节,IV系列,ADD长度字节,ADD系列,CipherData, Tag系列,Tag长度字节
    // [RDLen] + RD + [IVLen] +IV + [ADDLen] + ADD + CipherData + Tag +[TagLen] (Len = 1Byte)
    class function ENCEncryptFile(const AFileIn, AFileOut: string; const AKey: string): Boolean; overload; static;
    //解密文件 加密模式 AES256_GCM
    class function ENCDecryptFile(const AFileIn, AFileOut: string; const AKey: string): Boolean; overload; static;
    //加密后保存为同一个文件
    class function ENCEncryptFile(const AFileName: string; const AKey: string): Boolean; overload; static;
    //解密后保存为同一个文件
    class function ENCDecryptFile(const AFileName: string; const AKey: string): Boolean; overload; static;
  end;

const
  {
  PUBLICKEY_FLAG_PKCS1_START:  RawByteString = '-----BEGIN RSA PUBLIC KEY-----';    //PCK#1
  PUBLICKEY_FLAG_PKCS1_END:    RawByteString = '-----END RSA PUBLIC KEY-----';      //PCK#1
  PUBLICKEY_FLAG_PKCS8_START:  RawByteString = '-----BEGIN PUBLIC KEY-----';        //PCK#8
  PUBLICKEY_FLAG_PKCS8_END:    RawByteString = '-----END PUBLIC KEY-----';          //PCK#8
  PRIVATEKEY_FLAG_PKCS1_START: RawByteString = '-----BEGIN RSA PRIVATE KEY-----';   //PCK#1
  PRIVATEKEY_FLAG_PKCS1_END:   RawByteString = '-----END RSA PRIVATE KEY-----';     //PCK#1
  PRIVATEKEY_FLAG_PKCS8_START: RawByteString = '-----BEGIN PRIVATE KEY-----';       //PCK#8
  PRIVATEKEY_FLAG_PKCS8_END:   RawByteString = '-----END PRIVATE KEY-----';         //PCK#8
  PUBLICKEY_FLAG_ECC_START:    RawByteString = '-----BEGIN PUBLIC KEY-----';        //ECC
  PUBLICKEY_FLAG_ECC_END:      RawByteString = '-----END PUBLIC KEY-----';          //ECC
  PRIVATEKEY_FLAG_ECC_START:   RawByteString = '-----BEGIN EC PRIVATE KEY-----';    //ECC
  PRIVATEKEY_FLAG_ECC_END:     RawByteString = '-----END EC PRIVATE KEY-----';      //ECC
  CERTIFICATE_FLAG_START:      RawByteString = '-----BEGIN CERTIFICATE-----';
  CERTIFICATE_FLAG_END:        RawByteString = '-----END CERTIFICATE-----';
  }

  PUBLICKEY_FLAG_PKCS1_START:  AnsiString = '-----BEGIN RSA PUBLIC KEY-----';    //PCK#1
  PUBLICKEY_FLAG_PKCS1_END:    AnsiString = '-----END RSA PUBLIC KEY-----';      //PCK#1
  PUBLICKEY_FLAG_PKCS8_START:  AnsiString = '-----BEGIN PUBLIC KEY-----';        //PCK#8
  PUBLICKEY_FLAG_PKCS8_END:    AnsiString = '-----END PUBLIC KEY-----';          //PCK#8
  PRIVATEKEY_FLAG_PKCS1_START: AnsiString = '-----BEGIN RSA PRIVATE KEY-----';   //PCK#1
  PRIVATEKEY_FLAG_PKCS1_END:   AnsiString = '-----END RSA PRIVATE KEY-----';     //PCK#1
  PRIVATEKEY_FLAG_PKCS8_START: AnsiString = '-----BEGIN PRIVATE KEY-----';       //PCK#8
  PRIVATEKEY_FLAG_PKCS8_END:   AnsiString = '-----END PRIVATE KEY-----';         //PCK#8
  PUBLICKEY_FLAG_ECC_START:    AnsiString = '-----BEGIN PUBLIC KEY-----';        //ECC
  PUBLICKEY_FLAG_ECC_END:      AnsiString = '-----END PUBLIC KEY-----';          //ECC
  PRIVATEKEY_FLAG_ECC_START:   AnsiString = '-----BEGIN EC PRIVATE KEY-----';    //ECC
  PRIVATEKEY_FLAG_ECC_END:     AnsiString = '-----END EC PRIVATE KEY-----';      //ECC
  CERTIFICATE_FLAG_START:      AnsiString = '-----BEGIN CERTIFICATE-----';
  CERTIFICATE_FLAG_END:        AnsiString = '-----END CERTIFICATE-----';

懒得再上传代码了,要代码的去这里:

盒子问答 v2.1

相关推荐
BillKu18 小时前
Delphi 5 中操作 Word 表格时禁用鼠标交互
word·delphi
深耕AI20 小时前
Win64OpenSSL-3_5_2.exe【安装步骤】
openssl
lincats11 天前
一步一步学习使用FireMonkey动画(6) 用实例理解动画的运行状态
ide·delphi·livebindings·delphi 12.3·firemonkey
洋哥网络科技12 天前
openssl升级
openssl
lincats12 天前
一步一步学习使用FireMonkey动画(3) 使用Delphi的基本动画组件类
ide·delphi·delphi 12.3·firemonkey
lincats13 天前
一步一步学习使用FireMonkey动画(1) 使用动画组件为窗体添加动态效果
android·ide·delphi·livebindings·delphi 12.3·firemonkey
lincats17 天前
一步一步学习使用LiveBindings(16)使用代码创建LiveBindings绑定
delphi·livebindings·delphi 12.3·firedac·firemonkey
lincats20 天前
一步一步学习使用LiveBindings(14)TListView进阶使用(2),打造天气预报程序
delphi·livebindings·delphi 12.3·firedac·firemonkey·tlistview
lincats21 天前
一步一步学习使用LiveBindings(13) TListView的进阶使用(1)
delphi·livebindings·delphi 12.3·firemonkey·tlistview