C#.NET Framework 使用BC库(BouncyCastle) RSA 公钥加密 私钥解密 ver:20230706

环境说明:

.NET Framework 4.6 的控制台程序 。

2020年以后 ,有部分PKCS8私钥(openssl生成)无法用RsaUtil.LoadPrivateKey(strPriPkcs8, "PKCS8")来解析 (https://www.cnblogs.com/runliuv/p/17474269.html)

可以尝试用BC库来处理。

另外,在.NET中:私钥加密,公钥解密。也只能用BC库实现。

加密解析:

//假设私钥长度为1024, 1024/8-11=117。
//如果明文的长度小于117,直接全加密,然后转base64。(data.Length <= maxBlockSize)
//如果明文长度大于117,则每117分一段加密,写入到另一个Stream中,最后转base64。

如果要和其它语言互通,这个分段长度需要和其它语言约定好,不一是 私钥长度/8-11。

解密解析:

//假设私钥长度为1024, 1024/8 =128。
//如果明文的长度小于 128,直接全解密。(data.Length <= maxBlockSize)
//如果明文长度大于 128,则每 128 分一段解密,写入到另一个Stream中,最后 GetString。

用“支付宝开放平台开发助手”生成一组公私钥:

PKCS8私钥:

MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMz0Czg6QUtTISa2pUkloeQB/TEpHdqrfyroWpKLW9B/LWFSOGH9nyTk1pPZaeadyEZQ6gay/C0pUAetLraq9bMA/Luxq68b87uG7WX7dKytEO2/87qGpGMRs97H+GlkzWil2QO2KK4cHnAcVicPsmi5aZ72U0BWJFyPhtd+qdmrAgMBAAECgYEAvW67iAbgHt0BASVD9C3iSjpEaVHVlC165o/IVzaTcEx8Bz3Ve0zN8W3JnvIO3ebsG4HiLLr2Nk++9rltOc0eNeGMv7F1e/OFot1wN0ON6s1g4bYh1z5Uz8FcYiMWcqHHICrx+oSFeK9x+I2Zge7enQXcsVnqEhm77ZE5YczSryECQQD9nB58e5efYchF+cYbmURioX18cUMuhQbB9Aq2N55cd689Lg35KZqT8JQTp/8tQSdCJG8d2nU8VKspUKTEAuaDAkEAzuKIIoc9PVJvy90LhIPA9c1S8BPCI7EMCaTZqJ5o3VaR2dqvUZDGX7kL3kYkQ+n7mq3KIECvkEFzA+FOP96XuQJBAJQTKHW0T/YeSKoayUHp/lS8R6F2HCy4PRbXn71+wfbpZqcJEd2OHhQM3tiPOV258esbjMlYeSUNppZL4LgVnXMCQQC7Lvs9Ql+GPDAqo7ToEM1lmICR906QPIBHuX+1sJ3wpYMROWumwPa7ZRH36j6ls+6R5OwcgmpWeuE1gYTrBNsBAkEAn2pEtAljX1foQff6CLozYg/J6J9RmVFcJ6qz0LX3052qNFBQYw8CMHB7VkVNzsDIDC8LX5uP2pzTrdPLew+pPA==

与之匹配的 PKCS1 私钥,用助手转换的:

MIICXwIBAAKBgQDM9As4OkFLUyEmtqVJJaHkAf0xKR3aq38q6FqSi1vQfy1hUjhh/Z8k5NaT2WnmnchGUOoGsvwtKVAHrS62qvWzAPy7sauvG/O7hu1l+3SsrRDtv/O6hqRjEbPex/hpZM1opdkDtiiuHB5wHFYnD7JouWme9lNAViRcj4bXfqnZqwIDAQABAoGBAL1uu4gG4B7dAQElQ/Qt4ko6RGlR1ZQteuaPyFc2k3BMfAc91XtMzfFtyZ7yDt3m7BuB4iy69jZPvva5bTnNHjXhjL+xdXvzhaLdcDdDjerNYOG2Idc+VM/BXGIjFnKhxyAq8fqEhXivcfiNmYHu3p0F3LFZ6hIZu+2ROWHM0q8hAkEA/ZwefHuXn2HIRfnGG5lEYqF9fHFDLoUGwfQKtjeeXHevPS4N+Smak/CUE6f/LUEnQiRvHdp1PFSrKVCkxALmgwJBAM7iiCKHPT1Sb8vdC4SDwPXNUvATwiOxDAmk2aieaN1Wkdnar1GQxl+5C95GJEPp+5qtyiBAr5BBcwPhTj/el7kCQQCUEyh1tE/2HkiqGslB6f5UvEehdhwsuD0W15+9fsH26WanCRHdjh4UDN7YjzldufHrG4zJWHklDaaWS+C4FZ1zAkEAuy77PUJfhjwwKqO06BDNZZiAkfdOkDyAR7l/tbCd8KWDETlrpsD2u2UR9+o+pbPukeTsHIJqVnrhNYGE6wTbAQJBAJ9qRLQJY19X6EH3+gi6M2IPyeifUZlRXCeqs9C199OdqjRQUGMPAjBwe1ZFTc7AyAwvC1+bj9qc063Ty3sPqTw=

与之匹配的公钥:

MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM9As4OkFLUyEmtqVJJaHkAf0xKR3aq38q6FqSi1vQfy1hUjhh/Z8k5NaT2WnmnchGUOoGsvwtKVAHrS62qvWzAPy7sauvG/O7hu1l+3SsrRDtv/O6hqRjEbPex/hpZM1opdkDtiiuHB5wHFYnD7JouWme9lNAViRcj4bXfqnZqwIDAQAB

BCSignUtil 辅助类,nuget 中引用 Portable.BouncyCastle。

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Security;
using System;
using System.IO;
using System.Text; namespace CommonUtils
{
public static class BCSignUtil
{
/// <summary>
/// 签名
/// </summary>
/// <param name="orgData">原数据字符串</param>
/// <param name="privateKeyPKCS8">必须是PKCS8的</param>
/// <param name="algorithm">算法</param>
/// <returns></returns>
public static string SignData(string orgData, string privateKeyPKCS8, string algorithm)
{
if (string.IsNullOrEmpty(orgData))
throw new Exception("字符串不能为空!"); if (string.IsNullOrEmpty(privateKeyPKCS8))
throw new Exception("privateKeyPKCS8不能为空!"); if (string.IsNullOrEmpty(privateKeyPKCS8))
throw new Exception("algorithm 不能为空!"); AsymmetricKeyParameter priKey = GetPrivateKeyParameter(privateKeyPKCS8); byte[] byteData = Encoding.UTF8.GetBytes(orgData); ISigner normalSig = SignerUtilities.GetSigner(algorithm);
normalSig.Init(true, priKey);
normalSig.BlockUpdate(byteData, 0, byteData.Length);//注意:是byte数组和数组长度,别写成string的长度了
byte[] normalResult = normalSig.GenerateSignature(); //签名结果
string sign = Convert.ToBase64String(normalResult); return sign;
} private static AsymmetricKeyParameter GetPrivateKeyParameter(string privateKeyPem)
{
//获取私钥纯字符串
privateKeyPem = privateKeyPem.Replace("-----BEGIN RSA PRIVATE KEY-----", "").Replace("-----END RSA PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim();
privateKeyPem = privateKeyPem.Replace("-----BEGIN PRIVATE KEY-----", "").Replace("-----END PRIVATE KEY-----", "").Replace("\r", "").Replace("\n", "").Trim(); byte[] privateInfoByte = Convert.FromBase64String(privateKeyPem); AsymmetricKeyParameter priKey = PrivateKeyFactory.CreateKey(privateInfoByte);
return priKey;
} /// <summary>
/// 验证签名
/// </summary>
/// <param name="orgData">原数据字符串</param>
/// <param name="publicKeyPem">公钥</param>
/// <param name="responseSign">对方的签名串</param>
/// <param name="algorithm">算法</param>
/// <returns></returns>
public static bool VerifySignature(string orgData, string publicKeyPem, string responseSign, string algorithm)
{ AsymmetricKeyParameter pubKey = GetPublicKeyParameter(publicKeyPem); byte[] signBytes = Convert.FromBase64String(responseSign);
byte[] plainBytes = Encoding.UTF8.GetBytes(orgData); ISigner verifier = SignerUtilities.GetSigner(algorithm);
verifier.Init(false, pubKey);
verifier.BlockUpdate(plainBytes, 0, plainBytes.Length);//注意:是byte数组和数组长度,别写成string的长度了 bool isOK = verifier.VerifySignature(signBytes); //验签结果
return isOK;
} private static AsymmetricKeyParameter GetPublicKeyParameter(string publicKeyPem)
{
//获取公钥纯字符串
publicKeyPem = publicKeyPem.Replace("-----BEGIN PUBLIC KEY-----", "").Replace("-----END PUBLIC KEY-----", "").Replace("\r", "").Replace("\n", "").Trim(); byte[] publicInfoByte = Convert.FromBase64String(publicKeyPem); AsymmetricKeyParameter pubKey = PublicKeyFactory.CreateKey(publicInfoByte);
return pubKey;
} /// <summary>
/// RSA加密
/// </summary>
/// <param name="orgData">数据</param>
/// <param name="key">私钥、公钥</param>
/// <param name="isPublicKey">是否为公钥</param>
/// <param name="privateKeySize">私钥长度,一般是1024或2048</param>
/// <returns></returns>
public static string EncryptByKey(string orgData, string key, bool isPublicKey, int privateKeySize)
{
//非对称加密算法,加解密用
IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine());
//加密 //1024长度是117,双方协商好
int maxBlockSize = privateKeySize / 8 - 11; //加密块最大长度限制 engine.Init(true, isPublicKey ? GetPublicKeyParameter(key) : GetPrivateKeyParameter(key));
byte[] byteData = System.Text.Encoding.UTF8.GetBytes(orgData); int inputLen = byteData.Length;
MemoryStream ms = new MemoryStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0)
{
if (inputLen - offSet > maxBlockSize)
{
cache = engine.ProcessBlock(byteData, offSet, maxBlockSize);
}
else
{
cache = engine.ProcessBlock(byteData, offSet, inputLen - offSet);
}
ms.Write(cache, 0, cache.Length);
i++;
offSet = i * maxBlockSize;
}
byte[] encryptedData = ms.ToArray(); //var ResultData = engine.ProcessBlock(byteData, 0, byteData.Length);
return Convert.ToBase64String(encryptedData);
//Console.WriteLine("密文(base64编码):" + Convert.ToBase64String(testData) + Environment.NewLine); }
/// <summary>
/// RSA解密
/// </summary>
/// <param name="orgData">数据</param>
/// <param name="key">私钥、公钥</param>
/// <param name="isPublicKey">是否为公钥</param>
/// <param name="privateKeySize">私钥长度,一般是1024或2048</param>
/// <returns></returns>
public static string DecryptByKey(string orgData, string key, bool isPublicKey, int privateKeySize)
{
orgData = orgData.Replace("\r", "").Replace("\n", "").Replace(" ", "");
//非对称加密算法,加解密用
IAsymmetricBlockCipher engine = new Pkcs1Encoding(new RsaEngine()); //解密 //1024长度是128,双方协商好
int maxBlockSize = privateKeySize / 8; //解密块最大长度限制 engine.Init(false, isPublicKey ? GetPublicKeyParameter(key) : GetPrivateKeyParameter(key));
byte[] byteData = Convert.FromBase64String(orgData); int inputLen = byteData.Length;
MemoryStream ms = new MemoryStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 对数据分段加密
while (inputLen - offSet > 0)
{
if (inputLen - offSet > maxBlockSize)
{
cache = engine.ProcessBlock(byteData, offSet, maxBlockSize);
}
else
{
cache = engine.ProcessBlock(byteData, offSet, inputLen - offSet);
}
ms.Write(cache, 0, cache.Length);
i++;
offSet = i * maxBlockSize;
}
byte[] encryptedData = ms.ToArray(); //var ResultData = engine.ProcessBlock(byteData, 0, byteData.Length);
return Encoding.UTF8.GetString(ms.ToArray());
//Console.WriteLine("密文(base64编码):" + Convert.ToBase64String(testData) + Environment.NewLine); } }
}

使用代码:

using CommonUtils;
using System; namespace ConsoleNetFxRsa加密签名使用BC库
{
class Program
{
static void Main(string[] args)
{
try
{
//PKCS8格式私钥
string strPriPkcs8 = "MIICeQIBADANBgkqhkiG9w0BAQEFAASCAmMwggJfAgEAAoGBAMz0Czg6QUtTISa2pUkloeQB/TEpHdqrfyroWpKLW9B/LWFSOGH9nyTk1pPZaeadyEZQ6gay/C0pUAetLraq9bMA/Luxq68b87uG7WX7dKytEO2/87qGpGMRs97H+GlkzWil2QO2KK4cHnAcVicPsmi5aZ72U0BWJFyPhtd+qdmrAgMBAAECgYEAvW67iAbgHt0BASVD9C3iSjpEaVHVlC165o/IVzaTcEx8Bz3Ve0zN8W3JnvIO3ebsG4HiLLr2Nk++9rltOc0eNeGMv7F1e/OFot1wN0ON6s1g4bYh1z5Uz8FcYiMWcqHHICrx+oSFeK9x+I2Zge7enQXcsVnqEhm77ZE5YczSryECQQD9nB58e5efYchF+cYbmURioX18cUMuhQbB9Aq2N55cd689Lg35KZqT8JQTp/8tQSdCJG8d2nU8VKspUKTEAuaDAkEAzuKIIoc9PVJvy90LhIPA9c1S8BPCI7EMCaTZqJ5o3VaR2dqvUZDGX7kL3kYkQ+n7mq3KIECvkEFzA+FOP96XuQJBAJQTKHW0T/YeSKoayUHp/lS8R6F2HCy4PRbXn71+wfbpZqcJEd2OHhQM3tiPOV258esbjMlYeSUNppZL4LgVnXMCQQC7Lvs9Ql+GPDAqo7ToEM1lmICR906QPIBHuX+1sJ3wpYMROWumwPa7ZRH36j6ls+6R5OwcgmpWeuE1gYTrBNsBAkEAn2pEtAljX1foQff6CLozYg/J6J9RmVFcJ6qz0LX3052qNFBQYw8CMHB7VkVNzsDIDC8LX5uP2pzTrdPLew+pPA==";
//PKCS1格式私钥
string strPriPkcs1 = "MIICXwIBAAKBgQDM9As4OkFLUyEmtqVJJaHkAf0xKR3aq38q6FqSi1vQfy1hUjhh/Z8k5NaT2WnmnchGUOoGsvwtKVAHrS62qvWzAPy7sauvG/O7hu1l+3SsrRDtv/O6hqRjEbPex/hpZM1opdkDtiiuHB5wHFYnD7JouWme9lNAViRcj4bXfqnZqwIDAQABAoGBAL1uu4gG4B7dAQElQ/Qt4ko6RGlR1ZQteuaPyFc2k3BMfAc91XtMzfFtyZ7yDt3m7BuB4iy69jZPvva5bTnNHjXhjL+xdXvzhaLdcDdDjerNYOG2Idc+VM/BXGIjFnKhxyAq8fqEhXivcfiNmYHu3p0F3LFZ6hIZu+2ROWHM0q8hAkEA/ZwefHuXn2HIRfnGG5lEYqF9fHFDLoUGwfQKtjeeXHevPS4N+Smak/CUE6f/LUEnQiRvHdp1PFSrKVCkxALmgwJBAM7iiCKHPT1Sb8vdC4SDwPXNUvATwiOxDAmk2aieaN1Wkdnar1GQxl+5C95GJEPp+5qtyiBAr5BBcwPhTj/el7kCQQCUEyh1tE/2HkiqGslB6f5UvEehdhwsuD0W15+9fsH26WanCRHdjh4UDN7YjzldufHrG4zJWHklDaaWS+C4FZ1zAkEAuy77PUJfhjwwKqO06BDNZZiAkfdOkDyAR7l/tbCd8KWDETlrpsD2u2UR9+o+pbPukeTsHIJqVnrhNYGE6wTbAQJBAJ9qRLQJY19X6EH3+gi6M2IPyeifUZlRXCeqs9C199OdqjRQUGMPAjBwe1ZFTc7AyAwvC1+bj9qc063Ty3sPqTw=";
//公钥
string strPub = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDM9As4OkFLUyEmtqVJJaHkAf0xKR3aq38q6FqSi1vQfy1hUjhh/Z8k5NaT2WnmnchGUOoGsvwtKVAHrS62qvWzAPy7sauvG/O7hu1l+3SsrRDtv/O6hqRjEbPex/hpZM1opdkDtiiuHB5wHFYnD7JouWme9lNAViRcj4bXfqnZqwIDAQAB"; string strDJM = "泰酷拉!123ABC";//待签名字符串
strDJM = "泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC泰酷拉!123ABC";//待加密字符串,超过117字符的测试 Console.WriteLine("待签名字符串:" + strDJM); #region 一、私钥签名
//string algorithm = "SHA1withRSA";
string algorithm = "SHA256withRSA";
string strSigned = BCSignUtil.SignData(strDJM, strPriPkcs8, algorithm); //PKCS8
Console.WriteLine("签名值:" + strSigned);
#endregion #region 二、公钥验签(验证签名)
//二、公钥验签(验证签名)
//验证签名
bool bCheck = BCSignUtil.VerifySignature(strDJM, strPub, strSigned, algorithm);//验证签名双方要保持一致
Console.WriteLine("验证签名:" + bCheck.ToString());
#endregion

          //私钥长度,常用 1024 或 2048
int privateKeySize = 1024; //公钥加密
string strJiamihou= BCSignUtil.EncryptByKey(strDJM, strPub,true, privateKeySize);
Console.WriteLine("加密后:" + strJiamihou); //私钥解密
string strJiemihou = BCSignUtil.DecryptByKey(strJiamihou, strPriPkcs8, false, privateKeySize);
Console.WriteLine("解密后:" + strJiemihou); //私钥加密
strJiamihou = BCSignUtil.EncryptByKey(strDJM, strPriPkcs8, false, privateKeySize);
Console.WriteLine("私钥加密后:" + strJiamihou); //公钥解密
strJiemihou = BCSignUtil.DecryptByKey(strJiamihou, strPub, true, privateKeySize);
Console.WriteLine("公钥解密后:" + strJiemihou);
}
catch (Exception ex)
{
Console.WriteLine("ex:" + ex.Message);
} Console.WriteLine("hello END.");
Console.ReadKey();
}
}
}

这里演示了2组:

1:公钥加密,私钥解密。

2:私钥加密,公钥解密。

C#.NET Framework 使用BC库(BouncyCastle) RSA 公钥加密 私钥解密 ver:20230706的更多相关文章

  1. RSA公钥加密私钥解密

    公司的项目需要电科院测评,必须保证数据的完整性和保密性,为这两个特性不得不搞个RSA+SHA1加密. 页面处理过程: 每次登录前,先向后端发送请求,由RSA生成一对公钥和私钥,获取公钥中的模modul ...

  2. RSA 公钥加密——私钥解密

    作者:刘巍然-学酥链接:http://www.zhihu.com/question/25912483/answer/31653639来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...

  3. RSA公钥加密-私钥解密/私钥加密-公钥解密

    package com.tebon.ams.util;import org.apache.commons.codec.binary.Base64;import org.apache.log4j.Log ...

  4. Java RSA 公钥加密私钥解密

    package com.lee.utils; import java.io.DataInputStream; import java.io.File; import java.io.FileInput ...

  5. RSA不对称加密,公钥加密私钥解密,私钥加密公钥解密

    RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作. RSA是被研究得最广泛的公钥算法,从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一 ...

  6. RSA加解密工具类RSAUtils.java,实现公钥加密私钥解密和私钥解密公钥解密

    package com.geostar.gfstack.cas.util; import org.apache.commons.codec.binary.Base64; import javax.cr ...

  7. RSA 加密算法 Java 公钥加密私钥解密 和 私钥加密公钥解密 的特点

    package com.smt.cipher.unsymmetry; import org.apache.commons.codec.binary.Base64; import org.apache. ...

  8. C# 基于大整数类的RSA算法实现(公钥加密私钥解密,私钥加密公钥解密)

    但是C#自带的RSA算法类RSACryptoServiceProvider只支持公钥加密私钥解密,即数字证书的使用. 所以参考了一些网上的资料写了一个RSA的算法实现.算法实现是基于网上提供的一个大整 ...

  9. RSA加解密 公钥加密私钥解密 公加私解 && C++ 调用openssl库 的代码实例

    前提:秘钥长度=1024 ============================================== 对一片(117字节)明文加密 ========================= ...

  10. OpenSSL和Python实现RSA Key公钥加密私钥解密

    基于非对称算法的RSA Key主要有两个用途,数字签名和验证(私钥签名,公钥验证),以及非对称加解密(公钥加密,私钥解密).本文提供一个基于OpenSSL和Python进行非对称加解密的例子. 1. ...

随机推荐

  1. 面试题:JS如何最快的执行垃圾回收机制

    因为没看见答案,所以也不知道对不对. JavaScript 的垃圾回收机制是由 JavaScript 引擎自动管理的,通常情况下我们无法控制垃圾回收机制的执行时间和频率. 然而,我们可以采取一些优化策 ...

  2. Vue上传XLS文件

    data() { return { tableData:[] } }, //原生JS+XLSX包实现 xls文件上传 methods: { //上传excel表格文件 uploadHandler(da ...

  3. Java的对象克隆

    本节我们会讨论 Cloneable 接口,这个接口指示一个类提供了一个安全的 clone() 方法. Object 类提供的 clone() 方法是 "浅拷贝",并没有克隆对象中引 ...

  4. 基于django+ansible+webssh运维自动化管理系统

    基于django+ansible+webssh运维自动化管理系统   前言 最初开发这个基于Django ansible运维自动化管理系统的想法其实从大学时候就已经有了,但是苦于技术原因和没有线上环境 ...

  5. vue中watch的详细用法(深度侦听)

    vsCode插件 在vue中,使用watch来响应数据的变化.watch的用法大致有三种.下面代码是watch的一种简单的用法: <input type="text" v-m ...

  6. sklearn数据预处理中fit(),transform()与fit_transform()的区别

    1 概述 注意这是数据预处理中的方法: Fit(): Method calculates the parameters μ and σ and saves them as internal objec ...

  7. 一文搞懂 Promise 新 Api allSettled 的用法和 all 区别,以及如何在不支持新特性的环境下实现一个 Polyfill

    开始 一文搞懂 Promise 新 Api allSettled 的用法和 all 区别,以及如何在不支持新特性的环境下实现一个 Polyfill allSettled 的用法 const runAl ...

  8. Django笔记三十九之settings配置介绍

    本文首发于公众号:Hunter后端 原文链接:Django笔记三十九之settings配置介绍 这一篇笔记介绍 Django 里 settings.py 里一些常用的配置项,这些配置有一些是在之前的笔 ...

  9. Docker私有仓库harbor

    Docker私有仓库harbor 目录 Docker私有仓库harbor Harbor私有仓库介绍 Harbor部署 harbor页面不显示排错思路 Harbor的使用 Harbor拉镜像 自制镜像推 ...

  10. 2022-01-15:中心对称数 III。 中心对称数是指一个数字在旋转了 180 度之后看起来依旧相同的数字(或者上下颠倒地看)。 写一个函数来计算范围在 [low, high] 之间中心对称数的个

    2022-01-15:中心对称数 III. 中心对称数是指一个数字在旋转了 180 度之后看起来依旧相同的数字(或者上下颠倒地看). 写一个函数来计算范围在 [low, high] 之间中心对称数的个 ...