Skip to content

Commit 63f34e3

Browse files
feat(key_manager): add sign and verify methods (scaleway#2551)
Co-authored-by: Laure-di <[email protected]>
1 parent 9bcb489 commit 63f34e3

File tree

1 file changed

+234
-6
lines changed

1 file changed

+234
-6
lines changed

api/key_manager/v1alpha1/key_manager_sdk.go

Lines changed: 234 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,114 @@ func (enum *DataKeyAlgorithmSymmetricEncryption) UnmarshalJSON(data []byte) erro
7777
return nil
7878
}
7979

80+
type KeyAlgorithmAsymmetricEncryption string
81+
82+
const (
83+
KeyAlgorithmAsymmetricEncryptionUnknownAsymmetricEncryption = KeyAlgorithmAsymmetricEncryption("unknown_asymmetric_encryption")
84+
// RSA-OAEP (Optimal Asymmetric Encryption Padding) with a 2048-bit key and SHA-256 hash function.
85+
KeyAlgorithmAsymmetricEncryptionRsaOaep2048Sha256 = KeyAlgorithmAsymmetricEncryption("rsa_oaep_2048_sha256")
86+
// RSA-OAEP (Optimal Asymmetric Encryption Padding) with a 3072-bit key and SHA-256 hash function (recommended).
87+
KeyAlgorithmAsymmetricEncryptionRsaOaep3072Sha256 = KeyAlgorithmAsymmetricEncryption("rsa_oaep_3072_sha256")
88+
// RSA-OAEP (Optimal Asymmetric Encryption Padding) with a 4096-bit key and SHA-256 hash function.
89+
KeyAlgorithmAsymmetricEncryptionRsaOaep4096Sha256 = KeyAlgorithmAsymmetricEncryption("rsa_oaep_4096_sha256")
90+
)
91+
92+
func (enum KeyAlgorithmAsymmetricEncryption) String() string {
93+
if enum == "" {
94+
// return default value if empty
95+
return string(KeyAlgorithmAsymmetricEncryptionUnknownAsymmetricEncryption)
96+
}
97+
return string(enum)
98+
}
99+
100+
func (enum KeyAlgorithmAsymmetricEncryption) Values() []KeyAlgorithmAsymmetricEncryption {
101+
return []KeyAlgorithmAsymmetricEncryption{
102+
"unknown_asymmetric_encryption",
103+
"rsa_oaep_2048_sha256",
104+
"rsa_oaep_3072_sha256",
105+
"rsa_oaep_4096_sha256",
106+
}
107+
}
108+
109+
func (enum KeyAlgorithmAsymmetricEncryption) MarshalJSON() ([]byte, error) {
110+
return []byte(fmt.Sprintf(`"%s"`, enum)), nil
111+
}
112+
113+
func (enum *KeyAlgorithmAsymmetricEncryption) UnmarshalJSON(data []byte) error {
114+
tmp := ""
115+
116+
if err := json.Unmarshal(data, &tmp); err != nil {
117+
return err
118+
}
119+
120+
*enum = KeyAlgorithmAsymmetricEncryption(KeyAlgorithmAsymmetricEncryption(tmp).String())
121+
return nil
122+
}
123+
124+
type KeyAlgorithmAsymmetricSigning string
125+
126+
const (
127+
KeyAlgorithmAsymmetricSigningUnknownAsymmetricSigning = KeyAlgorithmAsymmetricSigning("unknown_asymmetric_signing")
128+
// ECDSA (Elliptic Curve Digital Signature Algorithm) on the P-256 Curve and SHA-256 hash function (recommended).
129+
KeyAlgorithmAsymmetricSigningEcP256Sha256 = KeyAlgorithmAsymmetricSigning("ec_p256_sha256")
130+
// ECDSA (Elliptic Curve Digital Signature Algorithm) on the P-384 Curve and SHA-384 hash function.
131+
KeyAlgorithmAsymmetricSigningEcP384Sha384 = KeyAlgorithmAsymmetricSigning("ec_p384_sha384")
132+
// RSA-PSS (Probabilistic Signature Scheme) with a 2048-bit key and SHA-256 hash function.
133+
KeyAlgorithmAsymmetricSigningRsaPss2048Sha256 = KeyAlgorithmAsymmetricSigning("rsa_pss_2048_sha256")
134+
// RSA-PSS (Probabilistic Signature Scheme) with a 3072-bit key and SHA-256 hash function.
135+
KeyAlgorithmAsymmetricSigningRsaPss3072Sha256 = KeyAlgorithmAsymmetricSigning("rsa_pss_3072_sha256")
136+
// RSA-PSS (Probabilistic Signature Scheme) with a 4096-bit key and SHA-256 hash function.
137+
KeyAlgorithmAsymmetricSigningRsaPss4096Sha256 = KeyAlgorithmAsymmetricSigning("rsa_pss_4096_sha256")
138+
// RSA-PKCS1 (Public Key Cryptography Standards) with a 2048-bit key and SHA-256 hash function.
139+
KeyAlgorithmAsymmetricSigningRsaPkcs1_2048Sha256 = KeyAlgorithmAsymmetricSigning("rsa_pkcs1_2048_sha256")
140+
// RSA-PKCS1 (Public Key Cryptography Standards) with a 3072-bit key and SHA-256 hash function.
141+
KeyAlgorithmAsymmetricSigningRsaPkcs1_3072Sha256 = KeyAlgorithmAsymmetricSigning("rsa_pkcs1_3072_sha256")
142+
// RSA-PKCS1 (Public Key Cryptography Standards) with a 4096-bit key and SHA-256 hash function.
143+
KeyAlgorithmAsymmetricSigningRsaPkcs1_4096Sha256 = KeyAlgorithmAsymmetricSigning("rsa_pkcs1_4096_sha256")
144+
)
145+
146+
func (enum KeyAlgorithmAsymmetricSigning) String() string {
147+
if enum == "" {
148+
// return default value if empty
149+
return string(KeyAlgorithmAsymmetricSigningUnknownAsymmetricSigning)
150+
}
151+
return string(enum)
152+
}
153+
154+
func (enum KeyAlgorithmAsymmetricSigning) Values() []KeyAlgorithmAsymmetricSigning {
155+
return []KeyAlgorithmAsymmetricSigning{
156+
"unknown_asymmetric_signing",
157+
"ec_p256_sha256",
158+
"ec_p384_sha384",
159+
"rsa_pss_2048_sha256",
160+
"rsa_pss_3072_sha256",
161+
"rsa_pss_4096_sha256",
162+
"rsa_pkcs1_2048_sha256",
163+
"rsa_pkcs1_3072_sha256",
164+
"rsa_pkcs1_4096_sha256",
165+
}
166+
}
167+
168+
func (enum KeyAlgorithmAsymmetricSigning) MarshalJSON() ([]byte, error) {
169+
return []byte(fmt.Sprintf(`"%s"`, enum)), nil
170+
}
171+
172+
func (enum *KeyAlgorithmAsymmetricSigning) UnmarshalJSON(data []byte) error {
173+
tmp := ""
174+
175+
if err := json.Unmarshal(data, &tmp); err != nil {
176+
return err
177+
}
178+
179+
*enum = KeyAlgorithmAsymmetricSigning(KeyAlgorithmAsymmetricSigning(tmp).String())
180+
return nil
181+
}
182+
80183
type KeyAlgorithmSymmetricEncryption string
81184

82185
const (
83186
KeyAlgorithmSymmetricEncryptionUnknownSymmetricEncryption = KeyAlgorithmSymmetricEncryption("unknown_symmetric_encryption")
84-
// Key Manager currently only supports the `AES-GCM` (256-bits) key algorithm.
187+
// 256-bit Advanced Encryption Standard (AES-256) keys in Galois Counter Mode (GCM).
85188
KeyAlgorithmSymmetricEncryptionAes256Gcm = KeyAlgorithmSymmetricEncryption("aes_256_gcm")
86189
)
87190

@@ -258,8 +361,16 @@ type KeyRotationPolicy struct {
258361
type KeyUsage struct {
259362
// SymmetricEncryption: see the `Key.Algorithm.SymmetricEncryption` enum for a description of values.
260363
// Default value: unknown_symmetric_encryption
261-
// Precisely one of SymmetricEncryption must be set.
364+
// Precisely one of SymmetricEncryption, AsymmetricEncryption, AsymmetricSigning must be set.
262365
SymmetricEncryption *KeyAlgorithmSymmetricEncryption `json:"symmetric_encryption,omitempty"`
366+
367+
// AsymmetricEncryption: default value: unknown_asymmetric_encryption
368+
// Precisely one of SymmetricEncryption, AsymmetricEncryption, AsymmetricSigning must be set.
369+
AsymmetricEncryption *KeyAlgorithmAsymmetricEncryption `json:"asymmetric_encryption,omitempty"`
370+
371+
// AsymmetricSigning: default value: unknown_asymmetric_signing
372+
// Precisely one of SymmetricEncryption, AsymmetricEncryption, AsymmetricSigning must be set.
373+
AsymmetricSigning *KeyAlgorithmAsymmetricSigning `json:"asymmetric_signing,omitempty"`
263374
}
264375

265376
// Key: key.
@@ -370,13 +481,13 @@ type DecryptRequest struct {
370481
// Region: region to target. If none is passed will use default region from the config.
371482
Region scw.Region `json:"-"`
372483

373-
// KeyID: ID of the key to decrypt.
484+
// KeyID: the key must have an usage set to `symmetric_encryption` or `asymmetric_encryption`.
374485
KeyID string `json:"-"`
375486

376487
// Ciphertext: data size must be between 1 and 131071 bytes.
377488
Ciphertext []byte `json:"ciphertext"`
378489

379-
// AssociatedData: the additional data must match the value passed in the encryption request.
490+
// AssociatedData: the additional data must match the value passed in the encryption request. Only supported by keys with a usage set to `symmetric_encryption`.
380491
AssociatedData *[]byte `json:"associated_data,omitempty"`
381492
}
382493

@@ -433,13 +544,13 @@ type EncryptRequest struct {
433544
// Region: region to target. If none is passed will use default region from the config.
434545
Region scw.Region `json:"-"`
435546

436-
// KeyID: ID of the key to encrypt.
547+
// KeyID: the key must have an usage set to `symmetric_encryption` or `asymmetric_encryption`.
437548
KeyID string `json:"-"`
438549

439550
// Plaintext: data size must be between 1 and 65535 bytes.
440551
Plaintext []byte `json:"plaintext"`
441552

442-
// AssociatedData: additional data which will not be encrypted, but authenticated and appended to the encrypted payload.
553+
// AssociatedData: additional data which will not be encrypted, but authenticated and appended to the encrypted payload. Only supported by keys with a usage set to `symmetric_encryption`.
443554
AssociatedData *[]byte `json:"associated_data,omitempty"`
444555
}
445556

@@ -578,6 +689,27 @@ type RotateKeyRequest struct {
578689
KeyID string `json:"-"`
579690
}
580691

692+
// SignRequest: sign request.
693+
type SignRequest struct {
694+
// Region: region to target. If none is passed will use default region from the config.
695+
Region scw.Region `json:"-"`
696+
697+
// KeyID: ID of the key to use for signing.
698+
KeyID string `json:"-"`
699+
700+
// Digest: the digest must be generated using the same algorithm defined in the key’s algorithm settings.
701+
Digest []byte `json:"digest"`
702+
}
703+
704+
// SignResponse: sign response.
705+
type SignResponse struct {
706+
// KeyID: ID of the key used to generate the signature.
707+
KeyID string `json:"key_id"`
708+
709+
// Signature: the message signature.
710+
Signature []byte `json:"signature"`
711+
}
712+
581713
// UnprotectKeyRequest: unprotect key request.
582714
type UnprotectKeyRequest struct {
583715
// Region: region to target. If none is passed will use default region from the config.
@@ -608,6 +740,30 @@ type UpdateKeyRequest struct {
608740
RotationPolicy *KeyRotationPolicy `json:"rotation_policy,omitempty"`
609741
}
610742

743+
// VerifyRequest: verify request.
744+
type VerifyRequest struct {
745+
// Region: region to target. If none is passed will use default region from the config.
746+
Region scw.Region `json:"-"`
747+
748+
// KeyID: ID of the key to use for signature verification.
749+
KeyID string `json:"-"`
750+
751+
// Digest: must be generated using the same algorithm specified in the key’s configuration.
752+
Digest []byte `json:"digest"`
753+
754+
// Signature: the message signature to verify.
755+
Signature []byte `json:"signature"`
756+
}
757+
758+
// VerifyResponse: verify response.
759+
type VerifyResponse struct {
760+
// KeyID: ID of the key used for verification.
761+
KeyID string `json:"key_id"`
762+
763+
// Valid: returns `true` if the signature is valid for the digest and key, `false` otherwise.
764+
Valid bool `json:"valid"`
765+
}
766+
611767
// This API allows you to create, manage and use cryptographic keys in a centralized and secure service.
612768
type API struct {
613769
client *scw.Client
@@ -1120,6 +1276,78 @@ func (s *API) Decrypt(req *DecryptRequest, opts ...scw.RequestOption) (*DecryptR
11201276
return &resp, nil
11211277
}
11221278

1279+
// Sign: Use a given key to sign a message digest. The key must have its usage set to `asymmetric_signing`. The digest must be created using the same digest algorithm that is defined in the key's algorithm configuration.
1280+
func (s *API) Sign(req *SignRequest, opts ...scw.RequestOption) (*SignResponse, error) {
1281+
var err error
1282+
1283+
if req.Region == "" {
1284+
defaultRegion, _ := s.client.GetDefaultRegion()
1285+
req.Region = defaultRegion
1286+
}
1287+
1288+
if fmt.Sprint(req.Region) == "" {
1289+
return nil, errors.New("field Region cannot be empty in request")
1290+
}
1291+
1292+
if fmt.Sprint(req.KeyID) == "" {
1293+
return nil, errors.New("field KeyID cannot be empty in request")
1294+
}
1295+
1296+
scwReq := &scw.ScalewayRequest{
1297+
Method: "POST",
1298+
Path: "/key-manager/v1alpha1/regions/" + fmt.Sprint(req.Region) + "/keys/" + fmt.Sprint(req.KeyID) + "/sign",
1299+
}
1300+
1301+
err = scwReq.SetBody(req)
1302+
if err != nil {
1303+
return nil, err
1304+
}
1305+
1306+
var resp SignResponse
1307+
1308+
err = s.client.Do(scwReq, &resp, opts...)
1309+
if err != nil {
1310+
return nil, err
1311+
}
1312+
return &resp, nil
1313+
}
1314+
1315+
// Verify: Use a given key to verify a message signature against a message digest. The key must have its usage set to `asymmetric_signing`. The message digest must be generated using the same digest algorithm that is defined in the key's algorithm configuration.
1316+
func (s *API) Verify(req *VerifyRequest, opts ...scw.RequestOption) (*VerifyResponse, error) {
1317+
var err error
1318+
1319+
if req.Region == "" {
1320+
defaultRegion, _ := s.client.GetDefaultRegion()
1321+
req.Region = defaultRegion
1322+
}
1323+
1324+
if fmt.Sprint(req.Region) == "" {
1325+
return nil, errors.New("field Region cannot be empty in request")
1326+
}
1327+
1328+
if fmt.Sprint(req.KeyID) == "" {
1329+
return nil, errors.New("field KeyID cannot be empty in request")
1330+
}
1331+
1332+
scwReq := &scw.ScalewayRequest{
1333+
Method: "POST",
1334+
Path: "/key-manager/v1alpha1/regions/" + fmt.Sprint(req.Region) + "/keys/" + fmt.Sprint(req.KeyID) + "/verify",
1335+
}
1336+
1337+
err = scwReq.SetBody(req)
1338+
if err != nil {
1339+
return nil, err
1340+
}
1341+
1342+
var resp VerifyResponse
1343+
1344+
err = s.client.Do(scwReq, &resp, opts...)
1345+
if err != nil {
1346+
return nil, err
1347+
}
1348+
return &resp, nil
1349+
}
1350+
11231351
// ImportKeyMaterial: Import externally generated key material into Key Manager to derive a new cryptographic key. The key's origin must be `external`.
11241352
func (s *API) ImportKeyMaterial(req *ImportKeyMaterialRequest, opts ...scw.RequestOption) (*Key, error) {
11251353
var err error

0 commit comments

Comments
 (0)