美文网首页
Java服务端使用RSA私钥加密,客户端使用公钥解密(C#和C语

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

作者: KwokKwok | 来源:发表于2019-02-13 16:18 被阅读3次

    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库。

    /// <summary>
    /// 使用RSA公钥解密
    /// </summary>
    /// <param name="encrypted">经过base64编码的字符串</param>
    /// <returns>解密信息</returns>
    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<byte> plainTextBytes = new List<byte>();
        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 <stdlib.h>
    #include <string.h>
    
    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 <stdlib.h>
    #include <string.h>
    #include <openssl/rsa.h>
    #include <openssl/bio.h>
    #include <openssl/err.h>
    #include <openssl/pem.h>
    
    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语

          本文链接:https://www.haomeiwen.com/subject/qxocjqtx.html