2015-09-07 52 views
1

我有一个将RSA密钥大小硬编码为384位的遗留应用程序,我需要能够在我的Java应用程序中验证这些密钥的签名。问题:有没有一种方法可以在Java中创建和使用密钥大小小于512的RSA密钥?Java中小于512位的RSA密钥大小

(我完全意识到有一个原因限制512位,但我不能改变遗留应用程序)。

+1

您是否需要在您的(非遗留)应用程序中生成密钥,或者您是否可以使用从外部生成的密钥? –

+2

“为了分析512位导出密钥,该项目征求了U. Penn的Nadia Heninger的帮助,他一直致力于”Factoring as a Service“,正是因为这一点,她的平台在群集上使用cado-nfs EC2虚拟服务器,以及(与Nadia处理崩溃有关的手持方式)能够分解一堆512位密钥 - 每个约7.5小时,EC2时间为104美元。“ –

+2

@MaartenBodewes这意味着分解384位密钥的速度要快得多。它应该在个位数分钟的地方,对吧? –

回答

3

是的,但您必须使用另一个提供商。当您尝试使用384位RSA密钥时,Sun RSAKeyFactory(底层服务提供商实施KeyFactory)和RSAKeyPairGenerator都会返回异常。

正确安装充气城堡供应商后,这将然而工作:

Security.addProvider(new BouncyCastleProvider()); 

KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC"); 
kpg.initialize(384); 
KeyPair kp = kpg.generateKeyPair(); 
PublicKey genPub = kp.getPublic(); 

byte[] enc = genPub.getEncoded(); 

KeyFactory kf = KeyFactory.getInstance("RSA", "BC"); 
X509EncodedKeySpec ks = new X509EncodedKeySpec(enc); 
PublicKey decPub = kf.generatePublic(ks); 

Signature sig = Signature.getInstance("SHA1withRSA", "BC"); 
sig.initVerify(decPub); 
byte[] faultySig = new byte[384/Byte.SIZE]; 
boolean verifies = sig.verify(faultySig); 

System.out.println(verifies + " for " + decPub.getAlgorithm()); 

注意,因为由Signature实例的KeyFactoryinit方法生成的,甚至会默默地用充气城堡提供关键的类型如果没有指定"BC"

+0

谢谢!作品真的很好! :) –

0

如果您想手动编写代码来创建更小的密钥,我可以为我编写的C#程序提供源代码。您应该很容易移植到Java。请记住,即使使用已建立的算法来实现自己的加密例程的一般警告也有很好的理由。因为除非程序员非常小心,否则即使算法本身很好,该软件也可能会受到侧通道攻击的影响。话虽如此,在384位,您的安全性已经足够低,甚至不需要旁路通道攻击,也不应该成为一个主要问题(直接分解攻击会更便宜,更容易)。

所有这一切,这里是源代码。它与那些不在那里的窗口进行交互,但至少它应该给你一个RSA keygen如何工作的好主意。我刚刚尝试了384位密钥,即使在C#中,它也可以在一秒之内生成它们。也请原谅代码中的任何低效率。我主要写它只是为了确保我理解它是如何工作的。这是代码。

此外,我会分享项目in Dropbox,以防有人想在那里看看它。

using System; 
using System.Numerics; 
using System.Security.Cryptography; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace RSAinCS 
{ 
    public partial class Form1 : Form 
    { 
     RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); 
     struct RSAKey 
     { 
      internal BigInteger p; // one prime factor of the modulus 
      internal BigInteger q; // another prime factor of the modulus 
      internal BigInteger n; // modulus, a part of both the public key and the private key 
      internal BigInteger totient; // product of p-1 and q-1. Must be kept secret. We calculate it because we need to confirm our public exponent (65537) doesn't divide it evenly 
      internal BigInteger e; // public exponent. Together with n forms the public key 
      internal BigInteger d; // private exponent. Together with n forms the private key. Must be kept secret 
     } 

     struct EGCDReturnStruct 
     { 
      internal BigInteger g; 
      internal BigInteger x; 
      internal BigInteger y; 
     } 

     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      int bitLength = 0; 
      Int32.TryParse(comboBox1.Text, out bitLength); 
      if (bitLength == 0) return; 
      Task.Run(() => { doWork(bitLength); }); 
     } 

     void doWork(int bitLength) 
     { 
      RSAKey rsaKey = generateKey(bitLength); 
      BeginInvoke(new Action(() => textBox2.Text = rsaKey.p.ToString())); 
      BeginInvoke(new Action(() => textBox3.Text = rsaKey.q.ToString())); 
      BeginInvoke(new Action(() => textBox4.Text = rsaKey.n.ToString())); 
      BeginInvoke(new Action(() => textBox5.Text = rsaKey.totient.ToString())); 
      BeginInvoke(new Action(() => textBox6.Text = rsaKey.e.ToString())); 
      BeginInvoke(new Action(() => textBox7.Text = rsaKey.d.ToString())); 
      BeginInvoke(new Action(() => textBox8.Text = textBox1.Text)); 
      BigInteger message = convertTextToBigInteger(textBox8.Text); 
      BeginInvoke(new Action(() => textBox9.Text = message.ToString())); 
      BigInteger cipherText = BigInteger.ModPow (message,rsaKey.e,rsaKey.n); 
      BeginInvoke(new Action(() => textBox10.Text = cipherText.ToString())); 
      BigInteger decryptedCipherText = BigInteger.ModPow(cipherText, rsaKey.d, rsaKey.n); 
      BeginInvoke(new Action(() => textBox11.Text = decryptedCipherText.ToString())); 
      BeginInvoke(new Action(() => textBox12.Text = convertBigIntegerToText(decryptedCipherText))); 
     } 

     string convertBigIntegerToText(BigInteger b) 
     { 
      StringBuilder sb = new StringBuilder(); 
      byte[] letterByte = new byte[1]; 
      string letter; 
      while (b > 0) 
      { 
       letterByte[0] = (byte)(b % 256); 
       letter = ASCIIEncoding.UTF8.GetString(letterByte); 
       sb.Append(letter); 
       b /= 256; 
      } 
      return sb.ToString(); 
     } 

     BigInteger convertTextToBigInteger(string s) 
     { 
      BigInteger textInteger = 0; 
      byte[] textBytes = ASCIIEncoding.UTF8.GetBytes(s); 
      for (int i = 0; i < textBytes.Length; i++) 
      { 
       textInteger += textBytes[textBytes.Length-1-i]; 
       if (i < textBytes.Length - 1) textInteger *= 256; 
      } 
      return textInteger; 
     } 

     RSAKey generateKey(int bitLength) 
     { 
      RSAKey rsaKey = new RSAKey(); 
      // Generate 2 large primes. The first will be p, and the second will be q. 
      for (int i = 0; i < 2; i++) 
      { 
       // The bit length of each prime, p and q, is half the bit length of the whole modulus, and we divide by 8 for byte length 
       byte[] primeBytes = new byte[bitLength/16]; 
       rng.GetBytes(primeBytes); 
       BigInteger primeNumber = 0; 
       for (int j = 0; j < primeBytes.Length; j++) 
       { 
        primeNumber += primeBytes[j]; 
        if (j < primeBytes.Length - 1) primeNumber *= 256; 
       } 
       if (primeNumber % 2 == 0) primeNumber++; // Make our prime odd 

       // This next bit of code ensures zeros in the high bits don't give us small (less secure) prime factors of the modulus 
       BigInteger highBitValue = BigInteger.Pow(2, (bitLength/2) - 1); 
       BigInteger secondBitValue = BigInteger.Pow(2, (bitLength/2) - 2); 
       if (primeNumber < secondBitValue) primeNumber += secondBitValue; 
       if (primeNumber < highBitValue) primeNumber += highBitValue; 

       if (isProbablyPrime(primeNumber, 100) == true) 
       { 
        if (i == 0) rsaKey.p = primeNumber; 
        else rsaKey.q = primeNumber; 
       } 
       else 
       { 
        i--; 
        continue; 
       } 
      } 
      rsaKey.n = rsaKey.p * rsaKey.q; 
      rsaKey.totient = (rsaKey.p - 1) * (rsaKey.q - 1); 
      // A little recursion. Checks if totient is OK for use with our chose public exponent. If not, runs method again 
      // I also have it repeat if the modInv method returns a value less than 0. This may be fixable in the modInv or egcd method, not sure 
      if (rsaKey.totient % 65537 == 0 || modInv(65537, rsaKey.totient) < 0) return generateKey(bitLength); 
      //if (rsaKey.totient % 65537 == 0) return generateKey(bitLength); 
      else 
      { 
       rsaKey.e = 65537; 
       rsaKey.d = modInv(rsaKey.e, rsaKey.totient); 
       return rsaKey; 
      } 
     } 

     BigInteger modInv(BigInteger a, BigInteger m) 
     { 
      EGCDReturnStruct eGCDReturnStruct = new EGCDReturnStruct(); 
      eGCDReturnStruct = egcd(a, m); 
      if (eGCDReturnStruct.g != 1) throw new Exception("Modular Inverse Does Not Exist"); 
      else return eGCDReturnStruct.x % m; 
     } 

     EGCDReturnStruct egcd(BigInteger a, BigInteger b) 
     { 
      EGCDReturnStruct eGCDReturnStruct = new EGCDReturnStruct(); 
      if (a == 0) 
      { 
       eGCDReturnStruct.g = b; 
       eGCDReturnStruct.x = 0; 
       eGCDReturnStruct.y = 1; 
       return eGCDReturnStruct; 
      } 
      else 
      { 
       eGCDReturnStruct = egcd(b % a, a); 
       BigInteger temp = eGCDReturnStruct.x; 
       eGCDReturnStruct.x = eGCDReturnStruct.y; 
       eGCDReturnStruct.y = temp; 
       eGCDReturnStruct.x -= (b/a) * eGCDReturnStruct.y; 
       return eGCDReturnStruct; 
      } 
     } 

     bool isProbablyPrime(BigInteger testNumber, int confidence) 
     { 
      int[] firstPrimes = {2,3,5,7,11,13,17,19}; 

      for (int i = 0; i < firstPrimes.Length; i++) 
      { 
       if ((testNumber % firstPrimes[i]) == 0) return false; 
      } 
      for (int i = 2; i < 101; i++) 
      { 
       if (BigInteger.ModPow(i, testNumber - 1, testNumber) != 1) return false; 
      } 
      BigInteger nMinusOne = testNumber - 1; 
      BigInteger nMinusOneTemp = nMinusOne; 
      int s = 0; 
      while (nMinusOneTemp % 2 == 0) 
      { 
       s++; 
       nMinusOneTemp /= 2; 
      } 
      BigInteger d = nMinusOneTemp; 
      bool probablyPrime = true; 
      int counter = 0; 
      int a = 2; 
      while ((counter < confidence) & (probablyPrime == true) & (a < testNumber)) 
      { 
       counter++; 
       probablyPrime = false; 
       if (BigInteger.ModPow(a, d, testNumber) == 1) 
       { 
        probablyPrime = true; 
       } 
       else 
       { 
        for (int r = 0; r < s; r++) 
        { 
         BigInteger j = BigInteger.ModPow(a, d, testNumber); 
         for (BigInteger t = 0; t < r; t++) 
         { 
          j = (j * BigInteger.ModPow(j, 2, testNumber)) % testNumber; 
         } 
         if (j == nMinusOne) 
         { 
          probablyPrime = true; 
          break; 
         } 
        } 
       } 
       if (probablyPrime == true) 
       { 
        a++; 
       } 
       else 
       { 
        return false; 
       } 
      } 
      return true; 
     } 
    } 
}