用于React NativeJS的SHA256 ComputeHash的等价版本(来自C#)。

问题描述 投票:0回答:1

我试图建立一个等价的SHA256 ComputeHash版本(从C#,从下面的示例中完全相同的输出),到React NativeJavaScript.这是下面的C#。

public static string Hash(string input)
{
    if (string.IsNullOrWhiteSpace(input)) return "";

    using (SHA256 hasher = SHA256.Create())
    {
        // Convert the input string to a byte array and compute the hash.
        byte[] data = hasher.ComputeHash(Encoding.Unicode.GetBytes(input));

        // Create a new Stringbuilder to collect the bytes
        // and create a string.
        StringBuilder sBuilder = new StringBuilder();

        // Loop through each byte of the hashed data 
        // and format each one as a hexadecimal string.
        for (int i = 0; i < data.Length; i++)
        {
            sBuilder.Append(data[i].ToString("X2"));
        }

        // Return the hexadecimal string.
        return $"0x{sBuilder.ToString().ToLower()}";
    }
}

我试了下面的方法,但没有产生相同的Hash。

import * as Crypto from 'expo-crypto';

const hash = await Crypto.digestStringAsync(
    Crypto.CryptoDigestAlgorithm.SHA256,
    "StringIWantToHash"
);

有谁知道,要么是JavaScript出了什么问题,要么是C#的完全等价版本?

javascript c# react-native hash expo
1个回答
1
投票

解决方案1:使用UTF8代替Unicode。

嗯,这是一个 编码问题.

Encoding.Unicode 是微软对UTF-16(一种双宽编码,由于历史原因,在Windows世界中使用,但其他人没有使用)的误导性名称。http:/msdn.microsoft.comen-uslibrarysystem.text.encoding.unicode.aspx。 (见 这个 回答)

你应该使用 Encoding.UTF8.GetBytes 而不是。

使用 js-sha256 这样的库。

const jssha = require('js-sha256')

function hash(input)
{
    const hashString = "0x" + jssha.sha256(input)
    return hashString;
}

const hashResult = hash("StringIWantToHash")
// Output: 0x29c506d0d69a16e413d63921b7de79525c43715931d8d93127dbeb46eacda2f9

我们可以在C#中实现类似的功能,只要使用 UTF8编码:

public static string Hash(string input)
{
    if (string.IsNullOrWhiteSpace(input)) return "";

    using (SHA256 hasher = SHA256.Create())
    {
        // Convert the input string to a byte array and compute the hash.
        byte[] data = hasher.ComputeHash(Encoding.UTF8.GetBytes(input)); // Note that UTF8 here

        // Create a new Stringbuilder to collect the bytes
        // and create a string.
        StringBuilder sBuilder = new StringBuilder();

        // Loop through each byte of the hashed data 
        // and format each one as a hexadecimal string.
        for (int i = 0; i < data.Length; i++)
        {
            sBuilder.Append(data[i].ToString("X2"));
        }

        // Return the hexadecimal string.
        return $"0x{sBuilder.ToString().ToLower()}"; 
    }
}

static void Main()
{
    var hashResult = Hash("StringIWantToHash");
    // Output: 0x29c506d0d69a16e413d63921b7de79525c43715931d8d93127dbeb46eacda2f9
}

另外,我相信其他帮助计算SHA256哈希值的JSReact Native库也使用UTF8编码,所以我认为你可以使用其他任何加密库来实现。

解决方法2:如果你需要使用Unicode怎么办?

在这种情况下,你需要在JS代码中手动表示C#编码。当你使用Unicode编码时,如果是普通的拉丁字符,在字符串中的每一个字节后都会有'0'字节。对于其他符号(有超过255个数字)Unicode需要2个字节来表示。

var input = "StringIWantToHash";
var encodedInput = Encoding.Unicode.GetBytes(input);
// Output: [83, 0, 116, 0, 114, 0, 105, 0, 110, 0, ...]

所以我们需要在JS代码中进行表示。

const jssha = require('js-sha256')

function hash(input)
{
    var bytes = [];
    for (var i = 0; i < input.length; i++)
    {
        const code = input.charCodeAt(i);
        bytes = bytes.concat([code & 0xff, code / 256 >>> 0]);
    }

    const hashString = "0x" + jssha.sha256(bytes)
    return hashString;
}

const hashResult = hash("StringIWantToHash")
// Output: 0x029dbc4b54b39bed6d684175b2d76cc5622c60fe91f0bde9865b977d0d9a531d

3
投票

Expo React Native。

解决方案1:安装 sha256

yarn add sha256
import React, { Component } from "react";
import { Text, StyleSheet, View } from "react-native";
const sha256 = require("sha256");

const isNullOrWhitespace = (input) => {
  if (typeof input === "undefined" || input == null) return true;
  return input.replace(/\s/g, "").length < 1;
};

const getByteArray = (input) => {
  let bytes = [];
  for (var i = 0, k = 0; i < input.length; i++, k += 2) {
    bytes[k] = input.charCodeAt(i);
    bytes[k + 1] = 0;
  }
  return bytes;
};


const hash = async (input) => {
  if (isNullOrWhitespace(input)) {
    return "";
  }
  var bytes = getByteArray(input);
  const hashString = "0x" + sha256(bytes, { asBytes: false });
  return hashString;
};

export default class App extends Component {
  state = {
    encodedString: "",
  };
  async UNSAFE_componentWillMount() {
    const encodedString = await hash("test2"); //0x39a2272982dc7e6e5d109ab36ec280f6cd3b4b7440af5c739ed808d4ec02aae4
    this.setState({ encodedString: encodedString });
  }
  render() {
    const { encodedString } = this.state;
    return (
      <View style={styles.container}>
        <Text>{encodedString}</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center",
  },
});

解决方案2:

你使用的是 ToString("X2") 在c#中,这意味着你必须将哈希转换为HEX(基数16)。

这里id演示。https:/snack.expo.io@nomi9995expo-crypto。

你需要将哈希转换为HEX(基数16),就像这样

await hash.toString(16);

试试这个,结果和c#一样。

代码:Node js

  import React, { Component } from "react";
  import { Text, StyleSheet, View } from "react-native";

  import * as Crypto from "expo-crypto";

  const isNullOrWhitespace = (input) => {
    if (typeof input === "undefined" || input == null) return true;
    return input.replace(/\s/g, "").length < 1;
  };

  const hash = async (input) => {
    if (isNullOrWhitespace(input)) {
      return "";
    }
    let hash = await Crypto.digestStringAsync(
      Crypto.CryptoDigestAlgorithm.SHA256,
      input
    );
    const sBuilder = await hash.toString(16);

    return `0x${sBuilder.toLowerCase()}`;
  };

  export default class App extends Component {
    state = {
      encodedString: "",
    };
    async UNSAFE_componentWillMount() {
      const result = await hash("StringIWantToHash"); //here you can pass your string
      this.setState({ encodedString: result });
    }
    render() {
      const { encodedString } = this.state;
      return (
        <View style={styles.container}>
          <Text>{encodedString}</Text>
        </View>
      );
    }
  }

  const styles = StyleSheet.create({
    container: {
      flex: 1,
      justifyContent: "center",
      alignItems: "center",
    },
  });

Node js:

安装 隐语

yarn add crypto-js

试试这个,结果和c#一样。

var CryptoJS = require("crypto-js");

const isNullOrWhitespace = (input) => {
  if (typeof input === "undefined" || input == null) return true;
  return input.replace(/\s/g, "").length < 1;
};

const hash = (input) => {
  if (isNullOrWhitespace(input)) {
    return "";
  }
  let hash = CryptoJS.SHA256(input);
  const sBuilder=hash.toString(CryptoJS.enc.Hex);

  return `0x${sBuilder.toLowerCase()}`;
};


const result=hash("StringIWantToHash");
console.log(result,"result"); // it will give the same result as C#

enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.