Color scheme: Riviera
You are here: start » en » Documentation » Post-Quantum Cryptography » WvdS Crypto Service overview » How-to guides » Call the Windows service

Call the Windows service

This guide shows how a program uses the named pipe to generate keys, sign and verify, encrypt and decrypt, and run an ML-KEM key exchange. The examples use PowerShell; any language that can open a named pipe and write JSON works the same way.

Before you begin, start the service on \\.\pipe\wvds_crypto as described in Build and test.

Connect and define a helper

$pipe = [System.IO.Pipes.NamedPipeClientStream]::new('.', 'wvds_crypto', 'InOut')
$pipe.Connect(5000)
$utf8 = [System.Text.UTF8Encoding]::new($false)
$reader = [System.IO.StreamReader]::new($pipe, $utf8)
$writer = [System.IO.StreamWriter]::new($pipe, $utf8)
$writer.NewLine = "`n"; $writer.AutoFlush = $true
 
function Invoke-Crypto([hashtable] $request) {
    $writer.WriteLine(($request | ConvertTo-Json -Compress))
    $reader.ReadLine() | ConvertFrom-Json
}

Each request is one line, and so is each response. The connection stays open for further requests.

Sign and verify

$key = Invoke-Crypto @{ operation = 'keygen'; request_id = 'k1'; algorithm = 'ML-DSA'; level = 'ML-DSA-65' }
$message = [Convert]::ToBase64String($utf8.GetBytes('reading 42'))
 
$sig = Invoke-Crypto @{ operation = 'ml_dsa_sign'; request_id = 's1'; key_id = $key.key_id; message = $message }
 
$check = Invoke-Crypto @{ operation = 'ml_dsa_verify'; request_id = 'v1'; level = 'ML-DSA-65'
                          public_key = $key.public_key; message = $message; signature = $sig.signature }
$check.valid   # True

keygen returns key_id and the public key. Keep the public key yourself if signatures need to remain verifiable after the service restarts. An ML-DSA-65 signature is 3309 bytes long (signature_size).

For ml_dsa_verify, check the valid field. A bad signature isn't an error: the response has success: true and valid: false.

Encrypt and decrypt

$aes = Invoke-Crypto @{ operation = 'keygen'; request_id = 'k2'; algorithm = 'AES-256-GCM' }
 
$enc = Invoke-Crypto @{ operation = 'aes_encrypt'; request_id = 'e1'; key_id = $aes.key_id; plaintext = $message }
 
$dec = Invoke-Crypto @{ operation = 'aes_decrypt'; request_id = 'd1'; key_id = $aes.key_id
                        ciphertext = $enc.ciphertext; nonce = $enc.nonce; tag = $enc.tag }
$utf8.GetString([Convert]::FromBase64String($dec.plaintext))   # reading 42

The service picks the nonce. Store or transmit ciphertext, nonce, and tag together; if any one is missing, the message can't be decrypted. Optionally, aad binds additional data to the ciphertext that stays unencrypted; if you use it, pass the same aad when you decrypt.

Agree on a key with ML-KEM

The recipient generates a key pair and hands out the public key:

$kem = Invoke-Crypto @{ operation = 'keygen'; request_id = 'k3'; algorithm = 'ML-KEM-768' }

The sender encapsulates with that public key and sends the ciphertext to the recipient:

$cap = Invoke-Crypto @{ operation = 'ml_kem_encapsulate'; request_id = 'c1'; public_key = $kem.public_key; level = 'ML-KEM-768' }

The recipient decapsulates:

$dcp = Invoke-Crypto @{ operation = 'ml_kem_decapsulate'; request_id = 'c2'; key_id = $kem.key_id; ciphertext = $cap.ciphertext }
$cap.shared_secret -eq $dcp.shared_secret   # True

Both sides now hold the same 32-byte secret. It leaves the service in the clear, as Base64 in the response. Use hkdf to derive a key for the actual purpose, and treat the secret on the client side like a key. For a hybrid scheme per BSI TR-02102-1, also combine it with a classical algorithm; see Algorithms and parameter sets.

Detect errors

$r = Invoke-Crypto @{ operation = 'keygen'; request_id = 'k4'; algorithm = 'ML-KEM'; level = 'ML-KEM-999' }
if (-not $r.success) { "$($r.error.code): $($r.error.message)" }

Output: UNSUPPORTED_ALGORITHM: Unsupported ML-KEM level: ML-KEM-999

Check success on every response. For what the codes mean, see Error codes.

Close the connection

$pipe.Dispose()
en/wiki/pqcrypt/svc/how-to/call-windows-service.txt · Last modified: by Wolfgang van der Stille