Java服务端使用私钥加密信息,然后C#和C使用公钥解密确认信息。数据的传输使用base64编码。
生成密钥
可以使用支付宝的工具生成公私钥,可以同时生成常规公私钥及pkcs8
编码私钥(java需要)。
服务端使用私钥加密信息(java/kotlin)
import sun.misc.BASE64Decoder
import sun.misc.BASE64Encoder
import java.io.IOException
import java.security.KeyFactory
import java.security.NoSuchAlgorithmException
import java.security.PrivateKey
import java.security.PublicKey
import java.security.spec.InvalidKeySpecException
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import javax.crypto.Cipher
object RSATool {
private fun decrypt(encrypted: ByteArray): String {
val cipher = Cipher.getInstance(RSA)
cipher.init(Cipher.DECRYPT_MODE, loadPublicKey(PUB_KEY))
var offset = 0;
var resultArray = ByteArray(0)
while (offset < encrypted.size) {
val needDecryptCount = encrypted.size - offset
val count = if (needDecryptCount > 128) 128 else needDecryptCount
resultArray += cipher.doFinal(encrypted, offset, count)
offset += count
}
return resultArray.toString(Charsets.UTF_8)
}
fun encrypt(msg: String): String {
val cipher = Cipher.getInstance(RSA)
cipher.init(Cipher.ENCRYPT_MODE, loadPrivateKey(PRIVATE_KEY))
val array = msg.toByteArray()
var offset = 0
var result = ByteArray(0)
while (offset < array.size) {
val needEncryptCount = array.size - offset
val count = if (needEncryptCount > 117) 117 else needEncryptCount
result += cipher.doFinal(array, offset, count)
offset += count
}
return result.toBase64String()
}
@Throws(Exception::class)
private fun loadPublicKey(publicKeyStr: String): PublicKey {
try {
val buffer = base64Decode(publicKeyStr)
val keyFactory = KeyFactory.getInstance(RSA)
val keySpec = X509EncodedKeySpec(buffer)
return keyFactory.generatePublic(keySpec)
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException(e)
} catch (e: InvalidKeySpecException) {
throw RuntimeException(e)
}
}
@Throws(Exception::class)
private fun loadPrivateKey(privateKeyStr: String): PrivateKey {
try {
val buffer = base64Decode(privateKeyStr)
val keySpec = PKCS8EncodedKeySpec(buffer)
val keyFactory = KeyFactory.getInstance(RSA)
return keyFactory.generatePrivate(keySpec)
} catch (e: NoSuchAlgorithmException) {
throw RuntimeException(e)
} catch (e: InvalidKeySpecException) {
throw RuntimeException(e)
}
}
public fun base64Encode(data: ByteArray): String {
return BASE64Encoder().encode(data)
}
@Throws(IOException::class)
public fun base64Decode(data: String): ByteArray {
return BASE64Decoder().decodeBuffer(data)
}
fun ByteArray.toBase64String(): String {
return base64Encode(this)
}
private const val RSA = "RSA"
// 公私钥都去除BEGIN和END行,私钥使用pkcs8格式。
// 避免泄密问题,这里的公私钥是错误的
private const val PRIVATE_KEY = "MSdsdfasSDADASDADADASDsdaSDSA\n" +
"V8znUasdfasw=ASDASDASDASDASDASDASDAS"
private const val PUB_KEY = "MJibP\n" +
"SDAASDFAWDASDASDDADASD"
}
客户端使用公钥解密验证信息(C#)
使用了
BouncyCastle
库。
///
/// 使用RSA公钥解密
///
/// 经过base64编码的字符串
/// 解密信息
private static string Decrypt(string encrypted)
{
// base64解密
var bytesToDecrypt = Convert.FromBase64String(encrypted);
var decryptEngine = new Pkcs1Encoding(new RsaEngine());
using (var txtreader = new StringReader(PUBLIC_KEY))
{
var keyParameter = (AsymmetricKeyParameter)new PemReader(txtreader).ReadObject();
decryptEngine.Init(false, keyParameter);
}
int length = bytesToDecrypt.Length;
int blockSize = decryptEngine.GetInputBlockSize();
List plainTextBytes = new List();
for (int chunkPosition = 0;
chunkPosition < length;
chunkPosition += blockSize)
{
int chunkSize = Math.Min(blockSize, length - chunkPosition);
plainTextBytes.AddRange(decryptEngine.ProcessBlock(
bytesToDecrypt, chunkPosition, chunkSize
));
}
return Encoding.UTF8.GetString(plainTextBytes.ToArray());
}
private const string PUBLIC_KEY = @"-----BEGIN PUBLIC KEY-----
asdfasfasfasfasdfasdasfafasdasfasfasdfasfasdfasfasd
-----END PUBLIC KEY-----";
底层使用公钥解密验证信息(C)
解密使用
openssl
的库,在Windows上需要先编译,在VS中设置库引用和包含引用,可以参考知乎、CSDN。
Base64工具类
测试过几个版本,但二进制数据解析不正确。本版本主要基于苹果开源的代码,修复了换行符导致解析失败的问题。
#include
#include
char * RemoveCharFromStr(char * str, char target);
int Base64DecodeLen(const char *bufcoded);
int Base64Decode(char *bufplain, const char *bufcoded);
int Base64EncodeLen(int len);
int Base64Encode(char *encoded, const char *string, int len);
#include "Base64.h"
static const unsigned char pr2six[256] =
{
/* ASCII table */
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
};
char * RemoveCharFromStr(char * str, char target) {
int i, j, L, n = 0;
L = strlen(str);
char * result = malloc(L);
int index = 0;
for (i = 0;i <= L - n;i++) {
if (str[i] != target) {
result[index] = str[i];
index++;
}
}
return result;
}
int Base64DecodeLen(const char *bufcoded)
{
int nbytesdecoded;
register const unsigned char *bufin;
register int nprbytes;
bufin = (const unsigned char *)bufcoded;
while (pr2six[*(bufin++)] <= 63);
nprbytes = strlen(bufcoded) - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
return nbytesdecoded + 1;
}
int Base64Decode(char *bufplain, const char *bufcoded)
{
int nbytesdecoded;
register const unsigned char *bufin;
register unsigned char *bufout;
register int nprbytes;
bufin = (const unsigned char *)bufcoded;
while (pr2six[*(bufin++)] <= 63);
int a = *(bufin);
nprbytes = strlen(bufcoded) - 1;
nbytesdecoded = ((nprbytes + 3) / 4) * 3;
bufout = (unsigned char *)bufplain;
bufin = (const unsigned char *)bufcoded;
while (nprbytes > 4) {
*(bufout++) =
(unsigned char)(pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
*(bufout++) =
(unsigned char)(pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
*(bufout++) =
(unsigned char)(pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
bufin += 4;
nprbytes -= 4;
}
/* Note: (nprbytes == 1) would be an error, so just ingore that case */
if (nprbytes > 1) {
*(bufout++) =
(unsigned char)(pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4);
}
if (nprbytes > 2) {
*(bufout++) =
(unsigned char)(pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2);
}
if (nprbytes > 3) {
*(bufout++) =
(unsigned char)(pr2six[bufin[2]] << 6 | pr2six[bufin[3]]);
}
*(bufout++) = '\0';
nbytesdecoded -= (4 - nprbytes) & 3;
return nbytesdecoded;
}
static const char basis_64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int Base64EncodeLen(int len)
{
return ((len + 2) / 3 * 4) + 1;
}
int Base64Encode(char *encoded, const char *string, int len)
{
int i;
char *p;
p = encoded;
for (i = 0; i < len - 2; i += 3) {
*p++ = basis_64[(string[i] >> 2) & 0x3F];
*p++ = basis_64[((string[i] & 0x3) << 4) |
((int)(string[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2) |
((int)(string[i + 2] & 0xC0) >> 6)];
*p++ = basis_64[string[i + 2] & 0x3F];
}
if (i < len) {
*p++ = basis_64[(string[i] >> 2) & 0x3F];
if (i == (len - 1)) {
*p++ = basis_64[((string[i] & 0x3) << 4)];
*p++ = '=';
}
else {
*p++ = basis_64[((string[i] & 0x3) << 4) |
((int)(string[i + 1] & 0xF0) >> 4)];
*p++ = basis_64[((string[i + 1] & 0xF) << 2)];
}
*p++ = '=';
}
*p++ = '\0';
return p - encoded;
}
公钥解码
RSADecoder.h
#include
#include
#include
#include
#include
#include
void PrintLastError(char* msgTitle);
int DecryptByPublicKey(unsigned char* enc_data, int data_len, unsigned char* key, unsigned char*decrypted);
RSA * CreateRSA(unsigned char* key, int public);
int Test(const char * base64Str, unsigned char * decrypted);
RSADecoder.c
#include "RSADecoder.h"
#include "Base64.h"
RSA * CreateRSA(unsigned char* key, int public)
{
RSA *rsa = NULL;
BIO *keybio;
keybio = BIO_new_mem_buf(key, -1);
if (keybio == NULL)
{
printf("创建RSA失败(BIO)。");
return 0;
}
if (public)
{
rsa = PEM_read_bio_RSA_PUBKEY(keybio, &rsa, NULL, NULL);
}
else
{
rsa = PEM_read_bio_RSAPrivateKey(keybio, &rsa, NULL, NULL);
}
if (rsa == NULL)
{
printf("创建RSA失败。");
}
return rsa;
}
int DecryptByPublicKey(unsigned char* enc_data, int data_len, unsigned char* key, unsigned char*decrypted)
{
RSA * rsa = CreateRSA(key, 1);
int length = RSA_public_decrypt(data_len, enc_data, decrypted, rsa, RSA_PKCS1_PADDING);
return length;
}
void PrintLastError(char* msgTitle)
{
char* err = malloc(130);;
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
printf("%s: %s\n", msgTitle, err);
free(err);
}
int Test(const char * base64Str,unsigned char * decrypted) {
char * publicKey = "-----BEGIN PUBLIC KEY-----\n"
"asdfadfasfafasdfasfasdfsfsadfasdafasdfasfas"
"-----END PUBLIC KEY-----\n";
unsigned char encrypted[4096];
memset(encrypted, 0, 4096);
char* encData = RemoveCharFromStr(base64Str, '\n');
int len = Base64Decode(encrypted, encData);
int length = DecryptByPublicKey(encrypted, len, publicKey, decrypted);
return length;
}