Encryption 使用加密密码文件执行Sqoop导入时获取BadPaddingException

Encryption 使用加密密码文件执行Sqoop导入时获取BadPaddingException,encryption,sqoop,password-encryption,encryption-symmetric,Encryption,Sqoop,Password Encryption,Encryption Symmetric,我使用openssl加密文件,然后将其放在HDFS上,我使用了AES/ECB、128位和salt选项,通过一些研究,我发现openssl使用PKCS5填充作为默认值,这些都是默认值。以下是我的加密过程: # echo -n "password" > .pw # openssl enc -aes-128-ecb -salt -in .pw -out .pw.enc # hdfs dfs -put .pw.enc /user/user1/ Sqoop版本是1.4.6 命令: sqoop im

我使用
openssl
加密文件,然后将其放在HDFS上,我使用了AES/ECB、128位和salt选项,通过一些研究,我发现openssl使用PKCS5填充作为默认值,这些都是默认值。以下是我的加密过程:

# echo -n "password" > .pw
# openssl enc -aes-128-ecb -salt -in .pw -out .pw.enc
# hdfs dfs -put .pw.enc /user/user1/
Sqoop版本是1.4.6

命令:

sqoop import \
-Dorg.apache.sqoop.credentials.loader.class=org.apache.sqoop.util.password.CryptoFileLoader \
-Dorg.apache.sqoop.credentials.loader.crypto.passphrase=sqoop \
--connect jdbc:oracle:thin:@host/database \
--username user1 \
--password-file /user/user1/.pw.enc \
--table db.table1 \
--hive-import \
--hive-overwrite \
--hive-table hivedb.table1 \
--hive-drop-import-delims
其中:

17/03/08 15:10:37 WARN tool.BaseSqoopTool: Failed to load password file
java.io.IOException: Can't decrypt the password
        at org.apache.sqoop.util.password.CryptoFileLoader.loadPassword(CryptoFileLoader.java:151)
        at org.apache.sqoop.util.CredentialsUtil.fetchPasswordFromLoader(CredentialsUtil.java:81)
        at org.apache.sqoop.util.CredentialsUtil.fetchPassword(CredentialsUtil.java:66)
        at org.apache.sqoop.tool.BaseSqoopTool.applyCredentialsOptions(BaseSqoopTool.java:1042)
        at org.apache.sqoop.tool.BaseSqoopTool.applyCommonOptions(BaseSqoopTool.java:997)
        at org.apache.sqoop.tool.ImportTool.applyOptions(ImportTool.java:875)
        at org.apache.sqoop.tool.SqoopTool.parseArguments(SqoopTool.java:435)
        at org.apache.sqoop.Sqoop.run(Sqoop.java:131)
        at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
        at org.apache.sqoop.Sqoop.runSqoop(Sqoop.java:179)
        at org.apache.sqoop.Sqoop.runTool(Sqoop.java:218)
        at org.apache.sqoop.Sqoop.runTool(Sqoop.java:227)
        at org.apache.sqoop.Sqoop.main(Sqoop.java:236)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
        at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
        at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
        at javax.crypto.Cipher.doFinal(Cipher.java:2165)
        at org.apache.sqoop.util.password.CryptoFileLoader.loadPassword(CryptoFileLoader.java:149)
        ... 12 more
Error while loading password file: Can't decrypt the password
我还尝试手动提供其他CryptoFileLoader参数,并将本地文件传递给
--密码文件

我可以使用
openssl
成功解密该文件。我不能用Java程序解密(?)

我看到了填充的问题,但我不知道它是什么,也不知道如何用某种填充方法或其他方法对文件进行加密,我对加密没有经验

类中还有
org.apache.sqoop.credentials.loader.crypto.iterations
参数,指示PBKDF2迭代的次数,但我不知道它是否改变了什么


谢谢您的帮助。

我不是Sqoop和Hadoop的专家,但从您的异常开始

CryptoFileLoader.loadPassword(CryptoFileLoader.java:151)
我看了一下的源代码

在我看来,事情与您所做的有些不同:密码使用PBKDF2算法存储在加密文件中,这与应用AES-128-ECB不同。发件人:

PBKDF2将伪随机函数(如基于哈希的消息身份验证码(HMAC))与salt值一起应用于输入密码或密码短语,并多次重复该过程以生成派生密钥,该密钥随后可在后续操作中用作加密密钥。增加的计算工作使得密码破解更加困难,这被称为密钥拉伸

无法从Openssl命令行执行PBKDF2。我用Java做了一个小测试,它可能是一个替代方案

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;

public class Test {

    /*Default is AES in electronic code book with padding.*/
    private static String DEFAULT_ALG = "AES/ECB/PKCS5Padding";
    /*Default salt is not much secure, use your own!*/
    private static String DEFAULT_SALT = "SALT";
    /*Iterate 10000 times by default.*/
    private static int DEFAULT_ITERATIONS = 10000;
    /*One of valid key sizes for default algorithm (AES).*/
    private static int DEFAULT_KEY_LEN = 128;

    public static void main(String[] args) throws IOException {

        String inputFileName = "C:\\temp\\in.txt";   /*Enter your input (plain) file path */
        String outputFileName = "C:\\temp\\out.bin"; /*Enter your output (encrypted) file path */
        String passPhrase = "mypassphrase";          /*Enter your passphrase */
        String salt = DEFAULT_SALT;
        String alg = DEFAULT_ALG;
        int iterations = DEFAULT_ITERATIONS;
        int keyLen = DEFAULT_KEY_LEN;

        SecretKeyFactory factory = null;
        try {
            factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        } catch (NoSuchAlgorithmException e) {
            throw new IOException("Can't load SecretKeyFactory", e);
        }

        SecretKeySpec key = null;
        try {
            String algOnly = alg.split("/")[0];
            key = new SecretKeySpec(
                    factory.generateSecret(
                            new PBEKeySpec(passPhrase.toCharArray(), salt.getBytes(), iterations, keyLen)).getEncoded(),
                    algOnly);
        } catch (Exception e) {
            throw new IOException("Can't generate secret key", e);
        }

        Cipher crypto = null;
        try {
            crypto = Cipher.getInstance(alg);
        } catch (Exception e) {
            throw new IOException("Can't initialize the decryptor", e);
        }

        Path inputFileLocation = Paths.get(inputFileName);
        byte[] decrypted = Files.readAllBytes(inputFileLocation);
        byte[] encrypted;

        try {
            crypto.init(Cipher.ENCRYPT_MODE, key);
            encrypted = crypto.doFinal(decrypted);
        } catch (Exception e) {
            throw new IOException("Can't decrypt the password", e);
        }

        Path outputFileLocation = Paths.get(outputFileName);
        Files.write(outputFileLocation, encrypted);
    }
}

正如Simone的回答一样,openssl和java实现之间的加密算法存在差异。这就是为什么您可以使用openssl进行解密而不会出现问题(因为它再次调用了自己的(不同的)算法)

经过深入研究,我从()中找到了以下答案:

简短回答:openssl enc(未使用-K表示原始)使用的不是PBKDF2;它几乎是PBKDF1,迭代次数为1

似乎有两种方法可以解决这个问题:

a) 在java中找到一些可以解密openssl正在做什么的东西——在本文的一篇文章中引用了一个java库“BouncyCastle”(如果您乐于使用它而不是标准加密文件),其中他们实现了与openssl使用的完全相同的算法

b) 查找其他一些命令行实用程序来代替实现PBKDF2的openssl。本文还提到了许多不同语言的实现


(由于Dave引用了关键观察值,因此应归功于他)

一个错误的填充异常是由decrypotion失败引起的。数据、键、模式和/或iv中存在错误。但由于未提供示例测试数据,因此很难调查原因。您需要转储各种输入并将它们添加到问题中。不要使用ECB模式,这是不安全的,请参阅,向下滚动到企鹅模式。取而代之的是将CBC模式与随机IV一起使用,只需在加密数据前加上IV前缀即可用于解密,它不需要保密。对于AES,某些指针使用全长密钥,这意味着128、192或256位(16、24或32字节)。使用短密钥将导致错误或不确定的填充,这取决于实现。不要加密密码,当攻击者获得DB时,他也将获得加密密钥。用随机盐在HMAC上迭代大约100毫秒,并用散列保存盐。使用诸如password_hash、PBKDF2、Bcrypt等函数和类似函数。关键是让攻击者花费大量时间通过暴力手段查找密码。@zaph感谢您的评论。正如我所看到的,CBC更安全,但我还不需要太多的安全性,因为我只希望数据库密码不显示在Sqoop导入配置中,也不显示为文件中的纯文本。我尝试改用CBC,但它需要一个IV参数,我无法传递它,因为它没有在CryptoFileLoader中定义如何传递。我想我会更深入地研究这个填充异常和您在上一篇评论中提到的迭代。谢谢链接。他们让我对加密过程和标准有了更深入的了解。我根据我的CryptoFile类和Simone的答案制作了一个Java程序,而不是openssl,现在可以运行了。谢谢你的答案。我不知道我不能做PBKDF2迭代,也不需要它。我根据您在这里发布的代码和CryptoFileLoader类编写了一个Java程序,解决了我的问题。