Convert a string to a byte array in PowerShell version 2

100,060

Solution 1

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

That's a very common pattern for sending cryptographic data in a text format.

Solution 2

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.

Share:
100,060
James Drinkard
Author by

James Drinkard

Software developer living in St. Charles, Missouri with 23+ years experience in programming with 20 years of JAVA. While I certainly don't claim to know everything, I have a reputation for finding solutions and getting the job done in a professional manner. I made a career change to go into full-time programming in 1999 and have never regretted the decision. When I wasn't at work, I liked to study and experiment with code, read, and fix things. I am curious by nature. Coding is the most rewarding career I can think of. I never get tired of learning and doing new things in it. Currently not working commercially, but I stay somewhat active on SO to help when I can and give back to the community. Helping people is a worthy goal in life, it transcends professions. I'm planning on returning to work after a year or so.

Updated on June 17, 2020

Comments

  • James Drinkard
    James Drinkard almost 4 years

    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.

    Here is the code:

    # 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.