4

在将此标记为重复之前,请阅读完整的问题。

我在这里查看了无数关于这个问题的问题,每个答案都说要安装 JCE。但是,如果我想将程序发送给其他人,另一台计算机,几乎任何开发计算机之外的东西,他们也必须安装 JCE。

有没有一种方法可以使用较小的键大小而无需安装任何东西?

我的加密方法;

public static String encrypt(String in) throws NoSuchAlgorithmException,
   NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException,
   IllegalBlockSizeException, BadPaddingException, IOException {

    String out = " ";

    // generate a key
    KeyGenerator keygen = KeyGenerator.getInstance("AES");
    keygen.init(128);
    byte[] key = keygen.generateKey().getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    // build the initialization vector
    SecureRandom random = new SecureRandom();
    byte iv[] = new byte[16]; //generate random 16 byte IV. AES is always 16bytes
    random.nextBytes(iv);
    IvParameterSpec ivspec = new IvParameterSpec(iv);

    saveKey(key, iv); //<-- save to file

    // initialize the cipher for encrypt mode
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);

    byte[] encrypted = cipher.doFinal(in.getBytes());

    out = asHex(encrypted);

    return out;
}

还有我的解密方法:

public static String decrypt(String in) throws NoSuchAlgorithmException,
  NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException,
  IllegalBlockSizeException, BadPaddingException, IOException, KeyFileNotFoundException, UnknownKeyException {

    String out = " ";

    byte[] key = readKey("key").clone(); //<--from file
    SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");

    byte[] iv = readKey("iv"); //<-- from file
    IvParameterSpec ivspec = new IvParameterSpec(iv);

    //initialize the cipher for decryption
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivspec);

    // decrypt the message
    byte[] decrypted = cipher.doFinal(in.getBytes());

    out = asHex(decrypted);

    return out;
}

我的 saveKey() 方法:

private static void saveKey(byte[] key, byte[] iv) throws FileNotFoundException, IOException {

    File keyFile = new File(Logging.getCurrentDir() + "\\cikey.key");

    keys.setProperty("key", asHex(key));
    keys.setProperty("iv", asHex(iv));

    keys.store(new FileOutputStream(keyFile.getAbsolutePath(), false), null);
}

我的 readKey() 方法:

 private static byte[] readKey(String request) throws KeyFileNotFoundException, UnknownKeyException, FileNotFoundException, IOException {

    File keyFile = new File(Logging.getCurrentDir() + "\\cikey.key");
    byte[] storage;

    keys.load(new FileInputStream(keyFile));

    if (!keyFile.exists())
        throw new KeyFileNotFoundException("Key file not located.");

    if (keys.containsKey(request) == false)
        throw new UnknownKeyException("Key not found.");
    else
        storage = keys.getProperty(request).getBytes();

    return storage;
}

asHex() 方法(将数组转换为字符串):

public static String asHex(byte buf[]) {

    StringBuilder strbuf = new StringBuilder(buf.length * 2);

    for (int i = 0; i < buf.length; i++) {
        if (((int) buf[i] & 0xff) < 0x10)
            strbuf.append("0");

        strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
    }
    return strbuf.toString();
}
4

1 回答 1

3

有没有一种方法可以使用较小的键大小而无需安装任何东西?

您不能使用密钥大小小于 128 位的 AES,但还有其他可用的密码:DES、Blowfish 等。它们不如 AES 安全,但如果您的应用程序(如大多数应用程序那样)仍然可以解决问题) 不值得进行复杂的黑客攻击。以下是 56 位 DES 的示例:

 public static String encrypt(String in) throws Exception {
    String out = " ";
    // generate a key
    KeyGenerator keygen = KeyGenerator.getInstance("DES");
    keygen.init(56);
    byte[] key = keygen.generateKey().getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(key, "DES");

    // build the initialization vector
    SecureRandom random = new SecureRandom();
    byte iv[] = new byte[8]; //generate random 8 byte IV. 
    random.nextBytes(iv);
    IvParameterSpec ivspec = new IvParameterSpec(iv);
    // initialize the cipher for encrypt mode
    Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);

    byte[] encrypted = cipher.doFinal(in.getBytes());

    out = asHex(encrypted);

    return out;
}

存储和读取代码中的密钥也存在问题。您将它们存储为十六进制,但从默认平台编码中读取为符号。这是一个如何使两个操作统一的示例:

private static void saveKey(byte[] key, byte[] iv) throws IOException {
    File keyFile = new File("C:/cikey.key");
    keys.setProperty("key", toHexString(key));
    keys.setProperty("iv", toHexString(iv));
    keys.store(new FileOutputStream(keyFile.getAbsolutePath(), false), null);
}

private static byte[] readKey(String request) throws IOException {
    File keyFile = new File("C:/cikey.key");
    keys.load(new FileInputStream(keyFile));
    return toByteArray(keys.getProperty(request));
}

public static String toHexString(byte[] array) {
    return DatatypeConverter.printHexBinary(array);
}

public static byte[] toByteArray(String s) {
    return DatatypeConverter.parseHexBinary(s);
}
于 2013-08-29T21:51:45.413 回答