2 java encryption cryptography aes hmac
我正在尝试找到一种方法来完成我的 Java 课程作业。我需要加密一个文件,但老实说我并没有真正理解这些说明。我实现了文件加密和解密,但是我怀疑它是否按照说明进行操作。指令如下:
\n\n我写的代码是这样的,它成功加密了一个文本文件。这是我的应用程序的完整代码。
\n\nimport java.io.FileNotFoundException;\nimport java.io.*;\nimport java.util.Scanner;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.security.AlgorithmParameters;\nimport java.security.SecureRandom;\nimport java.security.spec.KeySpec;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.SecretKey;\nimport javax.crypto.SecretKeyFactory;\nimport javax.crypto.spec.IvParameterSpec;\nimport javax.crypto.spec.PBEKeySpec;\nimport javax.crypto.spec.SecretKeySpec;\n\npublic class AESFileEncryption {\n\n/*public AESFileEncryption(String nameoffile){\n\n}\npublic String FileReturn(String filename){\n String fl = filename; \n return fl; \n}*/\n\npublic static void main(String[] args) throws Exception {\n\n File f = new File("plainfile.txt");\n File g = new File("plainfile.txt.8102");\n File fl = new File("plainfile.txt.8102");\n\n if(g.exists() && !g.isDirectory()){\n System.out.println("The file is already encrypted...");\n String fname = fl.getAbsolutePath();\n System.out.print("Absolute Encrypted File Pathname => "+ fname);\n System.exit(0);\n } \n else if(f.exists() && !f.isDirectory()) { \n System.out.println(" The file is found.The encryption process is going to begin...");\n\n } \n else{\n System.out.println(" The file is missing!!!!");\n System.exit(0);\n }\n\n // file to be encrypted\n FileInputStream inFile = new FileInputStream("plainfile.txt"); \n\n // encrypted file\n FileOutputStream outFile = new FileOutputStream("plainfile.txt.8102");\n\n\n // password to encrypt the file\n Scanner scan= new Scanner(System.in);\n System.out.println("Enter the password : => ");\n String password= scan.nextLine();\n\n //String password = "javapapers";\n\n // password, iv and salt should be transferred to the other end\n // in a secure manner\n\n // salt is used for encoding\n // writing it to a file\n // salt should be transferred to the recipient securely\n // for decryption\n byte[] salt = new byte[8];\n SecureRandom secureRandom = new SecureRandom();\n secureRandom.nextBytes(salt);\n FileOutputStream saltOutFile = new FileOutputStream("salt.enc");\n saltOutFile.write(salt);\n saltOutFile.close();\n\n SecretKeyFactory factory = SecretKeyFactory\n .getInstance("PBKDF2WithHmacSHA1");\n KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536,\n 256);\n SecretKey secretKey = factory.generateSecret(keySpec);\n SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");\n\n //\n Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");\n cipher.init(Cipher.ENCRYPT_MODE, secret);\n AlgorithmParameters params = cipher.getParameters();\n\n // iv adds randomness to the text and just makes the mechanism more\n // secure\n // used while initializing the cipher\n // file to store the iv\n FileOutputStream ivOutFile = new FileOutputStream("iv.enc");\n byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();\n ivOutFile.write(iv);\n ivOutFile.close();\n\n //file encryption\n byte[] input = new byte[64];\n int bytesRead;\n\n while ((bytesRead = inFile.read(input)) != -1) {\n byte[] output = cipher.update(input, 0, bytesRead);\n if (output != null)\n outFile.write(output);\n }\n\n byte[] output = cipher.doFinal();\n if (output != null)\n outFile.write(output);\n\n inFile.close();\n outFile.flush();\n outFile.close();\n\n System.out.println("File Encrypted.");\n\n }\n\n}\nRun Code Online (Sandbox Code Playgroud)\n
讲师表示应该应用 HMAC 来为密文创建身份验证标记。这称为先加密后 MAC。HMAC 是一种密钥哈希函数,它为拥有正确密钥的接收者提供真实性(和完整性,因为没有完整性的真实性没有任何意义)检查。由于它本质上是一个哈希函数,因此它通过更新内部状态来工作。
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec macKey = new SecretKeySpec(macKeyBytes, "HmacSHA1");
mac.init(macKey);
mac.update(iv); // update for IV
...
mac.update(output); // update for each ciphertext chunk
...
byte[] authTag = mac.doFinal();
outfile.write(authTag); // at the very end
Run Code Online (Sandbox Code Playgroud)
仍然存在一个问题,那就是macKeyBytes. 它不应与您通过 PBKDF2 从密码生成的加密密钥相同。您应该使用生成的密钥分别导出加密和 MAC 密钥。这通常是使用HKDF完成的,但您也可以再次使用 HMAC 来完成。伪代码:
byte[] encKeyBytes = hmacSha256(key, "Encryption");
byte[] macKeyBytes = hmacSha256(key, "Authentication");
Run Code Online (Sandbox Code Playgroud)
该指令没有提及任何有关密钥或密码的信息,因此我假设它应该是静态密钥(用于测试目的)。您使用 PBKDF2 的方式是可以的,但盐也必须写入文件中。否则,如果没有随机盐,接收者将无法导出相同的密钥。另外,salt 的长度应该是 16 个字节。
当前代码的另一个问题是您将 IV 写入单独的文件中。不要那样做。只需将 IV 写入密文文件的开头即可。IV 与 CBC 模式下的块大小相同,而 AES 的块大小固定为 16 字节。接收者将始终知道要为 IV 读取多少字节。
| 归档时间: |
|
| 查看次数: |
8919 次 |
| 最近记录: |