【问题标题】:Generate the same keys with Rfc2898DeriveBytes in c# and pbkdf2 in go使用 c# 中的 Rfc2898DeriveBytes 和 go 中的 pbkdf2 生成相同的密钥
【发布时间】:2017-12-04 11:20:54
【问题描述】:

为什么 C# 中的 Rfc2898DeriveBytes 和 go lang 中的 pbkdf2 生成不同的密钥?

我的C#代码

using System;
using System.Security.Cryptography;
using System.Text;

public class Test
{
        private static byte[] passBytes = new byte[]
        {164,176,124,62,244,154,226,211,177,90,202,180,12,142,25,225};

        private static byte[] saltBytes = new byte[]
        {173,205,190,172,239,190,242,63,219,205,173,196,218,171,142,214};

        public static byte[] GetKey()
        {
            var key = new Rfc2898DeriveBytes(Encoding.UTF8.GetString(passBytes, 0, 16), saltBytes).GetBytes(16);
            return key;
        }

    public static void Main()
    {
        System.Console.WriteLine(Convert.ToBase64String(GetKey()));
    }
}

输出: 77U85CphtSEwPP9a2T/jaQ==


golang 代码

package main

import (

    b64 "encoding/base64"
    "golang.org/x/crypto/pbkdf2"
    "crypto/sha1"

)

var (
    pass[]byte = []byte{164,176,124,62,244,154,226,211,177,90,202,180,12,142,25,225}
    salt[]byte = []byte{173,205,190,172,239,190,242,63,219,205,173,196,218,171,142,214}
)


func getKey() (key[]byte){
    key =  pbkdf2.Key(pass,salt,1000,16,sha1.New)
    return
}


func main() {
    print(b64.StdEncoding.EncodeToString(getKey()))
}

输出: hnuuu+he4aF7vAzA8rfQtw==

我必须做些不同的事情吗?

【问题讨论】:

  • 它们是否都使用相同的迭代次数和 SHA1?同样在passBytes 上使用UTF8 似乎很可疑,因为passBytes 可能不是有效的UTF-8 字符串。
  • 接收字符串的 Rfc2898DeriveBytes ctor 立即通过 UTF-8 编码将其转换为字节。您可以通过将字节直接传递给基于 byte[] 的 ctor 来跳过字符串的创建。
  • @bartonjs c# 代码有什么问题? Encoding.UTF8.GetString(passBytes, 0, 16) 不是应该在 passBytes 上使用的正确编码吗?
  • @avut 我的意思是,您有字节,您可以将其转换为字符串(通过 UTF8),然后将其传递给将字符串转换为字节(通过 UTF8)的构造函数。您只需使用直接获取字节的构造函数之一即可节省工作。
  • @bartonjs 好的!我明白你的意思。但是为什么输出不同不应该相同呢?是什么使输出不同。 C# 中的默认编码不是 UTF-16 吗?那么将字符串转换为 UTF-8 应该给出相同的输出吗?我很困惑。

标签: c# go pbkdf2


【解决方案1】:

您在初始化 C# 实例时使用了不同的变体(采用 UTF-8 string 的构造函数)。此外,正如 zaph 已经指出的那样,您需要对 C# 和 golang 代码使用相同的迭代次数。 golang 版本为 password 和 salt 接受 []byte 参数,而 C# 对应版本是 Rfc2898DeriveBytes Constructor (Byte[] password, Byte[] salt, Int32 iterations)。

byte[] passBytes = new byte[]
    {164,176,124,62,244,154,226,211,177,90,202,180,12,142,25,225};

byte[] saltBytes = new byte[]
    {173,205,190,172,239,190,242,63,219,205,173,196,218,171,142,214};

var pbkdf2 = new Rfc2898DeriveBytes(passBytes, saltBytes, 1000);
var key = Convert.ToBase64String(pbkdf2.GetBytes(16));

上述代码的输出与golang版本相同。

【讨论】:

  • 感谢您的回复。如果我需要在 golang 中复制 C# 代码??
  • @avut 这取决于您要复制的 C# 功能。如果 iterations 没有在 C# 构造函数中指定,我认为默认值为 1000。但是,有 C# 构造函数使用随机盐(Rfc2898DeriveBytes(String, Int32, Int32) 和 Rfc2898DeriveBytes(String, Int32, Int32)),在这种情况下你无法复制。
猜你喜欢
  • 1970-01-01
  • 2012-06-08
  • 2020-01-24
  • 2015-04-25
  • 2011-12-25
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 2019-05-03
相关资源
最近更新 更多