<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>开发 on Tuan's Blog</title><link>https://blog.cloudorz.com/categories/%E5%BC%80%E5%8F%91/</link><description>Recent content in 开发 on Tuan's Blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>mt</copyright><lastBuildDate>Sun, 01 Nov 2026 10:00:00 +0800</lastBuildDate><atom:link href="https://blog.cloudorz.com/categories/%E5%BC%80%E5%8F%91/index.xml" rel="self" type="application/rss+xml"/><item><title>支付宝当面付 - 公钥私钥生成</title><link>https://blog.cloudorz.com/p/generate-new-pvipkey-pubkey-for-alipay/</link><pubDate>Tue, 16 Jan 2024 16:42:05 +0800</pubDate><guid>https://blog.cloudorz.com/p/generate-new-pvipkey-pubkey-for-alipay/</guid><description>&lt;img src="https://blog.cloudorz.com/p/generate-new-pvipkey-pubkey-for-alipay/cover.svg" alt="Featured image of post 支付宝当面付 - 公钥私钥生成" /&gt;&lt;h2 id="前言"&gt;前言&#10;&lt;/h2&gt;&lt;p&gt;接入支付宝当面付时，开放平台要求为应用配置接口加签方式。选择“公钥”模式、加签算法 &lt;strong&gt;RSA2&lt;/strong&gt;（即 &lt;code&gt;SHA256withRSA&lt;/code&gt;，密钥长度 &lt;strong&gt;2048 位&lt;/strong&gt;）时，需要我们自己生成一对 RSA 密钥：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;应用私钥&lt;/strong&gt;：自己保存，用来给请求签名；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;应用公钥&lt;/strong&gt;：上传到支付宝开放平台，支付宝用它验证请求的签名。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;上传应用公钥后，平台会返回一个 &lt;strong&gt;支付宝公钥&lt;/strong&gt;，用来在项目里验证支付宝返回的数据和异步通知。&lt;/p&gt;&#10;&lt;p&gt;官方有密钥生成工具，但其实一条 &lt;code&gt;openssl&lt;/code&gt; 命令就能搞定。&lt;/p&gt;&#10;&lt;p&gt;&lt;img alt="密钥的流向" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.cloudorz.com/p/generate-new-pvipkey-pubkey-for-alipay/key-flow.svg"&gt;&lt;/p&gt;&#10;&lt;h2 id="步骤"&gt;步骤&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;生成 &lt;code&gt;私钥&lt;/code&gt;（RSA 2048 位）。注意：私钥需要保存好，不要泄露。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out private_key.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;较新的 OpenSSL / LibreSSL 用 &lt;code&gt;genpkey&lt;/code&gt; 生成 RSA 密钥默认就是 2048 位，所以原来的写法 &lt;code&gt;openssl genpkey -algorithm RSA -out private_key.pem&lt;/code&gt; 在新版本上结果一样；但老版本的默认值可能是 1024 位，显式写上 &lt;code&gt;rsa_keygen_bits:2048&lt;/code&gt; 更稳妥。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;从上述 &lt;code&gt;私钥&lt;/code&gt; 中导出 &lt;code&gt;公钥&lt;/code&gt;。注意：公钥需要上传到支付宝开放平台，不要泄露 &lt;code&gt;私钥&lt;/code&gt;。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openssl rsa -pubout -in private_key.pem -out public_key.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;把 &lt;code&gt;公钥&lt;/code&gt; 上传到支付宝开放平台（接口加签方式选择“公钥”，算法 RSA2），获取 &lt;code&gt;支付宝公钥&lt;/code&gt;。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&#10;&lt;p&gt;将第一步得到的 &lt;code&gt;私钥&lt;/code&gt; 和平台给的 &lt;code&gt;支付宝公钥&lt;/code&gt; 配置到项目中即可。&lt;/p&gt;&#10;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h2 id="密钥格式说明"&gt;密钥格式说明&#10;&lt;/h2&gt;&lt;h3 id="私钥pkcs8-与-pkcs1"&gt;私钥：PKCS#8 与 PKCS#1&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;openssl genpkey&lt;/code&gt; 输出的是 &lt;strong&gt;PKCS#8&lt;/strong&gt; 格式，文件头是 &lt;code&gt;-----BEGIN PRIVATE KEY-----&lt;/code&gt;。支付宝的 Java SDK 使用的就是 PKCS#8 格式的私钥。&lt;/p&gt;&#10;&lt;p&gt;部分非 Java 语言的 SDK 或旧代码要求 &lt;strong&gt;PKCS#1&lt;/strong&gt; 格式（文件头是 &lt;code&gt;-----BEGIN RSA PRIVATE KEY-----&lt;/code&gt;），可以这样转换：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# OpenSSL 3.x：需要加 -traditional 才会输出 PKCS#1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;openssl rsa -in private_key.pem -traditional -out private_key_pkcs1.pem&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;OpenSSL 1.1.x 以及 macOS 自带的 LibreSSL 下，&lt;code&gt;openssl rsa -in private_key.pem -out private_key_pkcs1.pem&lt;/code&gt; 默认就输出 PKCS#1，不需要（也不认识）&lt;code&gt;-traditional&lt;/code&gt;。具体用哪种，以所用 SDK 的文档为准。&lt;/p&gt;&#10;&lt;h3 id="公钥"&gt;公钥&#10;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;openssl rsa -pubout&lt;/code&gt; 导出的公钥文件头是 &lt;code&gt;-----BEGIN PUBLIC KEY-----&lt;/code&gt;（X.509 SubjectPublicKeyInfo 格式），这正是开放平台需要的格式，不用转换。&lt;/p&gt;&#10;&lt;h3 id="去掉头尾和换行"&gt;去掉头尾和换行&#10;&lt;/h3&gt;&lt;p&gt;开放平台上传公钥、以及很多 SDK 配置私钥时，填的是一整行纯 Base64 字符串，不带 &lt;code&gt;-----BEGIN ...-----&lt;/code&gt; / &lt;code&gt;-----END ...-----&lt;/code&gt; 头尾，也不带换行。可以这样处理：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;&#10;&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1&#10;&lt;/span&gt;&lt;span class="lnt"&gt;2&#10;&lt;/span&gt;&lt;span class="lnt"&gt;3&#10;&lt;/span&gt;&lt;span class="lnt"&gt;4&#10;&lt;/span&gt;&lt;span class="lnt"&gt;5&#10;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#10;&lt;td class="lntd"&gt;&#10;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 上传到开放平台的应用公钥&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -v &lt;span class="s1"&gt;&amp;#39;^-----&amp;#39;&lt;/span&gt; public_key.pem &lt;span class="p"&gt;|&lt;/span&gt; tr -d &lt;span class="s1"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt; &amp;gt; public_key.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 填到项目配置里的应用私钥（需要单行字符串时）&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;grep -v &lt;span class="s1"&gt;&amp;#39;^-----&amp;#39;&lt;/span&gt; private_key.pem &lt;span class="p"&gt;|&lt;/span&gt; tr -d &lt;span class="s1"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt; &amp;gt; private_key.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#10;&lt;/div&gt;&#10;&lt;/div&gt;&lt;p&gt;&lt;img alt="命令与输出示意" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.cloudorz.com/p/generate-new-pvipkey-pubkey-for-alipay/openssl-terminal.svg"&gt;&lt;/p&gt;&#10;&lt;h2 id="注意事项"&gt;注意事项&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;私钥只保存在服务端，不要提交到 Git 仓库，也不要放到前端或客户端里。&lt;/li&gt;&#10;&lt;li&gt;自己验证一下密钥长度：&lt;code&gt;openssl rsa -in private_key.pem -noout -text | head -1&lt;/code&gt;，OpenSSL 3.x 输出 &lt;code&gt;Private-Key: (2048 bit, 2 primes)&lt;/code&gt;，LibreSSL 输出 &lt;code&gt;RSA Private-Key: (2048 bit)&lt;/code&gt;。&lt;/li&gt;&#10;&lt;li&gt;macOS 自带的 &lt;code&gt;/usr/bin/openssl&lt;/code&gt; 实际上是 LibreSSL，可以用 &lt;code&gt;openssl version&lt;/code&gt; 确认，上面的命令里只有 &lt;code&gt;-traditional&lt;/code&gt; 不通用。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;支付宝公钥&lt;/strong&gt; 和 &lt;strong&gt;应用公钥&lt;/strong&gt; 不是一个东西，项目里要配置的是平台返回的支付宝公钥，别填反了。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="参考"&gt;参考&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://opendocs.alipay.com/" target="_blank" rel="noopener"&#10; &gt;支付宝开放平台文档中心&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a class="link" href="https://docs.openssl.org/master/man1/openssl-genpkey/" target="_blank" rel="noopener"&#10; &gt;OpenSSL 文档：openssl-genpkey&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item></channel></rss>