Maven 3密码加密如何工作?

时间:2015-06-11 00:33:03

标签: security maven encryption passwords

我试图了解Maven 3的[密码加密功能。我发现这个功能记录不清,令人困惑。例如,feature documentationa blog post by the author of the feature在几个方面相互矛盾。

此问题比How does maven --encrypt-master-password work更广泛,Maven encrypt-master-password good practice for choosing password未涵盖。

具体来说,我正在尝试回答文档未涵盖的以下问题。我已经在斜体字下面的每个问题下面提供了我能够收集的信息。

  1. 加密主密码是否仅在一个用户可以访问(settings-security.xml)的文件夹中~/.m2中存在,从而提供安全性?如果是这样,为什么还要加密主密码' (为什么不使用一些随机值)?不是主密码'真的只是加密函数的熵输入?将其称为密码令人困惑 - 我希望Maven在解密任何加密的服务器密码之前提示我输入此密码,但事实并非如此。
  2. 我的理解是,这只是通过受操作系统保护的文件中存在来提供安全性。我相信Maven允许您加密主密码,这样如果您丢失settings-security.xml文件,您可以重新生成它。这是对的吗?

    1. 主密码和服务器密码是否使用相同的加密过程/密码?服务器密码基于主密码,因此算法必须存在一些差异。这个源代码在哪里?
    2. Marcelo Morales' answer on How does maven --encrypt-master-password work指向plexus-cihper project on GitHub的链接。目前还不清楚这只是密码,还是提供密码功能的实际Maven插件。

      1. 我发现多次加密相同的主密码或服务器密码会产生不同的哈希值。根据{{​​3}},这是因为' JVM配置特定的(通常是SHA1PRNG)64位随机盐'在加密之前添加到密码。 Maven在编译时使用它们来解密存储的密码。这是不是意味着盐必须存放在某个地方?
      2. 我不知道

        1. 我还观察到,如果主密码被重新加密并存储在settings-security.xml文件中,即使加密的主密码密文是现在不同了。有人能解释一下这是如何起作用的吗?
        2. 我不知道。在我看来,Maven正在做一些可疑的事情或在某处存储明文。

          1. 我的理解是加密密码只能与<server />文件中的settings.xml标记一起使用。这是真的? settings.xml中定义的服务器可以在哪里使用?
          2. 我的理解是<server />定义可以在<repositories /><distributionManagement />中使用,但不能在<scm />中使用。有人可以验证吗?

            1. 对于这样一个关键功能(构建系统安全性),在我看来,存在很多混乱和糟糕的文档。有人能指出Maven 3网站上的文档是如何工作的吗?是否有某个wiki链接允许我尝试改进文档?
            2. 我不知道

              对不起文字墙,感谢您的回答。

3 个答案:

答案 0 :(得分:11)

我的回答是基于阅读Maven源代码并进行一些研究。

  1. 加密的主密码是否只在settings-security.xml中只存在于一个只有一个用户可以访问的文件夹(~/.m2)中才能提供安全性?如果是这样,为什么还要加密'主密码'(为什么不使用一些随机值)呢? “主密码”不仅仅是加密函数的熵输入吗?将其称为密码令人困惑 - 我希望Maven在解密任何加密的服务器密码之前提示我输入此密码,但事实并非如此。
  2. 主密码是加密函数的输入,用于加密/解密服务器密码。如果某人拥有您的个人加密服务器密码,除非他们也拥有您的主密码,否则他们将无法对其进行解密。这意味着您可以与其他人自由共享您的maven settings.xml文件,而无需他们解密您的服务器密码。这也是主密码保存在单独文件中的原因。

    这个基本原理在encryption guide

    中有所解释
    1. 主密码和服务器密码是否使用相同的加密过程/密码?服务器密码基于主密码,因此算法必须存在一些差异。这个源代码在哪里?
    2. 据我所知,主密码使用与服务器密码相同的密码加密。解密服务器密码时,主密码(加密形式)是输入;解密主密码时,魔术字符串'“settings.security”'用作附加输入。

      您可以看到源代码PBECipherMavenCli.java

      1. 我发现多次加密相同的主密码或服务器密码会产生不同的哈希值。根据{{​​3}},这是因为在加密之前,'JVM配置特定的(通常是SHA1PRNG)64位随机盐'被添加到密码中。 Maven在编译时使用它们来解密存储的密码。这不是说盐必须存放在某个地方吗?
      2. 处理盐的传统方法是随机盐与加密文本一起存储。请参阅Marcelo Morales' answer on How does maven --encrypt-master-password work

        根据上面链接的源代码,salt似乎存储为Base64解码字节的前8个字节,就在加密密码之前。

        1. 我还观察到,如果主密码被重新加密并存储在settings-security.xml文件中,即使加密的主密码密文是现在不同了。有人能解释一下这是如何起作用的吗?
        2. 这是因为使用了主密码的解密形式,而不是加密的“密文”。因此,重新加密它不会影响服务器密码加密/解密。

          我不知道你最后两(5和6)个问题的答案。

答案 1 :(得分:2)

我需要知道这对于bnd(工具),所以我可以分享一些更深入的分析。

加密&#39;密码的语法为:

output    ::= '{' base64(packet) '}'
packet    ::= salt[8] padlen[1] encrypted[?] padding[padlen]
salt      ::= <random>
padlen    ::= <length of padding >
padding   ::= <random to make packet length a multiple of 16>

使用的密码是AES/CBC/PKCS5Padding。秘密密钥和初始化向量计算如下:

sha = sha256( X + salt[8] )
key = sha[0..16]
iv  = sha[16..32]

对于主密码,X是&#34; security.settings&#34;。由于这是一个众所周知的常量,因此主密码不会加密,而只会被模糊。对于服务器密码,X是解码的主密码。

为什么生成的数据包被填充似乎是浪费字节,因为数据包格式使剥离变得微不足道,它们永远不会成为加密/解密的一部分。他们只是在base64字符串中添加了一些随机字符。

唯一有用的方法是使用重定位工具。例如,如果将settings-security.xml挂载到构建服务器上的专用挂载上。然后,您可以在公共存储库中自由共享settings.xml文件。但是,这也是一个很糟糕的解决方案,因为您需要为所有用户和CI构建服务器安装相同的挂载点。

请注意,任何插件都可以解码所有服务器密码,因此永远不要使用服务器的真实密码。 Nexus可以创建代理密码。

答案 2 :(得分:1)

以下示例代码显示如何解密来自

的maven主密码

~/.m2/security-settings.xml

以及来自

的服务器密码

~/.m2/settings.xml

MavenPasswordDecryptor.java

的来源
import org.sonatype.plexus.components.cipher.DefaultPlexusCipher;

public class MavenPasswordDecryptor {
    public static void main(String[] args) throws Exception {

        if (args.length < 1 || args.length > 2 ) {
            System.out.println("Usage: java -jar maven-password-decryptor.jar <encrypted-password>");
            System.out.println("Usage: java -jar maven-password-decryptor.jar <encrypted-password> <master-password>");
            return;
        }

        DefaultPlexusCipher cipher = new DefaultPlexusCipher();

        String encryptedPassword = args[0];
        String passPhrase = (args.length == 2 && args[1] != null && !args[1].isEmpty()) ? args[1] : "settings.security";

        String result = cipher.decryptDecorated(encryptedPassword, passPhrase);

        System.out.println(result);
    }
}

GitHub上还有一个示例项目:

https://github.com/uweguenther/maven-password-decryptor