Java服务端使用RSA私钥加密,客户端使用公钥解密(C#和C语言)

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;
}

你可能感兴趣的:(Java服务端使用RSA私钥加密,客户端使用公钥解密(C#和C语言))