`
lingmin.guo
  • 浏览: 6385 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类
最新评论

JAVA JCE实现HASH+SALT强密文

阅读更多

口令的安全策略
在传统密码学家眼中只有一种加密是理想的,那就是“一次一密”,当然事实上这是不可能的。但如果我们套用这种词法,我们也可以说,口令安全策略的理想境界,我们可以称为单向、一人一密、一站一密。

单向:标准HASH算法的价值尽管在这个场景下,已经被推倒,但其单向性的思想依然是正确的,口令只要是能还原的,就意味着攻击者也能做到这一点,从而失去了意义,因此使用单向算法是必须的。

一人一密:同一个站点设置同样口令的不同用户,加密生成的密文内容并不相同。这样就能有效的应对结果碰撞和统计攻击。采用字典的攻击的方法基本是不收敛的。

一站一密:仅仅保证一人一密是不够的,还要保证使用同样信息、同样口令去注册不同网站的用户,在不同站点的口令加密结果是不同的。鉴于有大量用户用同样的信息、同样的口令去注册不同网站,如果能做到这一点,流失出的库信息会进一步打折扣。而攻击者基本会放弃生成密文字典的尝试。

实现这些说起来很简单,依然是HASH+SALT,关键在于每个站点要有不同的SALT,每个用户要有不同的盐。


具体实现
怎么来具体实现一站一密、一人一密的策略呢,在Java 6 中已支持使用JCE(JavaTM Cryptography Extension )实现PBKDF2加密算法。
在使用JCE之前须安装JCE Unlimited Strength Policy,步骤如下:
1、到 Java JCE下载(http://www.oracle.com/technetwork/java/javase/downloads/jce-6-download-429243.html);
2、解压缩ZIP;
3、将local_policy.jar and和US_export_policy.jar复制到JAVA_HOME/jre/lib/security。


安装好了,就可以用了,代码如下:

String systemPassword = "password"; //一站一密
String userPassword = "User Password"; //用户密码
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] salt = new byte[16];
SecureRandom random = new SecureRandom();
random.nextBytes(salt); // 一人一粒‘盐’
KeySpec spec = new PBEKeySpec(systemPassword.toCharArray(), salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");

//加密逻辑
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] ciphertext = cipher.doFinal(userPassword.getBytes("UTF-8"));

//保存IV,解密时需要
String ivStr = new BigInteger(iv).toString(16);
System.out.println("IV: " + ivStr);
//保存Encrypted Data,解密时需要
String encryData = new BigInteger(ciphertext).toString(16);
System.out.println("Encrypted Data: " + encryData);

//解密逻辑
KeySpec dspec = new PBEKeySpec(systemPassword.toCharArray(), salt, 1024, 256);
SecretKey dsecretKey = new SecretKeySpec(factory.generateSecret(dspec).getEncoded(), "AES");
Cipher dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");

dcipher.init(Cipher.DECRYPT_MODE, dsecretKey,
	new IvParameterSpec(new BigInteger(ivStr, 16).toByteArray()));
String plaintext = new String(dcipher.doFinal(new BigInteger(encryData,16).toByteArray()),"UTF-8");
//有了解密后的文本,只需和用户输入的密码比对就可以了
System.out.println(plaintext);

 

 

1
2
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics