Automating Windows password generation

The gcloud compute reset-windows-password command allows a user with write access to the Compute Engine project to securely retrieve passwords for accounts on Windows instances.

The command does this by sending a username and an RSA public key to the instance. The agent running on the instance then does one of the following:

  • Creates an account on the instance for that username and generates a random password.
  • Resets the password to a random value if the account already exists.

The agent running on the instance encrypts the password with the provided public key and sends it back to the client to be decrypted by the corresponding private key.

This section describes how this process works and gives you some example scripts that replicate these steps programmatically. If you want to manually follow these steps, read the Manual instructions section.

Before you begin

  • Create a Windows instance.
  • If you haven't already, set up authentication. Authentication is the process by which your identity is verified for access to Google Cloud services and APIs. To run code or samples from a local development environment, you can authenticate to Compute Engine as follows.

    Select the tab for how you plan to use the samples on this page:


    When you use the Google Cloud console to access Google Cloud services and APIs, you don't need to set up authentication.


    1. Install the Google Cloud CLI, then initialize it by running the following command:

      gcloud init
    2. Set a default region and zone.


    To use the REST API samples on this page in a local development environment, you use the credentials you provide to the gcloud CLI.

      Install the Google Cloud CLI, then initialize it by running the following command:

      gcloud init

    For more information, see Authenticate for using REST in the Google Cloud authentication documentation.

Automate password generation


//  Copyright 2018 Google Inc. All Rights Reserved.
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.

package main

import (

	daisyCompute ""

var (
	instance = flag.String("instance", "", "instance to reset password on")
	zone     = flag.String("zone", "", "zone instance is in")
	project  = flag.String("project", "", "project instance is in")
	user     = flag.String("user", "", "user to reset password for")

func getInstanceMetadata(client daisyCompute.Client, i, z, p string) (*compute.Metadata, error) {
	ins, err := client.GetInstance(p, z, i)
	if err != nil {
		return nil, fmt.Errorf("error getting instance: %v", err)

	return ins.Metadata, nil

type windowsKeyJSON struct {
	ExpireOn string
	Exponent string
	Modulus  string
	UserName string

func generateKey(priv *rsa.PublicKey, u string) (*windowsKeyJSON, error) {
	bs := make([]byte, 4)
	binary.BigEndian.PutUint32(bs, uint32(priv.E))

	return &windowsKeyJSON{
		ExpireOn: time.Now().Add(5 * time.Minute).Format(time.RFC3339),
		// This is different than what the other tools produce,
		// AQAB vs AQABAA==, both are decoded as 65537.
		Exponent: base64.StdEncoding.EncodeToString(bs),
		Modulus:  base64.StdEncoding.EncodeToString(priv.N.Bytes()),
		UserName: u,
	}, nil

type credsJSON struct {
	ErrorMessage      string `json:"errorMessage,omitempty"`
	EncryptedPassword string `json:"encryptedPassword,omitempty"`
	Modulus           string `json:"modulus,omitempty"`

func getEncryptedPassword(client daisyCompute.Client, i, z, p, mod string) (string, error) {
	out, err := client.GetSerialPortOutput(p, z, i, 4, 0)
	if err != nil {
		return "", err

	for _, line := range strings.Split(out.Contents, "\n") {
		var creds credsJSON
		if err := json.Unmarshal([]byte(line), &creds); err != nil {
		if creds.Modulus == mod {
			if creds.ErrorMessage != "" {
				return "", fmt.Errorf("error from agent: %s", creds.ErrorMessage)
			return creds.EncryptedPassword, nil
	return "", errors.New("password not found in serial output")

func decryptPassword(priv *rsa.PrivateKey, ep string) (string, error) {
	bp, err := base64.StdEncoding.DecodeString(ep)
	if err != nil {
		return "", fmt.Errorf("error decoding password: %v", err)
	pwd, err := rsa.DecryptOAEP(sha1.New(), rand.Reader, priv, bp, nil)
	if err != nil {
		return "", fmt.Errorf("error decrypting password: %v", err)
	return string(pwd), nil

func resetPassword(client daisyCompute.Client, i, z, p, u string) (string, error) {
	md, err := getInstanceMetadata(client, *instance, *zone, *project)
	if err != nil {
		return "", fmt.Errorf("error getting instance metadata: %v", err)

	fmt.Println("Generating public/private key pair")
	key, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		return "", err

	winKey, err := generateKey(&key.PublicKey, u)
	if err != nil {
		return "", err

	data, err := json.Marshal(winKey)
	if err != nil {
		return "", err

	winKeys := string(data)
	var found bool
	for _, mdi := range md.Items {
		if mdi.Key == "windows-keys" {
			val := fmt.Sprintf("%s\n%s", *mdi.Value, winKeys)
			mdi.Value = &val
			found = true
	if !found {
		md.Items = append(md.Items, &compute.MetadataItems{Key: "windows-keys", Value: &winKeys})

	fmt.Println("Setting new 'windows-keys' metadata")
	if err := client.SetInstanceMetadata(p, z, i, md); err != nil {
		return "", err

	fmt.Println("Fetching encrypted password")
	var trys int
	var ep string
	for {
		time.Sleep(1 * time.Second)
		ep, err = getEncryptedPassword(client, i, z, p, winKey.Modulus)
		if err == nil {
		if trys > 10 {
			return "", err

	fmt.Println("Decrypting password")
	return decryptPassword(key, ep)

func main() {
	if *instance == "" {
		log.Fatal("-instance flag required")
	if *zone == "" {
		log.Fatal("-zone flag required")
	if *project == "" {
		log.Fatal("-project flag required")
	if *user == "" {
		log.Fatal("-user flag required")

	ctx := context.Background()
	client, err := daisyCompute.NewClient(ctx)
	if err != nil {
		log.Fatalf("Error creating compute service: %v", err)

	fmt.Printf("Resetting password on instance %q for user %q\n", *instance, *user)
	pw, err := resetPassword(client, *instance, *zone, *project, *user)
	if err != nil {
	fmt.Printf("- Username: %s\n- Password: %s\n", *user, pw)


#!/usr/bin/env python

# Copyright 2015 Google Inc. All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# See the License for the specific language governing permissions and
# limitations under the License.

import base64
import copy
import datetime
import json
import time

# PyCrypto library:
from Crypto.Cipher import PKCS1_OAEP
from Crypto.PublicKey import RSA
from Crypto.Util.number import long_to_bytes

# Google API Client Library for Python:
from oauth2client.client import GoogleCredentials
from googleapiclient.discovery import build

def GetCompute():
    """Get a compute object for communicating with the Compute Engine API."""
    credentials = GoogleCredentials.get_application_default()
    compute = build('compute', 'v1', credentials=credentials)
    return compute

def GetInstance(compute, instance, zone, project):
    """Get the data for a Google Compute Engine instance."""
    cmd = compute.instances().get(instance=instance, project=project,
    return cmd.execute()

def GetKey():
    """Get an RSA key for encryption."""
    # This uses the PyCrypto library
    key = RSA.generate(2048)
    return key

def GetModulusExponentInBase64(key):
    """Return the public modulus and exponent for the key in bas64 encoding."""
    mod = long_to_bytes(key.n)
    exp = long_to_bytes(key.e)

    modulus = base64.b64encode(mod)
    exponent = base64.b64encode(exp)

    return modulus, exponent

def GetExpirationTimeString():
    """Return an RFC3339 UTC timestamp for 5 minutes from now."""
    utc_now = datetime.datetime.utcnow()
    # These metadata entries are one-time-use, so the expiration time does
    # not need to be very far in the future. In fact, one minute would
    # generally be sufficient. Five minutes allows for minor variations
    # between the time on the client and the time on the server.
    expire_time = utc_now + datetime.timedelta(minutes=5)
    return expire_time.strftime('%Y-%m-%dT%H:%M:%SZ')

def GetJsonString(user, modulus, exponent, email):
    """Return the JSON string object that represents the windows-keys entry."""
    expire = GetExpirationTimeString()
    data = {'userName': user,
            'modulus': modulus,
            'exponent': exponent,
            'email': email,
            'expireOn': expire}
    return json.dumps(data)

def UpdateWindowsKeys(old_metadata, metadata_entry):
    """Return updated metadata contents with the new windows-keys entry."""
    # Simply overwrites the "windows-keys" metadata entry. Production code may
    # want to append new lines to the metadata value and remove any expired
    # entries.
    new_metadata = copy.deepcopy(old_metadata)
    new_metadata['items'] = [{
        'key': "windows-keys",
        'value': metadata_entry
    return new_metadata

def UpdateInstanceMetadata(compute, instance, zone, project, new_metadata):
    """Update the instance metadata."""
    cmd = compute.instances().setMetadata(instance=instance, project=project,
                                          zone=zone, body=new_metadata)
    return cmd.execute()

def GetSerialPortFourOutput(compute, instance, zone, project):
    """Get the output from serial port 4 from the instance."""
    # Encrypted passwords are printed to COM4 on the windows server:
    port = 4
    cmd = compute.instances().getSerialPortOutput(instance=instance,
                                                  zone=zone, port=port)
    output = cmd.execute()
    return output['contents']

def GetEncryptedPasswordFromSerialPort(serial_port_output, modulus):
    """Find and return the correct encrypted password, based on the modulus."""
    # In production code, this may need to be run multiple times if the output
    # does not yet contain the correct entry.
    output = serial_port_output.split('\n')
    for line in reversed(output):
            entry = json.loads(line)
            if modulus == entry['modulus']:
                return entry['encryptedPassword']
        except ValueError:

def DecryptPassword(encrypted_password, key):
    """Decrypt a base64 encoded encrypted password using the provided key."""
    decoded_password = base64.b64decode(encrypted_password)
    cipher =
    password = cipher.decrypt(decoded_password)
    return password

def main(instance, zone, project, user, email):
    # Setup
    compute = GetCompute()
    key = GetKey()
    modulus, exponent = GetModulusExponentInBase64(key)

    # Get existing metadata
    instance_ref = GetInstance(compute, instance, zone, project)
    old_metadata = instance_ref['metadata']

    # Create and set new metadata
    metadata_entry = GetJsonString(user, modulus,
                                   exponent, email)
    new_metadata = UpdateWindowsKeys(old_metadata, metadata_entry)
    result = UpdateInstanceMetadata(compute, instance, zone, project,

    # For this sample code, just sleep for 30 seconds instead of checking for
    # responses. In production code, this should monitor the status of the
    # metadata update operation.

    # Get and decrypt password from serial port output
    serial_port_output = GetSerialPortFourOutput(compute, instance,
                                                 zone, project)
    enc_password = GetEncryptedPasswordFromSerialPort(serial_port_output,
    password = DecryptPassword(enc_password, key)

    # Display the username, password and IP address for the instance
    print 'Username:   {0}'.format(user)
    print 'Password:   {0}'.format(password)
    ip = instance_ref['networkInterfaces'][0]['accessConfigs'][0]['natIP']
    print 'IP Address: {0}'.format(ip)

if __name__ == '__main__':
    instance = 'my-instance'
    zone = 'us-central1-a'
    project = 'my-project'
    user = 'example-user'
    email = ''
    main(instance, zone, project, user, email)


 * Copyright 2015 Google Inc. All Rights Reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * See the License for the specific language governing permissions and
 * limitations under the License.

 * This package demonstrates how to reset Windows passwords in Java.



import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;

import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.TimeZone;

import javax.crypto.Cipher;

public class ExampleCode {

  public ExampleCode() {}

  // Constants used to configure behavior.
  private static final String ZONE_NAME = "us-central1-a";
  private static final String PROJECT_NAME = "example-project-1234";
  private static final String INSTANCE_NAME = "test-instance";
  private static final String APPLICATION_NAME = "windows-pw-reset";

  // Constants for configuring user name, email, and SSH key expiration.
  private static final String USER_NAME = "example_user";
  private static final String EMAIL = "";

  // Keys are one-time use, so the metadata doesn't need to stay around for long.
  // 5 minutes chosen to allow for differences between time on the client
  // and time on the server.
  private static final long EXPIRE_TIME = 300000;

  // HttpTransport and JsonFactory used to create the Compute object.
  private static HttpTransport httpTransport;
  private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

  public static void main(String[] args) {
    ExampleCode ec = new ExampleCode();
    try {
      // Initialize Transport object.
      httpTransport = GoogleNetHttpTransport.newTrustedTransport();

      // Reset the password.
    } catch (Exception e) {

  public void resetPassword() throws Exception {
    // Get credentials to setup a connection with the Compute API.
    Credential cred = GoogleCredential.getApplicationDefault();

    // Create an instance of the Compute API.
    Compute compute = new Compute.Builder(httpTransport, JSON_FACTORY, null)

    // Get the instance object to gain access to the instance's metadata.
    Instance inst = compute.instances().get(PROJECT_NAME, ZONE_NAME, INSTANCE_NAME).execute();
    Metadata metadata = inst.getMetadata();

    // Generate the public/private key pair for encryption and decryption.
    KeyPair keys = generateKeys();

    // Update metadata from instance with new windows-keys entry.
    replaceMetadata(metadata, buildKeyMetadata(keys));

    // Tell Compute Engine to update the instance metadata with our changes.
    compute.instances().setMetadata(PROJECT_NAME, ZONE_NAME, INSTANCE_NAME, metadata).execute();

    System.out.println("Updating metadata...");

    // Sleep while waiting for metadata to propagate - production code may
    // want to monitor the status of the metadata update operation.

    System.out.println("Getting serial output...");

    // Request the output from serial port 4.
    // In production code, this operation should be polled.
    SerialPortOutput output = compute.instances()
        .getSerialPortOutput(PROJECT_NAME, ZONE_NAME, INSTANCE_NAME).setPort(4).execute();

    // Get the last line - this will be a JSON string corresponding to the
    // most recent password reset attempt.
    String[] entries = output.getContents().split("\n");
    String outputEntry = entries[entries.length - 1];

    // Parse output using the json-simple library.
    JSONParser parser = new JSONParser();
    JSONObject passwordDict = (JSONObject) parser.parse(outputEntry);

    String encryptedPassword = passwordDict.get("encryptedPassword").toString();

    // Output user name and decrypted password.
    System.out.println("\nUser name: " + passwordDict.get("userName").toString());
    System.out.println("Password: " + decryptPassword(encryptedPassword, keys));

  private String decryptPassword(String message, KeyPair keys) {
    try {
      // Add the bouncycastle provider - the built-in providers don't support RSA
      // with OAEPPadding.
      Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

      // Get the appropriate cipher instance.
      Cipher rsa = Cipher.getInstance("RSA/NONE/OAEPPadding", "BC");

      // Add the private key for decryption.
      rsa.init(Cipher.DECRYPT_MODE, keys.getPrivate());

      // Decrypt the text.
      byte[] rawMessage = Base64.decodeBase64(message);
      byte[] decryptedText = rsa.doFinal(rawMessage);

      // The password was encoded using UTF8. Transform into string.
      return new String(decryptedText, "UTF8");
    } catch (Exception e) {
    return "";

  private void replaceMetadata(Metadata input, JSONObject newMetadataItem) {
    // Transform the JSON object into a string that the API can use.
    String newItemString = newMetadataItem.toJSONString();

    // Get the list containing all of the Metadata entries for this instance.
    List<Items> items = input.getItems();

    // If the instance has no metadata, items can be returned as null.
    if (items == null)
      items = new LinkedList<Items>();

    // Find the "windows-keys" entry and update it.
    for (Items item : items) {
      if (item.getKey().compareTo("windows-keys") == 0) {
        // Replace item's value with the new entry.
        // To prevent race conditions, production code may want to maintain a
        // list where the oldest entries are removed once the 32KB limit is
        // reached for the metadata entry.

    // "windows.keys" entry doesn't exist in the metadata - append it.
    // This occurs when running password-reset for the first time on an instance.
    items.add(new Items().setKey("windows-keys").setValue(newItemString));

  private KeyPair generateKeys() throws NoSuchAlgorithmException {
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");

    // Key moduli for encryption/decryption are 2048 bits long.

    return keyGen.genKeyPair();

  private JSONObject buildKeyMetadata(KeyPair pair) throws NoSuchAlgorithmException,
      InvalidKeySpecException {
    // Object used for storing the metadata values.
    JSONObject metadataValues = new JSONObject();

    // Encode the public key into the required JSON format.

    // Add username and email.
    metadataValues.put("userName", USER_NAME);
    metadataValues.put("email", EMAIL);

    // Create the date on which the new keys expire.
    Date now = new Date();
    Date expireDate = new Date(now.getTime() + EXPIRE_TIME);

    // Format the date to match rfc3339.
    SimpleDateFormat rfc3339Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
    String dateString = rfc3339Format.format(expireDate);

    // Encode the expiration date for the returned JSON dictionary.
    metadataValues.put("expireOn", dateString);

    return metadataValues;

  private JSONObject jsonEncode(KeyPair keys) throws NoSuchAlgorithmException,
      InvalidKeySpecException {
    KeyFactory factory = KeyFactory.getInstance("RSA");

    // Get the RSA spec for key manipulation.
    RSAPublicKeySpec pubSpec = factory.getKeySpec(keys.getPublic(), RSAPublicKeySpec.class);

    // Extract required parts of the key.
    BigInteger modulus = pubSpec.getModulus();
    BigInteger exponent = pubSpec.getPublicExponent();

    // Grab an encoder for the modulus and exponent to encode using RFC 3548;
    // Java SE 7 requires an external library (Google's Guava used here)
    // Java SE 8 has a built-in Base64 class that can be used instead. Apache also has an RFC 3548
    // encoder.
    BaseEncoding stringEncoder = BaseEncoding.base64();

    // Strip out the leading 0 byte in the modulus.
    byte[] arr = Arrays.copyOfRange(modulus.toByteArray(), 1, modulus.toByteArray().length);

    JSONObject returnJson = new JSONObject();

    // Encode the modulus, add to returned JSON object.
    String modulusString = stringEncoder.encode(arr).replaceAll("\n", "");
    returnJson.put("modulus", modulusString);

    // Encode exponent, add to returned JSON object.
    String exponentString = stringEncoder.encode(exponent.toByteArray()).replaceAll("\n", "");
    returnJson.put("exponent", exponentString);

    return returnJson;

Manual instructions

The steps in this manual guide use OpenSSL for the cryptographic functions and the Bash shell/Linux tools for some other functions, but many other implementations are possible.

  1. Generate a 2048-bit RSA key pair. In OpenSSL, generate this key pair by running:

    $ openssl genrsa -out private_key 2048

    This creates a private key file named private_key with contents that look like the following:

    $ cat private_key
    -----END RSA PRIVATE KEY-----
  2. Generate a public key. To create the public key, run:

    $ openssl rsa -pubout -in private_key -out public_key

    This creates a public_key file that looks like this:

    $ cat public_key
    -----BEGIN PUBLIC KEY-----
    -----END PUBLIC KEY-----
  3. Extract the modulus and the exponent. A modulus and an exponent make up the public and private keys. From the public key, extract the modulus and the exponent:

    $ openssl rsa -in public_key -pubin -text -noout
    Public-Key: (2048 bit)
    Exponent: 65537 (0x10001)
  4. Encode the modulus and exponent. You must extract and base64-encode the modulus and exponent. Before encoding the modulus, remove the leading zero byte from the modulus. By default, the public_key file is already a base64-encoded string of bytes containing the following information:

    • 32 bytes of header information
    • 1 byte with the leading zero of the modulus
    • 256 bytes of modulus
    • 2 bytes of exponent header
    • 3 bytes of exponent

    The modulus and exponent need to be extracted and encoded separately from the rest of the file's contents. Extract and encode the modulus and exponent using the following commands:

    $ cat public_key | grep -v -- ----- | base64 -d | dd bs=1 skip=33 count=256 2>/dev/null | base64 -w 0; echo
    $ cat public_key | grep -v -- ----- | base64 -d | dd bs=1 skip=291 count=3 2>/dev/null | base64

    If you are running into problems encoding the modulus, make sure you have removed the leading zero byte from the modulus before attempting to encode it.

  5. Create a JSON object with a username and public key information. Create a JSON object with the following data:

    • userName: The username to log into the instance.
    • modulus: The base64 encoded modulus of the public key.
    • exponent: The base64 encoded exponent of the public key
    • email: The email address of the user requesting the password. This should be the email address of the Google Account that is authenticated to the API.
    • expireOn: An RFC 3399 encoded timestamp of when the key should expire. This should be in UTC time, set approximately five minutes in the future. Since these keys are only used for generating the username and password, they are no longer necessary after the password is created. The agent does not use keys that have expired.

    For example:

    {\"userName\": \"example-user\",  \"modulus\": \"wgsquN4IBNPqIUnu+h/5Za1kujb2YRhX1
    4FmOt0R7Q==\", \"exponent\": \"AQAB\", \"email\": \"\",
    \"expireOn\": \"2015-04-14T01:37:19Z\"}

    Note that there should be no newlines in the JSON string.

  6. Add the JSON object to the instance metadata. Set the instance metadata using the metadata key windows-keys and the JSON object as the key value.

    In order to update instance metadata in the API, you must provide a fingerprint with your request. Get the current fingerprint of the instance by making a GET request to the instance:

    "metadata": {
    "kind": "compute#metadata",
    "fingerprint": "5sFotm8Ee0I=",
    "items": [

    Next, make a POST request to the setMetadata method, providing the fingerprint and the JSON object you created:

     "fingerprint": "5sFotm8Ee0I=",
     "items": [
       "value": "{\"userName\": \"example-user\",  \"modulus\": \"wgsquN4IBNPqIUnu+h/5Za1kujb2YRhX1vCQVQAkBwnWigcCqOBVfRa5JoZfx6KIvEXjWqa77jPvlsxM4WPqnDIM2qiK36up3SKkYwFjff6F2ni/ry8vrwXCX3sGZ1hbIHlK0O012HpA3ISeEswVZmX2X67naOvJXfY5v0hGPWqCADao+xVxrmxsZD4IWnKl1UaZzI5lhAzr8fw6utHwx1EZ/MSgsEki6tujcZfN+GUDRnmJGQSnPTXmsf7Q4DKreTZk49cuyB3prV91S0x3DYjCUpSXrkVy1Ha5XicGD/q+ystuFsJnrrhbNXJbpSjM6sjo/aduAkZJl4FmOt0R7Q==\", \"exponent\": \"AQAB\", \"email\": \"\", \"expireOn': '2015\"04-14T01:37:19Z\"}\n",
       "key": "windows-keys"
      } ]

    The name of the key should be windows-keys and the value should be set to one or more JSON strings like the one above. Multiple strings should be separated by newlines. When adding multiple entries, ensure that the metadata value does not exceed 32 KB.

  7. Read the output from serial port number four. The agent on the instance will automatically take the value of windows-keys and create an encrypted password. Read the encrypted password by querying serial port number four. In the API, make a GET request to the getSerialPortOutput method, passing in port=4 as a query parameter:

     "kind": "compute#serialPortOutput",
     "selfLink": "",
     "contents": "{\"ready\":true,\"version\":\"Microsoft Windows NT 6.1.7601 Service Pack 1\"}\n{\"encryptedPassword\":\"uiHDEhxyvj6lF5GalH

    The serial port output may contain multiple responses, separated by newlines. To find the correct response, match the modulus that you passed in, to the output of the serial port. Each response is a JSON encoded string with the following fields:

    • userName: The username that was passed to the instance.
    • passwordFound: A Boolean value indicating whether the password generation was successful.
    • encryptedPassword: A base64 encoded, encrypted password.
    • modulus: The modulus that was previously passed in.
    • exponent: The exponent that was previously passed in.

    For information about serial port output retention, see Viewing serial port output.

  8. Decrypt the password. To get the password, use the previously created private key to decrypt the encrypted password. The password must be decrypted with Optimal Asymmetric Encryption Padding (OAEP). For OpenSSL, the command to decrypt input data is:

    $ openssl rsautl -decrypt -inkey private_key -oaep

    To decrypt the password above, provide the encryptedPassword value. Remember to remove the \\ escape characters from the string beforehand or the decryption will fail:

    $ echo 'uiHDEhxyvj6lF5GalHh9TsMZb4bG6Y9qGmFb9S3XI291MncHcaxP0rFu0kyjxlEXDs8y4L1KOhy6iyB42Lh+vZ4XIMjmvU4rZrjsBZ5Tx
    bvGRJXyswkOJ4jTZl+7e6+SZfEal8HJyRfZKiqTjrz+DLjYSlXrfIRqlvKeAFGOJq6IRojNWiTOOh8Zorc0iHDTIkf+MY0scfbBUo5m30Bf4w==' |
    base64 -d | openssl rsautl -decrypt -inkey private_key -oaep

    The command prints out the decrypted password:


    The username and password for this account would be:

    username: example-user
    password: dDkJ_3]*QYS-#>X
  9. Throw away the keys. Unlike SSH Keys, the keys used for retrieving/resetting Windows passwords are meant to be ephemeral. Reusing public/private key pairs is not recommended and may not work as expected. If the key has been saved to disk, the files should be deleted at the end of the process. Better yet, if possible, keep the key in memory and discard it when the process has completed.

What's next