Maven 3 密码加密是如何工作的?
How does Maven 3 password encryption work?
我正在尝试了解 Maven 3 的[密码加密功能。我发现此功能的文档很少且令人困惑。例如,feature documentation and a blog post by the author of the feature在几个点上相互矛盾。
这个问题比 How does maven --encrypt-master-password work and is not covered by Maven encrypt-master-password good practice for choosing password 更广泛。
具体来说,我试图回答以下文档未涵盖的问题。我已经在每个问题下方用斜体字列出了到目前为止我能够收集到的信息。
- 加密的主密码是否仅通过存在于
settings-security.xml
中只有一个用户可以访问的文件夹 (~/.m2
) 中来提供安全性?如果是这样,为什么还要为 'master password' 加密(为什么不使用一些随机值)? 'master password' 真的只是加密函数的熵输入吗?称它为密码令人困惑 - 我希望 Maven 在解密任何加密的服务器密码之前提示我输入此密码,但它没有。
我的理解是,是的,这仅通过存在于受操作系统保护的文件中来提供安全性。我相信 Maven 允许您加密主密码,这样如果您丢失了 settings-security.xml
文件,您可以重新生成它。这是正确的吗?
- 主密码和服务器密码是否使用相同的加密方式process/cipher?服务器密码是基于主密码的,所以算法上肯定有一些区别。这个的源代码在哪里?
Marcelo Morales' answer on How does maven --encrypt-master-password work links to the plexus-cihper project on GitHub。目前尚不清楚这只是密码,还是提供密码功能的实际 Maven 插件。
- 我观察到多次加密的同一个主密码或服务器密码会给出不同的哈希值。根据 Marcelo Morales' answer on How does maven --encrypt-master-password work,这是因为 'a JVM-configuration-specific (usually SHA1PRNG) 64-bit random salt' 在加密之前添加到密码中。 Maven 在编译时使用时解密存储的密码。这是否意味着盐必须存储在某个地方?
我不知道。
- 我还观察到,如果主密码被重新加密并存储在
settings-security.xml
文件中,使用一个加密的主密码加密的常规密码仍然有效,即使加密主密码密文现在不同了[=73=]。有人可以解释这是如何工作的吗?
我不知道。在我看来,这就像 Maven 正在做一些可疑的事情或在某处存储明文。
- 我的理解是加密密码只能与
settings.xml
文件中的<server />
标签一起使用。这是真的? settings.xml
中定义的服务器可以用在什么地方?
我的理解是<server />
定义可以在<repositories />
和<distributionManagement />
中使用,但不能在<scm />
中使用。有人可以验证一下吗?
- 在我看来,对于如此重要的功能(构建系统安全性),存在很多混乱和糟糕的文档。有人可以指出 Maven 3 网站上的文档是如何工作的吗?是否有 wiki link 可以让我尝试改进文档?
我不知道
抱歉文字墙,感谢您的回答。
我的回答是基于阅读 Maven 源代码和做一些研究。
- Does the encrypted master password provide security simply by existing in
settings-security.xml
in a folder that only one user can
access (~/.m2
)? If so, why bother with encrypting a 'master
password' (why not just use some random value)? Isn't the 'master
password' really just an entropy input to the cryptographic function?
Calling it a password is confusing - I expected Maven to prompt me for
this password before de-crypting any encrypted server passwords, but
it did not.
主密码是 encrypting/decrypting 服务器密码的加密功能的输入。如果有人拥有您的个人加密服务器密码,除非他们也有您的主密码,否则他们将无法解密。这意味着您可以自由地与他人共享您的 maven settings.xml 文件,而他们无法解密您的服务器密码。这也是主密码保存在单独文件中的原因。
这个基本原理在 encryption guide
中有所解释
- Do the master password and server passwords use the same encryption process/cipher? The server passwords are based on the master password,
so there must be some difference in the algorithm. Where is the source
code for this located?
据我所知,主密码是使用与服务器密码相同的密码加密的。解密服务器密码时,输入主密码(未加密形式);解密主密码时,魔术字符串“"settings.security"”用作附加输入。
可以看到源码PBECipher and MavenCli.java.
- I have observed that the same master password or server password encrypted multiple times gives different hashes. According to Marcelo
Morales' answer on How does maven --encrypt-master-password
work, this is because 'a
JVM-configuration-specific (usually SHA1PRNG) 64-bit random salt' is
added to the password prior to encrypting. Maven decrypts stored
passwords when they are used at compile time. Doesn't this mean the
salts have to be stored somewhere?
处理盐的传统方法是随机盐与加密文本一起存储。见 Wikipedia article.
根据上面链接的源代码,盐似乎存储为 Base64 解码字节的前 8 个字节,就在加密密码之前。
- I have also observed that a regular password encrypted using one encrypted master password will still work if the master password is
re-encrypted and stored in the
settings-security.xml
file, even
though the encrypted master password ciphertext is now different.
Can someone explain how this works?
这是因为使用了解密形式的主密码,而不是加密的"ciphertext"。因此重新加密它不会影响服务器密码 encryption/decryption.
我不知道你最后两个(5 和 6)问题的答案。
我需要了解 bnd(tools) 的这一点,以便我可以分享一些更深入的分析。
'encrypted' 密码的语法为:
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 为“security.settings”。由于这是一个众所周知的常量 主密码未加密,只是被隐藏了 。对于服务器密码,X 是解码后的主密码。
为什么生成的数据包被填充似乎是字节的浪费,因为数据包格式使得剥离变得微不足道并且它们从来不是 encryption/decryption 的一部分。他们只是在 base64 字符串中添加了一些随机字符。
唯一有用的方法是使用重定位工具。例如,如果您将 settings-security.xml 挂载到构建服务器上的私有挂载上。然后,您可以在 public 存储库中自由共享 settings.xml
文件。但是,这也是一个糟糕的解决方案,因为您需要为所有用户将其安装在相同的安装点并 CI 构建服务器。
请注意,任何插件都可以解码您所有的服务器密码,因此切勿为服务器使用真实密码。 Nexus 可以创建代理密码。
这里是展示如何从
解密 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上还有一个示例项目:
我正在尝试了解 Maven 3 的[密码加密功能。我发现此功能的文档很少且令人困惑。例如,feature documentation and a blog post by the author of the feature在几个点上相互矛盾。
这个问题比 How does maven --encrypt-master-password work and is not covered by Maven encrypt-master-password good practice for choosing password 更广泛。
具体来说,我试图回答以下文档未涵盖的问题。我已经在每个问题下方用斜体字列出了到目前为止我能够收集到的信息。
- 加密的主密码是否仅通过存在于
settings-security.xml
中只有一个用户可以访问的文件夹 (~/.m2
) 中来提供安全性?如果是这样,为什么还要为 'master password' 加密(为什么不使用一些随机值)? 'master password' 真的只是加密函数的熵输入吗?称它为密码令人困惑 - 我希望 Maven 在解密任何加密的服务器密码之前提示我输入此密码,但它没有。
我的理解是,是的,这仅通过存在于受操作系统保护的文件中来提供安全性。我相信 Maven 允许您加密主密码,这样如果您丢失了 settings-security.xml
文件,您可以重新生成它。这是正确的吗?
- 主密码和服务器密码是否使用相同的加密方式process/cipher?服务器密码是基于主密码的,所以算法上肯定有一些区别。这个的源代码在哪里?
Marcelo Morales' answer on How does maven --encrypt-master-password work links to the plexus-cihper project on GitHub。目前尚不清楚这只是密码,还是提供密码功能的实际 Maven 插件。
- 我观察到多次加密的同一个主密码或服务器密码会给出不同的哈希值。根据 Marcelo Morales' answer on How does maven --encrypt-master-password work,这是因为 'a JVM-configuration-specific (usually SHA1PRNG) 64-bit random salt' 在加密之前添加到密码中。 Maven 在编译时使用时解密存储的密码。这是否意味着盐必须存储在某个地方?
我不知道。
- 我还观察到,如果主密码被重新加密并存储在
settings-security.xml
文件中,使用一个加密的主密码加密的常规密码仍然有效,即使加密主密码密文现在不同了[=73=]。有人可以解释这是如何工作的吗?
我不知道。在我看来,这就像 Maven 正在做一些可疑的事情或在某处存储明文。
- 我的理解是加密密码只能与
settings.xml
文件中的<server />
标签一起使用。这是真的?settings.xml
中定义的服务器可以用在什么地方?
我的理解是<server />
定义可以在<repositories />
和<distributionManagement />
中使用,但不能在<scm />
中使用。有人可以验证一下吗?
- 在我看来,对于如此重要的功能(构建系统安全性),存在很多混乱和糟糕的文档。有人可以指出 Maven 3 网站上的文档是如何工作的吗?是否有 wiki link 可以让我尝试改进文档?
我不知道
抱歉文字墙,感谢您的回答。
我的回答是基于阅读 Maven 源代码和做一些研究。
- Does the encrypted master password provide security simply by existing in
settings-security.xml
in a folder that only one user can access (~/.m2
)? If so, why bother with encrypting a 'master password' (why not just use some random value)? Isn't the 'master password' really just an entropy input to the cryptographic function? Calling it a password is confusing - I expected Maven to prompt me for this password before de-crypting any encrypted server passwords, but it did not.
主密码是 encrypting/decrypting 服务器密码的加密功能的输入。如果有人拥有您的个人加密服务器密码,除非他们也有您的主密码,否则他们将无法解密。这意味着您可以自由地与他人共享您的 maven settings.xml 文件,而他们无法解密您的服务器密码。这也是主密码保存在单独文件中的原因。
这个基本原理在 encryption guide
中有所解释
- Do the master password and server passwords use the same encryption process/cipher? The server passwords are based on the master password, so there must be some difference in the algorithm. Where is the source code for this located?
据我所知,主密码是使用与服务器密码相同的密码加密的。解密服务器密码时,输入主密码(未加密形式);解密主密码时,魔术字符串“"settings.security"”用作附加输入。
可以看到源码PBECipher and MavenCli.java.
- I have observed that the same master password or server password encrypted multiple times gives different hashes. According to Marcelo Morales' answer on How does maven --encrypt-master-password work, this is because 'a JVM-configuration-specific (usually SHA1PRNG) 64-bit random salt' is added to the password prior to encrypting. Maven decrypts stored passwords when they are used at compile time. Doesn't this mean the salts have to be stored somewhere?
处理盐的传统方法是随机盐与加密文本一起存储。见 Wikipedia article.
根据上面链接的源代码,盐似乎存储为 Base64 解码字节的前 8 个字节,就在加密密码之前。
- I have also observed that a regular password encrypted using one encrypted master password will still work if the master password is re-encrypted and stored in the
settings-security.xml
file, even though the encrypted master password ciphertext is now different. Can someone explain how this works?
这是因为使用了解密形式的主密码,而不是加密的"ciphertext"。因此重新加密它不会影响服务器密码 encryption/decryption.
我不知道你最后两个(5 和 6)问题的答案。
我需要了解 bnd(tools) 的这一点,以便我可以分享一些更深入的分析。
'encrypted' 密码的语法为:
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 为“security.settings”。由于这是一个众所周知的常量 主密码未加密,只是被隐藏了 。对于服务器密码,X 是解码后的主密码。
为什么生成的数据包被填充似乎是字节的浪费,因为数据包格式使得剥离变得微不足道并且它们从来不是 encryption/decryption 的一部分。他们只是在 base64 字符串中添加了一些随机字符。
唯一有用的方法是使用重定位工具。例如,如果您将 settings-security.xml 挂载到构建服务器上的私有挂载上。然后,您可以在 public 存储库中自由共享 settings.xml
文件。但是,这也是一个糟糕的解决方案,因为您需要为所有用户将其安装在相同的安装点并 CI 构建服务器。
请注意,任何插件都可以解码您所有的服务器密码,因此切勿为服务器使用真实密码。 Nexus 可以创建代理密码。
这里是展示如何从
解密 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上还有一个示例项目: