Documentation ¶
Overview ¶
Package examples contains sample code that uses the GREP11 API to communicate with an IBM Cloud HPCS instance.
At a high level, a GREP11 function call to an HPCS server instance consists of the following steps:
- Connect to the HPCS server instance
- Create a crypto client instance
- Create a GREP11 gRPC request message
- Send the gRPC request message to the HPCS server instance
- Receive the gRPC response from the HPCS server instance and check if an error occured
GREP11 is derived from Enterprise PKCS #11 (EP11) over gRPC, and since this API is based on the PKCS #11 specification, all API input messages (protobuf messages) have a Mechanism field that must be specified. A mechanism is a value that determines what cryptographic operation is to be performed. Some cryptographic operations require a mechanism parameter such as an initialization vector for encrypt operations using an AES key. A helper function, util.SetMechParm, is provided to reduce the code clutter when setting your mechanism parameter within your gRPC input (request) messages.
The GREP11 API is contained within the protobuf source file protos/server.proto and describes the Crypto service, its methods, and the input and output (request and response) messages. For more information about the GREP11 API, please visit https://cloud.ibm.com/docs/hs-crypto?topic=hs-crypto-grep11-api-ref
As described in the hpcs-grep11-go README.md file, there are three different types of ciper flows each consisting of a set of sub-operations that can be used for most GREP11 operations. For example, the Encrypt operation consists of EncryptInit(), Encrypt(), EncryptUpdate(), EncryptFinal() and EncryptSingle() sub-operations.
GREP11 sub-operations for Encrypt: - EncryptInit() is used to initialize an operation and must be run prior to Encrypt(), EncryptUpdate(), or EncryptFinal() calls
- Encrypt() is used to encrypt data without the need to perform EncryptUpdate() or EncryptFinal() sub-operations
- EncryptUpdate() is used to perform update operations as part of a multi-part operation
- EncryptFinal() is used to perform final operations as part of a multi-part operation
- EncryptSingle() is an IBM EP11 extension to the standard PKCS#11 specification and used to perform a single call without the need to use the Init, Update, and Final sub-operations
Cipher Flow 1: EncryptInit(), Encrypt() Ciper Flow 2: EncryptInit(), EncryptUpdate(), EncryptUpdate()..., EncryptFinal() Ciper Flow 3: EncryptSingle()
Key Templates ¶
For key operations (GenerateKey, GenerateKeyPair, DeriveKey, WrapKey, UnwrapKey), you will be required to supply key attributes. The attributes will vary depending on the type of key operation being performed. Helper functions and a helper type have been provided to configure and properly format attributes associated with keys.
The following code snippet shows how to use the helper functions and helper type for generating an RSA key pair.
publicExponent := 17 publicKeyTemplate := ep11.EP11Attributes{ ep11.CKA_ENCRYPT: true, ep11.CKA_VERIFY: true, ep11.CKA_MODULUS_BITS: 2048, ep11.CKA_PUBLIC_EXPONENT: publicExponent, ep11.CKA_EXTRACTABLE: false, } privateKeyTemplate := ep11.EP11Attributes{ ep11.CKA_PRIVATE: true, ep11.CKA_SENSITIVE: true, ep11.CKA_DECRYPT: true, ep11.CKA_SIGN: true, ep11.CKA_EXTRACTABLE: false, } generateKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_RSA_PKCS_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(publicKeyTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyTemplate), }
The ep11.EP11Attributes type is a map containing PKCS11 constants and their values.
The util.AttributeMap helper function converts the EP11Attributes map into a protobuf format suitable for transporting via gRPC.
Error Messages ¶
The helper function, util.Convert(), can be used to extract information from the returned gRPC error data structure. The Grep11Error data structure consists of a return code field whose value correlates with a standard PKCS11 error code. The error codes can be found in the ep11/header_consts.go file. In addition to the return code, there may be additional information contained in the Details field of the Grep11Error data structure.
The following code snippet shows how the util.Convert() function is used to check for errors after a verify operation:
if ok, ep11Status := util.Convert(err); !ok { if ep11Status.Code == ep11.CKR_SIGNATURE_INVALID { panic(fmt.Errorf("Invalid signature")) } else { panic(fmt.Errorf("Verify error: [%d]: %s", ep11Status.Code, ep11Status.Detail)) } }
IBM Cloud Identity Access and Management (IAM) Bearer Tokens ¶
Helper functions and a helper data type (IAMPerRPCCredentials) are provided to request and manage bearer tokens obtained from the IBM Cloud via IAM. The tokens are incorporated into the gRPC credentials call option during the initial connection (gRPC Dial) through the use of the GetRequestMetadata and getToken helper functions contained in util/util.go.
The following code snippet shows how to setup IBM Cloud HPCS credentials:
var ( Address = "<grep11_server_address>:<port>" APIKey = "<ibm_cloud_apikey>" HPCSInstanceID = "<hpcs_instance_id>" IAMEndpoint = "https://iam.cloud.ibm.com" ) var callOpts = []grpc.DialOption{ grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})), grpc.WithPerRPCCredentials(&util.IAMPerRPCCredentials{ APIKey: APIKey, Instance: HPCSInstanceID, Endpoint: IAMEndpoint, }), }
The instance address and port, APIKey, and the HPCS instance ID need to be specified. Update the server_test.go file with the connection information prior to running the examples.
Example (DeriveKey) ¶
Example_deriveKey generates ECDHE key pairs for Alice and Bob and then derives AES keys for both of them. The names Bob and Alice are described in https://en.wikipedia.org/wiki/Diffie–Hellman_key_exchange. Flow: connect, generate key pairs for Alice and Bob, derive AES key for Bob, derive AES key for Alice,
encrypt with Alice's AES key and decrypt with Bob's AES key
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %s", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) // Generate ECDH key pairs for Alice and Bob ecParameters, err := asn1.Marshal(util.OIDNamedCurveP256) if err != nil { panic(fmt.Errorf("Unable to encode parameter OID: %s", err)) } publicKeyTemplate := ep11.EP11Attributes{ ep11.CKA_EC_PARAMS: ecParameters, ep11.CKA_EXTRACTABLE: false, } privateKeyTemplate := ep11.EP11Attributes{ ep11.CKA_DERIVE: true, ep11.CKA_EXTRACTABLE: false, } generateECKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_EC_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(publicKeyTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyTemplate), } // Generate Alice's EC key pair aliceECKeypairResponse, err := cryptoClient.GenerateKeyPair(context.Background(), generateECKeypairRequest) if err != nil { panic(fmt.Errorf("Generate Alice EC key pair error: %s", err)) } fmt.Println("Generated Alice EC key pair") // Generate Bob's EC key pair bobECKeypairResponse, err := cryptoClient.GenerateKeyPair(context.Background(), generateECKeypairRequest) if err != nil { panic(fmt.Errorf("Generate Bob EC key pair error: %s", err)) } fmt.Println("Generated Bob EC key pair") // Derive AES key for Alice and Bob deriveKeyTemplate := ep11.EP11Attributes{ ep11.CKA_CLASS: ep11.CKO_SECRET_KEY, ep11.CKA_KEY_TYPE: ep11.CKK_AES, ep11.CKA_VALUE_LEN: 128 / 8, ep11.CKA_ENCRYPT: true, ep11.CKA_DECRYPT: true, } // Extract Bob's EC coordinates combinedCoordinates, err := util.GetPubkeyBytesFromSPKI(bobECKeypairResponse.PubKeyBytes) if err != nil { panic(fmt.Errorf("Bob's EC key cannot obtain coordinates: %s", err)) } aliceDerivekeyRequest := &pb.DeriveKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_ECDH1_DERIVE, Parameter: util.SetMechParm(combinedCoordinates)}, Template: util.AttributeMap(deriveKeyTemplate), BaseKey: aliceECKeypairResponse.PrivKeyBytes, } // Derive AES key for Alice aliceDerivekeyResponse, err := cryptoClient.DeriveKey(context.Background(), aliceDerivekeyRequest) if err != nil { panic(fmt.Errorf("Alice EC key derive error: %s", err)) } // Extract Alice's EC coordinates combinedCoordinates, err = util.GetPubkeyBytesFromSPKI(aliceECKeypairResponse.PubKeyBytes) if err != nil { panic(fmt.Errorf("Alice's EC key cannot obtain coordinates: %s", err)) } bobDerivekeyRequest := &pb.DeriveKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_ECDH1_DERIVE, Parameter: util.SetMechParm(combinedCoordinates)}, Template: util.AttributeMap(deriveKeyTemplate), BaseKey: bobECKeypairResponse.PrivKeyBytes, } // Derive AES key for Bob bobDerivekeyResponse, err := cryptoClient.DeriveKey(context.Background(), bobDerivekeyRequest) if err != nil { panic(fmt.Errorf("Bob EC Key Derive Error: %s", err)) } // Encrypt with Alice's AES key and decrypt with Bob's AES key var msg = []byte("hello world!") rngTemplate := &pb.GenerateRandomRequest{ Len: (uint64)(ep11.AES_BLOCK_SIZE), } // Generate a 16 byte initialization vector for the encrypt/decrypt operations rng, err := cryptoClient.GenerateRandom(context.Background(), rngTemplate) if err != nil { panic(fmt.Errorf("GenerateRandom error: %s", err)) } iv := rng.Rnd[:ep11.AES_BLOCK_SIZE] encryptRequest := &pb.EncryptSingleRequest{ Key: aliceDerivekeyResponse.NewKeyBytes, Mech: &pb.Mechanism{Mechanism: ep11.CKM_AES_CBC_PAD, Parameter: util.SetMechParm(iv)}, Plain: msg, } // Encrypt the data using Alices's derived AES key encryptResponse, err := cryptoClient.EncryptSingle(context.Background(), encryptRequest) if err != nil { panic(fmt.Errorf("Encrypt error: %s", err)) } decryptRequest := &pb.DecryptSingleRequest{ Key: bobDerivekeyResponse.NewKeyBytes, Mech: &pb.Mechanism{Mechanism: ep11.CKM_AES_CBC_PAD, Parameter: util.SetMechParm(iv)}, Ciphered: encryptResponse.Ciphered, } // Decrypt the data using Bob's derived AES key decryptResponse, err := cryptoClient.DecryptSingle(context.Background(), decryptRequest) if err != nil { panic(fmt.Errorf("Decrypt error: %s", err)) } if !bytes.Equal(decryptResponse.Plain, msg) { panic(fmt.Errorf("Decrypted message[%v] is different from the original message: [%v]", decryptResponse.Plain, msg)) } else { fmt.Println("Alice and Bob get the same derived key") }
Output: Generated Alice EC key pair Generated Bob EC key pair Alice and Bob get the same derived key
Example (DeriveKeyUsingDHKeyPair) ¶
Example_deriveKeyUsingDHKeyPair derives keys and shares encrypted message between two users Flow: connect, generate Diffie-Hellman key pairs, derive keys from Diffie-Hellman key pairs, share encypted message
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %v", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) dhDomainTemplate := ep11.EP11Attributes{ ep11.CKA_PRIME_BITS: 2048, } generateKeyRequest := &pb.GenerateKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_DH_PKCS_PARAMETER_GEN}, Template: util.AttributeMap(dhDomainTemplate), } // Create Diffie-Hellman domain parameters for Alice and Bob to use. They will used by the Diffie-Hellman GenerateKeyPair requests. commonGenerateKeyResponse, err := cryptoClient.GenerateKey(context.Background(), generateKeyRequest) if err != nil { panic(fmt.Errorf("GenerateKeyPair error: %s", err)) } fmt.Println("Generated Diffie-Hellman domain parameters for Alice and Bob") commonPublicKeyTemplate := ep11.EP11Attributes{ ep11.CKA_DERIVE: true, // to verify a signature ep11.CKA_EXTRACTABLE: false, ep11.CKA_IBM_STRUCT_PARAMS: commonGenerateKeyResponse.KeyBytes, } privateKeyTemplate := ep11.EP11Attributes{ ep11.CKA_DERIVE: true, // to generate a signature ep11.CKA_PRIVATE: true, ep11.CKA_SENSITIVE: true, ep11.CKA_EXTRACTABLE: false, } // Now generate the Diffie-Hellman key pair for Alice using Alice's domain parameters created in the previous step aliceGenerateKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_DH_PKCS_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(commonPublicKeyTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyTemplate), } aliceGenerateKeyPairResponse, err := cryptoClient.GenerateKeyPair(context.Background(), aliceGenerateKeypairRequest) if err != nil { panic(fmt.Errorf("GenerateKeyPair error: %s", err)) } fmt.Println("Generated Diffie-Hellman key pair for Alice") // Now generate the Diffie-Hellman key pair for Bob using Bob's domain parameters created in the previous step bobGenerateKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_DH_PKCS_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(commonPublicKeyTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyTemplate), } bobGenerateKeyPairResponse, err := cryptoClient.GenerateKeyPair(context.Background(), bobGenerateKeypairRequest) if err != nil { panic(fmt.Errorf("GenerateKeyPair error: %s", err)) } fmt.Println("Generated Diffie-Hellman key pair for Bob") deriveKeyTemplate := ep11.EP11Attributes{ ep11.CKA_CLASS: ep11.CKO_SECRET_KEY, ep11.CKA_KEY_TYPE: ep11.CKK_AES, ep11.CKA_VALUE_LEN: 128 / 8, ep11.CKA_ENCRYPT: true, ep11.CKA_DECRYPT: true, } // The next step is to derive an AES key for Alice and Bob using each other's public key information // Get contents of public key alicPublicKey := util.DHPubKeyASN{} _, err = asn1.Unmarshal(aliceGenerateKeyPairResponse.PubKeyBytes, &alicPublicKey) if err != nil { panic(fmt.Errorf("Failed to unmarshal Alice's public key: %s", err)) } bobPublicKey := util.DHPubKeyASN{} _, err = asn1.Unmarshal(bobGenerateKeyPairResponse.PubKeyBytes, &bobPublicKey) if err != nil { panic(fmt.Errorf("Failed to unmarshal Bob's public key: %s", err)) } // Retrieve integer from public key: Alice's and Bob's public key is still ASN1 integer encoded, therefore, they need to be decoded var bigIntData *big.Int _, err = asn1.Unmarshal(bobPublicKey.PublicKey.Bytes, &bigIntData) if err != nil { panic(fmt.Errorf("Failed to unmarshal Bob's public key integer: %s", err)) } bobPubInteger := bigIntData.Bytes() _, err = asn1.Unmarshal(alicPublicKey.PublicKey.Bytes, &bigIntData) if err != nil { panic(fmt.Errorf("Failed to unmarshal Alice's public key integer: %s", err)) } alicePubInteger := bigIntData.Bytes() aliceDeriveKeyRequest := &pb.DeriveKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_DH_PKCS_DERIVE, Parameter: util.SetMechParm(bobPubInteger)}, Template: util.AttributeMap(deriveKeyTemplate), BaseKey: aliceGenerateKeyPairResponse.PrivKeyBytes, } aliceDeriveKeyResponse, err := cryptoClient.DeriveKey(context.Background(), aliceDeriveKeyRequest) if err != nil { panic(fmt.Errorf("Key derive error: %s", err)) } fmt.Println("Key derived for Alice") bobDeriveKeyRequest := &pb.DeriveKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_DH_PKCS_DERIVE, Parameter: util.SetMechParm(alicePubInteger)}, Template: util.AttributeMap(deriveKeyTemplate), BaseKey: bobGenerateKeyPairResponse.PrivKeyBytes, } bobDeriveKeyResponse, err := cryptoClient.DeriveKey(context.Background(), bobDeriveKeyRequest) if err != nil { panic(fmt.Errorf("Key derive error: %s", err)) } fmt.Println("Key derived for Bob") // Encrypt with Alice's key and decrypt with Bob's key var msg = []byte("hello world!") rngTemplate := &pb.GenerateRandomRequest{ Len: (uint64)(ep11.AES_BLOCK_SIZE), } rng, err := cryptoClient.GenerateRandom(context.Background(), rngTemplate) if err != nil { panic(fmt.Errorf("GenerateRandom error: %s", err)) } iv := rng.Rnd[:ep11.AES_BLOCK_SIZE] encryptRequest := &pb.EncryptSingleRequest{ Key: aliceDeriveKeyResponse.NewKeyBytes, Mech: &pb.Mechanism{Mechanism: ep11.CKM_AES_CBC_PAD, Parameter: util.SetMechParm(iv)}, Plain: msg, } encryptResponse, err := cryptoClient.EncryptSingle(context.Background(), encryptRequest) if err != nil { panic(fmt.Errorf("Encrypt error: %s", err)) } decryptRequest := &pb.DecryptSingleRequest{ Key: bobDeriveKeyResponse.NewKeyBytes, Mech: &pb.Mechanism{Mechanism: ep11.CKM_AES_CBC_PAD, Parameter: util.SetMechParm(iv)}, Ciphered: encryptResponse.Ciphered, } decryptResponse, err := cryptoClient.DecryptSingle(context.Background(), decryptRequest) if err != nil { panic(fmt.Errorf("Decrypt error: %s", err)) } if !bytes.Equal(decryptResponse.Plain, msg) { panic(fmt.Errorf("Decrypted message[%v] is different from the original message: [%v]", decryptResponse.Plain, msg)) } else { fmt.Println("Alice and Bob generated the same derived key") }
Output: Generated Diffie-Hellman domain parameters for Alice and Bob Generated Diffie-Hellman key pair for Alice Generated Diffie-Hellman key pair for Bob Key derived for Alice Key derived for Bob Alice and Bob generated the same derived key
Example (Digest) ¶
Example_digest calculates the digest of some plain text Flow: connect, digest PKCS #11 single-part data, digest PKCS #11 multi-part data
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %s", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) digestData := []byte("This is data that is longer than 64 bytes. This is the data that is longer than 64 bytes.") digestInitRequest := &pb.DigestInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_SHA256}, } digestInitResponse, err := cryptoClient.DigestInit(context.Background(), digestInitRequest) if err != nil { panic(fmt.Errorf("Digest init error: %s", err)) } digestRequest := &pb.DigestRequest{ State: digestInitResponse.State, Data: digestData, } digestResponse, err := cryptoClient.Digest(context.Background(), digestRequest) if err != nil { panic(fmt.Errorf("Digest error: %s", err)) } else { fmt.Printf("Digest data using a single digest operation: %x\n", digestResponse.Digest) } // Digest using mutiple operations digestInitResponse, err = cryptoClient.DigestInit(context.Background(), digestInitRequest) if err != nil { panic(fmt.Errorf("DigestInit error: %s", err)) } digestUpdateRequest := &pb.DigestUpdateRequest{ State: digestInitResponse.State, Data: digestData[:64], } digestUpdateResponse, err := cryptoClient.DigestUpdate(context.Background(), digestUpdateRequest) if err != nil { panic(fmt.Errorf("DigestUpdate error: %s", err)) } digestUpdateRequest = &pb.DigestUpdateRequest{ State: digestUpdateResponse.State, Data: digestData[64:], } digestUpdateResponse, err = cryptoClient.DigestUpdate(context.Background(), digestUpdateRequest) if err != nil { panic(fmt.Errorf("DigestUpdate error: %s", err)) } digestFinalRequestInfo := &pb.DigestFinalRequest{ State: digestUpdateResponse.State, } digestFinalResponse, err := cryptoClient.DigestFinal(context.Background(), digestFinalRequestInfo) if err != nil { panic(fmt.Errorf("DigestFinal error: %s", err)) } else { fmt.Printf("Digest data using multiple operations: %x\n", digestFinalResponse.Digest) }
Output: Digest data using a single digest operation: b036abead70a9739648ab94d556bf120494eab3a470b5ee12be559b9dbc8c408 Digest data using multiple operations: b036abead70a9739648ab94d556bf120494eab3a470b5ee12be559b9dbc8c408
Example (EncryptAndDecryptUsingAES) ¶
Example_encryptAndDecryptUsingAES generates an AES key then encrypts and decrypts plain text using the generated AES key Flow: connect, generate AES key, generate IV, encrypt PKCS #11 multi-part data, decrypt PKCS #11 multi-part data
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %s", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) keyLen := 128 // Setup the AES key's attributes keyTemplate := ep11.EP11Attributes{ ep11.CKA_VALUE_LEN: keyLen / 8, ep11.CKA_WRAP: false, ep11.CKA_UNWRAP: false, ep11.CKA_ENCRYPT: true, ep11.CKA_DECRYPT: true, ep11.CKA_EXTRACTABLE: false, // set to false! } generateKeyRequest := &pb.GenerateKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_AES_KEY_GEN}, Template: util.AttributeMap(keyTemplate), } generateKeyResponse, err := cryptoClient.GenerateKey(context.Background(), generateKeyRequest) if err != nil { panic(fmt.Errorf("GenerateKey Error: %s", err)) } fmt.Println("Generated AES Key") rngTemplate := &pb.GenerateRandomRequest{ Len: (uint64)(ep11.AES_BLOCK_SIZE), } // Generate 16 bytes of random data for the initialization vector rng, err := cryptoClient.GenerateRandom(context.Background(), rngTemplate) if err != nil { panic(fmt.Errorf("GenerateRandom Error: %s", err)) } iv := rng.Rnd[:ep11.AES_BLOCK_SIZE] fmt.Println("Generated IV") encryptInitRequest := &pb.EncryptInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_AES_CBC_PAD, Parameter: util.SetMechParm(iv)}, Key: generateKeyResponse.KeyBytes, // you may want to store this } encryptInitResponse, err := cryptoClient.EncryptInit(context.Background(), encryptInitRequest) if err != nil { panic(fmt.Errorf("Failed EncryptInit [%s]", err)) } plain := []byte("Hello, this is a very long and creative message") encryptUpdateRequest := &pb.EncryptUpdateRequest{ State: encryptInitResponse.State, Plain: plain[:20], } encryptUpdateResponse, err := cryptoClient.EncryptUpdate(context.Background(), encryptUpdateRequest) if err != nil { panic(fmt.Errorf("Failed EncryptUpdate [%s]", err)) } ciphertext := encryptUpdateResponse.Ciphered[:] encryptUpdateRequest = &pb.EncryptUpdateRequest{ State: encryptUpdateResponse.State, Plain: plain[20:], } encryptUpdateResponse, err = cryptoClient.EncryptUpdate(context.Background(), encryptUpdateRequest) if err != nil { panic(fmt.Errorf("Failed EncryptUpdate [%s]", err)) } ciphertext = append(ciphertext, encryptUpdateResponse.Ciphered...) encryptFinalRequest := &pb.EncryptFinalRequest{ State: encryptUpdateResponse.State, } encryptFinalResponse, err := cryptoClient.EncryptFinal(context.Background(), encryptFinalRequest) if err != nil { panic(fmt.Errorf("Failed EncryptFinal [%s]", err)) } ciphertext = append(ciphertext, encryptFinalResponse.Ciphered...) fmt.Println("Encrypted message") decryptInitRequest := &pb.DecryptInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_AES_CBC_PAD, Parameter: util.SetMechParm(iv)}, Key: generateKeyResponse.KeyBytes, } decryptInitResponse, err := cryptoClient.DecryptInit(context.Background(), decryptInitRequest) if err != nil { panic(fmt.Errorf("Failed DecryptInit [%s]", err)) } decryptUpdateRequest := &pb.DecryptUpdateRequest{ State: decryptInitResponse.State, Ciphered: ciphertext[:16], } decryptUpdateResponse, err := cryptoClient.DecryptUpdate(context.Background(), decryptUpdateRequest) if err != nil { panic(fmt.Errorf("Failed DecryptUpdate [%s]", err)) } plaintext := decryptUpdateResponse.Plain[:] decryptUpdateRequest = &pb.DecryptUpdateRequest{ State: decryptUpdateResponse.State, Ciphered: ciphertext[16:], } decryptUpdateResponse, err = cryptoClient.DecryptUpdate(context.Background(), decryptUpdateRequest) if err != nil { panic(fmt.Errorf("Failed DecryptUpdate [%s]", err)) } plaintext = append(plaintext, decryptUpdateResponse.Plain...) decryptFinalRequest := &pb.DecryptFinalRequest{ State: decryptUpdateResponse.State, } decryptFinalResponse, err := cryptoClient.DecryptFinal(context.Background(), decryptFinalRequest) if err != nil { panic(fmt.Errorf("Failed DecryptFinal [%s]", err)) } plaintext = append(plaintext, decryptFinalResponse.Plain...) if !reflect.DeepEqual(plain, plaintext) { panic(fmt.Errorf("Failed comparing plain text of cipher single")) } fmt.Printf("Decrypted message\n%s\n", plaintext)
Output: Generated AES Key Generated IV Encrypted message Decrypted message Hello, this is a very long and creative message
Example (GenerateGenericKey) ¶
Example_generateGenericKey creates a generic key Generic keys can be used to derive new keys Flow: connect, generate generic key
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %s", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) keyLen := 128 // bits keyTemplate := ep11.EP11Attributes{ ep11.CKA_KEY_TYPE: ep11.CKK_GENERIC_SECRET, ep11.CKA_CLASS: ep11.CKO_SECRET_KEY, ep11.CKA_VALUE_LEN: keyLen / 8, ep11.CKA_EXTRACTABLE: false, } generateKeyRequest := &pb.GenerateKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_GENERIC_SECRET_KEY_GEN}, Template: util.AttributeMap(keyTemplate), } generateKeyResponse, err := cryptoClient.GenerateKey(context.Background(), generateKeyRequest) if err != nil { panic(fmt.Errorf("GenerateKey Error: %s", err)) } _ = generateKeyResponse // simulates the use of the Generic key fmt.Println("Generated Generic Key")
Output: Generated Generic Key
Example (GetMechanismInfo) ¶
Example_getMechanismInfo retrieves a mechanism list and retrieves detailed information for the CKM_RSA_PKCS mechanism Flow: connect, get mechanism list, get mechanism info
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %s", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) mechanismListRequest := &pb.GetMechanismListRequest{} // Retrieve a list of all supported mechanisms mechanismListResponse, err := cryptoClient.GetMechanismList(context.Background(), mechanismListRequest) if err != nil { panic(fmt.Errorf("Get mechanism list error: %s", err)) } fmt.Printf("Got mechanism list:\n%v ...\n", mechanismListResponse.Mechs[:1]) mechanismInfoRequest := &pb.GetMechanismInfoRequest{ Mech: ep11.CKM_RSA_PKCS, } // Retrieve information about the CKM_RSA_PKCS mechanism mechanismInfoResponse, err := cryptoClient.GetMechanismInfo(context.Background(), mechanismInfoRequest) if err != nil { panic(fmt.Errorf("Get mechanism info error: %s", err)) } _ = mechanismInfoResponse // simulate use of mechanismInfoResponse
Output: Got mechanism list: [CKM_RSA_PKCS] ...
Example (SignAndVerifyToTestErrorHandling) ¶
Example_signAndVerifyToTestErrorHandling signs some data, modifies the signature and verifies the expected returned error code Flow: connect, generate ECDSA key pair, sign PKCS #11 single-part data, modify signature to force verify error,
verify PKCS #11 single-part data, ensure proper error is returned
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %s", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) ecParameters, err := asn1.Marshal(util.OIDNamedCurveP256) if err != nil { panic(fmt.Errorf("Unable to encode parameter OID: %s", err)) } publicKeyTemplate := ep11.EP11Attributes{ ep11.CKA_EC_PARAMS: ecParameters, ep11.CKA_VERIFY: true, ep11.CKA_EXTRACTABLE: false, } privateKeyTemplate := ep11.EP11Attributes{ ep11.CKA_SIGN: true, ep11.CKA_EXTRACTABLE: false, } generateKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_EC_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(publicKeyTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyTemplate), } generateKeyPairResponse, err := cryptoClient.GenerateKeyPair(context.Background(), generateKeypairRequest) if err != nil { panic(fmt.Errorf("GenerateKeyPair error: %s", err)) } fmt.Println("Generated ECDSA key pair") signInitRequest := &pb.SignInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_ECDSA}, PrivKey: generateKeyPairResponse.PrivKeyBytes, } signInitResponse, err := cryptoClient.SignInit(context.Background(), signInitRequest) if err != nil { panic(fmt.Errorf("SignInit error: %s", err)) } // Sign the data signData := sha256.Sum256([]byte("This data needs to be signed")) signRequest := &pb.SignRequest{ State: signInitResponse.State, Data: signData[:], } SignResponse, err := cryptoClient.Sign(context.Background(), signRequest) if err != nil { panic(fmt.Errorf("Sign error: %s", err)) } fmt.Println("Data signed") // Modify signature to force returned error code SignResponse.Signature[0] = 255 verifyInitRequest := &pb.VerifyInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_ECDSA}, PubKey: generateKeyPairResponse.PubKeyBytes, } verifyInitResponse, err := cryptoClient.VerifyInit(context.Background(), verifyInitRequest) if err != nil { panic(fmt.Errorf("VerifyInit error: %s", err)) } verifyRequest := &pb.VerifyRequest{ State: verifyInitResponse.State, Data: []byte(signData[:]), Signature: SignResponse.Signature, } // Verify the data -- expect an error _, err = cryptoClient.Verify(context.Background(), verifyRequest) if ok, ep11Status := util.Convert(err); !ok { if ep11Status.Code == ep11.CKR_SIGNATURE_INVALID { fmt.Printf("Invalid signature\n") return } panic(fmt.Errorf("Verify error: [%d]: %s", ep11Status.Code, ep11Status.Detail)) }
Output: Generated ECDSA key pair Data signed Invalid signature
Example (SignAndVerifyUsingDSAKeyPair) ¶
Example_signAndVerifyUsingDSAKeyPair generates a DSA key pair then signs the sample message and verifies the signed message using the DSA key pair Flow: connect, generate DSA key pair, sign PKCS #11 single-part data, PKCS #11 verify single-part data
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %v", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) dsaDomainTemplate := ep11.EP11Attributes{ ep11.CKA_PRIME_BITS: 2048, } generateKeyRequest := &pb.GenerateKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_DSA_PARAMETER_GEN}, Template: util.AttributeMap(dsaDomainTemplate), } // First obtain DSA domain parameters that will used by the DSA GenerateKeyPair request generateKeyResponse, err := cryptoClient.GenerateKey(context.Background(), generateKeyRequest) if err != nil { panic(fmt.Errorf("GenerateKeyPair error: %s", err)) } fmt.Println("Generated DSA domain parameters") publicKeyTemplate := ep11.EP11Attributes{ ep11.CKA_VERIFY: true, // to verify a signature ep11.CKA_EXTRACTABLE: false, ep11.CKA_IBM_STRUCT_PARAMS: generateKeyResponse.KeyBytes, } privateKeyTemplate := ep11.EP11Attributes{ ep11.CKA_SIGN: true, // to generate a signature ep11.CKA_PRIVATE: true, ep11.CKA_SENSITIVE: true, ep11.CKA_EXTRACTABLE: false, } // Now generate the DSA key pair using the domain parameters created in the previous step generateKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_DSA_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(publicKeyTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyTemplate), } generateKeyPairResponse, err := cryptoClient.GenerateKeyPair(context.Background(), generateKeypairRequest) if err != nil { panic(fmt.Errorf("GenerateKeyPair error: %s", err)) } fmt.Println("Generated DSA key pair") signInitRequest := &pb.SignInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_DSA_SHA1}, PrivKey: generateKeyPairResponse.PrivKeyBytes, } signInitResponse, err := cryptoClient.SignInit(context.Background(), signInitRequest) if err != nil { panic(fmt.Errorf("SignInit error: %s", err)) } signData := sha256.Sum256([]byte("This data needs to be signed")) signRequest := &pb.SignRequest{ State: signInitResponse.State, Data: []byte(signData[:]), } // Sign the data SignResponse, err := cryptoClient.Sign(context.Background(), signRequest) if err != nil { panic(fmt.Errorf("Sign error: %s", err)) } fmt.Println("Data signed") verifyInitRequest := &pb.VerifyInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_DSA_SHA1}, PubKey: generateKeyPairResponse.PubKeyBytes, } verifyInitResponse, err := cryptoClient.VerifyInit(context.Background(), verifyInitRequest) if err != nil { panic(fmt.Errorf("VerifyInit error: %s", err)) } verifyRequest := &pb.VerifyRequest{ State: verifyInitResponse.State, Data: []byte(signData[:]), Signature: SignResponse.Signature, } // Verify the data _, err = cryptoClient.Verify(context.Background(), verifyRequest) if ok, ep11Status := util.Convert(err); !ok { if ep11Status.Code == ep11.CKR_SIGNATURE_INVALID { panic(fmt.Errorf("Invalid signature")) } else { panic(fmt.Errorf("Verify error: [%d]: %s", ep11Status.Code, ep11Status.Detail)) } } fmt.Println("Verified")
Output: Generated DSA domain parameters Generated DSA key pair Data signed Verified
Example (SignAndVerifyUsingECDSAKeyPair) ¶
Example_signAndVerifyUsingECDSAKeyPair generates an ECDSA key pair then uses the key pair to sign and verify a sample message Flow: connect, generate ECDSA key pair, sign PKCS #11 single-part data, verify PKCS #11 single-part data
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %s", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) ecParameters, err := asn1.Marshal(util.OIDNamedCurveP256) if err != nil { panic(fmt.Errorf("Unable to encode parameter OID: %s", err)) } publicKeyECTemplate := ep11.EP11Attributes{ ep11.CKA_EC_PARAMS: ecParameters, ep11.CKA_VERIFY: true, ep11.CKA_EXTRACTABLE: false, } privateKeyECTemplate := ep11.EP11Attributes{ ep11.CKA_SIGN: true, ep11.CKA_EXTRACTABLE: false, } generateKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_EC_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(publicKeyECTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyECTemplate), } generateKeyPairResponse, err := cryptoClient.GenerateKeyPair(context.Background(), generateKeypairRequest) if err != nil { panic(fmt.Errorf("GenerateKeyPair error: %s", err)) } fmt.Println("Generated ECDSA PKCS key pair") signInitRequest := &pb.SignInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_ECDSA}, PrivKey: generateKeyPairResponse.PrivKeyBytes, } signInitResponse, err := cryptoClient.SignInit(context.Background(), signInitRequest) if err != nil { panic(fmt.Errorf("SignInit error: %s", err)) } signData := sha256.Sum256([]byte("This data needs to be signed")) signRequest := &pb.SignRequest{ State: signInitResponse.State, Data: signData[:], } // Sign the data SignResponse, err := cryptoClient.Sign(context.Background(), signRequest) if err != nil { panic(fmt.Errorf("Sign error: %s", err)) } fmt.Println("Data signed") verifyInitRequest := &pb.VerifyInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_ECDSA}, PubKey: generateKeyPairResponse.PubKeyBytes, } verifyInitResponse, err := cryptoClient.VerifyInit(context.Background(), verifyInitRequest) if err != nil { panic(fmt.Errorf("VerifyInit error: %s", err)) } verifyRequest := &pb.VerifyRequest{ State: verifyInitResponse.State, Data: []byte(signData[:]), Signature: SignResponse.Signature, } // Verify the data _, err = cryptoClient.Verify(context.Background(), verifyRequest) if ok, ep11Status := util.Convert(err); !ok { if ep11Status.Code == ep11.CKR_SIGNATURE_INVALID { panic(fmt.Errorf("Invalid signature")) } else { panic(fmt.Errorf("Verify error: [%d]: %s", ep11Status.Code, ep11Status.Detail)) } } fmt.Println("Verified")
Output: Generated ECDSA PKCS key pair Data signed Verified
Example (SignAndVerifyUsingRSAKeyPair) ¶
Example_signAndVerifyUsingRSAKeyPair generates an RSA key pair then signs a sample message and verifies the signed message using the RSA key pair Flow: connect, generate RSA key pair, sign PKCS #11 single-part data, PKCS #11 verify single-part data
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %v", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) // Generate RSA key pair publicExponent := 17 publicKeyTemplate := ep11.EP11Attributes{ ep11.CKA_ENCRYPT: true, ep11.CKA_VERIFY: true, // to verify a signature ep11.CKA_MODULUS_BITS: 2048, ep11.CKA_PUBLIC_EXPONENT: publicExponent, ep11.CKA_EXTRACTABLE: false, } privateKeyTemplate := ep11.EP11Attributes{ ep11.CKA_PRIVATE: true, ep11.CKA_SENSITIVE: true, ep11.CKA_DECRYPT: true, ep11.CKA_SIGN: true, // to generate a signature ep11.CKA_EXTRACTABLE: false, } generateKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_RSA_PKCS_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(publicKeyTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyTemplate), } generateKeyPairResponse, err := cryptoClient.GenerateKeyPair(context.Background(), generateKeypairRequest) if err != nil { panic(fmt.Errorf("GenerateKeyPair error: %s", err)) } fmt.Println("Generated RSA PKCS key pair") signInitRequest := &pb.SignInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_SHA1_RSA_PKCS}, PrivKey: generateKeyPairResponse.PrivKeyBytes, } signInitResponse, err := cryptoClient.SignInit(context.Background(), signInitRequest) if err != nil { panic(fmt.Errorf("SignInit error: %s", err)) } signData := sha256.Sum256([]byte("This data needs to be signed")) signRequest := &pb.SignRequest{ State: signInitResponse.State, Data: []byte(signData[:]), } // Sign the data SignResponse, err := cryptoClient.Sign(context.Background(), signRequest) if err != nil { panic(fmt.Errorf("Sign error: %s", err)) } fmt.Println("Data signed") verifyInitRequest := &pb.VerifyInitRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_SHA1_RSA_PKCS}, PubKey: generateKeyPairResponse.PubKeyBytes, } verifyInitResponse, err := cryptoClient.VerifyInit(context.Background(), verifyInitRequest) if err != nil { panic(fmt.Errorf("VerifyInit error: %s", err)) } verifyRequest := &pb.VerifyRequest{ State: verifyInitResponse.State, Data: []byte(signData[:]), Signature: SignResponse.Signature, } // Verify the data _, err = cryptoClient.Verify(context.Background(), verifyRequest) if ok, ep11Status := util.Convert(err); !ok { if ep11Status.Code == ep11.CKR_SIGNATURE_INVALID { panic(fmt.Errorf("Invalid signature")) } else { panic(fmt.Errorf("Verify error: [%d]: %s", ep11Status.Code, ep11Status.Detail)) } } fmt.Println("Verified")
Output: Generated RSA PKCS key pair Data signed Verified
Example (Tls) ¶
Example_tls tests TLS communication between a client and server using a certificate and private key that are dynamically generated
package main import ( "context" "crypto/rand" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "fmt" "io/ioutil" "math/big" "net/http" "strings" "time" "github.com/IBM-Cloud/hpcs-grep11-go/ep11" pb "github.com/IBM-Cloud/hpcs-grep11-go/grpc" "github.com/IBM-Cloud/hpcs-grep11-go/util" grpc "google.golang.org/grpc" ) // generateECDSAKeyPair generates a 256 bit ECDSA key pair func generateECDSAKeyPair(cryptoClient pb.CryptoClient) ([]byte, []byte, error) { ecParameters, err := asn1.Marshal(util.OIDNamedCurveP256) if err != nil { return nil, nil, fmt.Errorf("Unable to encode parameter OID: %s", err) } publicKeyECTemplate := ep11.EP11Attributes{ ep11.CKA_EC_PARAMS: ecParameters, ep11.CKA_VERIFY: true, ep11.CKA_EXTRACTABLE: false, } privateKeyECTemplate := ep11.EP11Attributes{ ep11.CKA_SIGN: true, ep11.CKA_EXTRACTABLE: false, } generateECKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_EC_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(publicKeyECTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyECTemplate), } var ecKeypairResponse *pb.GenerateKeyPairResponse ecKeypairResponse, err = cryptoClient.GenerateKeyPair(context.Background(), generateECKeypairRequest) if err != nil { return nil, nil, fmt.Errorf("Generate ECDSA key pair error: %s", err) } return ecKeypairResponse.PrivKeyBytes, ecKeypairResponse.PubKeyBytes, nil } func createECDSASelfSignedCert(privKey *util.EP11PrivateKey, commonName string, sigAlg x509.SignatureAlgorithm) ([]byte, error) { template := x509.Certificate{ SerialNumber: big.NewInt(123456789), Subject: pkix.Name{ CommonName: commonName, }, NotBefore: time.Now(), NotAfter: time.Now().Add(time.Hour * 24 * 180), DNSNames: []string{"localhost"}, } certDERBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, privKey.Public(), privKey) if err != nil { return nil, fmt.Errorf("Failed to create certificate: %s", err) } return certDERBytes, nil } // StartServer starts https server func CreateServer(listenAddr string) *http.Server { mux := http.NewServeMux() mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { w.Write([]byte("Hello")) }) httpServer := &http.Server{ Addr: listenAddr, Handler: mux, } return httpServer } func newHTTPTestClient(caCertDER []byte) *http.Client { x509Cert, err := x509.ParseCertificate(caCertDER) if err != nil { fmt.Printf("x509.ParseCertificate failed: %s\n", err) return nil } clientCertPool := x509.NewCertPool() // Append the client certificates from the CA clientCertPool.AddCert(x509Cert) httpClient := &http.Client{ Transport: &http.Transport{ TLSClientConfig: &tls.Config{ ServerName: "localhost", RootCAs: clientCertPool, }, }, } return httpClient } func ping(client *http.Client, serverAddr string) (string, error) { // serverAddr in format of a.b.c.d:port in ipv4 or [::]:port in ipv6 var serverPort string id := strings.LastIndex(serverAddr, ":") if id != -1 { serverPort = serverAddr[id:] } else { serverPort = serverAddr } fullAddr := "https://localhost" + serverPort resp, err := client.Get(fullAddr) if err != nil { return "", fmt.Errorf("Http client get failed: %s", err) } data, err := ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { return "", fmt.Errorf("ioutil.ReadAll failed: %s", err) } return string(data), nil } // Example_tls tests TLS communication between a client and server using a certificate and private key that are dynamically generated func main() { conn, err := grpc.Dial(Address, callOpts...) if err != nil { fmt.Printf("Could not connect to server: %s", err) return } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) privKeyBlob, spki, err := generateECDSAKeyPair(cryptoClient) if err != nil { fmt.Printf("Failed to generate ECDSA key pair: %s", err) return } // Create signer and raw certificate to build up TLS certificate priv, err := util.NewEP11Signer(cryptoClient, privKeyBlob, spki) if err != nil { fmt.Printf("NewEP11Signer error: %s\n", err) return } certDER, err := createECDSASelfSignedCert(priv, "localhost", x509.ECDSAWithSHA256) if err != nil { fmt.Printf("createECDSASelfSignedCert error: %s\n", err) return } tlsCert := tls.Certificate{ Certificate: [][]byte{certDER}, PrivateKey: priv, } // Create and start server thread tlsCfg := &tls.Config{ Certificates: []tls.Certificate{tlsCert}, ClientAuth: tls.NoClientCert, } lis, err := tls.Listen("tcp", ":0", tlsCfg) if err != nil { fmt.Printf("Failed to listen: %s\n", err) return } httpServer := CreateServer(lis.Addr().String()) defer httpServer.Close() go func() { httpServer.Serve(lis) }() // Create TLS client client := newHTTPTestClient(certDER) strResp, err := ping(client, lis.Addr().String()) if err != nil { fmt.Printf("Ping failed: %s\n", err) } else { fmt.Printf("Response data from https server: [%s]\n", strResp) } return }
Output: Response data from https server: [Hello]
Example (WrapAndUnwrapAttributeBoundKey) ¶
Example_wrapAndUnWrapAttributeBoundKey wraps an AES key with a RSA public key and then unwraps it with the RSA private key Flow: connect, generate generic symmetric key for MAC use, generate AES key, generate RSA key pair, wrap/unwrap AES key with RSA key pair
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %s", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) // Create MAC Key keyLen := 128 // bits macKeyTemplate := ep11.EP11Attributes{ ep11.CKA_KEY_TYPE: ep11.CKK_GENERIC_SECRET, ep11.CKA_CLASS: ep11.CKO_SECRET_KEY, ep11.CKA_VALUE_LEN: keyLen / 8, ep11.CKA_EXTRACTABLE: false, ep11.CKA_IBM_ATTRBOUND: true, } generateMacKeyRequest := &pb.GenerateKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_GENERIC_SECRET_KEY_GEN}, Template: util.AttributeMap(macKeyTemplate), } generateMacKeyResponse, err := cryptoClient.GenerateKey(context.Background(), generateMacKeyRequest) if err != nil { panic(fmt.Errorf("GenerateKey Error: %s", err)) } fmt.Println("Generated Generic MAC key") // Generate a AES key aesKeyTemplate := ep11.EP11Attributes{ ep11.CKA_VALUE_LEN: 128 / 8, ep11.CKA_ENCRYPT: true, ep11.CKA_DECRYPT: true, ep11.CKA_EXTRACTABLE: true, // must be true to be wrapped ep11.CKA_IBM_ATTRBOUND: true, } generateKeyRequest := &pb.GenerateKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_AES_KEY_GEN}, Template: util.AttributeMap(aesKeyTemplate), } generateKeyResponse, err := cryptoClient.GenerateKey(context.Background(), generateKeyRequest) if err != nil { panic(fmt.Errorf("Generate AES key error: %s", err)) } else { fmt.Println("Generated AES key") } // Generate RSA key pairs publicExponent := 17 publicKeyTemplate := ep11.EP11Attributes{ ep11.CKA_ENCRYPT: true, ep11.CKA_WRAP: true, // to wrap a key ep11.CKA_MODULUS_BITS: 2048, ep11.CKA_PUBLIC_EXPONENT: publicExponent, ep11.CKA_EXTRACTABLE: false, ep11.CKA_IBM_ATTRBOUND: true, } privateKeyTemplate := ep11.EP11Attributes{ ep11.CKA_PRIVATE: true, ep11.CKA_SENSITIVE: true, ep11.CKA_DECRYPT: true, ep11.CKA_UNWRAP: true, // to unwrap a key ep11.CKA_EXTRACTABLE: false, ep11.CKA_IBM_ATTRBOUND: true, } generateKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_RSA_PKCS_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(publicKeyTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyTemplate), } generateKeyPairResponse, err := cryptoClient.GenerateKeyPair(context.Background(), generateKeypairRequest) if err != nil { panic(fmt.Errorf("GenerateKeyPair error: %s", err)) } fmt.Println("Generated RSA PKCS key pair") wrapKeyRequest := &pb.WrapKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_IBM_ATTRIBUTEBOUND_WRAP}, KeK: generateKeyPairResponse.PubKeyBytes, Key: generateKeyResponse.KeyBytes, MacKey: generateMacKeyResponse.KeyBytes, } // Wrap the AES key wrapKeyResponse, err := cryptoClient.WrapKey(context.Background(), wrapKeyRequest) if err != nil { panic(fmt.Errorf("Wrap AES key error: %s", err)) } fmt.Println("Wrapped AES key") aesUnwrapKeyTemplate := ep11.EP11Attributes{ ep11.CKA_CLASS: ep11.CKO_SECRET_KEY, ep11.CKA_KEY_TYPE: ep11.CKK_AES, ep11.CKA_VALUE_LEN: 128 / 8, ep11.CKA_ENCRYPT: true, ep11.CKA_DECRYPT: true, ep11.CKA_EXTRACTABLE: true, // must be true to be wrapped } unwrapRequest := &pb.UnwrapKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_IBM_ATTRIBUTEBOUND_WRAP}, KeK: generateKeyPairResponse.PrivKeyBytes, MacKey: generateMacKeyResponse.KeyBytes, Wrapped: wrapKeyResponse.Wrapped, Template: util.AttributeMap(aesUnwrapKeyTemplate), } // Unwrap the AES key unwrappedResponse, err := cryptoClient.UnwrapKey(context.Background(), unwrapRequest) if err != nil { panic(fmt.Errorf("Unwrap AES key error: %s", err)) } if !bytes.Equal(generateKeyResponse.GetCheckSum()[:3], unwrappedResponse.GetCheckSum()[:3]) { panic(fmt.Errorf("Unwrap AES key has a different checksum than the original key")) } else { fmt.Println("Unwrapped AES key") }
Output: Generated Generic MAC key Generated AES key Generated RSA PKCS key pair Wrapped AES key Unwrapped AES key
Example (WrapAndUnwrapKey) ¶
Example_wrapAndUnWrapKey wraps an AES key with a RSA public key and then unwraps it with the RSA private key Flow: connect, generate AES key, generate RSA key pair, wrap/unwrap AES key with RSA key pair
conn, err := grpc.Dial(Address, callOpts...) if err != nil { panic(fmt.Errorf("Could not connect to server: %s", err)) } defer conn.Close() cryptoClient := pb.NewCryptoClient(conn) // Generate a AES key aesKeyTemplate := ep11.EP11Attributes{ ep11.CKA_VALUE_LEN: 128 / 8, ep11.CKA_ENCRYPT: true, ep11.CKA_DECRYPT: true, ep11.CKA_EXTRACTABLE: true, // must be true to be wrapped } generateKeyRequest := &pb.GenerateKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_AES_KEY_GEN}, Template: util.AttributeMap(aesKeyTemplate), } generateKeyResponse, err := cryptoClient.GenerateKey(context.Background(), generateKeyRequest) if err != nil { panic(fmt.Errorf("Generate AES key error: %s", err)) } else { fmt.Println("Generated AES key") } // Generate RSA key pairs publicExponent := 17 publicKeyTemplate := ep11.EP11Attributes{ ep11.CKA_ENCRYPT: true, ep11.CKA_WRAP: true, // to wrap a key ep11.CKA_MODULUS_BITS: 2048, ep11.CKA_PUBLIC_EXPONENT: publicExponent, ep11.CKA_EXTRACTABLE: false, } privateKeyTemplate := ep11.EP11Attributes{ ep11.CKA_PRIVATE: true, ep11.CKA_SENSITIVE: true, ep11.CKA_DECRYPT: true, ep11.CKA_UNWRAP: true, // to unwrap a key ep11.CKA_EXTRACTABLE: false, } generateKeypairRequest := &pb.GenerateKeyPairRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_RSA_PKCS_KEY_PAIR_GEN}, PubKeyTemplate: util.AttributeMap(publicKeyTemplate), PrivKeyTemplate: util.AttributeMap(privateKeyTemplate), } generateKeyPairResponse, err := cryptoClient.GenerateKeyPair(context.Background(), generateKeypairRequest) if err != nil { panic(fmt.Errorf("GenerateKeyPair error: %s", err)) } fmt.Println("Generated RSA PKCS key pair") wrapKeyRequest := &pb.WrapKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_RSA_PKCS}, KeK: generateKeyPairResponse.PubKeyBytes, Key: generateKeyResponse.KeyBytes, } // Wrap the AES key wrapKeyResponse, err := cryptoClient.WrapKey(context.Background(), wrapKeyRequest) if err != nil { panic(fmt.Errorf("Wrap AES key error: %s", err)) } fmt.Println("Wrapped AES key") aesUnwrapKeyTemplate := ep11.EP11Attributes{ ep11.CKA_CLASS: ep11.CKO_SECRET_KEY, ep11.CKA_KEY_TYPE: ep11.CKK_AES, ep11.CKA_VALUE_LEN: 128 / 8, ep11.CKA_ENCRYPT: true, ep11.CKA_DECRYPT: true, ep11.CKA_EXTRACTABLE: true, // must be true to be wrapped } unwrapRequest := &pb.UnwrapKeyRequest{ Mech: &pb.Mechanism{Mechanism: ep11.CKM_RSA_PKCS}, KeK: generateKeyPairResponse.PrivKeyBytes, Wrapped: wrapKeyResponse.Wrapped, Template: util.AttributeMap(aesUnwrapKeyTemplate), } // Unwrap the AES key unwrappedResponse, err := cryptoClient.UnwrapKey(context.Background(), unwrapRequest) if err != nil { panic(fmt.Errorf("Unwrap AES key error: %s", err)) } if !bytes.Equal(generateKeyResponse.GetCheckSum()[:3], unwrappedResponse.GetCheckSum()[:3]) { panic(fmt.Errorf("Unwrap AES key has a different checksum than the original key")) } else { fmt.Println("Unwrapped AES key") }
Output: Generated AES key Generated RSA PKCS key pair Wrapped AES key Unwrapped AES key