在密码学中,scrypt(念作“ess crypt”)是Colin Percival于2009年所发明的金钥推衍函数,当初设计用在他所创立的Tarsnap服务上。设计时考虑到大规模的客制硬件攻击而刻意设计需要大量内存运算。2016年,scrypt算法发布在RFC 7914。scrypt的简化版被用在数个密码货币的工作量证明(Proof-of-Work)上。

Scrypt不仅计算所需时间长,而且占用的内存也多,使得并行计算多个摘要异常困难,因此利用rainbow table进行暴力攻击更加困难。Scrypt 没有在生产环境中大规模应用,并且缺乏仔细的审察和广泛的函数库支持。但是,Scrypt 在算法层面只要没有破绽,它的安全性应该高于PBKDF2和bcrypt。

Scrypt 算法 Java 的实现

/**

* Pure Java implementation of the scrypt.

*

* @param password

* Password.

* @param salt

* Salt.

* @param cost

* Overall CPU/MEM cost parameter. 2^15 for testing, but 2^20 recommended.

* @param blocksize

* Block size for each mixing loop (memory usage).

* @param parallel

* Parallelization to control the number of independent mixing loops.

* @param length

* Intended length of the derived key.

*

* @return The derived key.

*

* @throws NoSuchAlgorithmException

* when HMAC_SHA256 is not available.

* @throws IllegalArgumentException

* when parameters invalid

*/

protected static byte[] scrypt(byte[] password, byte[] salt, int cost, int blocksize, int parallel, int length)

throws GeneralSecurityException {

if (cost < 2 || (cost & (cost - 1)) != 0) throw new IllegalArgumentException("Cost must be a power of 2 greater than 1");

if (cost > Integer.MAX_VALUE / 128 / blocksize) throw new IllegalArgumentException("Parameter cost is too large");

if (blocksize > Integer.MAX_VALUE / 128 / parallel) throw new IllegalArgumentException("Parameter blocksize is too large");

Mac mac = Mac.getInstance("HmacSHA256");

mac.init(new SecretKeySpec(password, "HmacSHA256"));

byte[] key = new byte[length];

byte[] b1 = new byte[128 * blocksize * parallel];

byte[] xy = new byte[256 * blocksize];

byte[] v1 = new byte[128 * blocksize * cost];

pbkdf2(mac, salt, 1, b1, parallel * 128 * blocksize);

for (int i = 0; i < parallel; i++) {

smix(b1, i * 128 * blocksize, blocksize, cost, v1, xy);

}

pbkdf2(mac, b1, 1, key, length);

return key;

}

private static void smix(byte[] b1, int bi, int round, int cpu, byte[] v1, byte[] xy) {

int xi = 0;

int yi = 128 * round;

System.arraycopy(b1, bi, xy, xi, 128 * round);

for (int i = 0; i < cpu; i++) {

System.arraycopy(xy, xi, v1, i * (128 * round), 128 * round);

blockMixSalsa8(xy, xi, yi, round);

}

for (int i = 0; i < cpu; i++) {

int j = integerify(xy, xi, round) & (cpu - 1);

blockxor(v1, j * (128 * round), xy, xi, 128 * round);

blockMixSalsa8(xy, xi, yi, round);

}

System.arraycopy(xy, xi, b1, bi, 128 * round);

}

private static void blockMixSalsa8(byte[] by, int bi, int yi, int round) {

byte[] x1 = new byte[64];

System.arraycopy(by, bi + (2 * round - 1) * 64, x1, 0, 64);

for (int i = 0; i < 2 * round; i++) {

blockxor(by, i * 64, x1, 0, 64);

salsa(x1);

System.arraycopy(x1, 0, by, yi + (i * 64), 64);

}

for (int i = 0; i < round; i++) {

System.arraycopy(by, yi + (i * 2) * 64, by, bi + (i * 64), 64);

}

for (int i = 0; i < round; i++) {

System.arraycopy(by, yi + (i * 2 + 1) * 64, by, bi + (i + round) * 64, 64);

}

}

private static int r1(int left, int right) {

return (left << right) | (left >>> (32 - right));

}

private static void salsa(byte[] b1) {

int[] base32 = new int[16];

for (int i = 0; i < 16; i++) {

base32[i] = (b1[i * 4 + 0] & 0xff) << 0;

base32[i] |= (b1[i * 4 + 1] & 0xff) << 8;

base32[i] |= (b1[i * 4 + 2] & 0xff) << 16;

base32[i] |= (b1[i * 4 + 3] & 0xff) << 24;

}

int[] x1 = new int[16];

System.arraycopy(base32, 0, x1, 0, 16);

for (int i = 8; i > 0; i -= 2) {

x1[4] ^= r1(x1[0] + x1[12], 7);

x1[8] ^= r1(x1[4] + x1[0], 9);

x1[12] ^= r1(x1[8] + x1[4], 13);

x1[0] ^= r1(x1[12] + x1[8], 18);

x1[9] ^= r1(x1[5] + x1[1], 7);

x1[13] ^= r1(x1[9] + x1[5], 9);

x1[1] ^= r1(x1[13] + x1[9], 13);

x1[5] ^= r1(x1[1] + x1[13], 18);

x1[14] ^= r1(x1[10] + x1[6], 7);

x1[2] ^= r1(x1[14] + x1[10], 9);

x1[6] ^= r1(x1[2] + x1[14], 13);

x1[10] ^= r1(x1[6] + x1[2], 18);

x1[3] ^= r1(x1[15] + x1[11], 7);

x1[7] ^= r1(x1[3] + x1[15], 9);

x1[11] ^= r1(x1[7] + x1[3], 13);

x1[15] ^= r1(x1[11] + x1[7], 18);

x1[1] ^= r1(x1[0] + x1[3], 7);

x1[2] ^= r1(x1[1] + x1[0], 9);

x1[3] ^= r1(x1[2] + x1[1], 13);

x1[0] ^= r1(x1[3] + x1[2], 18);

x1[6] ^= r1(x1[5] + x1[4], 7);

x1[7] ^= r1(x1[6] + x1[5], 9);

x1[4] ^= r1(x1[7] + x1[6], 13);

x1[5] ^= r1(x1[4] + x1[7], 18);

x1[11] ^= r1(x1[10] + x1[9], 7);

x1[8] ^= r1(x1[11] + x1[10], 9);

x1[9] ^= r1(x1[8] + x1[11], 13);

x1[10] ^= r1(x1[9] + x1[8], 18);

x1[12] ^= r1(x1[15] + x1[14], 7);

x1[13] ^= r1(x1[12] + x1[15], 9);

x1[14] ^= r1(x1[13] + x1[12], 13);

x1[15] ^= r1(x1[14] + x1[13], 18);

}

for (int i = 0; i < 16; ++i) {

base32[i] = x1[i] + base32[i];

}

for (int i = 0; i < 16; i++) {

b1[i * 4 + 0] = (byte) (base32[i] >> 0 & 0xff);

b1[i * 4 + 1] = (byte) (base32[i] >> 8 & 0xff);

b1[i * 4 + 2] = (byte) (base32[i] >> 16 & 0xff);

b1[i * 4 + 3] = (byte) (base32[i] >> 24 & 0xff);

}

}

private static void blockxor(byte[] s1, int si, byte[] d1, int di, int length) {

for (int i = 0; i < length; i++) {

d1[di + i] ^= s1[si + i];

}

}

private static int integerify(byte[] b1, int bi, int round) {

bi += (2 * round - 1) * 64;

int n = (b1[bi + 0] & 0xff) << 0;

n |= (b1[bi + 1] & 0xff) << 8;

n |= (b1[bi + 2] & 0xff) << 16;

n |= (b1[bi + 3] & 0xff) << 24;

return n;

}

/**

* Implementation of PBKDF2 (RFC2898).

*

* @param mac

* Pre-initialized {@link Mac} instance to use.

* @param salt

* Salt.

* @param iterations

* Iteration count.

* @param key

* Byte array that derived key will be placed in.

* @param length

* Intended length, in octets, of the derived key.

*

* @throws GeneralSecurityException

* If key length is too long

*/

protected static void pbkdf2(Mac mac, byte[] salt, int iterations, byte[] key, int length) throws GeneralSecurityException {

int len = mac.getMacLength();

byte[] u1 = new byte[len];

byte[] t1 = new byte[len];

byte[] block = new byte[salt.length + 4];

int limit = (int) Math.ceil((double) length / len);

int r = length - (limit - 1) * len;

System.arraycopy(salt, 0, block, 0, salt.length);

for (int i = 1; i <= limit; i++) {

block[salt.length + 0] = (byte) (i >> 24 & 0xff);

block[salt.length + 1] = (byte) (i >> 16 & 0xff);

block[salt.length + 2] = (byte) (i >> 8 & 0xff);

block[salt.length + 3] = (byte) (i >> 0 & 0xff);

mac.update(block);

mac.doFinal(u1, 0);

System.arraycopy(u1, 0, t1, 0, len);

for (int j = 1; j < iterations; j++) {

mac.update(u1);

mac.doFinal(u1, 0);

for (int k = 0; k < len; k++) {

t1[k] ^= u1[k];

}

}

System.arraycopy(t1, 0, key, (i - 1) * len, (i == limit ? r : len));

}

}

下面是 Scrypt 算法的调用。

package com.cv4j.blockchain.study.scrypt;

import java.io.UnsupportedEncodingException;

import java.security.GeneralSecurityException;

/**

* Created by tony on 2018/8/5.

*/

public class Test {

public static void main(String[] args) {

byte[] password = new byte[0];

try {

password = "123456".getBytes("UTF-8");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

byte[] salt = new byte[0];

try {

salt = "abcdefg".getBytes("UTF-8");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

long start = System.currentTimeMillis();

byte[] scrypt = new byte[0];

try {

scrypt = Scrypt.scrypt(password,salt,131072,8,1,32);

} catch (GeneralSecurityException e) {

e.printStackTrace();

}

String str = HashUtils.encodeBase64(scrypt);

long end = System.currentTimeMillis();

System.out.println("加密后的值:"+str);

System.out.println("花费时间:"+(end-start)+" ms");

}

}

下面的代码实现了真正的加密

scrypt = Scrypt.scrypt(password,salt,131072,8,1,32);

加密后的字节数组还需要使用 Base64 进行 encode。

Scrypt 算法 C 的实现

#include

#include

#include

#include

#include "crypto_scrypt.h"

jbyteArray JNICALL Java_io_merculet_scrypt_util_SignUtils_scryptN(JNIEnv *env, jclass cls, jbyteArray passwd, jbyteArray salt,

jint N, jint r, jint p, jint dkLen)

{

jint Plen = (*env)->GetArrayLength(env, passwd);

jint Slen = (*env)->GetArrayLength(env, salt);

jbyte *P = (*env)->GetByteArrayElements(env, passwd, NULL);

jbyte *S = (*env)->GetByteArrayElements(env, salt, NULL);

uint8_t *buf = malloc(sizeof(uint8_t) * dkLen);

jbyteArray DK = NULL;

if (P == NULL || S == NULL || buf == NULL) goto cleanup;

if (crypto_scrypt((uint8_t *) P, Plen, (uint8_t *) S, Slen, N, r, p, buf, dkLen)) {

jclass e = (*env)->FindClass(env, "java/lang/IllegalArgumentException");

char *msg;

switch (errno) {

case EINVAL:

msg = "N must be a power of 2 greater than 1";

break;

case EFBIG:

case ENOMEM:

msg = "Insufficient memory available";

break;

default:

msg = "Memory allocation failed";

}

(*env)->ThrowNew(env, e, msg);

goto cleanup;

}

DK = (*env)->NewByteArray(env, dkLen);

if (DK == NULL) goto cleanup;

(*env)->SetByteArrayRegion(env, DK, 0, dkLen, (jbyte *) buf);

cleanup:

if (P) (*env)->ReleaseByteArrayElements(env, passwd, P, JNI_ABORT);

if (S) (*env)->ReleaseByteArrayElements(env, salt, S, JNI_ABORT);

if (buf) free(buf);

return DK;

}

在 Android 中调用 Scrypt 算法。

byte[] password = new byte[0];

try {

password = "123456".getBytes("UTF-8");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

byte[] salt = new byte[0];

try {

salt = "abcdefg".getBytes("UTF-8");

} catch (UnsupportedEncodingException e) {

e.printStackTrace();

}

byte[] scrypt = SignUtils.scryptN(password,salt,131072,8,1,32);

String str = HashUtils.encodeBase64(scrypt);

其中,SignUtils 是通过 JNI 来调用 C 的代码。

public class SignUtils {

// Used to load the 'native-lib' library on application startup.

static {

System.loadLibrary("scrypt");

}

public static native byte[] scryptN(byte[] password, byte[] salt, int cost, int blocksize, int parallel, int length);

}

另外,需要注意的是在 Android 中,Base64 的工具类略有不同。

import android.util.Base64;

/**

* Created by tony on 2018/8/1.

*/

public final class HashUtils {

/**

* Decodes a Base64 string to a byte array.

*

* @param string

* (in Base64)

* @return Base64 decoded byte array

* @see https://en.wikipedia.org/wiki/Base64

*/

public static byte[] decodeBase64(String string) {

return Base64.decode(string.getBytes(), Base64.DEFAULT);

}

/**

* Encodes a byte array into a Base64 string.

*

* @param array

* (byte array)

* @return Base64 encoded string

* @see https://en.wikipedia.org/wiki/Base64

*/

public static String encodeBase64(byte[] array) {

return new String(Base64.encode(array, Base64.DEFAULT));

}

}

完整的 Scrypt C 版本已经放到github上,方便在 App 中进行调用。

github地址:https://github.com/fengzhizi715/Scrypt_jni

总结

上面整理了 Scrypt 的两种实现方式,如果对于安全性要求很高的密码,可以采用 Scrypt 算法。该算法唯一的缺点就是慢。

java挖矿算法_Scrypt 不止是加密算法,也是莱特币的挖矿算法相关推荐

  1. Java MD5和SHA256等常用加密算法

    前言 我们在做java项目开发的时候,在前后端接口分离模式下,接口信息需要加密处理,做签名认证,还有在用户登录信息密码等也都需要数据加密.信息加密是现在几乎所有项目都需要用到的技术,身份认证.单点登陆 ...

  2. java信息安全性_java-信息安全(二十)国密算法 SM1,SM2,SM3,SM4

    一.概述 国密即国家密码局认定的国产密码算法.主要有SM1,SM2,SM3,SM4.密钥长度和分组长度均为128位.目前主要使用公开的SM2.SM3.SM4三类算法,分别是非对称算法.哈希算法和对称算 ...

  3. 【Android 内存优化】Java 内存模型 ( Java 虚拟机内存模型 | 线程私有区 | 共享数据区 | 内存回收算法 | 引用计数 | 可达性分析 )

    文章目录 一. Java 虚拟机内存模型 二. 程序计数器 ( 线程私有区 ) 三. 虚拟机栈 ( 线程私有区 ) 四. 本地方法栈 ( 线程私有区 ) 五. 方法区 ( 共享数据区 ) 1. 方法区 ...

  4. Java中CAS(Compare And Swap,比较和交换)算法的技术原理简述

    - title: Java中CAS(Compare And Swap,比较和交换)算法的技术原理简述 - date: 2021/8/14 文章目录 CAS全称 Compare And Swap,是一种 ...

  5. 阿里云CDN不止于加速:基于https国密算法构建安全数据传输链路

    网络数据安全得到前所未有的重视 HTTPS成为解决传输安全问题利器 大家都知道,HTTP 本身是明文传输的,没有经过任何安全处理,网站HTTPS解决方案通过在HTTP协议之上引入证书服务,完美解决网站 ...

  6. Java数据结构(1.1):数据结构入门+线性表、算法时间复杂度与空间复杂度、线性表、顺序表、单双链表实现、Java线性表、栈、队列、Java栈与队列。

    数据结构与算法入门 问题1:为什么要学习数据结构          如果说学习语文的最终目的是写小说的话,那么能不能在识字.组词.造句后就直接写小说了,肯定是不行的, 中间还有一个必经的阶段:就是写作 ...

  7. 证明DES解密算法实际上是DES加密算法的逆

    证明DES解密算法实际上是DES加密算法的逆 DES加密算法和解密算法如图: 如图,首先明文输入,进行第一轮的加密.RE0直接作为LE1,RE0与K1作用于轮函数F然后再与LE0疑惑作为RE1,这是第 ...

  8. 用java实现凯撒加密系统,JAVA如何实现caesar凯撒加密算法

    Carsar加密算法在java中是最简单的加密算法,那么你知道要如何实现吗?下面我们就去看看JAVA如何实现caesar凯撒加密算法的内容. public class Caesar { public ...

  9. Java数据结构与算法(九)-程序员常用的10中算法

    本章目录 第14章 程序员常用的10中算法 14.1 二分查找算法(非递归) 14.1.1 二分查找算法(非递归)介绍 14.2 分治算法 14.2.1 分治算法介绍 14.2.2 分治算法最佳实践- ...

最新文章

  1. meson 中调用shell script
  2. fastboot 重启到recovery
  3. TensorFlow ImportError: (‘Failed to import pydot. You must `pip install pydot`)
  4. 爱国者强烈推荐:nanopiR1——你懂的功能,懂你的开发板
  5. 科普:算法岗是什么?我适不适合算法岗?选什么方向的算法岗?
  6. .NET正则表达式使用高级技巧之替换类
  7. 删了自己写的代码?判刑10个月!
  8. 命令提示符操作及Java的特点
  9. 【总结】防病毒网关---防毒墙
  10. 怎么卸载php xshell,xftp5如何卸载?xshell5卸载不了怎么办?
  11. Android锁屏Demo
  12. 盐值加密、公钥秘钥 理解
  13. 倒看北斗星---念霍去病
  14. 适合苹果的蓝牙耳机推荐,音质超好的蓝牙耳机推荐
  15. Kinect Fusion三维重建
  16. 淘宝新手开店怎么做才能破零
  17. 马云给员工的超牛演讲
  18. 什么是TDK?什么是网站的TDK?扫(myself的)盲
  19. C++:应用有限差分法求解随时间变化 平流方程 ut = - c * ux 在一个空间维度上,与 恒定速度,使用FTCS方法,正向时间差, 居中空间差(附完整源码)
  20. 分享百度短网址生成工具和接口 mr.baidu.com/xxxxx

热门文章

  1. hdu1518深搜DFS
  2. 做人应该知道的十个道理
  3. 读书笔记《数据挖掘概念与技术》第2章 数据预处理 2.4 数据集成和变换
  4. 对软件测试工程师面试题目的回答[转]
  5. 买台式电脑还是笔记本好?
  6. redis做分布式锁可能不那么简单
  7. windows10风格 springboot activiti 整合项目框架源码 shiro 安全框架 druid 数据库连接池...
  8. 用Vue来实现图片上传多种方式
  9. Hive 正则匹配函数 regexp_extract
  10. leveldb demo