Java SHA256 генерирует другой хеш, как в Python - PullRequest
0 голосов
/ 27 сентября 2018

Я пытаюсь сгенерировать OTP, но после того, как я попытался переписать код с python на java, я получил разные результаты.Я не понимаю, почему, потому что некоторые из символов вывода одинаковы (когда я меняю uname или ctr).

КОД ПИТОНА:

from Crypto.Hash import SHA256

def get_otp(uname, ctr):

    inp = uname+str(ctr)
    binp = inp.encode('ascii')

    hash=SHA256.new()
    hash.update(binp)
    dgst=bytearray(hash.digest())

    out = ''
    for x in range(9):
       out += chr(ord('a')+int(dgst[x])%26)
       if x % 3 == 2 and x != 8:
           out += '-'

    return out

print(get_otp('78951', 501585052583))

КОД ЯВА:

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class Main 
{
    public static void main(String[] args) throws NoSuchAlgorithmException 
    {
        System.out.println(get_otp("78951", "501585052583"));        
    }

    public static String get_otp(String uname, String otp) throws NoSuchAlgorithmException
    {
        String input = uname + otp;        
        byte[] binInput = input.getBytes(StandardCharsets.US_ASCII);

        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(binInput);

        String retVal = "";

        for(int i = 0; i < 9; ++i)
        {
           retVal += ((char)(((int)'a') + Math.floorMod((int)hash[i], 26)));

            if(i % 3 == 2 && i != 8)
                retVal += '-';
        }

        return retVal;
    }
}

Спасибо за помощь.

Ответы [ 2 ]

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

в криптобайтах обычно не подписаны;Поэтому я бы предложил «исправить» это несоответствие в среде Java, поменяв цикл таким образом:

    for(int i = 0; i < 9; ++i) {
        if(i > 0 && i % 3 == 0)
            retVal += '-';

        // bitwise AND with 0xff is to undo sign extension Java
        // does by default
        retVal += (char)('a' + (hash[i] & 0xff) % 26);
    }

многие оригинальные скобки и приведения были избыточны, поэтому я удалил их.если ваши реализации только когда-либо будут Java и Python, не имеет значения, где вы «исправляете» эту

другую криптографическую точку;если вам действительно нужен текстовый одноразовый пароль, почему бы просто не сделать что-то вроде:

public static String get_otp2()
{
    final SecureRandom rng = new SecureRandom();
    String out = "";
    for (int i = 0; i < 9; i++)  {
        if(i > 0 && i % 3 == 0)
            out += '-';
        out += (char)('a' + rng.nextInt(26));
    }
    return out;
}

и сохранить это где-нибудь?

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

Java-байты подписаны, но Python-байты не подписаны, поэтому сначала необходимо выполнить преобразование в значение дополнения со знаком twos:

        b = dgst[x]
        b = (b & 127) - (b & 128) # sign-extend                                 
        out += chr(ord('a')+(b%26))  
...