Почему я всегда получаю неправильный результат дес-экб в нативном шифре nodejs? - PullRequest
0 голосов
/ 26 сентября 2018

Вот мой код:

const crypto = require('crypto')
let enterJS = 'h';
let enterStr = null;
enterStr = encrypt(enterJS, 'des-ecb').toUpperCase();
console.log("===============>>>> ENTER STR : " + enterStr);
function encrypt(plaintext, algorithm) {
    var keyStr = "imtestKey";
    var key = new Buffer(keyStr);
    var cipher = crypto.createCipher(algorithm, key);
    cipher.setAutoPadding(true);
    var ciph = cipher.update(plaintext, 'ascii');
    var ciphf = cipher.final();
    return ciph.toString('hex') + ciphf.toString('hex');
}

Но результат, который я получил:

============== >>>> ENTER STR: 16CE7F2DEB9BB56D

Какой правильный результат я проверяю на этом веб-сайте: http://tool.chacuo.net/cryptdes

des-mode: ecb

fill-режим: pkcs7padding

пароль: imtestKey

вывод: hex

Правильный результат (такой же, как у моего кода Java):

832e52ebd3fb9059

Версия моего узла v8.9.0, как мне получить правильный результат?

Это мой код Java:

import java.lang.StringBuilder;
import javax.crypto.Cipher;
import java.security.SecureRandom;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.SecretKeyFactory;
import javax.crypto.SecretKey;

public class Test {
    public static void main(String[] args) {
        String js = "h";
        try {
            byte[] bs = encrypt(js.getBytes(), "imtestKey".getBytes());
            System.out.println(byte2hex(bs));
        } catch(Exception ex) {

        }
    }

    public static byte[] encrypt(byte[] src, byte[] key) throws Exception {
        SecureRandom sr = new SecureRandom();
        DESKeySpec dks = new DESKeySpec(key);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        SecretKey securekey = keyFactory.generateSecret(dks);
        Cipher cipher = Cipher.getInstance("DES");
        cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
        return cipher.doFinal(src);
    }


    public static String byte2hex(byte[] b) {
        StringBuilder sb = new StringBuilder();
        String stmp = "";

        for(int n = 0; b != null && n < b.length; ++n) {
            stmp = Integer.toHexString(b[n] & 255);
            if (stmp.length() == 1) {
                sb.append("0").append(stmp);
            } else {
                sb.append(stmp);
            }
        }

        return sb.toString().toUpperCase();
    }
}

1 Ответ

0 голосов
/ 27 сентября 2018

За исключением аспектов безопасности (как было указано, DES и ECB, а также отсутствие ключа не является небезопасным), вы используете устаревшую crypto.createCipher() функцию, которую получает ключ из предоставленного пароля.

Реализация crypto.createCipher() позволяет получить ключи, используя функцию OpenSSL EVP_BytesToKey с алгоритмом дайджеста, установленным на MD5, одна итерацияи без соли .Отсутствие соли допускает атаки по словарю, так как один и тот же пароль всегда создает один и тот же ключ.Низкое число итераций и некриптографически безопасный алгоритм хеширования позволяют очень быстро проверять пароли.

Вместо этого используйте crypto.createCipheriv(), который использует предоставленный ключ как есть:

const crypto = require('crypto')
let enterJS = 'h';
let enterStr = null;
function encrypt(plaintext, algorithm) {
    var keyStr = "imtestKey";
    var key = Buffer.alloc(8, keyStr);
    var cipher = crypto.createCipheriv(algorithm, key, Buffer.alloc(0));
    cipher.setAutoPadding(true);
    var ciph = cipher.update(Buffer.from(plaintext));
    var ciphf = cipher.final();
    return Buffer.concat([ciph, ciphf]).toString('hex');
}
enterStr = encrypt(enterJS, 'des-ecb').toUpperCase();
console.log("===============>>>> ENTER STR : " + enterStr);

API createCipheriv отклонит ваш 9-байтовый длинный ключ, потому что DES требует 8-байтовый ключ.Я сделал обходной путь, чтобы взять первые 8 байтов из предоставленного пароля в качестве ключа, и теперь он печатает желаемый результат.

Вывод:

===============>>>> ENTER STR : 832E52EBD3FB9059
...