CryptoGuardOSS / cryptoguard

GNU General Public License v3.0
106 stars 30 forks source link

Small keysize RSA not detected #25

Open tl2cents opened 2 years ago

tl2cents commented 2 years ago

Hi, I'm conducting academic research on Java Cryptography API based misuse using your tool. After reading the paper and source codes, I believe that your team have implemented the rules to detect the RSA cipher with keysize < 2048 bits. I tried my test codes using 512-bit RSA , however, with no warnings. I also tried to use a default keysize (2048 bits) RSA to encrypt messages. Strangely, this time cryptoguard reported an issue saying : "Cause: Used default key size". I'm confused ,since by far, 2048-bit RSA is a secure cipher and cryptoguard arises a warning. Some improval in InsecureAssymCryptoFinder.java may help to solve this issue. I'm also trying to find ways to solve this missed-detection problem.

The test codes :

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import javax.xml.bind.DatatypeConverter;

public class RSA {
    /**
     * @param publicKey
     * @param srcBytes
     * @return
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public static byte[] encrypt(RSAPublicKey publicKey, byte[] srcBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        if(publicKey!=null){
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] resultBytes = cipher.doFinal(srcBytes);
            return resultBytes;
        }
        return null;
    }

    /**
     * @param privateKey
     * @param srcBytes
     * @return
     * @throws NoSuchAlgorithmException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws IllegalBlockSizeException
     * @throws BadPaddingException
     */
    public static byte[] decrypt(RSAPrivateKey privateKey, byte[] srcBytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException{
        if(privateKey!=null){
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] resultBytes = cipher.doFinal(srcBytes);
            return resultBytes;
        }
        return null;
    }

    /**
     * @param args
     * @throws NoSuchAlgorithmException
     * @throws BadPaddingException
     * @throws IllegalBlockSizeException
     * @throws NoSuchPaddingException
     * @throws InvalidKeyException
     * @throws IOException
     */
    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, IOException {
        String msg ="Super super secret message.Please keep it in mind.";
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // keyPairGen.initialize(512,new SecureRandom());
        keyPairGen.initialize(512);
        KeyPair keyPair = keyPairGen.generateKeyPair();
        RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();
        RSAPublicKey publicKey = (RSAPublicKey)keyPair.getPublic();

        Cipher cipher = Cipher.getInstance("RSA");
        byte[] srcBytes = msg.getBytes();
        // byte[] resultBytes = encrypt(publicKey, srcBytes);

        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] resultBytes = cipher.doFinal(srcBytes);
        byte[] decBytes = decrypt(privateKey, resultBytes);

        System.out.println(publicKey.toString());
        System.out.println(privateKey.getPrivateExponent());
        System.out.println("paintext is:" + msg);
        System.out.println("encrypted message is: " + DatatypeConverter.printBase64Binary(resultBytes));
        System.out.println("decrypted message is: " + new String(decBytes));
    }
}

Updated : 3.25. I've debugged the source code. Finally , I find that for some codes, cryptoguard can correctly identify the RSA small size key misuse , but for the above codes, it can't. The bug is from this line : java/rule/ExportGradeKeyInitializationFinder.java: 88. The two strings here may seem like this:

<RSA: void main(java.lang.String[])>[70]
[<RSA: void main(java.lang.String[70]]

It's strange but I'm not going to figure out the deeper reason causing strings like this. Logically speaking, the two strings indicate the same line in the source code, so the checking should be passed to do more slicing analysis. I simply parse the line number in the original strings and compare them to determine whether we should analyze more or return right here. A simple demo here :

 if (!(initializationCallsites.toString().contains(keyInitializationSite))) {
      String regEx = "[^0-9]";
      Pattern p = Pattern.compile(regEx);
      Matcher m1 = p.matcher(initializationCallsites.toString());
      Matcher m2 = p.matcher(keyInitializationSite);
      try {
        int i1 = Integer.valueOf(m1.replaceAll("").trim());
        int i2 = Integer.valueOf(m2.replaceAll("").trim());
        if (i1 != i2) {
          return;
        }
      } catch (NumberFormatException e) {
        return;
      }
    }

Hopefully, you may have better ways to solve this issue.

sazzad114 commented 1 year ago

Thank you so much for creating the issue! I would encourage you to open a pull request. :)