简体   繁体   中英

How to get the same result in c# with SecureRandom.getInstance("SHA1PRNG") in java

I generated a random byte array of length 32 using SHA1PRNG in java, how can I get the same result in c#?

Java Code:

String seed = "Test";
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
random.setSeed(seed.getBytes(StandardCharsets.UTF_8));
byte[] password = new byte[32];
random.nextBytes(password);
var encoder = java.util.Base64.getEncoder();
System.out.println(new String(encoder.encode(password), StandardCharsets.UTF_8));

I tried to use SHA1CryptoServiceProvider, but its HashSize is only 160(Length of 20)

C# Code:

string seed = "Test";
byte[] keyArray = new byte[32];
using (var sha1 = new SHA1CryptoServiceProvider())
{
  byte[] hash = sha1.ComputeHash(Encoding.UTF8.GetBytes(seed));
  var rd = sha1.ComputeHash(hash);
  keyArray = rd.ToArray();
}
Console.WriteLine(Convert.ToBase64String(keyArray));

I copied the code of SHA1PRNG from java to c#. But I'm not sure it will work in all scenarios.

public sealed class SHA1PRNG
{
    private const int DIGEST_SIZE = 20;

    private SHA1PRNG()
    {

    }

    private static void updateState(byte[] state, byte[] output)
    {
        int last = 1;
        int v;
        byte t;
        bool zf = false;

        // state(n + 1) = (state(n) + output(n) + 1) % 2^160;
        for (int i = 0; i < state.Length; i++)
        {
            // Add two bytes
            v = (int)(sbyte)state[i] + (int)(sbyte)output[i] + last;
            // Result is lower 8 bits
            t = (byte)(sbyte)v;
            // Store result. Check for state collision.
            zf = zf | (state[i] != t);
            state[i] = t;
            // High 8 bits are carry. Store for next iteration.
            last = v >> 8;
        }

        // Make sure at least one bit changes!
        if (!zf)
        {
            state[0] = (byte)(sbyte)(state[0]+1);
        }
    }

    public static void GetBytes(byte[] seed, byte[] result)
    {
        byte[] state;
        byte[] remainder = null;
        int remCount;
        int index = 0;
        int todo;
        byte[] output = remainder;

        using (var sha1 = new SHA1CryptoServiceProvider())
        {
            state = sha1.ComputeHash(seed);
            remCount = 0;

            // Use remainder from last time
            int r = remCount;
            if (r > 0)
            {
                // How many bytes?
                todo = (result.Length - index) < (DIGEST_SIZE - r) ?
                            (result.Length - index) : (DIGEST_SIZE - r);
                // Copy the bytes, zero the buffer
                for (int i = 0; i < todo; i++)
                {
                    result[i] = output[r];
                    output[r++] = 0;
                }
                remCount += todo;
                index += todo;
            }

            // If we need more bytes, make them.
            while (index < result.Length)
            {
                // Step the state
                output = sha1.ComputeHash(state);
                updateState(state, output);

                // How many bytes?
                todo = (result.Length - index) > DIGEST_SIZE ?
                    DIGEST_SIZE : result.Length - index;
                // Copy the bytes, zero the buffer
                for (int i = 0; i < todo; i++)
                {
                    result[index++] = output[i];
                    output[i] = 0;
                }
                remCount += todo;
            }

            // Store remainder for next time
            remainder = output;
            remCount %= DIGEST_SIZE;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM