PHP 使用证书实现 XML 数字签名和验签( SHA256 with RSA)

用秘钥给XML报文添加签名域(具体用到什么样的签名方式请看 github 上面的测试用例)

首先

需要安装扩展 xmlseclibs
地址:https://github.com/robrichards/xmlseclibs

然后

看下面示例(github上面也有测试的调用示例)

/**
 * generateXMLSignFields XML生成签名域
 * Use sha256withrsa algorithm to generate XML internal signature
 * @param $xml
 * @return string
 * @throws \Exception
 * @author   liuml  <liumenglei0211@163.com>
 * @DateTime 2018/12/21  16:37
 */
protected function generateXMLSignFields($xml, $prefix = 'ds')
{
    // 加载要签名的XML
    $doc = new \DOMDocument();
    $doc->loadXML($xml);

    // 创建一个新的安全对象
    $objDSig = new XMLSecurityDSig($prefix);
    // 使用c14n专属规范化
    $objDSig->setCanonicalMethod(XMLSecurityDSig::C14N);
    // 签名使用 SHA-256
    $objDSig->addReference(
        $doc,
        XMLSecurityDSig::SHA1,
        ['http://www.w3.org/2000/09/xmldsig#enveloped-signature'],
        ['force_uri' => true]
    );

    // 创建一个新的(私有)安全密钥
    $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, ['type' => 'private']);

    // 如果密钥有密码,则使用它进行设置
    // $objKey->passphrase = '<passphrase>';

    // 加载私钥
    $objKey->loadKey("-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->privateKey, 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----\n");

    // 对XML文件签名
    $objDSig->sign($objKey);

    // 将关联的公钥添加到签名
    // $objDSig->add509Cert("-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->publicKey, 64, "\n", true) . "\n-----END PUBLIC KEY-----\n");

    // 将签名附加到XML
    $objDSig->appendSignature($doc->documentElement);
    // saveXML 里面 LIBXML_NOEMPTYTAG 是为了不简写空值的标签。例:(<test />  => <test></test>)
    // 也可以直接这样写 return $doc->saveXML();
    return $doc->saveXML($doc->documentElement, LIBXML_NOEMPTYTAG);
}

/**
 * checkResponseSign 验证签名
 * Validate signatures in XML
 * @param $xml
 * @return bool
 * @throws \Exception
 * @author   liuml  <liumenglei0211@163.com>
 * @DateTime 2018/12/21  17:51
 */
protected function checkResponseSign($xml)
{
    $doc = new \DOMDocument();
    $doc->loadXML($xml);
    $objXMLSecDSig = new XMLSecurityDSig();

    $objDSig = $objXMLSecDSig->locateSignature($doc);
    if (!$objDSig) {
        throw new \Exception("Cannot locate Signature Node");
    }
    $objXMLSecDSig->canonicalizeSignedInfo();
    $objXMLSecDSig->idKeys = array('wsu:Id');
    $objXMLSecDSig->idNS   = array('wsu' => 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd');

    $retVal = $objXMLSecDSig->validateReference();
    if (!$retVal) {
        throw new \Exception("Reference Validation Failed");
    }

    $objKey = $objXMLSecDSig->locateKey();
    if (!$objKey) {
        throw new \Exception("We have no idea about the key");
    }

    $key = NULL;

    $objKeyInfo = XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig);

    if (!$objKeyInfo->key && empty($key)) {
        $objKey->loadKey("-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->myBankPublicKey, 64, "\n",true) . "\n-----END PUBLIC KEY-----\n");
    }

    if ($objXMLSecDSig->verify($objKey) === 1) {
        return true;
    } else {
        return false;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RSA数字签名是一种常用的数字签名算法,实现代码如下: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <openssl/rsa.h> #include <openssl/pem.h> // 生成RSA密钥对 int generate_key(char *pub_key_file, char *pri_key_file, int key_len) { int ret = 0; RSA *rsa = NULL; BIGNUM *bne = NULL; BIO *bp_public = NULL, *bp_private = NULL; char *pub_key = NULL, *pri_key = NULL; // 生成RSA密钥对 bne = BN_new(); ret = BN_set_word(bne, RSA_F4); if (ret != 1) { printf("BN_set_word failed\n"); return -1; } rsa = RSA_new(); ret = RSA_generate_key_ex(rsa, key_len, bne, NULL); if (ret != 1) { printf("RSA_generate_key_ex failed\n"); return -1; } // 将密钥对输出到文件 bp_public = BIO_new(BIO_s_file()); bp_private = BIO_new(BIO_s_file()); ret = BIO_write_filename(bp_public, pub_key_file); if (ret <= 0) { printf("BIO_write_filename public failed\n"); return -1; } ret = PEM_write_bio_RSAPublicKey(bp_public, rsa); if (ret != 1) { printf("PEM_write_bio_RSAPublicKey failed\n"); return -1; } ret = BIO_write_filename(bp_private, pri_key_file); if (ret <= 0) { printf("BIO_write_filename private failed\n"); return -1; } ret = PEM_write_bio_RSAPrivateKey(bp_private, rsa, NULL, NULL, 0, NULL, NULL); if (ret != 1) { printf("PEM_write_bio_RSAPrivateKey failed\n"); return -1; } RSA_free(rsa); BN_free(bne); BIO_free_all(bp_public); BIO_free_all(bp_private); return 0; } // RSA数字签名 int rsa_sign(char *data, int data_len, char *pri_key_file, char *signature, int *sig_len) { int ret = 0; RSA *rsa = NULL; FILE *fp = NULL; char *pri_key = NULL; // 读取密钥文件 fp = fopen(pri_key_file, "rb"); if (fp == NULL) { printf("open private key file failed\n"); return -1; } rsa = PEM_read_RSAPrivateKey(fp, &rsa, NULL, NULL); if (rsa == NULL) { printf("PEM_read_RSAPrivateKey failed\n"); return -1; } // RSA数字签名 ret = RSA_sign(NID_sha256, (unsigned char *)data, data_len, (unsigned char *)signature, (unsigned int *)sig_len, rsa); if (ret != 1) { printf("RSA_sign failed\n"); return -1; } RSA_free(rsa); fclose(fp); return 0; } // RSA数字验签 int rsa_verify(char *data, int data_len, char *pub_key_file, char *signature, int sig_len) { int ret = 0; RSA *rsa = NULL; FILE *fp = NULL; char *pub_key = NULL; // 读取密钥文件 fp = fopen(pub_key_file, "rb"); if (fp == NULL) { printf("open public key file failed\n"); return -1; } rsa = PEM_read_RSAPublicKey(fp, &rsa, NULL, NULL); if (rsa == NULL) { printf("PEM_read_RSAPublicKey failed\n"); return -1; } // RSA数字验签 ret = RSA_verify(NID_sha256, (unsigned char *)data, data_len, (unsigned char *)signature, sig_len, rsa); if (ret != 1) { printf("RSA_verify failed\n"); return -1; } RSA_free(rsa); fclose(fp); return 0; } ``` 使用示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char *argv[]) { int ret = 0; char *pub_key_file = "rsa_public_key.pem"; char *pri_key_file = "rsa_private_key.pem"; char *data = "Hello, World!"; char signature[1024] = {0}; int sig_len = 0; // 生成RSA密钥对 ret = generate_key(pub_key_file, pri_key_file, 2048); if (ret != 0) { printf("generate_key failed\n"); return -1; } // RSA数字签名 ret = rsa_sign(data, strlen(data), pri_key_file, signature, &sig_len); if (ret != 0) { printf("rsa_sign failed\n"); return -1; } printf("signature: "); for (int i = 0; i < sig_len; i++) { printf("%02x", signature[i]); } printf("\n"); // RSA数字验签 ret = rsa_verify(data, strlen(data), pub_key_file, signature, sig_len); if (ret != 0) { printf("rsa_verify failed\n"); return -1; } printf("verify success\n"); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值