2

Why do Rfc2898DeriveBytes in C# and pbkdf2 in go lang generate different keys?

my C# code

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())); } } 

output: 77U85CphtSEwPP9a2T/jaQ==


golang code

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())) } 

output: hnuuu+he4aF7vAzA8rfQtw==

Is there something different i must do?

5
  • Do they both use the same iteration count and SHA1? Also using UTF8 on passBytes seem suspect because the passBytes may not be a valid UTF-8 string. Commented Jun 30, 2017 at 14:03
  • The Rfc2898DeriveBytes ctors that takes a string just immediately turn it into bytes via the UTF-8 encoding. You can skip the creation of the string by just passing the bytes directly to a byte[]-based ctor. Commented Jun 30, 2017 at 15:01
  • @bartonjs whats wrong in the c# code? Is Encoding.UTF8.GetString(passBytes, 0, 16) not the right encoding supposed to be used on passBytes ? Commented Jul 8, 2017 at 0:27
  • @avut My point is that you have bytes which you turn into a string (via UTF8) that you pass to a constructor that turns the string into bytes (via UTF8). You'd save work by just using one of the constructors that took bytes directly. Commented Jul 8, 2017 at 1:50
  • @bartonjs Alright! I get it what you mean. But why is the output different shouldn't it be same? What is making output different. Isn't default encoding in C# is UTF-16? So Turning string into UTF-8 should give the same output? I'm confused. Commented Jul 8, 2017 at 13:43

1 Answer 1

1

You're using different variant (the constructor that takes UTF-8 string) when initializing C# instance. In addition, as already pointed by zaph, you need to use same iteration count for both C# and golang codes. The golang version takes []byte arguments both for password and salt, and the C# counterpart is 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)); 

The output of above code is the same with golang version.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for reply. And in case I need to replicate the C# code in golang??
@avut It depends on which C# functionality that you want to replicate. If iterations is not specified in the C# constructor, I think the default value will be 1000. However, there are C# constructors that use random salt (Rfc2898DeriveBytes(String, Int32, Int32) and Rfc2898DeriveBytes(String, Int32, Int32)), and in this case you can't replicate.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.