关于【ras非对称加密】,.net语言公钥加密,java语言私钥解密的问题

客户端与服务端进行接口通讯时,往往采用ras加解密来保障通讯过程数据安全。

我们公司做的安卓app,接口全是明文,运行了2年左右,测试部突袭我们app,对我们app进行了漏洞扫描。

抓取了登录过程中发送参数与返回参数,并通过代理,改掉了返回参数,欺骗客户端。导致在账号和密码错误的情况下,顺利登入了app。这是一个巨大的漏洞。向全公司做了通报。并要求立马修复。

该app接口原本并非本人设计,我最近刚接手这个app。于是迅速启动修复方案。即采用ras非对称加解密的方式,在通讯过程对参数进行加密。

1、首先由本人在网上通过在线工具,生成了一套key。配对的公钥pub与私钥pri。

2、公钥给了后端.net开发人员,期望对接口返回结果采用公钥进行加密;同时,私钥给了安卓开发人员,期望对接口返回结果采用私钥进行解密。

3、在改动接口前,首先需要将服务端的加密后密文,客户端能够解析,这一步优先级最高,务必先调通。

在调试过程中,遇到了没有想过的问题,就是.net语言和java语言对ras加解密的方式不同。

java直接对在线生成后的私钥,拿来就能用,但.net拿到的公钥无法直接使用,.net需使用xml格式的公钥才能使用。

于是按照.net xml的公钥格式,拼接出了xml的字符串。加密后,无法用java采用私钥解密。

后来推测,xml虽然格式正确了,但内容可能并不是简单的拼接,需要通过工具进行转换。

果不其然,网上提供了java将ras公钥转换为.net公钥的方法,代码如下:

package com.jusitan.utils;


import java.io.File;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class Ras {
   static String pubkey="MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAunE5gTO1KOTtuoJXMjCX"+
"UvoSVeRG6UhkCRsHenEj4vWuP+tuVrQe76AaigW9K5BZqIM98DZMJvohk+kakDdP"+
"UH4bEQ/0MYAiWRUbGFhPp3d46qwhZMglhAbGDbliVO4MLZIhruTwPoz6uMcxsgh2"+
"DXUwDViWdZ8xuKATdYgnXBQBaz8Fg8GUqoFa2cfQj1lTi002fku+J84ucxwvDWpq"+
"4d37GdZzfDFKJ4n5cqHqo+8HSNqXatASZVLsXdVmgtETdwLiHc5jmIzau3HVr78a"+
"xcoJ6SasBhMKnkMQF7oT6tymkWLi14OGP9zPslvjG0F1XGNtzNhOpEl3SrbjNX7D"+
"juF/cR1i9R2lV7VoeixgqxOFnLdHeGvZVeRmLytzLXE/hSrT4enDqerQKgq/I+PW"+
"WBbLvq9JzPjRdN8VTvbgofN5EoK+z4ZcD33AVNr5M8x50C1yfbLVe0eGbt5FWaNE"+
"1x0OUOCteUUojXh2BNNL3bRujGFPNuIy4nPcPpEK67GXyOPNjA3E/WY7ybwKHHR/"+
"sgL8gCPGMbtCmdYoSicxSoWqP8oLZMn7l7dK9YLfiNS8qiL4EEtb49lSXJHYXMDw"+
"bAyU6GOSB8e8ZpJutSBnnAMhLmjg/OLcOA7Hlj9ifntbKc32GPungxOO6AKrLekD"+
"FwxxTBhHTHyYXO0UHliyRQ8CAwEAAQ==" ;
	
	/**
	 * @param args
	 */
   
  
   
	public static void main(String[] args) {
		try {
			// PrivateKey privateKey=RSAUtils.getRSAPrivateKeyBybase64("");
			   PublicKey publicKey=RSAUtils.getRSAPublidKeyBybase64(pubkey);
			   String publicKeyXml = getRSAPublicKeyAsNetFormat(publicKey.getEncoded());
			  // String privateKeyXml = getRSAPrivateKeyAsNetFormat(privateKey.getEncoded());
			System.out.println(publicKeyXml);
			//getRSAPublicKeyAsNetFormat(publicKey.getEncoded());
		} catch (Exception e) {
			e.printStackTrace();
		}
		 
	}

	private static String getRSAPrivateKeyAsNetFormat(byte[] encodedPrivkey) {
        try {
            StringBuffer buff = new StringBuffer(1024);

            PKCS8EncodedKeySpec pvkKeySpec = new PKCS8EncodedKeySpec(
                    encodedPrivkey);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPrivateCrtKey pvkKey = (RSAPrivateCrtKey) keyFactory
                    .generatePrivate(pvkKeySpec);

            buff.append("<RSAKeyValue>");
            buff.append("<Modulus>"
                    + com.sun.org.apache.xml.internal.security.utils.Base64.encode(removeMSZero(pvkKey.getModulus().toByteArray()))
                    + "</Modulus>");

            buff.append("<Exponent>"
                    + com.sun.org.apache.xml.internal.security.utils.Base64.encode(removeMSZero(pvkKey.getPublicExponent()
                    .toByteArray())) + "</Exponent>");

            buff.append("<P>"
                    + com.sun.org.apache.xml.internal.security.utils.Base64.encode(removeMSZero(pvkKey.getPrimeP().toByteArray()))
                    + "</P>");

            buff.append("<Q>"
                    + com.sun.org.apache.xml.internal.security.utils.Base64.encode(removeMSZero(pvkKey.getPrimeQ().toByteArray()))
                    + "</Q>");

            buff.append("<DP>"
                    + com.sun.org.apache.xml.internal.security.utils.Base64.encode(removeMSZero(pvkKey.getPrimeExponentP()
                    .toByteArray())) + "</DP>");

            buff.append("<DQ>"
                    + com.sun.org.apache.xml.internal.security.utils.Base64.encode(removeMSZero(pvkKey.getPrimeExponentQ()
                    .toByteArray())) + "</DQ>");

            buff.append("<InverseQ>"
                    + com.sun.org.apache.xml.internal.security.utils.Base64.encode(removeMSZero(pvkKey.getCrtCoefficient()
                    .toByteArray())) + "</InverseQ>");

            buff.append("<D>"
                    + com.sun.org.apache.xml.internal.security.utils.Base64.encode(removeMSZero(pvkKey.getPrivateExponent()
                    .toByteArray())) + "</D>");
            buff.append("</RSAKeyValue>");

            return buff.toString().replaceAll("[ \t\n\r]", "");
        } catch (Exception e) {
            System.err.println(e);
            return null;
        }
    }

    private static String getRSAPublicKeyAsNetFormat(byte[] encodedPublicKey) {
        try {

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            RSAPublicKey pukKey = (RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(encodedPublicKey));

            StringBuffer buff = new StringBuffer(1024);
            buff.append("<RSAKeyValue>");
            buff.append("<Modulus>"
                    + com.sun.org.apache.xml.internal.security.utils.Base64.encode(removeMSZero(pukKey.getModulus().toByteArray()))
                    + "</Modulus>");
            buff.append("<Exponent>"
                    + com.sun.org.apache.xml.internal.security.utils.Base64.encode(removeMSZero(pukKey.getPublicExponent().toByteArray())) + "</Exponent>");
            buff.append("</RSAKeyValue>");

            return buff.toString().replaceAll("[ \t\n\r]", "");
        } catch (Exception e) {
            System.err.println(e);
            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;
    }
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.jusitan.utils;

import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import com.sun.org.apache.xml.internal.security.exceptions.Base64DecodingException;
import com.sun.org.apache.xml.internal.security.utils.Base64;

public abstract class RSAUtils {
    private static final Logger LOGGER = LoggerFactory.getLogger(RSAUtils.class);
    private static final String ALGORITHOM = "RSA";
    private static final Provider DEFAULT_PROVIDER = new BouncyCastleProvider();
    private static final String SIGNATURE_MD5WITHRSA = "MD5withRSA";
    private static final String SIGNATURE_SHA1WITHRSA = "SHA1withRSA";
    private static final String SIGNATURE_ALGORITHM_DEFAULT = "NONEwithRSA";
    private static final String CIPHER_TRANSFORMATION_DEFAULT = "RSA/ECB/PKCS1Padding";
    private static final String HASHID_SHA1 = "01";
    private static final String HASHID_MD5 = "02";
    private static KeyPairGenerator keyPairGen = null;
    private static KeyFactory keyFactory = null;

    static {
        try {
            keyPairGen = KeyPairGenerator.getInstance("RSA", DEFAULT_PROVIDER);
            keyFactory = KeyFactory.getInstance("RSA", DEFAULT_PROVIDER);
        } catch (NoSuchAlgorithmException var1) {
            LOGGER.error(var1.getMessage());
        }

    }

    private RSAUtils() {
    }

    public static synchronized KeyPair generateRSAKeyPair(int keysize, BigInteger publicExponent) {
        try {
            keyPairGen.initialize(new RSAKeyGenParameterSpec(keysize, publicExponent), new SecureRandom());
            return keyPairGen.generateKeyPair();
        } catch (Exception var3) {
            LOGGER.error("生成模长 =" + keysize + ",指数=" + publicExponent + "的RSA密钥对失败", var3);
            return null;
        }
    }

    public static PrivateKey getRSAPrivateKey(String hexModulus, String hexPrivateExponent) {
        if(!StringUtils.isEmpty(hexModulus) && !StringUtils.isEmpty(hexPrivateExponent)) {
            BigInteger mbig = new BigInteger(hexModulus, 16);
            BigInteger ebig = new BigInteger(hexPrivateExponent, 16);
            RSAPrivateKeySpec prispec = new RSAPrivateKeySpec(mbig, ebig);

            try {
                return keyFactory.generatePrivate(prispec);
            } catch (InvalidKeySpecException var6) {
                LOGGER.error("hexModulus or hexPrivateExponent value is invalid. return null(RSAPrivateKey).");
                return null;
            }
        } else {
            if(LOGGER.isDebugEnabled()) {
                LOGGER.debug("hexModulus and hexPrivateExponent cannot be empty. RSAPrivateKey value is null to return.");
            }

            return null;
        }
    }

    public static PublicKey getRSAPublidKey(String hexModulus, String hexPublicExponent) {
        if(!StringUtils.isEmpty(hexModulus) && !StringUtils.isEmpty(hexPublicExponent)) {
            BigInteger mbig = new BigInteger(hexModulus, 16);
            BigInteger ebig = new BigInteger(hexPublicExponent, 16);
            RSAPublicKeySpec pubspec = new RSAPublicKeySpec(mbig, ebig);

            try {
                return keyFactory.generatePublic(pubspec);
            } catch (InvalidKeySpecException var6) {
                LOGGER.error("hexModulus or hexPublicExponent value is invalid. return null(RSAPublicKey).");
                return null;
            }
        } else {
            if(LOGGER.isDebugEnabled()) {
                LOGGER.debug("hexModulus and hexPublicExponent cannot be empty. return null(RSAPublicKey).");
            }

            return null;
        }
    }
    
    public static RSAPublicKey getRSAPublidKeyBybase64(String base64s) throws Base64DecodingException {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(com.sun.org.apache.xml.internal.security.utils.Base64.decode(base64s));
        RSAPublicKey publicKey = null;

        try {
            publicKey = (RSAPublicKey)keyFactory.generatePublic(keySpec);
        } catch (InvalidKeySpecException var4) {
            LOGGER.error("base64编码=" + base64s + "转RSA公钥失败", var4);
        }

        return publicKey;
    }
    public static RSAPrivateKey getRSAPrivateKeyBybase64(String base64s) throws Base64DecodingException {
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(com.sun.org.apache.xml.internal.security.utils.Base64.decode(base64s));
        RSAPrivateKey privateKey = null;

        try {
            privateKey = (RSAPrivateKey)keyFactory.generatePrivate(keySpec);
        } catch (InvalidKeySpecException var4) {
            LOGGER.error("base64编码=" + base64s + "转RSA私钥失败", var4);
        }

        return privateKey;
    }
   
}

得到转换后的xml后,.net 就可以使用了。

转换后的xml如下;

<RSAKeyValue><Modulus>unE5gTO1KOTtuoJXMjCXUvoSVeRG6UhkCRsHenEj4vWuP+tuVrQe76AaigW9K5BZqIM98DZMJvohk+kakDdPUH4bEQ/0MYAiWRUbGFhPp3d46qwhZMglhAbGDbliVO4MLZIhruTwPoz6uMcxsgh2DXUwDViWdZ8xuKATdYgnXBQBaz8Fg8GUqoFa2cfQj1lTi002fku+J84ucxwvDWpq4d37GdZzfDFKJ4n5cqHqo+8HSNqXatASZVLsXdVmgtETdwLiHc5jmIzau3HVr78axcoJ6SasBhMKnkMQF7oT6tymkWLi14OGP9zPslvjG0F1XGNtzNhOpEl3SrbjNX7DjuF/cR1i9R2lV7VoeixgqxOFnLdHeGvZVeRmLytzLXE/hSrT4enDqerQKgq/I+PWWBbLvq9JzPjRdN8VTvbgofN5EoK+z4ZcD33AVNr5M8x50C1yfbLVe0eGbt5FWaNE1x0OUOCteUUojXh2BNNL3bRujGFPNuIy4nPcPpEK67GXyOPNjA3E/WY7ybwKHHR/sgL8gCPGMbtCmdYoSicxSoWqP8oLZMn7l7dK9YLfiNS8qiL4EEtb49lSXJHYXMDwbAyU6GOSB8e8ZpJutSBnnAMhLmjg/OLcOA7Hlj9ifntbKc32GPungxOO6AKrLekDFwxxTBhHTHyYXO0UHliyRQ8=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>
 

RAS-3072(也称为RSA-3072)是一种非对称加密算法,用于加密解密数据。以下是使用 C++ 实现 RAS-3072 加密解密的基本步骤: 1. 生成公钥私钥 首先,需要生成一个公钥和一个私钥对。公钥用于加密数据,私钥用于解密数据。生成公钥私钥的步骤如下: - 选择两个大素数 p 和 q,使得它们的积 N = p * q 非常大(通常在几千位以上)。 - 计算欧拉函数 φ(N) = (p-1) * (q-1)。 - 选择一个小于 φ(N) 且与 φ(N) 互质的整数 e,它将作为公钥的一部分。 - 计算 e 的模反元素 d,它将作为私钥的一部分。d 满足以下条件:d * e ≡ 1 (mod φ(N))。 2. 加密数据 一旦公钥私钥被生成,就可以使用公钥加密数据。加密的步骤如下: - 将要加密的数据转换为一个整数 m,该整数应小于 N。 - 计算 c ≡ m^e (mod N),其中 e 是公钥中的指数。得到的 c 是加密后的数据。 3. 解密数据 一旦加密的数据需要被解密,就可以使用私钥解密数据。解密的步骤如下: - 将加密后的数据 c 转换为一个整数。 - 计算 m ≡ c^d (mod N),其中 d 是私钥中的指数。得到的 m 是解密后的数据。 下面是使用 C++ 实现 RAS-3072 加密解密的示例代码: ```cpp #include <iostream> #include <vector> #include <random> #include <chrono> #include <gmpxx.h> using namespace std; // 生成随机大素数 mpz_class generate_prime(int num_bits) { random_device rd; mt19937 gen(rd()); uniform_int_distribution<mpz_class> dist(mpz_class(1) << (num_bits-1), mpz_class(1) << num_bits); while (true) { auto p = dist(gen); if (mpz_probab_prime_p(p.get_mpz_t(), 25) > 0) { return p; } } } // 生成公钥私钥 void generate_key(mpz_class& N, mpz_class& e, mpz_class& d, int num_bits) { auto p = generate_prime(num_bits); auto q = generate_prime(num_bits); N = p * q; mpz_class phi = (p - 1) * (q - 1); while (true) { e = generate_prime(num_bits); if (gcd(e, phi) == 1) { break; } } mpz_invert(d.get_mpz_t(), e.get_mpz_t(), phi.get_mpz_t()); } // 加密数据 mpz_class encrypt(mpz_class m, mpz_class N, mpz_class e) { mpz_class c; mpz_powm(c.get_mpz_t(), m.get_mpz_t(), e.get_mpz_t(), N.get_mpz_t()); return c; } // 解密数据 mpz_class decrypt(mpz_class c, mpz_class N, mpz_class d) { mpz_class m; mpz_powm(m.get_mpz_t(), c.get_mpz_t(), d.get_mpz_t(), N.get_mpz_t()); return m; } int main() { // 生成公钥私钥 mpz_class N, e, d; generate_key(N, e, d, 3072); // 要加密的数据 string plaintext = "Hello, world!"; mpz_class m(plaintext.c_str()); // 加密数据 auto c = encrypt(m, N, e); cout << "Encrypted: " << c.get_str() << endl; // 解密数据 auto decrypted = decrypt(c, N, d); cout << "Decrypted: " << decrypted.get_str() << endl; return 0; } ``` 需要注意的是,RAS-3072 是一种非常复杂的加密算法,实现起来也比较复杂。如果需要使用加密算法来保护敏感数据,请务必仔细考虑安全性和实现细节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值