【发布时间】:2016-02-02 05:16:57
【问题描述】:
Openbravo 软件及其衍生软件(例如 unicentaopos)具有以下加密实现,以将数据库密码存储在普通配置文件中。
package com.openbravo.pos.util;
import java.io.UnsupportedEncodingException;
import java.security.*;
import javax.crypto.*;
/**
*
* @author JG uniCenta
*/
public class AltEncrypter {
private Cipher cipherDecrypt;
private Cipher cipherEncrypt;
/** Creates a new instance of Encrypter
* @param passPhrase */
public AltEncrypter(String passPhrase) {
try {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(passPhrase.getBytes("UTF8"));
KeyGenerator kGen = KeyGenerator.getInstance("DESEDE");
kGen.init(168, sr);
Key key = kGen.generateKey();
cipherEncrypt = Cipher.getInstance("DESEDE/ECB/PKCS5Padding");
cipherEncrypt.init(Cipher.ENCRYPT_MODE, key);
cipherDecrypt = Cipher.getInstance("DESEDE/ECB/PKCS5Padding");
cipherDecrypt.init(Cipher.DECRYPT_MODE, key);
} catch (UnsupportedEncodingException | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
}
}
/**
*
* @param str
* @return
*/
public String encrypt(String str) {
try {
return StringUtils.byte2hex(cipherEncrypt.doFinal(str.getBytes("UTF8")));
} catch (UnsupportedEncodingException | BadPaddingException | IllegalBlockSizeException e) {
}
return null;
}
/**
*
* @param str
* @return
*/
public String decrypt(String str) {
try {
return new String(cipherDecrypt.doFinal(StringUtils.hex2byte(str)), "UTF8");
} catch (UnsupportedEncodingException | BadPaddingException | IllegalBlockSizeException e) {
}
return null;
}
}
为了加密,使用如下(只加密密码):
config.setProperty("db.user", jtxtDbUser.getText());
AltEncrypter cypher = new AltEncrypter("cypherkey" + jtxtDbUser.getText());
config.setProperty("db.password", "crypt:" + cypher.encrypt(new String(jtxtDbPassword.getPassword())));
要解密,使用以下内容:
String sDBUser = m_App.getProperties().getProperty("db.user");
String sDBPassword = m_App.getProperties().getProperty("db.password");
if (sDBUser != null && sDBPassword != null && sDBPassword.startsWith("crypt:")) {
AltEncrypter cypher = new AltEncrypter("cypherkey" + sDBUser);
sDBPassword = cypher.decrypt(sDBPassword.substring(6));
}
我正在使用 C# 开发一个独立的软件模块,我想从该配置文件中读取数据库密码。关于如何实现这一点的任何建议?
通过分析代码,我可以推断:
- 密码“加密”是可逆的,因为它后来在软件中用于构建数据库连接字符串。
- 基本密码是“cypherkey”+用户名
- 密码存储在普通文件中,格式为
db.password=crypt:XXX
其中 XXX 是加密密码。
请帮我弄清楚如何解密密码。不需要帮助实际读取纯文件。请假设我已经在 C# 程序的变量中存储了用户名和加密密码(没有“crypt:”部分)。
我一直在尝试修改有关类似问题的现有示例,但它们专注于 AES,到目前为止我还没有成功。
基本上,应该在 C# 中构建以下函数:
private string DecryptPassword(string username, string encryptedPassword)
我该怎么做?
该软件是开源的,可以找到here
一个测试用例:DecryptPassword("mark", "19215E9576DE6A96D5F03FE1D3073DCC") 应该返回密码getmeback。基本密码是cypherkeymark。我在不同的机器上测试过,使用相同的用户名,“散列”密码总是相同的。
【问题讨论】:
-
SHA1 是单向哈希;不是可逆的密码系统。
-
这件事比这更复杂,它使用一个伪随机数生成器,使用 SHA1 以密码的 UTF-8 编码为种子,生成一个 168 位密钥,然后在 Encrypt 中增加三倍 DES -Decrypt-Encrypt ("EDE") 模式用于
str参数的加密(这确实是可逆的)。如果 C# 中不存在SecureRandom.getInstance("SHA1PRNG");的等价物,那你就完蛋了。一旦你有了它,你所需要的就是再次派生原始密钥并通过三重DES解密运行encryptedPassword。如果不介意可以发布一些测试数据进行测试吗? -
确实,这似乎不是 SHA1,而是自定义的加密/解密方法。标题已编辑。我知道密码是可逆的,因为它稍后在原始软件中用于构建数据库连接字符串。该软件是开源的,可以在here找到一个测试用例:
DecryptPassword("mark", "19215E9576DE6A96D5F03FE1D3073DCC")应该返回密码getmeback。基本密码是“cypherkeymark”。我在不同的机器上测试过,相同用户名的“散列”密码总是相同的。 -
只是对您的评论 @MaximilianGerhardt 的一个小修正:“它使用使用 SHA1 的伪随机数生成器,该生成器使用 passphrase 的 UTF-8 编码来生成168 位密钥”。
标签: java c# encryption cryptography