以下内容为查阅多方资料整理所得, 并非原创内容, 仅供参考
以下内容可能在未来进行修改丶更新
这些内容具有时效性, 在JAVA或C#的未来版本和不同版本之间可能不适用
C#与JAVA的RSA密钥格式不同, 需要转换
RSA加密使用了随机数, 同样的内容和密钥, 每次加密结果内容不一样, 但解密结果一致
JAVA端RSA丶AES加密: 以下内容已经验证
package utils.encrypt;
import sun.misc.*;
import java.io.IOException;
/**
* BASE64编码(和C#_Convert.ToBase64String方法编码通用)
*/
public class BASE64 {
private static final BASE64Encoder encoder = new BASE64Encoder();
private static final BASE64Decoder decoder = new BASE64Decoder();
public static String encode(byte[] src) {
return encoder.encode(src);
}
public static byte[] decode(String src) {
try {
return decoder.decodeBuffer(src);
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return null;
}
}
package utils.encrypt;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Random;
/**
* AES加解密类 key:密钥_16位长度字符串 iv:偏移值_16位长度字符串
*/
public class AESEncrypt {
//启用
public static final boolean enable = true;
//获取密钥
public static String createKey() {
return createKey(16);
}
public static String createKey(int length) {
if (enable) {
createKeyIgnoreEnable(length);
}
return null;
}
public static String createKeyIgnoreEnable(int length) {
return genRandomString(length);
}
//加密/key
public static String encrypt(String source, String key, String iv) {
if (enable) {
return encryptIgnoreEnable(source, key, iv);
}
return source;
}
//加密/key()
public static String encryptIgnoreEnable(String source, String key, String iv) {
if (key.length() == 16 && iv != null && iv.length() == 16) {
try {
byte[] src = source.getBytes("UTF8");
src = operation(src, key, iv, Cipher.ENCRYPT_MODE);
return BASE64.encode(src);
} catch (Exception e) {
System.out.println("AESEncryot Error:" + e.getMessage());
e.printStackTrace();
}
}
return source;
}
//解密
public static String decrypt(String source, String key, String iv) {
if (enable) {
return decryptIgnoreEnable(source, key, iv);
}
return source;
}
public static String decryptIgnoreEnable(String source, String key, String iv) {
if (key != null && key.length() == 16 && iv != null && iv.length() == 16) {
try {
byte[] src = BASE64.decode(source);
src = operation(src, key, iv, Cipher.DECRYPT_MODE);
return new String(src, "UTF8");
} catch (Exception e) {
System.out.println("AESDecryot Error:" + e.getMessage());
e.printStackTrace();
}
}
return source;
}
private static byte[] operation(byte[] src, String key, String iv, int mode) throws Exception {
byte[] keyRaw = key.getBytes();
byte[] ivRaw = iv.getBytes();
SecretKeySpec keySpec = new SecretKeySpec(keyRaw, "AES");
IvParameterSpec ivSpec = new IvParameterSpec(ivRaw);
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");// "AES/CBC/NoPadding"
cipher.init(mode, keySpec, ivSpec);
//加密
if (mode == Cipher.ENCRYPT_MODE) {
//长度处理(加密时:textSize必须为blockSize的整倍数)
int blockSize = cipher.getBlockSize();
int textSize = src.length;
if (textSize % blockSize != 0) {
textSize = textSize + blockSize - (textSize % blockSize);
}
byte[] plaintext = new byte[textSize];
System.arraycopy(src, 0, plaintext, 0, src.length);
byte[] result = cipher.doFinal(plaintext);
return result;
}
//解密
byte[] result = cipher.doFinal(src);
return result;
}
//随机字符串源字符串
private static final String sourceString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
//生成随机字符串
private static String genRandomString(final int length) {
String result = "";
Random random = new SecureRandom();
for (int i = 0; i < length; i++) {
result += sourceString.charAt(random.nextInt(sourceString.length()));
}
return result;
}
}
package utils.encrypt;
import javax.crypto.Cipher;
import java.io.*;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* RSA加解密类(分段加密)
*/
public class RSAEncrypt {
//启用
public static final boolean enable = true;
//密钥长度
public static final int KEYLENGTH = 1024;
//最大加密长度=KEYLENGTH/8-11
public static final int MAXENCRYPTSIZE = 117;
//最大解密长度=KEYLENGTH/8
public static final int MAXDECRYPTSIZE = 128;
//获取密钥
public static RSAKey createKey() {
if (enable) {
return createKeyIgnoreEnable();
}
return new RSAKey();
}
public static RSAKey createKeyIgnoreEnable() {
try {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
// 初始化密钥对生成器,密钥大小为96-1024位
keyPairGen.initialize(KEYLENGTH, new SecureRandom());
// 生成一个密钥对,保存在keyPair中
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
//得到密钥字符串
RSAKey key = new RSAKey();
key.publicKey = BASE64.encode(publicKey.getEncoded());
key.privateKey = BASE64.encode(privateKey.getEncoded());
return key;
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return new RSAKey();
}
//加密
public static String encript(String source, String key) {
if (enable) {
return encriptIgnoreEnable(source, key, KEYLENGTH);
}
return source;
}
//解密
public static String decript(String source, String key) {
if (enable) {
return decriptIgnoreEnable(source, key, KEYLENGTH);
}
return source;
}
//加密(忽略enable)
public static String encriptIgnoreEnable(String source, String key, int keyLength) {
if (key != null && !key.equals("")) {
try {
byte[] src = source.getBytes("UTF8");
//RSA加密
byte[] decoded = BASE64.decode(key); //BSAE64解码
RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
src = encript(src, pubKey, keyLength);
//BASE64编码
return BASE64.encode(src);
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
return source;
}
//解密(忽略enable)
public static String decriptIgnoreEnable(String source, String key, int keyLength) {
if (key != null && !key.equals("")) {
try {
byte[] src = BASE64.decode(source);
//RSA加密
byte[] decoded = BASE64.decode(key); //BSAE64解码
RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
src = decript(src, priKey, keyLength);
//BASE64编码
return new String(src, "UTF8");
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
}
return source;
}
private static byte[] encript(byte[] src, RSAPublicKey key, int keyLength) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, key);
//分段加密
byte[] cache;
int offset = 0;
int length = src.length;
int maxEncryptLength = (int) (keyLength / 8 - 11);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
int i = 0;
while (length - offset > 0) {
if (length - offset > maxEncryptLength) {
cache = cipher.doFinal(src, offset, maxEncryptLength);
} else {
cache = cipher.doFinal(src, offset, length - offset);
}
outStream.write(cache, 0, cache.length);
i++;
offset = i * maxEncryptLength;
}
return outStream.toByteArray();
}
private static byte[] decript(byte[] src, RSAPrivateKey key, int keyLength) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, key);
//分段解密
byte[] cache;
int offset = 0;
int length = src.length;
int maxDecryptLength = (int) (keyLength / 8);
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
int i = 0;
while (length - offset > 0) {
if (length - offset > maxDecryptLength) {
cache = cipher.doFinal(src, offset, maxDecryptLength);
} else {
cache = cipher.doFinal(src, offset, length - offset);
}
outStream.write(cache, 0, cache.length);
i++;
offset = i * maxDecryptLength;
}
return outStream.toByteArray();
}
public static class RSAKey {
public String publicKey;
public String privateKey;
}
}
JAVA端RSAKeyConvert类:
这些内容还未验证
package utils.encrypt;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
/**
* RSA密钥Convert类
*/
public class RSAKeyConvert {
//根据RSA标准密钥的mudulus丶exponent提取JAVA可用密钥
public static String getRSAKey(final String mudulus, final String exponent, final boolean isPrivateKey) {
try {
//Base64解码
byte[] m = BASE64.decode(mudulus);
byte[] e = BASE64.decode(exponent);
BigInteger b1 = new BigInteger(1, m);
BigInteger b2 = new BigInteger(1, e);
//获取密钥
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
Key key;
if (isPrivateKey) {
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(b1, b2);
key = (RSAPublicKey) keyFactory.generatePublic(keySpec);
} else {
RSAPrivateKeySpec priKeySpec = new RSAPrivateKeySpec(b1, b2);
key = (RSAPrivateKey) keyFactory.generatePrivate(priKeySpec);
}
//BASE64编码并返回
return BASE64.encode(key.getEncoded());
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return null;
}
public static String getRSAPublicKeyJavaAsNet(String publicKey){
byte[] encoded = BASE64.decode(publicKey);
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
RSAPublicKey pvkKey = (RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
//Buffer
StringBuffer buffer = new StringBuffer(1024);
buffer.append("<RSAKeyValue>");
buffer.append("<Modulus>"
+ b64encode(removeMSZero(pvkKey.getModulus().toByteArray()))
+ "</Modulus>");
buffer.append("<Exponent>"
+ b64encode(removeMSZero(pvkKey.getPublicExponent().toByteArray()))
+ "</Exponent>");
buffer.append("</RSAKeyValue>");
return buffer.toString().replaceAll("[ \t\n\r]","");
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return null;
}
public static String getRSAPrivateKeyJavaAsNet(String privateKey) {
byte[] encoded = BASE64.decode(privateKey);
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory.generatePrivate(keySpec);
//Buffer
StringBuffer buffer = new StringBuffer(1024);
buffer.append("<RSAKeyValue>");
buffer.append("<Modulus>"
+ b64encode(removeMSZero(pvkKey.getModulus().toByteArray()))
+ "</Modulus>");
buffer.append("<Exponent>"
+ b64encode(removeMSZero(pvkKey.getPublicExponent().toByteArray()))
+ "</Exponent>");
buffer.append("<P>"
+ b64encode(removeMSZero(pvkKey.getPrimeP().toByteArray()))
+ "</P>");
buffer.append("<Q>"
+ b64encode(removeMSZero(pvkKey.getPrimeQ().toByteArray()))
+ "</Q>");
buffer.append("<DP>"
+ b64encode(removeMSZero(pvkKey.getPrimeExponentP().toByteArray()))
+ "</DP>");
buffer.append("<DQ>"
+ b64encode(removeMSZero(pvkKey.getPrimeExponentQ().toByteArray()))
+ "</DQ>");
buffer.append("<InverseQ>"
+ b64encode(removeMSZero(pvkKey.getCrtCoefficient().toByteArray()))
+ "</InverseQ>");
buffer.append("<D>"
+ b64encode(removeMSZero(pvkKey.getPrivateExponent().toByteArray()))
+ "</D>");
buffer.append("</RSAKeyValue>");
return buffer.toString().replaceAll("[ \t\n\r]","");
} catch (Exception e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return null;
}
private static byte[] removeMSZero(byte[] data) {
byte[] data1;
int len = data.length;
if (data[0] == 0) {
data1 = new byte[data.length - 1];
System.arraycopy(data, 1, data1, 0, len - 1);
} else
data1 = data;
return data1;
}
private static String b64encode(byte[] data) {
return BASE64.encode(data);
}
}
C#端RSA丶AES加密: 以下内容已经验证
关键字:C# Unity XLua 加密
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
/// <summary>
/// key:密钥_16位长度字符串 iv:偏移值_16位长度字符串
/// </summary>
[XLua.LuaCallCSharp]
public static class AESEncrypt
{
public static bool enable = true;
/// <summary>
/// 获取随机密钥字符串(16位长度)
/// </summary>
public static string CreateKey(int length = 16)
{
if (enable)
{
return GenRandomString(length);
}
return null;
}
//加密
public static string Encrypt(string source, string key, string iv)
{
if (enable && key != null && iv != null && key.Length == 16 && iv.Length == 16)
{
byte[] src = Encoding.Default.GetBytes(source);
src = Operation(src, key, iv, true);
return Convert.ToBase64String(src);
}
return source;
}
//解密
public static string Decrypt(string source, string key, string iv)
{
if (enable && key != null && iv != null && key.Length == 16 && iv.Length == 16)
{
byte[] src = Convert.FromBase64String(source);
src = Operation(src, key, iv, false);
return Encoding.Default.GetString(src);
}
return source;
}
private static byte[] Operation(byte[] src, string key, string iv, bool isEncrypt)
{
byte[] keyRaw = Encoding.UTF8.GetBytes(key);
byte[] ivRaw = Encoding.UTF8.GetBytes(iv);
if (keyRaw.Length > 16)
{
byte[] temp = new byte[16];
Array.Copy(keyRaw, temp, 16);
keyRaw = temp;
}
RijndaelManaged cipher = new RijndaelManaged();
cipher.Mode = CipherMode.CBC;
cipher.Padding = PaddingMode.Zeros;
cipher.KeySize = 128;
cipher.BlockSize = 128;
cipher.Key = keyRaw;
cipher.IV = ivRaw;
ICryptoTransform cTransform = isEncrypt ? cipher.CreateEncryptor() : cipher.CreateDecryptor();
byte[] result = cTransform.TransformFinalBlock(src, 0, src.Length);
cTransform.Dispose();
cipher.Dispose();
return result;
}
//随机字符串源字符串
private const string sourceString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
//生成随机字符串
private static string GenRandomString(int length)
{
string result = "";
for (int i = 0; i < length; i++)
{
result += sourceString[UnityEngine.Random.Range(0, sourceString.Length)];
}
return result;
}
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;
[XLua.LuaCallCSharp]
public static class RSAEncrypt
{
public static bool enable = true;
//密钥长度
public static int KEYLENGTH { get; private set; } = 1024;
//最大加密长度
public static int MAXENCRYPTSIZE { get; private set; } = 117;
//解密最大长度
public static int MAXDECRYPTSIZE { get; private set; } = 128;
public static RSAKey CreateKey()
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider(KEYLENGTH);
return new RSAKey()
{
publicKey = provider.ToXmlString(false),
privateKey = provider.ToXmlString(true)
};
}
public static void SetKeyLength(int keyLength)
{
if (keyLength != 512 && keyLength != 1024 && keyLength != 2048&& keyLength!=4096)
{
throw new Exception("RSAKey.Length must is 512/1024/2048/4096");
}
KEYLENGTH = keyLength;
MAXDECRYPTSIZE = KEYLENGTH / 8;
MAXENCRYPTSIZE = MAXDECRYPTSIZE - 11;
}
//加密
public static string Encrypt(string source, string publicKey)
{
if (enable)
{
byte[] src = Encoding.Default.GetBytes(source);
src = Encrypt(src, publicKey);
return Convert.ToBase64String(src);
}
return source;
}
//解密
public static string Decrypt(string source, string privateKey)
{
if (enable)
{
byte[] src = Convert.FromBase64String(source);
src = Decrypt(src, privateKey);
return Encoding.Default.GetString(src);
}
return source;
}
private static byte[] Encrypt(byte[] src, string publicKey)
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
provider.FromXmlString(publicKey);
int i = 0; //分段序号
int offset = 0; //偏移值
int length = src.Length; //数据长度
List<byte> data = new List<byte>();
while (length - offset > 0)
{
byte[] cache;
if (length - offset > MAXENCRYPTSIZE)
{
cache = provider.Encrypt(GetSplit(src, offset, MAXENCRYPTSIZE), false);
}
else
{
cache = provider.Encrypt(GetSplit(src, offset, length - offset), false);
}
i++;
data.AddRange(cache);
offset = i * MAXENCRYPTSIZE;
}
return data.ToArray();
}
private static byte[] Decrypt(byte[] src, string privateKey)
{
RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
provider.FromXmlString(privateKey);
int i = 0; //分段序号
int offset = 0; //偏移值
int length = src.Length; //数据长度
List<byte> data = new List<byte>();
while (length - offset > 0)
{
byte[] cache;
if (length - offset > MAXDECRYPTSIZE)
{
cache = provider.Decrypt(GetSplit(src, offset, MAXDECRYPTSIZE), false);
}
else
{
cache = provider.Decrypt(GetSplit(src, offset, length - offset), false);
}
i++;
data.AddRange(cache);
offset = i * MAXDECRYPTSIZE;
}
return data.ToArray();
}
private static byte[] GetSplit(byte[] input, int offset, int length)
{
byte[] output = new byte[length];
for (int i = offset; i < offset + length; i++)
{
output[i - offset] = input[i];
}
return output;
}
[XLua.LuaCallCSharp]
public class RSAKey
{
public string publicKey;
public string privateKey;
}
}
using System;
using System.Xml;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
/**
* 依赖于BouncyCastle Crypto.dll开源加密库
* 官网地址:http://www.bouncycastle.org/csharp/
*/
[XLua.LuaCallCSharp]
public static class RSAKeyConvert
{
public static string RSAPrivateKeyJava2DotNet(string privateKey)
{
RsaPrivateCrtKeyParameters privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent><P>{2}</P><Q>{3}</Q><DP>{4}</DP><DQ>{5}</DQ><InverseQ>{6}</InverseQ><D>{7}</D></RSAKeyValue>",
Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned()),
Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned()));
}
public static string RSAPrivateKeyDotNet2Java(string privateKey)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(privateKey);
BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
BigInteger exp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
BigInteger d = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("D")[0].InnerText));
BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("P")[0].InnerText));
BigInteger q = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Q")[0].InnerText));
BigInteger dp = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DP")[0].InnerText));
BigInteger dq = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("DQ")[0].InnerText));
BigInteger qinv = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("InverseQ")[0].InnerText));
RsaPrivateCrtKeyParameters privateKeyParam = new RsaPrivateCrtKeyParameters(m, exp, d, p, q, dp, dq, qinv);
PrivateKeyInfo privateKeyInfo = PrivateKeyInfoFactory.CreatePrivateKeyInfo(privateKeyParam);
byte[] serializedPrivateBytes = privateKeyInfo.ToAsn1Object().GetEncoded();
return Convert.ToBase64String(serializedPrivateBytes);
}
public static string RSAPublicKeyJava2DotNet(string publicKey)
{
RsaKeyParameters publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
return string.Format("<RSAKeyValue><Modulus>{0}</Modulus><Exponent>{1}</Exponent></RSAKeyValue>",
Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned()),
Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned()));
}
public static string RSAPublicKeyDotNet2Java(string publicKey)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(publicKey);
BigInteger m = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Modulus")[0].InnerText));
BigInteger p = new BigInteger(1, Convert.FromBase64String(doc.DocumentElement.GetElementsByTagName("Exponent")[0].InnerText));
RsaKeyParameters pub = new RsaKeyParameters(false, m, p);
SubjectPublicKeyInfo publicKeyInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(pub);
byte[] serializedPublicBytes = publicKeyInfo.ToAsn1Object().GetDerEncoded();
return Convert.ToBase64String(serializedPublicBytes);
}
}