Scrypt 不止是加密演算法,也是萊特幣的挖礦演算法

at_1發表於2021-09-09

在密碼學中,scrypt(唸作“ess crypt”)是Colin Percival於2009年所發明的金鑰推衍函式,當初設計用在他所創立的Tarsnap服務上。設計時考慮到大規模的客制硬體攻擊而刻意設計需要大量記憶體運算。2016年,scrypt演算法釋出在 。scrypt的簡化版被用在數個密碼貨幣的工作量證明(Proof-of-Work)上。

Scrypt不僅計算所需時間長,而且佔用的記憶體也多,使得平行計算多個摘要異常困難,因此利用rainbow table進行暴力攻擊更加困難。Scrypt 沒有在生產環境中大規模應用,並且缺乏仔細的審察和廣泛的函式庫支援。但是,Scrypt 在演算法層面只要沒有破綻,它的安全性應該高於PBKDF2和bcrypt。

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 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 >> (32 - right)); } private static void salsa(byte[] b1) { int[] base32 = new int[16]; for (int i = 0; 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 > 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 > 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

下面是 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 Java 版本已經放到github上。
github地址:

*/ 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 */ public static String encodeBase64(byte[] array) { return new String(Base64.encode(array, Base64.DEFAULT)); } }

完整的 Scrypt C 版本已經放到github上,方便在 App 中進行呼叫。
github地址:

總結

上面整理了 Scrypt 的兩種實現方式,如果對於安全性要求很高的密碼,可以採用 Scrypt 演算法。該演算法唯一的缺點就是慢。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1817/viewspace-2811505/,如需轉載,請註明出處,否則將追究法律責任。

相關文章