当前位置: 首页 > 知识库问答 >
问题:

使用给定的模数和指数加密字符串

姚伟
2023-03-14

我需要复制以下JAVA代码的功能,该代码接收具有公钥的指数和模的字符串,以生成具有所述参数的公钥并加密字符串:

package snippet;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.Security;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;

import javax.crypto.Cipher;

public class Snippet {
    public static void main(String ... strings) {
        try {
            // Needed if you don't have this provider
            Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
            //String and received public key example
            String ReceivedString = "1234";
            String publicRSA = "010001|0097152d7034a8b48383d3dba20c43d049";
            
            EncryptFunc(ReceivedString, publicRSA);
            
            //The result obtained from the ReceivedString and the publicRSA is as follows:
            //Result in hex [1234] -> [777786fe162598689a8dc172ed9418cb]

        } catch (Exception ex) {
            System.out.println("Error: " );
            ex.printStackTrace();
        }
    }
    
    public static String EncryptFunc(String ReceivedString, String clavePublica) throws Exception {
        String result = "";
        //We separate the received public string into exponent and modulus
        //We receive it as "exponent|modulus"
        String[] SplitKey = clavePublica.split("\\|");
        KeyFactory keyFactory = KeyFactory.getInstance("RSA","BC");
        RSAPublicKeySpec ks = new RSAPublicKeySpec(new BigInteger(hex2byte(SplitKey[1])), new BigInteger(hex2byte(SplitKey[0])));
        //With these specs, we generate the public key
        RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(ks);
        
        //We instantiate the cypher, with the EncryptFunc and the obtained public key
        Cipher cipher= Cipher.getInstance("RSA/None/NoPadding","BC");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        //We reverse the ReceivedString and encrypt it
        String ReceivedStringReverse = reverse(ReceivedString);
        byte[] cipherText2 = cipher.doFinal(ReceivedStringReverse.getBytes("UTF8"));
        result = byte2hex(cipherText2);
        
        System.out.println("result in hex ["+ReceivedString+"] -> ["+result+"]");
                
        return result;
    }
    
    public static byte[] hex2byte(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                                 + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }
    
    public static String byte2hex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte aByte : bytes) {
            result.append(String.format("%02x", aByte));
            // upper case
            // result.append(String.format("%02X", aByte));
        }
        return result.toString();
    }
    
    public static String reverse(String source) {
        int i, len = source.length();
        StringBuilder dest = new StringBuilder(len);

        for (i = (len - 1); i >= 0; i--){
            dest.append(source.charAt(i));
        }

        return dest.toString();
    }
}

我已经用这个尝试了几种方法,我在这里,这里,这里,这里和这里做了一些搜索。

我设法使用给定的参数创建了公钥,但是当我加密字符串时,结果总是不同的:

using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;

namespace RSACypherTest
{
    public class Program
    {
        public static RSACryptoServiceProvider rsa;
        static void Main(string[] args)
        {
            string str = "1234";
            string publicRSA = "010001|0097152d7034a8b48383d3dba20c43d049";
            string encrypted = "";
            Console.WriteLine("Original text: " + str);
            encrypted = Encrypt(str, publicRSA);
            Console.WriteLine("Encrypted text: " + encrypted);
            Console.ReadLine();
        }
        public static string Encrypt(string str, string PublicRSA)
        {
            string[] Separated = PublicRSA.Split('|');
            RsaKeyParameters pubParameters = MakeKey(Separated[1], Separated[0], false);
            IAsymmetricBlockCipher eng = new Pkcs1Encoding(new RsaEngine());
            eng.Init(true, pubParameters);
            byte[] plaintext = Encoding.UTF8.GetBytes(Reverse(str));
            byte[] encdata = eng.ProcessBlock(plaintext, 0, plaintext.Length);
            return ByteArrayToString(encdata);
        }
        public static string Reverse(string s)
        {
            char[] charArray = s.ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }
        public static string ByteArrayToString(byte[] ba)
        {
            return BitConverter.ToString(ba).Replace("-", "");
        }
        public static byte[] StringToByteArray(string hex)
        {
            int NumberChars = hex.Length;
            byte[] bytes = new byte[NumberChars / 2];
            for (int i = 0; i < NumberChars; i += 2)
                bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
            return bytes;
        }
        private static RsaKeyParameters MakeKey(string modulusHexString, string exponentHexString, bool isPrivateKey)
        {
            var modulus = new BigInteger(modulusHexString, 16);
            var exponent = new BigInteger(exponentHexString, 16);
            return new RsaKeyParameters(isPrivateKey, modulus, exponent);
        }
    }
}

我正在尝试使用BouncyCastle,因为它似乎是处理密钥生成和所有事情的最有效方式。任何有关这方面的帮助都将非常感激。

提前感谢。

共有2个答案

沈自珍
2023-03-14

虽然我不会将自己的答案标记为正确答案,但我发现有可能重新创建我的问题中提到的java代码的整个功能。

正如Michael Fehr在他的回答中提到的,任何加密方法都会试图避免创建重复或可预测的模式,这是绝对合乎逻辑的,正如这个答案完美描述的那样。

由于在这种特殊情况下,目标是复制java代码功能,并且所述功能围绕着在使用给定公钥加密字符串时获得相同的结果,因此我们可以使用本文中的答案来生成如下代码:

    private static string EncryptMessage(string str, string publicRSA)
    {
        string[] Separated = publicRSA.Split('|');
        RsaKeyParameters pubParameters = MakeKey(Separated[1], Separated[0], false);

        var eng = new RsaEngine();
        eng.Init(true, pubParameters);

        string x = Reverse(str);
        byte[] plaintext = Encoding.UTF8.GetBytes(x);

        var encdata = ByteArrayToString(eng.ProcessBlock(plaintext, 0, plaintext.Length));

        return encdata;
    }

    private static RsaKeyParameters MakeKey(string modulusHexString, string exponentHexString, bool isPrivateKey)
    {
        byte[] mod = StringToByteArray(modulusHexString);
        byte[] exp = StringToByteArray(exponentHexString);
        var modulus = new BigInteger(mod);
        var exponent = new BigInteger(exp);
        return new RsaKeyParameters(isPrivateKey, modulus, exponent);
    }

概括一下:

  1. 正如迈克尔·费尔所说,crypyography引擎不生成可重复/可预测的模式不仅是正常的,而且也是预期的。
  2. 为了实现上一点,他们在消息中添加了随机“填充”
  3. 可以(但不推荐)使用BouncyCastle生成无填充引擎,模拟Java代码的功能,如<code>Cipher rsa=Cipher.getInstance(“rsa/ECB/nopadding”)
甘永春
2023-03-14

这不是您问题的答案,但可能有助于您理解RSA加密。

我用C#设置了一个示例加密程序,并使用了您给定的公钥(转换了大整数模数

运行加密 5 次时,每次运行都会收到不同的编码数据(此处为 Base64 编码)。因此,这是 RSA 加密的预期行为。

由于C#允许我“构建”一个短密钥,因此不可能生成如此长的全新密钥对,我怀疑Bouncy Castle会这样做(但是在这里,有很多同事对BC有更好的理解:-)。

如果您想要该程序,则可以使用以下指向该程序的外部链接:https://jdoodle.com/ia/40。

结果:

加载预先创建的公钥public KeyXML2: lxUtcDSotIOD09uiDEPQSQ==AQAB

encryptedData in Base64: JIFfO7HXCvdi0nSxKb0eLA==
encryptedData in Base64: dvtRw0U0KtT/pDJZW2X0FA==
encryptedData in Base64: CqJJKZevO6jWH6DQ1dnkhQ==
encryptedData in Base64: G7cL6BBwxysItvD/Rg0PuA==
encryptedData in Base64: HcfZJITu/PzN84WgI8yc6g==

法典:

using System;
using System.Security.Cryptography;
using System.Text;

class RSACSPSample
{

    static void Main()
    {
        try
        {
            //Create byte arrays to hold original, encrypted, and decrypted data.
            byte[] dataToEncrypt = System.Text.Encoding.UTF8.GetBytes("1234");
            byte[] encryptedData;

            //Create a new instance of RSACryptoServiceProvider to generate
            //public and private key data.
            using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
            {
                Console.WriteLine("load a pre created public key");
                string publicKeyXML = "<RSAKeyValue><Modulus>AJcVLXA0qLSDg9PbogxD0Ek=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>";
                RSA.FromXmlString(publicKeyXML);
                string publicKeyXML2 = RSA.ToXmlString(false);
                Console.WriteLine("publicKeyXML2: " + publicKeyXML2);
                Console.WriteLine();

                //Pass the data to ENCRYPT, the public key information 
                //(using RSACryptoServiceProvider.ExportParameters(false),
                //and a boolean flag specifying no OAEP padding.
                for (int i = 0; i < 5; i++)
                {
                    encryptedData = RSAEncrypt(dataToEncrypt, RSA.ExportParameters(false), false);
                    string encryptedDataBase64 = Convert.ToBase64String(encryptedData);
                    Console.WriteLine("encryptedData in Base64: " + encryptedDataBase64);
                }

            }
        }
        catch (ArgumentNullException)
        {
            //Catch this exception in case the encryption did
            //not succeed.
            Console.WriteLine("Encryption failed.");
        }
    }

    public static byte[] RSAEncrypt(byte[] DataToEncrypt, RSAParameters RSAKeyInfo, bool DoOAEPPadding)
    {
        try
        {
            byte[] encryptedData;
            //Create a new instance of RSACryptoServiceProvider.
            using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
            {

                //Import the RSA Key information. This only needs
                //toinclude the public key information.
                RSA.ImportParameters(RSAKeyInfo);

                //Encrypt the passed byte array and specify OAEP padding.  
                //OAEP padding is only available on Microsoft Windows XP or
                //later.  
                encryptedData = RSA.Encrypt(DataToEncrypt, DoOAEPPadding);
            }
            return encryptedData;
        }
        //Catch and display a CryptographicException  
        //to the console.
        catch (CryptographicException e)
        {
            Console.WriteLine(e.Message);

            return null;
        }
    }
}
 类似资料:
  • 我想使用chacha20解密和加密字符串 BouncyCastleProvider正在使用chacha20技术。所以我包括了罐子。并尝试了代码,但无法工作。 pbe.java

  • 问题内容: 我是密码学的新手。我希望学习如何在文件中加密和解密文本……当我在net中引用相关文章时。我怀疑对同一文本进行多次加密后,单个文本的加密文本是否会相同?谁能解决我的疑问? 问题答案: 这是使用该类的示例:

  • 问题内容: 我正在尝试实施PKI。我想在Java中使用RSA而不使用弹性城堡来加密大字符串。我得到的问题是数据不得超过117个字节。我尝试寻找失败的解决方案。我是这种加密的新手。请提供一个大字符串作为示例来帮助我并进行解释。 问题答案: 一次不能使用超过128个字节的RSA加密解密。您必须拆分数据并在循环中进行处理,几乎可以随时将字节写入String / Array。如果您唯一的问题是数据大小,那

  • 问题内容: 我正在尝试加密数据库中的一些文本,以便在程序启动期间进行加载和解密。 我尝试了几种方法,包括第三方库https://github.com/richard-lyman/lithcrypt无济于事。使用以下方法对8/10项进行加密/解密,但是似乎在加密/解密中的某些时候留下了一些填充残留。就目前而言,我的代码是这样的: 有人告诉我,我可能需要填充字符串,但是我不得不填充流密码似乎很奇怪。

  • 我有一个大约有500行信息的文本文件。 有没有什么方法可以使用awk和sed实现这一点呢?

  • 本文向大家介绍PHP封装的字符串加密解密函数,包括了PHP封装的字符串加密解密函数的使用技巧和注意事项,需要的朋友参考一下 程序中经常使用的PHP加密解密字符串函数 代码如下: 使用方法: 非常给力的authcode加密函数,Discuz!经典代码(带详解): 函数authcode($string, $operation, $key, $expiry)中的$string:字符串,明文或密文;$op