Private/public key pairs

Private/public key pairs enable agents and the users' devices to create message hashes specific to conversations with each other. By using private/public key pairs, agents and the Message app can compute shared secrets and securely hash message content, making the content unreadable to Verified SMS and Google.

After you create an agent, you need to create the agent's key pair and update the agent's public key with Verified SMS. Once your agent is running, you need to get users' public keys before you can send them verified messages.

User public keys

When you're ready to send a verified message, you need to get the recipient's public key before you can create and store the message hash. You can get up to 10,000 public keys in a single API call.

Occasionally, the Messages app rotates public keys, so you need to get a user's public key before sending them any message, even if you've sent verified messages to the user previously. If you create a message hash with an outdated public key, the Messages app generates a hash with the current public key, resulting in a hash mismatch. If Verified SMS can't match message hashes, your message appears as unverified.

The Verified SMS Sample and SDK can get user public keys when you store hashes. If you choose to not use the Sample and SDK, the following code gets one or more users' public keys. For formatting and value options, see userKeys.batchGet.

curl -X POST "" \
  -H "Content-Type: application/json" \
  -H "`oauth2l header --json PATH_TO_SERVICE_ACCOUNT_KEY verifiedsms`" \
  -d "{
    'phoneNumbers': [

Agent private/public key pairs

Agents use their private keys and users' public keys during messaging hashing to obfuscate message content, and the Messages app uses users' private keys and agents' public keys. For a Verified SMS agent to function, the agent needs to create a key pair and share its current public key with Verified SMS so that the Message app can access it.

Create an agent's key pair

To create a key pair for your agent, run the following commands in a terminal.

openssl ecparam -name secp384r1 -genkey -outform PEM -noout -out verified-sms-agent_name-private-key-P-384.pem
openssl pkcs8 -topk8 -nocrypt -in verified-sms-agent_name-private-key-P-384.pem -outform DER -out verified-sms-agent_name-private-key-P-384-pkcs8.der
openssl ec -in verified-sms-agent_name-private-key-P-384.pem -pubout -outform DER -out verified-sms-agent_name-public-key-P-384.der

The commands generate three files:

  • verified-sms-agent_name-private-key-P-384.pem is a private key in PEM format that isn't used but is important to keep as a reference.
  • verified-sms-agent_name-private-key-P-384-pkcs8.der is a private key used by the SDK to create message hashes. Don't share this key with Verified SMS.
  • verified-sms-agent_name-public-key-P-384.der is a public key used by the Messages app to create message hashes for messages from your agent. Required to create your agent.

Store your private key files somewhere secure but available to your infrastructure. Never share your private keys.

Now that you've created keys for your agent, you need to update your agent's public key with Verified SMS.

Update an agent's public key

You can change your agent's private/public key pair at any time. Whether to comply with security requirements or rotate out a compromised key pair, updating your agent's key is as simple as creating a new key pair and updating your agent's public key with Verified SMS.

Consider updating keys no more than once per week so that all hashes for the three previous weeks remain valid in case of late message delivery.

The following code updates an agent's public key. For formatting and value options, see agents.updateKey.


curl -X PATCH "" \
  -H "Content-Type: application/json" \
  -H "`oauth2l header --json PATH_TO_SERVICE_ACCOUNT_KEY verifiedsms`" \
  -d "{
    'name': 'AGENT_ID',
    'publicKey': 'BASE64-ENCODED_PUBLIC_KEY'


Requires the Verified SMS Sample and SDK.
String agentId = getEnvVariable("VERIFIED_SMS_AGENT_ID");
String publicKeyPath = getEnvVariable("VERIFIED_SMS_PUBLIC_KEY_PATH");
String serviceAccountJson = getEnvVariable("VERIFIED_SMS_SERVICE_ACCOUNT_PATH");"Reading credentials/creating client ... ");
VerifiedSmsServiceClient verifiedSmsServiceClient =
        new VerifiedSmsServiceClient.Builder()
        .setServiceAccountKeyStream(new FileInputStream(serviceAccountJson))
        .build();"Reading public key... ");
byte[] publicKeyBytes = Files.readAllBytes(Paths.get(publicKeyPath));"Updating agent's public key in asynchronous way...");
CountDownLatch latch = new CountDownLatch(1);
        new VerifiedSmsCompletionCallback() {
            public void onSuccess() {
      "Updating key completed.");

            public void onFailure(Throwable t) {
                LOGGER.warning("  Updating key failed: " + t);

latch.await(); // Wait for callback to be completed."Shutting down the service...");


Requires the Verified SMS Sample and SDK.
import os
from verified_sms_client_library.verified_sms_service_client import VerifiedSmsServiceClient

def main():
    # Read enivronment variables
    agent_id = os.environ['VERIFIED_SMS_AGENT_ID']
    public_key_path = os.environ['VERIFIED_SMS_PUBLIC_KEY_PATH']
    service_account_location = os.environ['VERIFIED_SMS_SERVICE_ACCOUNT_PATH']

    # Read the private key file
    with open(public_key_path, mode='rb') as file:
        print('Reading the agent\'s public key ...')
        public_key_as_bytes =

        print('Creating the Verified SMS Api Client ...')
        vsms_service_client = VerifiedSmsServiceClient(service_account_location=service_account_location)

        print('Updating agent\'s public key')
        vsms_service_client.update_key(agent_id, public_key_as_bytes)


Requires the Verified SMS Sample and SDK.
const fs = require('fs');
const verifiedSmsServiceClient = require('./lib/verified_sms_client_library/verfied_sms_service_client');

// Read environment variables to run sample
let agentId = process.env.VERIFIED_SMS_AGENT_ID;
let publicKeyPath = process.env.VERIFIED_SMS_PUBLIC_KEY_PATH;
let serviceAccountLocation = process.env.VERIFIED_SMS_SERVICE_ACCOUNT_PATH;

// Convert into types needed for client library
let serviceAccountAsJson = require(serviceAccountLocation);

console.log('Reading public key...');
let publicKeyAsBytes = fs.readFileSync(publicKeyPath);
let publicKey = publicKeyAsBytes.toString('base64');

function updateKey() {
    console.log('Initializing the Verified SMS Service Client...');
    let updateKeyPromise = verifiedSmsServiceClient.updateKey(agentId, publicKey);

    console.log('Updating agent\'s public key...');
    updateKeyPromise.then((response) => {
    .catch((err) => {

module.exports = updateKey;

Get an agent's public key

If you're unsure which public key is registered with Verified SMS, you can get the agent's current registered public key. If the public key from the key pair you're using with your agent doesn't match the public key registered with Verified SMS, hashes you create and store may not be valid and may result in unverified messages.

The key registered with Verified SMS might not match your public key for two reasons:

  • You're using an old public/private key pair. Locate and use the key pair that matches the public key registered with Verified SMS.
  • You created a new key pair but didn't update the public key with Verified SMS. Update your public key.

When the public keys match, you're ready to begin hashing messages.

The following code gets an agent's public key. For formatting and value options, see agents.getKey.

curl -X GET "" \
  -H "Content-Type: application/json" \
  -H "`oauth2l header --json PATH_TO_SERVICE_ACCOUNT_KEY verifiedsms`"

Next steps

Now that your agent can fetch user public keys and has a public key registered with Verified SMS, you're ready to configure message hashing.