Convierta una cadena en una matriz de bytes en PowerShell versión 2

What I'm trying to do is use SHA1 UTF-8 encryption and then base64 encoding and on a password string value. However, I needed to do the encryption first, then the encoding, but I did it the other way around.

Aquí está el código:

# Create Input Data 
$enc = [system.Text.Encoding]::UTF8
$string1 = "This is a string to hash" 
$data1 = $enc.GetBytes($string1) 

# Create a New SHA1 Crypto Provider 
$sha = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider 

$# Now hash and display results 
$result1 = $sha.ComputeHash($data1) 

So, when I went to do the hashing I realized I had to have a byte[] from the string and I'm not sure how to do that. I'm thinking there is a simple way from the .Net libraries, but couldn't find an example.

So if I have a string, like:

$string = "password"

How do I convert that into a byte array that I can use on :: ComputeHash($string)?

So what I have to end up with is an encrypted SHA-1 and base 64 encoded UTF-8 password, which the code above does, but it's coming back different than when I coded this same thing in java, where I encrypted it first, then converted that result to base 64 encoding.

I'm making the assumption that while encrypting a string directly isn't supported in the api, there may be a work-around that will allow you to do this. That is what I'm attempting to do.

So I'm assuming my issue with the code is that I had to encrypt it first and then encode it to get the correct value. Correct or am I missing something here?

Here is the pertinent java code that does work:

//First method call uses a swing component to get the user entered password.
String password = getPassword(); 

//This line is where the work starts with the second and third methods below.
String hashed = byteToBase64(getHash(password));

//The second method call here gets the encryption.
public static byte[] getHash(String password) {
      MessageDigest digest = null;
      byte[] input = null;
      try {
             digest = MessageDigest.getInstance("SHA-1");
      } catch (NoSuchAlgorithmException e1) {
             e1.printStackTrace();
      }
      digest.reset();
      try {
             input = digest.digest(password.getBytes("UTF-8"));
      } catch (UnsupportedEncodingException e) {
             e.printStackTrace();
      }
      return input;
}

//Then the third method call here gets the encoding, FROM THE ENCRYPTED STRING.
public static String byteToBase64(byte[] data){
    return new String(Base64.encodeBase64(data));

When I run the java code with the password string of "password" I get

[91, -86, 97, -28, -55, -71, 63, 63, 6, -126, 37, 11, 108, -8, 51, 27, 126, -26, -113, -40] which is the encryption.

Then I when the encoding in java I get this: W6ph5Mm5Pz8GgiULbPgzG37mj9g=

but when I run it in PowerShell I get this because it's encoded first for UTF8:

91 170 97 228 201 185 63 63 6 130 37 11 108 248 51 27 126 230 143 216

Then when I run this line of code to convert it I get an error:

$base64 = [System.Convert]::FromBase64String($result)

Exception calling "FromBase64String" with "1" argument(s): "Invalid length for a Base-64 char array." At line:1 char:45

However, if I run the new line of code to make it hex from below I get:

$hexResult = [String]::Join("", ($result | % { "{0:X2}" -f $_}))
PS C:\Program Files (x86)\PowerGUI> Write-Host $hexResult

5BAA61E4C9B93F3F0682250B6CF8331B7EE68FD8

but I need to end up with this value:

W6ph5Mm5Pz8GgiULbPgzG37mj9g=

Again, this may not even be possible to do, but I'm trying to find a work-around to see.

preguntado el 08 de noviembre de 11 a las 14:11

$data1 already is a byte array - that's what Encoding.GetBytes($string1) devoluciones. -

Hopefully you aren't actually using UTF-9:en.wikipedia.org/wiki/UTF-9_and_UTF-18 -

No, it's UTF-8, I had a typo. -

You don't want FromBase64String, you want ToBase64String. Bytes != Base64. The code in my example produces exactly the output you want. -

You are correct, that worked! -

3 Respuestas

You most likely just need to convert your hash to base64 after the last line.

$enc = [system.Text.Encoding]::UTF8
$string1 = "This is a string to hash" 
$data1 = $enc.GetBytes($string1) 

# Create a New SHA1 Crypto Provider 
$sha = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider 

# Now hash and display results 
$result1 = $sha.ComputeHash($data1)
[System.Convert]::ToBase64String($result1)

Text->Bytes->Encrypt/Hash->Base64

Esa es una common pattern for sending cryptographic data in a text format.

Respondido el 16 de junio de 20 a las 16:06

Except in this case it appears that the api requires an encoded byte array and not just a byte array. - James Drinkard

I'm not sure what you mean by "the api", but a byte array is not aware of any encoding. The code above jives with SHA-1 generators (though some output hex instead of Base64). If your Java code is hashing an already Base64 encoded string, then you can certainly do that in PowerShell too (but it would be unusual). Maybe you could give us the output that the Java program produces... - Eric Nicholson

The .Net Framework library. The java code does the encryption first with a message digest, then it does the UTF-8 encoding. Apparently the .Net Framework can't do it that way is what I meant. I tried repeatedly to get a byte array from a string, but the only way I was successful was to use $encoding.getBytes(encodedString), not $somevariable.getBytes(regularString) - James Drinkard

The Java MessageDigest class also hashes a byte array and returns a byte array (that will match the .NET equivalent), so I'm not sure what you are getting at. Without code or sample output I'm not sure we can help. - Eric Nicholson

Understood, I'll add the java code in now. What I meant by "api" is just the .Net Framework library. Not sure if that was clear in earlier comments. - James Drinkard

It looks like you're on the right track. You have to pick a character encoding to convert between a string and a byte array. You picked UTF-8 above, but there are other options (e.g. ASCII, UTF-16, etc.).

Encrypting a string directly is not supported.

respondido 08 nov., 11:18

I'm new to the .Net Framework, so while not directly supported, do you have a solution with code that could work? Like using a Stream instead of a byte array? - James Drinkard

@James, it doesn't matter. Either way you have to map character data<=>byte data (streams are byte data). System.Encoding is the tool for that. You have to use some encoding for this, but it doesn't have to be the UTF-8 you're currently using. - Matthew Flaschen

The problem seems to be that in first bytearray, you are have signed bytes (-86 = 10101010) and in the second one unsigned bytes (170 = 10101010).

Respondido 15 ago 18, 15:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.