PIN change

Solaris provides a set of secure, encrypted endpoints for changing the PIN for your customers' cards. This page explains how to implement this process in your solution.

Prerequisites

There are two methods for changing a customer's PIN using your solution:

  1. Encrypted PIN change via device signing
  2. Encrypted PIN change via change request

You must implement the respective feature(s) in your solution depending on what you wish to offer your customers. If you use the device signing method for PIN change, then your customer's device must have already generated a private and public key pair before you can use the PIN change endpoints.

PIN requirements

  • The PIN must be exactly 4 numerical digits (i.e., 0123456789).
  • The digits may not be sequential in any order (e.g., 1234 or 4321).
  • A single digit may not repeat 3 or more times (e.g., 1111 or 1112).
  • PINs cannot be changed at ATMs, even if the ATM presents this option.

Implementation steps

Follow the instructions in the API documentation for the respective PIN change methods:

Code examples

JavaKotlinRubySwift
Copy
Copied
@Getter
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
class PinKey {
    String kid;
    String kty;
    String use;
    String alg;
    String n;
    String e;
}
 
@Getter
@AllArgsConstructor
@FieldDefaults(level = AccessLevel.PRIVATE)
class UpdatePinRequest {
    String encrypted_data;
    String id;
    String signature;
    String device_id;
}
 
private void solarisbank_pin_change_integration()  {
 
        //    STEP 1
        PinKey pin_key = client.get("/v1/cards/1234567mcrd/pin_keys/latest");
 
        //    STEP 2
        String payload_to_encrypt = "{\"pin\":\"1928\"}";
 
 
        //    STEP 3
        RSAPublicKey solaris_public_key = JWK.parse(new ObjectMapper().writeValueAsString(pin_key))
                .toRSAKey()
                .toRSAPublicKey();
 
        //    STEP 4
        JWEHeader jweHeader = new JWEHeader
                .Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256CBC_HS512)
                .build();
 
        JWEObject jweObject = new JWEObject(jweHeader, new Payload(payload_to_encrypt));
        jweObject.encrypt(new RSAEncrypter(solaris_public_key));
        String encrypted_data = jweObject.serialize();
         
        //    STEP 5
        String signature = extract_signature(encrypted_data);
 
        //    STEP 6
        client.post("/v1/cards/1234567mcrd/pin_update_requests", new UpdatePinRequest(encrypted_data, pin_key.getKid(), signature, device_id));
    }
Copy
Copied
data class PinKey(val kid: String, val kty: String, val use: String, val alg: String, val n: String, val e: String)
data class UpdatePinRequest(val encrypted_pin: String, val key_id: String, val signature: String, val device_id: String)
 
internal fun solarisbank_pin_change_integration() {
    //    STEP 1
    val pin_key: PinKey = client.get("/v1/cards/1234567mcrd/pin_keys/latest")
 
    //    STEP 2
    val payload_to_encrypt = "{\"pin\":\"1928\"}"
 
    //    STEP 3
    val solaris_public_key = JWK.parse(jacksonObjectMapper().writeValueAsString(pin_key))
        .toRSAKey()
        .toRSAPublicKey()
 
    //    STEP 4
    val jweHeader: JWEHeader = JWEHeader
        .Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256CBC_HS512)
        .build()
 
    val jweObject = JWEObject(
        jweHeader,
        Payload(payload_to_encrypt)
    )
    jweObject.encrypt(RSAEncrypter(solaris_public_key))
 
    val encrypted_data = jweObject.serialize()
 
    //    STEP 5
    val signature = extract_signature(encrypted_data)
 
    //    STEP 6
    client.post("/v1/cards/1234567mcrd/pin_update_requests, UpdatePinRequest(encrypted_data,pin_key.kid,signature,device_id))
}
Copy
Copied
  # STEP 1
  pin_key = client.get("/v1/cards/1234567mcrd/pin_keys/latest").data
 
  # STEP 2
  payload_to_encrypt = {
    "pin": "1928",
  }
 
  # STEP 3
  solaris_public_key = JOSE::JWK.from_map(pin_key.to_h.transform_keys(&:to_s))
 
  # STEP 4
  encrypted_data = JOSE::JWE.block_encrypt(
                      solaris_public_key,
                      payload_to_encrypt.to_json,
                      {
                          "alg" => "RSA-OAEP-256",
                          "enc" => "A256CBC-HS512",
                          "kid" => pin_key.kid
                      }
                  ).compact
  # STEP 5
  signature = my_device_binding_library_signing_function(encrypted_data)
 
  # STEP 6
  update_pin_request = {
    "encrypted_pin": encrypted_data,
    "key_id": pin_key.kid,
    "signature": signature,
    "device_id": device_id,
  }
 
  client.post("/v1/cards/1234567mcrd/pin_update_requests", update_pin_request)
end
 
def my_device_binding_library_signing_function(encrypted_payload)
  sha_hash = Digest::SHA256.digest(encrypted_payload)
  OpenSSL::PKey::EC.new($cards_device_signing_key).dsa_sign_asn1(sha_hash).unpack1("H*")
end
Copy
Copied
// https://github.com/airsidemobile/JOSESwift v2.4.0
import JOSESwift
 
// Use our toolkit for device binding and signing
import SolarisbankToolkit
 
 
// STEP 1: Retrieve JWK from endpoint
 
let pinKeyJSON = """
  {
    "kid": "84b5eb09-72b4-4bb4-b105-4cfd11573136",
    "kty": "RSA",
    "use": "enc",
    "alg": "RS256",
    "n": "0REZBtc6LmFoWgGe5esVU6QmtmSSnzQFNwnaUeMwVf-8OMa3uxZh1z4upxR80SbHhiPcAKcpkU-2GSE9MS7Fr6VG25tO7JsN8kPEZ59RzEiSn_8sd57AHaIPJnBUHfT5a7qgsgsoJNW6XISGaNfA4MiLskbCnQxDMaOEK9E7yYqC-do4arrqPy61l7gyWkG2IyZFWp48wiibmeBlHqBkihstD0mnXKbx--kjNx0xQ2s5gmvhO402-F4Vap1Yc3Ub1enG0H8u8sIIPG8JHIDO3GgX40WZAI3uRURi7346eWWl0RJ7Ai6Fy7sDFXsn6YiS0o9RegRWFufwMJ8TbIlm5w",
    "e": "AQAB"
  }
"""
 
// STEP 2: Create encryption payload
 
let payloadToEncrypt = "{\"pin\":\"1928\"}"
 
// STEP 3: Parse JWK
 
let jwk = try! RSAPublicKey(data: pinKeyJSON.data(using: .utf8)!)
let publicKey: SecKey = try! jwk.converted(to: SecKey.self)
 
// STEP 4: Encrypt and create JWE
 
var jweHeader = JWEHeader(keyManagementAlgorithm: .RSAOAEP256, contentEncryptionAlgorithm: .A256CBCHS512)
let kid = jwk["kid"]!
jweHeader.kid = kid
let encrypter = Encrypter(keyManagementAlgorithm: jweHeader.keyManagementAlgorithm!, contentEncryptionAlgorithm: jweHeader.contentEncryptionAlgorithm!, encryptionKey: publicKey)
let jwe = try! JWE(header: jweHeader, payload: Payload(payloadToEncrypt.data(using: .utf8)!), encrypter: encrypter!)
let encryptedData = jwe.compactSerializedString
 
// STEP 5: Create signature with device binding key (assuming device keypair to be available)
 
let deviceId = "…" // stored device ID
let keyPair = DeviceBinding.KeyPair.defaultKeyPair!
keyPair.sign(message: payloadToEncrypt) { signature in
 
  // STEP 6: Prepare payload and send
     
  let pinUpdateRequestPayload = """
    {
      "encrypted_pin": \(encryptedData),
      "key_id": \(kid),
      "signature": \(signature!),
      "device_id": \(deviceId)
    }
  """
 
  // Now execute POST request with generated payload
  // ...
}