diff --git a/.github/workflows/kms.yaml b/.github/workflows/kms.yaml new file mode 100644 index 0000000000..8eaf1bf695 --- /dev/null +++ b/.github/workflows/kms.yaml @@ -0,0 +1,68 @@ +name: kms +on: + push: + branches: + - main + paths: + - 'kms/**' + pull_request: + paths: + - 'kms/**' + pull_request_target: + types: [labeled] + paths: + - 'kms/**' + schedule: + - cron: '0 0 * * 0' +jobs: + test: + if: ${{ github.event.action != 'labeled' || github.event.label.name == 'actions:force-run' }} + runs-on: ubuntu-latest + timeout-minutes: 60 + permissions: + contents: 'write' + pull-requests: 'write' + id-token: 'write' + steps: + - uses: actions/checkout@v3.1.0 + with: + ref: ${{github.event.pull_request.head.sha}} + - uses: 'google-github-actions/auth@v1.0.0' + with: + workload_identity_provider: 'projects/1046198160504/locations/global/workloadIdentityPools/github-actions-pool/providers/github-actions-provider' + service_account: 'kokoro-system-test@long-door-651.iam.gserviceaccount.com' + create_credentials_file: 'true' + access_token_lifetime: 600s + - uses: actions/setup-node@v3.5.1 + with: + node-version: 16 + - run: npm install + working-directory: kms + - run: npm test + working-directory: kms + env: + MOCHA_REPORTER_SUITENAME: kms + MOCHA_REPORTER_OUTPUT: kms_sponge_log.xml + MOCHA_REPORTER: xunit + - if: ${{ github.event.action == 'labeled' && github.event.label.name == 'actions:force-run' }} + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + try { + await github.rest.issues.removeLabel({ + name: 'actions:force-run', + owner: 'GoogleCloudPlatform', + repo: 'nodejs-docs-samples', + issue_number: context.payload.pull_request.number + }); + } catch (e) { + if (!e.message.includes('Label does not exist')) { + throw e; + } + } + - if: ${{ github.event_name == 'schedule'}} + run: | + curl https://github.com/googleapis/repo-automation-bots/releases/download/flakybot-1.1.0/flakybot -o flakybot -s -L + chmod +x ./flakybot + ./flakybot --repo GoogleCloudPlatform/nodejs-docs-samples --commit_hash ${{github.sha}} --build_url https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} diff --git a/.github/workflows/workflows.json b/.github/workflows/workflows.json index 16482e3bd1..13773a413a 100644 --- a/.github/workflows/workflows.json +++ b/.github/workflows/workflows.json @@ -44,6 +44,7 @@ "healthcare/dicom", "healthcare/fhir", "healthcare/hl7v2", + "kms", "game-servers/snippets", "mediatranslation", "monitoring/opencensus", diff --git a/kms/createKeyAsymmetricDecrypt.js b/kms/createKeyAsymmetricDecrypt.js new file mode 100644 index 0000000000..e688fdbefa --- /dev/null +++ b/kms/createKeyAsymmetricDecrypt.js @@ -0,0 +1,76 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + id = 'my-asymmetric-decrypt-key' +) { + // [START kms_create_key_asymmetric_decrypt] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const id = 'my-asymmetric-decrypt-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the parent key ring name + const keyRingName = client.keyRingPath(projectId, locationId, keyRingId); + + async function createKeyAsymmetricDecrypt() { + const [key] = await client.createCryptoKey({ + parent: keyRingName, + cryptoKeyId: id, + cryptoKey: { + purpose: 'ASYMMETRIC_DECRYPT', + versionTemplate: { + algorithm: 'RSA_DECRYPT_OAEP_2048_SHA256', + }, + + // Optional: customize how long key versions should be kept before + // destroying. + destroyScheduledDuration: {seconds: 60 * 60 * 24}, + }, + }); + + console.log(`Created asymmetric key: ${key.name}`); + return key; + } + + return createKeyAsymmetricDecrypt(); + // [END kms_create_key_asymmetric_decrypt] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/createKeyAsymmetricSign.js b/kms/createKeyAsymmetricSign.js new file mode 100644 index 0000000000..73a998984b --- /dev/null +++ b/kms/createKeyAsymmetricSign.js @@ -0,0 +1,76 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + id = 'my-asymmetric-sign-key' +) { + // [START kms_create_key_asymmetric_sign] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const id = 'my-asymmetric-sign-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the parent key ring name + const keyRingName = client.keyRingPath(projectId, locationId, keyRingId); + + async function createKeyAsymmetricSign() { + const [key] = await client.createCryptoKey({ + parent: keyRingName, + cryptoKeyId: id, + cryptoKey: { + purpose: 'ASYMMETRIC_SIGN', + versionTemplate: { + algorithm: 'RSA_SIGN_PKCS1_2048_SHA256', + }, + + // Optional: customize how long key versions should be kept before + // destroying. + destroyScheduledDuration: {seconds: 60 * 60 * 24}, + }, + }); + + console.log(`Created asymmetric key: ${key.name}`); + return key; + } + + return createKeyAsymmetricSign(); + // [END kms_create_key_asymmetric_sign] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/createKeyHsm.js b/kms/createKeyHsm.js new file mode 100644 index 0000000000..9592c3e770 --- /dev/null +++ b/kms/createKeyHsm.js @@ -0,0 +1,77 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + id = 'my-hsm-encryption-key' +) { + // [START kms_create_key_hsm] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const id = 'my-hsm-encryption-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the parent key ring name + const keyRingName = client.keyRingPath(projectId, locationId, keyRingId); + + async function createKeyHsm() { + const [key] = await client.createCryptoKey({ + parent: keyRingName, + cryptoKeyId: id, + cryptoKey: { + purpose: 'ENCRYPT_DECRYPT', + versionTemplate: { + algorithm: 'GOOGLE_SYMMETRIC_ENCRYPTION', + protectionLevel: 'HSM', + }, + + // Optional: customize how long key versions should be kept before + // destroying. + destroyScheduledDuration: {seconds: 60 * 60 * 24}, + }, + }); + + console.log(`Created hsm key: ${key.name}`); + return key; + } + + return createKeyHsm(); + // [END kms_create_key_hsm] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/createKeyLabels.js b/kms/createKeyLabels.js new file mode 100644 index 0000000000..412eca44d8 --- /dev/null +++ b/kms/createKeyLabels.js @@ -0,0 +1,76 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + id = 'my-labeled-key' +) { + // [START kms_create_key_labels] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const id = 'my-labeled-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the parent key ring name + const keyRingName = client.keyRingPath(projectId, locationId, keyRingId); + + async function createKeyLabels() { + const [key] = await client.createCryptoKey({ + parent: keyRingName, + cryptoKeyId: id, + cryptoKey: { + purpose: 'ENCRYPT_DECRYPT', + versionTemplate: { + algorithm: 'GOOGLE_SYMMETRIC_ENCRYPTION', + }, + labels: { + team: 'alpha', + cost_center: 'cc1234', + }, + }, + }); + + console.log(`Created labeled key: ${key.name}`); + return key; + } + + return createKeyLabels(); + // [END kms_create_key_labels] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/createKeyMac.js b/kms/createKeyMac.js new file mode 100644 index 0000000000..ce117b2be6 --- /dev/null +++ b/kms/createKeyMac.js @@ -0,0 +1,76 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + id = 'my-mac-key' +) { + // [START kms_create_key_mac] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const id = 'my-mac-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the parent key ring name + const keyRingName = client.keyRingPath(projectId, locationId, keyRingId); + + async function createKeyMac() { + const [key] = await client.createCryptoKey({ + parent: keyRingName, + cryptoKeyId: id, + cryptoKey: { + purpose: 'MAC', + versionTemplate: { + algorithm: 'HMAC_SHA256', + }, + + // Optional: customize how long key versions should be kept before + // destroying. + destroyScheduledDuration: {seconds: 60 * 60 * 24}, + }, + }); + + console.log(`Created mac key: ${key.name}`); + return key; + } + + return createKeyMac(); + // [END kms_create_key_mac] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/createKeyRing.js b/kms/createKeyRing.js new file mode 100644 index 0000000000..36b2110fa9 --- /dev/null +++ b/kms/createKeyRing.js @@ -0,0 +1,64 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + id = 'my-key-ring' +) { + // [START kms_create_key_ring] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const id = 'my-key-ring'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the parent location name + const locationName = client.locationPath(projectId, locationId); + + async function createKeyRing() { + const [keyRing] = await client.createKeyRing({ + parent: locationName, + keyRingId: id, + }); + + console.log(`Created key ring: ${keyRing.name}`); + return keyRing; + } + + return createKeyRing(); + // [END kms_create_key_ring] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/createKeyRotationSchedule.js b/kms/createKeyRotationSchedule.js new file mode 100644 index 0000000000..23f3d5fe44 --- /dev/null +++ b/kms/createKeyRotationSchedule.js @@ -0,0 +1,82 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + id = 'my-rotating-encryption-key' +) { + // [START kms_create_key_rotation_schedule] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const id = 'my-rotating-encryption-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the parent key ring name + const keyRingName = client.keyRingPath(projectId, locationId, keyRingId); + + async function createKeyRotationSchedule() { + const [key] = await client.createCryptoKey({ + parent: keyRingName, + cryptoKeyId: id, + cryptoKey: { + purpose: 'ENCRYPT_DECRYPT', + versionTemplate: { + algorithm: 'GOOGLE_SYMMETRIC_ENCRYPTION', + }, + + // Rotate the key every 30 days. + rotationPeriod: { + seconds: 60 * 60 * 24 * 30, + }, + + // Start the first rotation in 24 hours. + nextRotationTime: { + seconds: new Date().getTime() / 1000 + 60 * 60 * 24, + }, + }, + }); + + console.log(`Created rotating key: ${key.name}`); + return key; + } + + return createKeyRotationSchedule(); + // [END kms_create_key_rotation_schedule] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/createKeySymmetricEncryptDecrypt.js b/kms/createKeySymmetricEncryptDecrypt.js new file mode 100644 index 0000000000..e4677347bd --- /dev/null +++ b/kms/createKeySymmetricEncryptDecrypt.js @@ -0,0 +1,72 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + id = 'my-symmetric-encryption-key' +) { + // [START kms_create_key_symmetric_encrypt_decrypt] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const id = 'my-symmetric-encryption-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the parent key ring name + const keyRingName = client.keyRingPath(projectId, locationId, keyRingId); + + async function createKeySymmetricEncryptDecrypt() { + const [key] = await client.createCryptoKey({ + parent: keyRingName, + cryptoKeyId: id, + cryptoKey: { + purpose: 'ENCRYPT_DECRYPT', + versionTemplate: { + algorithm: 'GOOGLE_SYMMETRIC_ENCRYPTION', + }, + }, + }); + + console.log(`Created symmetric key: ${key.name}`); + return key; + } + + return createKeySymmetricEncryptDecrypt(); + // [END kms_create_key_symmetric_encrypt_decrypt] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/createKeyVersion.js b/kms/createKeyVersion.js new file mode 100644 index 0000000000..5230f7638e --- /dev/null +++ b/kms/createKeyVersion.js @@ -0,0 +1,65 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key' +) { + // [START kms_create_key_version] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the parent key name + const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId); + + async function createKeyVersion() { + const [version] = await client.createCryptoKeyVersion({ + parent: keyName, + }); + + console.log(`Created key version: ${version.name}`); + return version; + } + + return createKeyVersion(); + // [END kms_create_key_version] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/decryptAsymmetric.js b/kms/decryptAsymmetric.js new file mode 100644 index 0000000000..d7bf5134e3 --- /dev/null +++ b/kms/decryptAsymmetric.js @@ -0,0 +1,102 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123', + ciphertext = Buffer.from('...') +) { + // [START kms_decrypt_asymmetric] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + // const ciphertext = Buffer.from('...'); + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + // Optional, but recommended: compute plaintext's CRC32C. + const crc32c = require('fast-crc32c'); + const ciphertextCrc32c = crc32c.calculate(ciphertext); + + async function decryptAsymmetric() { + const [decryptResponse] = await client.asymmetricDecrypt({ + name: versionName, + ciphertext: ciphertext, + ciphertextCrc32c: { + value: ciphertextCrc32c, + }, + }); + + // Optional, but recommended: perform integrity verification on decryptResponse. + // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + // https://cloud.google.com/kms/docs/data-integrity-guidelines + if (!decryptResponse.verifiedCiphertextCrc32c) { + throw new Error('AsymmetricDecrypt: request corrupted in-transit'); + } + if ( + crc32c.calculate(decryptResponse.plaintext) !== + Number(decryptResponse.plaintextCrc32c.value) + ) { + throw new Error('AsymmetricDecrypt: response corrupted in-transit'); + } + + // NOTE: The ciphertext must be properly formatted. In Node < 12, the + // crypto.publicEncrypt() function does not properly consume the OAEP + // padding and thus produces invalid ciphertext. If you are using Node to do + // public key encryption, please use version 12+. + const plaintext = decryptResponse.plaintext.toString('utf8'); + + console.log(`Plaintext: ${plaintext}`); + return plaintext; + } + + return decryptAsymmetric(); + // [END kms_decrypt_asymmetric] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/decryptSymmetric.js b/kms/decryptSymmetric.js new file mode 100644 index 0000000000..0291717ab2 --- /dev/null +++ b/kms/decryptSymmetric.js @@ -0,0 +1,88 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + ciphertext = Buffer.from('...') +) { + // [START kms_decrypt_symmetric] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // Ciphertext must be either a Buffer object or a base-64 encoded string + // const ciphertext = Buffer.from('...'); + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key name + const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId); + + // Optional, but recommended: compute ciphertext's CRC32C. + const crc32c = require('fast-crc32c'); + const ciphertextCrc32c = crc32c.calculate(ciphertext); + + async function decryptSymmetric() { + const [decryptResponse] = await client.decrypt({ + name: keyName, + ciphertext: ciphertext, + ciphertextCrc32c: { + value: ciphertextCrc32c, + }, + }); + + // Optional, but recommended: perform integrity verification on decryptResponse. + // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + // https://cloud.google.com/kms/docs/data-integrity-guidelines + if ( + crc32c.calculate(decryptResponse.plaintext) !== + Number(decryptResponse.plaintextCrc32c.value) + ) { + throw new Error('Decrypt: response corrupted in-transit'); + } + + const plaintext = decryptResponse.plaintext.toString(); + + console.log(`Plaintext: ${plaintext}`); + return plaintext; + } + + return decryptSymmetric(); + // [END kms_decrypt_symmetric] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/destroyKeyVersion.js b/kms/destroyKeyVersion.js new file mode 100644 index 0000000000..0a6571325b --- /dev/null +++ b/kms/destroyKeyVersion.js @@ -0,0 +1,73 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123' +) { + // [START kms_destroy_key_version] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function destroyKeyVersion() { + const [version] = await client.destroyCryptoKeyVersion({ + name: versionName, + }); + + console.log(`Destroyed key version: ${version.name}`); + return version; + } + + return destroyKeyVersion(); + // [END kms_destroy_key_version] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/disableKeyVersion.js b/kms/disableKeyVersion.js new file mode 100644 index 0000000000..a16db8e2c4 --- /dev/null +++ b/kms/disableKeyVersion.js @@ -0,0 +1,79 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123' +) { + // [START kms_disable_key_version] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function disableKeyVersion() { + const [version] = await client.updateCryptoKeyVersion({ + cryptoKeyVersion: { + name: versionName, + state: 'DISABLED', + }, + updateMask: { + paths: ['state'], + }, + }); + + console.log(`Disabled key version: ${version.name}`); + return version; + } + + return disableKeyVersion(); + // [END kms_disable_key_version] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/enableKeyVersion.js b/kms/enableKeyVersion.js new file mode 100644 index 0000000000..dec512b380 --- /dev/null +++ b/kms/enableKeyVersion.js @@ -0,0 +1,79 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123' +) { + // [START kms_enable_key_version] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function enableKeyVersion() { + const [version] = await client.updateCryptoKeyVersion({ + cryptoKeyVersion: { + name: versionName, + state: 'ENABLED', + }, + updateMask: { + paths: ['state'], + }, + }); + + console.log(`Enabled key version: ${version.name}`); + return version; + } + + return enableKeyVersion(); + // [END kms_enable_key_version] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/encryptAsymmetric.js b/kms/encryptAsymmetric.js new file mode 100644 index 0000000000..bea1311c93 --- /dev/null +++ b/kms/encryptAsymmetric.js @@ -0,0 +1,106 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123', + plaintextBuffer = Buffer.from('...') +) { + // [START kms_encrypt_asymmetric] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + // const plaintextBuffer = Buffer.from('...'); + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function encryptAsymmetric() { + // Get public key from Cloud KMS + const [publicKey] = await client.getPublicKey({ + name: versionName, + }); + + // Optional, but recommended: perform integrity verification on publicKey. + // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + // https://cloud.google.com/kms/docs/data-integrity-guidelines + const crc32c = require('fast-crc32c'); + if (publicKey.name !== versionName) { + throw new Error('GetPublicKey: request corrupted in-transit'); + } + if (crc32c.calculate(publicKey.pem) !== Number(publicKey.pemCrc32c.value)) { + throw new Error('GetPublicKey: response corrupted in-transit'); + } + + // Import and setup crypto + const crypto = require('crypto'); + + // Encrypt plaintext locally using the public key. This example uses a key + // that was configured with sha256 hash with OAEP padding. Update these + // values to match the Cloud KMS key. + // + // NOTE: In Node < 12, this function does not properly consume the OAEP + // padding and thus produces invalid ciphertext. If you are using Node to do + // public key encryption, please use version 12+. + const ciphertextBuffer = crypto.publicEncrypt( + { + key: publicKey.pem, + oaepHash: 'sha256', + padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, + }, + plaintextBuffer + ); + + console.log(`Ciphertext: ${ciphertextBuffer.toString('base64')}`); + return ciphertextBuffer; + } + + return encryptAsymmetric(); + // [END kms_encrypt_asymmetric] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/encryptSymmetric.js b/kms/encryptSymmetric.js new file mode 100644 index 0000000000..283492b111 --- /dev/null +++ b/kms/encryptSymmetric.js @@ -0,0 +1,90 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + plaintextBuffer = Buffer.from('...') +) { + // [START kms_encrypt_symmetric] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const plaintextBuffer = Buffer.from('...'); + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key name + const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId); + + // Optional, but recommended: compute plaintext's CRC32C. + const crc32c = require('fast-crc32c'); + const plaintextCrc32c = crc32c.calculate(plaintextBuffer); + + async function encryptSymmetric() { + const [encryptResponse] = await client.encrypt({ + name: keyName, + plaintext: plaintextBuffer, + plaintextCrc32c: { + value: plaintextCrc32c, + }, + }); + + const ciphertext = encryptResponse.ciphertext; + + // Optional, but recommended: perform integrity verification on encryptResponse. + // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + // https://cloud.google.com/kms/docs/data-integrity-guidelines + if (!encryptResponse.verifiedPlaintextCrc32c) { + throw new Error('Encrypt: request corrupted in-transit'); + } + if ( + crc32c.calculate(ciphertext) !== + Number(encryptResponse.ciphertextCrc32c.value) + ) { + throw new Error('Encrypt: response corrupted in-transit'); + } + + console.log(`Ciphertext: ${ciphertext.toString('base64')}`); + return ciphertext; + } + + return encryptSymmetric(); + // [END kms_encrypt_symmetric] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/generateRandomBytes.js b/kms/generateRandomBytes.js new file mode 100644 index 0000000000..6f0dc17f58 --- /dev/null +++ b/kms/generateRandomBytes.js @@ -0,0 +1,65 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + numBytes = 256 +) { + // [START kms_generate_random_bytes] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const numBytes = 256; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the location name + const locationName = client.locationPath(projectId, locationId); + + async function generateRandomBytes() { + const [randomBytesResponse] = await client.generateRandomBytes({ + location: locationName, + lengthBytes: numBytes, + protectionLevel: 'HSM', + }); + + console.log(`Random bytes: ${randomBytesResponse.data.toString('base64')}`); + return randomBytesResponse; + } + + return generateRandomBytes(); + // [END kms_generate_random_bytes] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/getKeyLabels.js b/kms/getKeyLabels.js new file mode 100644 index 0000000000..bee79d4833 --- /dev/null +++ b/kms/getKeyLabels.js @@ -0,0 +1,68 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key' +) { + // [START kms_get_key_labels] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key name + const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId); + + async function getKeyLabels() { + const [key] = await client.getCryptoKey({ + name: keyName, + }); + + for (const k in key.labels) { + console.log(`${k}: ${key.labels[k]}`); + } + + return key; + } + + return getKeyLabels(); + // [END kms_get_key_labels] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/getKeyVersionAttestation.js b/kms/getKeyVersionAttestation.js new file mode 100644 index 0000000000..4674873e43 --- /dev/null +++ b/kms/getKeyVersionAttestation.js @@ -0,0 +1,80 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123' +) { + // [START kms_get_key_version_attestation] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function getKeyVersionAttestation() { + const [version] = await client.getCryptoKeyVersion({ + name: versionName, + }); + + // Only HSM keys have an attestation. For other key types, the attestion + // will be nil. + const attestation = version.attestation; + if (!attestation) { + throw new Error('no attestation'); + } + + console.log(`Attestation: ${attestation.toString('base64')}`); + return attestation.content; + } + + return getKeyVersionAttestation(); + // [END kms_get_key_version_attestation] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/getPublicKey.js b/kms/getPublicKey.js new file mode 100644 index 0000000000..f47a9f7803 --- /dev/null +++ b/kms/getPublicKey.js @@ -0,0 +1,84 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123' +) { + // [START kms_get_public_key] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function getPublicKey() { + const [publicKey] = await client.getPublicKey({ + name: versionName, + }); + + // Optional, but recommended: perform integrity verification on publicKey. + // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + // https://cloud.google.com/kms/docs/data-integrity-guidelines + const crc32c = require('fast-crc32c'); + if (publicKey.name !== versionName) { + throw new Error('GetPublicKey: request corrupted in-transit'); + } + if (crc32c.calculate(publicKey.pem) !== Number(publicKey.pemCrc32c.value)) { + throw new Error('GetPublicKey: response corrupted in-transit'); + } + + console.log(`Public key pem: ${publicKey.pem}`); + + return publicKey; + } + + return getPublicKey(); + // [END kms_get_public_key] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/iamAddMember.js b/kms/iamAddMember.js new file mode 100644 index 0000000000..7ab63acddf --- /dev/null +++ b/kms/iamAddMember.js @@ -0,0 +1,88 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + member = 'user:foo@example.com' +) { + // [START kms_iam_add_member] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const member = 'user:foo@example.com'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the resource name + const resourceName = client.cryptoKeyPath( + projectId, + locationId, + keyRingId, + keyId + ); + + // The resource name could also be a key ring. + // const resourceName = client.keyRingPath(projectId, locationId, keyRingId); + + async function iamAddMember() { + // Get the current IAM policy. + const [policy] = await client.getIamPolicy({ + resource: resourceName, + }); + + // Add the member to the policy. + policy.bindings.push({ + role: 'roles/cloudkms.cryptoKeyEncrypterDecrypter', + members: [member], + }); + + // Save the updated policy. + const [updatedPolicy] = await client.setIamPolicy({ + resource: resourceName, + policy: policy, + }); + + console.log('Updated policy'); + return updatedPolicy; + } + + return iamAddMember(); + // [END kms_iam_add_member] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/iamGetPolicy.js b/kms/iamGetPolicy.js new file mode 100644 index 0000000000..bccabc8042 --- /dev/null +++ b/kms/iamGetPolicy.js @@ -0,0 +1,80 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key' +) { + // [START kms_iam_get_policy] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const member = 'user:foo@example.com'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the resource name + const resourceName = client.cryptoKeyPath( + projectId, + locationId, + keyRingId, + keyId + ); + + // The resource name could also be a key ring. + // const resourceName = client.keyRingPath(projectId, locationId, keyRingId); + + async function iamGetPolicy() { + const [policy] = await client.getIamPolicy({ + resource: resourceName, + }); + + for (const binding of policy.bindings) { + console.log(`Role: ${binding.role}`); + for (const member of binding.members) { + console.log(` - ${member}`); + } + } + + return policy; + } + + return iamGetPolicy(); + // [END kms_iam_get_policy] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/iamRemoveMember.js b/kms/iamRemoveMember.js new file mode 100644 index 0000000000..2f6f2cd9e9 --- /dev/null +++ b/kms/iamRemoveMember.js @@ -0,0 +1,95 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + member = 'user:foo@example.com' +) { + // [START kms_iam_remove_member] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const member = 'user:foo@example.com'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the resource name + const resourceName = client.cryptoKeyPath( + projectId, + locationId, + keyRingId, + keyId + ); + + // The resource name could also be a key ring. + // const resourceName = client.keyRingPath(projectId, locationId, keyRingId); + + async function iamRemoveMember() { + // Get the current IAM policy. + const [policy] = await client.getIamPolicy({ + resource: resourceName, + }); + + // Build a new list of policy bindings with the user excluded. + for (const i in policy.bindings) { + const binding = policy.bindings[i]; + if (binding.role !== 'roles/cloudkms.cryptoKeyEncrypterDecrypter') { + continue; + } + + const idx = binding.members.indexOf(member); + if (idx !== -1) { + binding.members.splice(idx, 1); + } + } + + // Save the updated IAM policy. + const [updatedPolicy] = await client.setIamPolicy({ + resource: resourceName, + policy: policy, + }); + + console.log('Updated policy'); + return updatedPolicy; + } + + return iamRemoveMember(); + // [END kms_iam_remove_member] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/package.json b/kms/package.json new file mode 100644 index 0000000000..89d0d86f2e --- /dev/null +++ b/kms/package.json @@ -0,0 +1,27 @@ +{ + "name": "nodejs-kms-samples", + "private": true, + "license": "Apache-2.0", + "files": [ + "*.js" + ], + "author": "Google LLC", + "repository": "googleapis/nodejs-kms", + "engines": { + "node": ">=12.0.0" + }, + "scripts": { + "test": "c8 mocha --recursive test/ --timeout=800000" + }, + "dependencies": { + "@google-cloud/kms": "^3.1.0", + "fast-crc32c": "^2.0.0", + "jslint": "^0.12.1" + }, + "devDependencies": { + "c8": "^7.0.0", + "chai": "^4.2.0", + "mocha": "^8.0.0", + "uuid": "^9.0.0" + } +} diff --git a/kms/quickstart.js b/kms/quickstart.js new file mode 100644 index 0000000000..9253bd221d --- /dev/null +++ b/kms/quickstart.js @@ -0,0 +1,61 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main(projectId = 'my-project', locationId = 'us-east1') { + // [START kms_quickstart] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the location name + const locationName = client.locationPath(projectId, locationId); + + async function listKeyRings() { + const [keyRings] = await client.listKeyRings({ + parent: locationName, + }); + + for (const keyRing of keyRings) { + console.log(keyRing.name); + } + + return keyRings; + } + + return listKeyRings(); + // [END kms_quickstart] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/restoreKeyVersion.js b/kms/restoreKeyVersion.js new file mode 100644 index 0000000000..f4366a0d7c --- /dev/null +++ b/kms/restoreKeyVersion.js @@ -0,0 +1,73 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123' +) { + // [START kms_restore_key_version] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function restoreKeyVersion() { + const [version] = await client.restoreCryptoKeyVersion({ + name: versionName, + }); + + console.log(`Restored key version: ${version.name}`); + return version; + } + + return restoreKeyVersion(); + // [END kms_restore_key_version] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/signAsymmetric.js b/kms/signAsymmetric.js new file mode 100644 index 0000000000..bf0c7039c8 --- /dev/null +++ b/kms/signAsymmetric.js @@ -0,0 +1,115 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'your-project-id', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123', + message = Buffer.from('...') +) { + // [START kms_sign_asymmetric] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'your-project-id'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + // const message = Buffer.from('...'); + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function signAsymmetric() { + // Create a digest of the message. The digest needs to match the digest + // configured for the Cloud KMS key. + const crypto = require('crypto'); + const hash = crypto.createHash('sha256'); + hash.update(message); + const digest = hash.digest(); + + // Optional but recommended: Compute digest's CRC32C. + // Ensure fast-crc32c has been installed, `npm i fast-crc32c`. + const crc32c = require('fast-crc32c'); + const digestCrc32c = crc32c.calculate(digest); + + // Sign the message with Cloud KMS + const [signResponse] = await client.asymmetricSign({ + name: versionName, + digest: { + sha256: digest, + }, + digestCrc32c: { + value: digestCrc32c, + }, + }); + + // Optional, but recommended: perform integrity verification on signResponse. + // For more details on ensuring E2E in-transit integrity to and from Cloud KMS visit: + // https://cloud.google.com/kms/docs/data-integrity-guidelines + if (signResponse.name !== versionName) { + throw new Error('AsymmetricSign: request corrupted in-transit'); + } + if (!signResponse.verifiedDigestCrc32c) { + throw new Error('AsymmetricSign: request corrupted in-transit'); + } + if ( + crc32c.calculate(signResponse.signature) !== + Number(signResponse.signatureCrc32c.value) + ) { + throw new Error('AsymmetricSign: response corrupted in-transit'); + } + + // Example of how to display signature. Because the signature is in a binary + // format, you need to encode the output before printing it to a console or + // displaying it on a screen. + const encoded = signResponse.signature.toString('base64'); + console.log(`Signature: ${encoded}`); + + return signResponse.signature; + } + + return signAsymmetric(); + // [END kms_sign_asymmetric] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/signMac.js b/kms/signMac.js new file mode 100644 index 0000000000..69a800b817 --- /dev/null +++ b/kms/signMac.js @@ -0,0 +1,82 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'your-project-id', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123', + data = Buffer.from('...') +) { + // [START kms_sign_mac] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'your-project-id'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + // const data = Buffer.from('...'); + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function signMac() { + // Sign the data with Cloud KMS + const [signResponse] = await client.macSign({ + name: versionName, + data: data, + }); + + // Example of how to display signature. Because the signature is in a binary + // format, you need to encode the output before printing it to a console or + // displaying it on a screen. + const encoded = signResponse.mac.toString('base64'); + console.log(`Signature: ${encoded}`); + + return signResponse; + } + + return signMac(); + // [END kms_sign_mac] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/test/kms.test.js b/kms/test/kms.test.js new file mode 100644 index 0000000000..57eeb776a7 --- /dev/null +++ b/kms/test/kms.test.js @@ -0,0 +1,855 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +const {describe, it, before, after, beforeEach, afterEach} = require('mocha'); +const {assert} = require('chai'); +const crypto = require('crypto'); +const {v4} = require('uuid'); + +const {KeyManagementServiceClient} = require('@google-cloud/kms'); +const client = new KeyManagementServiceClient(); + +const projectId = process.env.GCLOUD_PROJECT; +const locationId = 'us-east1'; +const keyRingId = v4(); +const asymmetricDecryptKeyId = v4(); +const asymmetricSignEcKeyId = v4(); +const asymmetricSignRsaKeyId = v4(); +const hsmKeyId = v4(); +const symmetricKeyId = v4(); +const hmacKeyId = v4(); + +const nodeMajorVersion = parseInt(process.version.match(/v?(\d+).*/)[1]); + +const originalConsoleLog = console.log; + +const waitForState = async (name, state) => { + const sleep = w => new Promise(r => setTimeout(r, w)); + + let [version] = await client.getCryptoKeyVersion({name}); + while (version.state !== state) { + await sleep(100); + [version] = await client.getCryptoKeyVersion({name}); + } +}; + +describe('Cloud KMS samples', () => { + before(async () => { + if (!projectId) { + throw new Error('missing GCLOUD_PROJECT!'); + } + + await client.createKeyRing({ + parent: client.locationPath(projectId, locationId), + keyRingId: keyRingId, + }); + + await client.createCryptoKey({ + parent: client.keyRingPath(projectId, locationId, keyRingId), + cryptoKeyId: asymmetricDecryptKeyId, + cryptoKey: { + purpose: 'ASYMMETRIC_DECRYPT', + versionTemplate: { + algorithm: 'RSA_DECRYPT_OAEP_2048_SHA256', + }, + labels: { + foo: 'bar', + zip: 'zap', + }, + }, + }); + await waitForState( + client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + asymmetricDecryptKeyId, + 1 + ), + 'ENABLED' + ); + + await client.createCryptoKey({ + parent: client.keyRingPath(projectId, locationId, keyRingId), + cryptoKeyId: asymmetricSignEcKeyId, + cryptoKey: { + purpose: 'ASYMMETRIC_SIGN', + versionTemplate: { + algorithm: 'EC_SIGN_P256_SHA256', + }, + labels: { + foo: 'bar', + zip: 'zap', + }, + }, + }); + await waitForState( + client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + asymmetricSignEcKeyId, + 1 + ), + 'ENABLED' + ); + + await client.createCryptoKey({ + parent: client.keyRingPath(projectId, locationId, keyRingId), + cryptoKeyId: asymmetricSignRsaKeyId, + cryptoKey: { + purpose: 'ASYMMETRIC_SIGN', + versionTemplate: { + algorithm: 'RSA_SIGN_PSS_2048_SHA256', + }, + labels: { + foo: 'bar', + zip: 'zap', + }, + }, + }); + await waitForState( + client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + asymmetricSignRsaKeyId, + 1 + ), + 'ENABLED' + ); + + await client.createCryptoKey({ + parent: client.keyRingPath(projectId, locationId, keyRingId), + cryptoKeyId: hsmKeyId, + cryptoKey: { + purpose: 'ENCRYPT_DECRYPT', + versionTemplate: { + algorithm: 'GOOGLE_SYMMETRIC_ENCRYPTION', + protectionLevel: 'HSM', + }, + labels: { + foo: 'bar', + zip: 'zap', + }, + }, + }); + await waitForState( + client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + hsmKeyId, + 1 + ), + 'ENABLED' + ); + + await client.createCryptoKey({ + parent: client.keyRingPath(projectId, locationId, keyRingId), + cryptoKeyId: symmetricKeyId, + cryptoKey: { + purpose: 'ENCRYPT_DECRYPT', + versionTemplate: { + algorithm: 'GOOGLE_SYMMETRIC_ENCRYPTION', + }, + labels: { + foo: 'bar', + zip: 'zap', + }, + }, + }); + await waitForState( + client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + symmetricKeyId, + 1 + ), + 'ENABLED' + ); + + await client.createCryptoKey({ + parent: client.keyRingPath(projectId, locationId, keyRingId), + cryptoKeyId: hmacKeyId, + cryptoKey: { + purpose: 'MAC', + versionTemplate: { + algorithm: 'HMAC_SHA256', + }, + labels: { + foo: 'bar', + zip: 'zap', + }, + }, + }); + await waitForState( + client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + hmacKeyId, + 1 + ), + 'ENABLED' + ); + }); + + beforeEach(async () => { + console.log = () => {}; + }); + + afterEach(async () => { + console.log = originalConsoleLog; + }); + + after(async () => { + if (!projectId) { + return; + } + + const [keys] = await client.listCryptoKeys({ + parent: client.keyRingPath(projectId, locationId, keyRingId), + }); + + keys.forEach(async key => { + if (key.rotationPeriod || key.nextRotationTime) { + // Remove the rotation period if one exists + await client.updateCryptoKey({ + cryptoKey: { + name: key.name, + rotationPeriod: null, + nextRotationTime: null, + }, + updateMask: { + paths: ['rotation_period', 'next_rotation_time'], + }, + }); + + const [versions] = await client.listCryptoKeyVersions({ + parent: key.name, + filter: 'state != DESTROYED AND state != DESTROY_SCHEDULED', + }); + + versions.forEach(async version => { + await client.destroyCryptoKeyVersion({ + name: version.name, + }); + }); + } + }); + }); + + it('creates asymmetric decryption keys', async () => { + const sample = require('../createKeyAsymmetricDecrypt'); + const key = await sample.main(projectId, locationId, keyRingId, v4()); + assert.equal(key.purpose, 'ASYMMETRIC_DECRYPT'); + assert.equal(key.versionTemplate.algorithm, 'RSA_DECRYPT_OAEP_2048_SHA256'); + }); + + it('creates asymmetric signing keys', async () => { + const sample = require('../createKeyAsymmetricSign'); + const key = await sample.main(projectId, locationId, keyRingId, v4()); + assert.equal(key.purpose, 'ASYMMETRIC_SIGN'); + assert.equal(key.versionTemplate.algorithm, 'RSA_SIGN_PKCS1_2048_SHA256'); + }); + + it('creates hsm keys', async () => { + const sample = require('../createKeyHsm'); + const key = await sample.main(projectId, locationId, keyRingId, v4()); + assert.equal(key.versionTemplate.protectionLevel, 'HSM'); + }); + + it('creates labeled keys', async () => { + const sample = require('../createKeyLabels'); + const key = await sample.main(projectId, locationId, keyRingId, v4()); + assert.equal(key.labels.team, 'alpha'); + assert.equal(key.labels.cost_center, 'cc1234'); + }); + + it('creates mac keys', async () => { + const sample = require('../createKeyMac'); + const key = await sample.main(projectId, locationId, keyRingId, v4()); + assert.equal(key.purpose, 'MAC'); + assert.equal(key.versionTemplate.algorithm, 'HMAC_SHA256'); + }); + + it('creates key rings', async () => { + const sample = require('../createKeyRing'); + const keyRing = await sample.main(projectId, locationId, v4()); + assert.match(keyRing.name, new RegExp(`${locationId}`)); + }); + + it('creates rotating keys', async () => { + const sample = require('../createKeyRotationSchedule'); + const key = await sample.main(projectId, locationId, keyRingId, v4()); + assert.exists(key.rotationPeriod); + assert.exists(key.nextRotationTime); + }); + + it('creates symmetric keys', async () => { + const sample = require('../createKeySymmetricEncryptDecrypt'); + const key = await sample.main(projectId, locationId, keyRingId, v4()); + assert.equal(key.purpose, 'ENCRYPT_DECRYPT'); + assert.equal(key.versionTemplate.algorithm, 'GOOGLE_SYMMETRIC_ENCRYPTION'); + }); + + it('creates key versions', async () => { + const sample = require('../createKeyVersion'); + const version = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId + ); + assert.match(version.name, new RegExp(`${keyRingId}`)); + }); + + it('decrypts asymmetric data', async () => { + if (nodeMajorVersion < 12) { + return; + } + + const plaintext = 'my message'; + + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + asymmetricDecryptKeyId, + 1 + ); + + const [publicKey] = await client.getPublicKey({name: versionName}); + + const ciphertextBuffer = crypto.publicEncrypt( + { + key: publicKey.pem, + oaepHash: 'sha256', + padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, + }, + Buffer.from(plaintext) + ); + + const sample = require('../decryptAsymmetric'); + const result = await sample.main( + projectId, + locationId, + keyRingId, + asymmetricDecryptKeyId, + 1, + ciphertextBuffer + ); + assert.equal(result, plaintext); + }); + + it('decrypts symmetric data', async () => { + const plaintext = 'my message'; + + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + symmetricKeyId, + 1 + ); + + const [encryptResponse] = await client.encrypt({ + name: versionName, + plaintext: Buffer.from(plaintext), + }); + + const sample = require('../decryptSymmetric'); + const result = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId, + encryptResponse.ciphertext + ); + assert.equal(result, plaintext); + }); + + it('destroys and restores key versions', async () => { + const destroySample = require('../destroyKeyVersion'); + const destroyedVersion = await destroySample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId, + 1 + ); + assert.equal(destroyedVersion.state, 'DESTROY_SCHEDULED'); + + const restoreSample = require('../restoreKeyVersion'); + const restoredVersion = await restoreSample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId, + 1 + ); + // Restored keys come back as disabled + assert.equal(restoredVersion.state, 'DISABLED'); + }); + + it('disables and enables key versions', async () => { + const disableSample = require('../disableKeyVersion'); + const disabledVersion = await disableSample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId, + 1 + ); + assert.equal(disabledVersion.state, 'DISABLED'); + + const enableSample = require('../enableKeyVersion'); + const enabledVersion = await enableSample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId, + 1 + ); + assert.equal(enabledVersion.state, 'ENABLED'); + }); + + it('encrypts with asymmetric keys', async () => { + if (nodeMajorVersion < 12) { + return; + } + + const plaintext = 'my message'; + + const sample = require('../encryptAsymmetric'); + const ciphertextBuffer = await sample.main( + projectId, + locationId, + keyRingId, + asymmetricDecryptKeyId, + 1, + Buffer.from(plaintext) + ); + + const [decryptResponse] = await client.asymmetricDecrypt({ + name: client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + asymmetricDecryptKeyId, + 1 + ), + ciphertext: ciphertextBuffer, + }); + + assert.equal(decryptResponse.plaintext.toString('utf8'), plaintext); + }); + + it('encrypts with symmetric keys', async () => { + const plaintext = 'my message'; + + const sample = require('../encryptSymmetric'); + const ciphertextBuffer = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId, + Buffer.from(plaintext) + ); + + const [decryptResponse] = await client.decrypt({ + name: client.cryptoKeyPath( + projectId, + locationId, + keyRingId, + symmetricKeyId + ), + ciphertext: ciphertextBuffer, + }); + + assert.equal(decryptResponse.plaintext.toString('utf8'), plaintext); + }); + + it('generates random bytes', async () => { + const sample = require('../generateRandomBytes'); + const result = await sample.main(projectId, locationId, 256); + assert.equal(result.data.length, 256); + }); + + it('gets keys with labels', async () => { + const sample = require('../getKeyLabels'); + const key = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId + ); + + assert.equal(key.labels.foo, 'bar'); + assert.equal(key.labels.zip, 'zap'); + }); + + it('gets version attestations', async () => { + const sample = require('../getKeyVersionAttestation'); + const attestation = await sample.main( + projectId, + locationId, + keyRingId, + hsmKeyId, + 1 + ); + + assert.exists(attestation); + }); + + it('errors on bad attestations', async () => { + const sample = require('../getKeyVersionAttestation'); + sample + .main(projectId, locationId, keyRingId, symmetricKeyId, 1) + .then(() => { + throw new Error('expected error'); + }) + .catch(err => { + assert.match(err, new RegExp('no attestation')); + }); + }); + + it('gets public keys', async () => { + const sample = require('../getPublicKey'); + const publicKey = await sample.main( + projectId, + locationId, + keyRingId, + asymmetricDecryptKeyId, + 1 + ); + + assert.exists(publicKey); + }); + + it('adds IAM members', async () => { + const sample = require('../iamAddMember'); + const policy = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId, + 'group:test@google.com' + ); + + let binding; + for (const b of policy.bindings) { + if (b.role === 'roles/cloudkms.cryptoKeyEncrypterDecrypter') { + binding = b; + break; + } + } + + assert.exists(binding); + assert.oneOf('group:test@google.com', binding.members); + }); + + it('get IAM policies', async () => { + const sample = require('../iamGetPolicy'); + const policy = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId + ); + + assert.exists(policy); + }); + + it('removes IAM members', async () => { + const resourceName = client.cryptoKeyPath( + projectId, + locationId, + keyRingId, + symmetricKeyId + ); + + const [policy] = await client.getIamPolicy({ + resource: resourceName, + }); + + policy.bindings.push({ + role: 'roles/cloudkms.publicKeyViewer', + members: ['group:test@google.com'], + }); + + policy.bindings.push({ + role: 'roles/cloudkms.cryptoKeyEncrypter', + members: ['group:test@google.com'], + }); + + await client.setIamPolicy({ + resource: resourceName, + policy: policy, + }); + + const sample = require('../iamRemoveMember'); + const updatedPolicy = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId, + 'group:test@google.com' + ); + + let binding; + for (const b of updatedPolicy.bindings) { + if (b.role === 'roles/cloudkms.cryptoKeyEncrypterDecrypter') { + binding = b; + break; + } + } + + assert.notExists(binding); + }); + + it('quickstarts', async () => { + const sample = require('../quickstart'); + const keyRings = await sample.main(projectId, locationId); + + assert.isNotEmpty(keyRings); + }); + + it('signs with asymmetric keys', async () => { + if (nodeMajorVersion < 12) { + return; + } + + const message = 'my message'; + + const sample = require('../signAsymmetric'); + const signatureBuffer = await sample.main( + projectId, + locationId, + keyRingId, + asymmetricSignEcKeyId, + 1, + message + ); + + const [publicKey] = await client.getPublicKey({ + name: client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + asymmetricSignEcKeyId, + 1 + ), + }); + + const verify = crypto.createVerify('SHA256'); + verify.update(message); + verify.end(); + + const verified = verify.verify(publicKey.pem, signatureBuffer); + assert.isTrue(verified); + }); + + it('signs with mac keys', async () => { + const data = 'my data'; + + const sample = require('../signMac'); + const result = await sample.main( + projectId, + locationId, + keyRingId, + hmacKeyId, + 1, + Buffer.from(data) + ); + + const [verifyResponse] = await client.macVerify({ + name: client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + hmacKeyId, + 1 + ), + data: Buffer.from(data), + mac: result.mac, + }); + + assert.isTrue(verifyResponse.success); + }); + + it('adds rotation schedules', async () => { + const sample = require('../updateKeyAddRotation'); + const key = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId + ); + assert.exists(key.rotationSchedule); + assert.exists(key.nextRotationTime); + }); + + it('removes labels', async () => { + const sample = require('../updateKeyRemoveLabels'); + const key = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId + ); + assert.isEmpty(key.labels); + }); + + it('removes rotation schedules', async () => { + const sample = require('../updateKeyRemoveRotation'); + const key = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId + ); + assert.notExists(key.rotationSchedule); + assert.notExists(key.nextRotationTime); + }); + + it('sets primary version', async () => { + const sample = require('../updateKeySetPrimary'); + const key = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId, + 1 + ); + assert.exists(key.primary); + }); + + it('updates labels', async () => { + const sample = require('../updateKeyUpdateLabels'); + const key = await sample.main( + projectId, + locationId, + keyRingId, + symmetricKeyId + ); + assert.equal(key.labels.new_label, 'new_value'); + }); + + it('verifies with asymmetric EC keys', async () => { + if (nodeMajorVersion < 12) { + return; + } + + const message = 'my message'; + + const digest = crypto.createHash('sha256'); + digest.update(message); + + const [signResponse] = await client.asymmetricSign({ + name: client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + asymmetricSignEcKeyId, + 1 + ), + digest: { + sha256: digest.digest(), + }, + }); + + const sample = require('../verifyAsymmetricEc'); + const verified = await sample.main( + projectId, + locationId, + keyRingId, + asymmetricSignEcKeyId, + 1, + message, + signResponse.signature + ); + + assert.isTrue(verified); + }); + + it('verifies with asymmetric RSA keys', async () => { + if (nodeMajorVersion < 12) { + return; + } + + const message = 'my message'; + + const digest = crypto.createHash('sha256'); + digest.update(message); + + const [signResponse] = await client.asymmetricSign({ + name: client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + asymmetricSignRsaKeyId, + 1 + ), + digest: { + sha256: digest.digest(), + }, + }); + + const sample = require('../verifyAsymmetricRsa'); + const verified = await sample.main( + projectId, + locationId, + keyRingId, + asymmetricSignRsaKeyId, + 1, + message, + signResponse.signature + ); + + assert.isTrue(verified); + }); + + it('verifies with mac keys', async () => { + const data = 'my data'; + + const [signResponse] = await client.macSign({ + name: client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + hmacKeyId, + 1 + ), + data: Buffer.from(data), + }); + + const sample = require('../verifyMac'); + const result = await sample.main( + projectId, + locationId, + keyRingId, + hmacKeyId, + 1, + Buffer.from(data), + signResponse.mac + ); + + assert.isTrue(result.success); + }); +}); diff --git a/kms/updateKeyAddRotation.js b/kms/updateKeyAddRotation.js new file mode 100644 index 0000000000..634675bc31 --- /dev/null +++ b/kms/updateKeyAddRotation.js @@ -0,0 +1,81 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key' +) { + // [START kms_update_key_add_rotation_schedule] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key name + const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId); + + async function updateKeyAddRotation() { + const [key] = await client.updateCryptoKey({ + cryptoKey: { + name: keyName, + + // Rotate the key every 30 days. + rotationPeriod: { + seconds: 60 * 60 * 24 * 30, + }, + + // Start the first rotation in 24 hours. + nextRotationTime: { + seconds: new Date().getTime() / 1000 + 60 * 60 * 24, + }, + }, + updateMask: { + paths: ['rotation_period', 'next_rotation_time'], + }, + }); + + console.log(`Updated rotation for: ${key.name}`); + return key; + } + + return updateKeyAddRotation(); + // [END kms_update_key_add_rotation_schedule] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/updateKeyRemoveLabels.js b/kms/updateKeyRemoveLabels.js new file mode 100644 index 0000000000..bef2b533cf --- /dev/null +++ b/kms/updateKeyRemoveLabels.js @@ -0,0 +1,72 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key' +) { + // [START kms_update_key_remove_labels] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key name + const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId); + + async function updateKeyRemoveLabels() { + const [key] = await client.updateCryptoKey({ + cryptoKey: { + name: keyName, + labels: null, + }, + updateMask: { + paths: ['labels'], + }, + }); + + console.log(`Removed labels from: ${key.name}`); + return key; + } + + return updateKeyRemoveLabels(); + // [END kms_update_key_remove_labels] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/updateKeyRemoveRotation.js b/kms/updateKeyRemoveRotation.js new file mode 100644 index 0000000000..2e355f06c4 --- /dev/null +++ b/kms/updateKeyRemoveRotation.js @@ -0,0 +1,72 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key' +) { + // [START kms_update_key_remove_rotation_schedule] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key name + const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId); + + async function updateKeyRemoveRotation() { + const [key] = await client.updateCryptoKey({ + cryptoKey: { + name: keyName, + rotationPeriod: null, + nextRotationTime: null, + }, + updateMask: { + paths: ['rotation_period', 'next_rotation_time'], + }, + }); + + console.log(`Removed rotation for: ${key.name}`); + return key; + } + + return updateKeyRemoveRotation(); + // [END kms_update_key_remove_rotation_schedule] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/updateKeySetPrimary.js b/kms/updateKeySetPrimary.js new file mode 100644 index 0000000000..046de0b24b --- /dev/null +++ b/kms/updateKeySetPrimary.js @@ -0,0 +1,68 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123' +) { + // [START kms_update_key_set_primary] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key name + const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId); + + async function updateKeySetPrimary() { + const [key] = await client.updateCryptoKeyPrimaryVersion({ + name: keyName, + cryptoKeyVersionId: versionId, + }); + + console.log(`Set primary to ${versionId}`); + return key; + } + + return updateKeySetPrimary(); + // [END kms_update_key_set_primary] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/updateKeyUpdateLabels.js b/kms/updateKeyUpdateLabels.js new file mode 100644 index 0000000000..d23ef89500 --- /dev/null +++ b/kms/updateKeyUpdateLabels.js @@ -0,0 +1,74 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'my-project', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key' +) { + // [START kms_update_key_update_labels] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'my-project'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key name + const keyName = client.cryptoKeyPath(projectId, locationId, keyRingId, keyId); + + async function updateKeyUpdateLabels() { + const [key] = await client.updateCryptoKey({ + cryptoKey: { + name: keyName, + labels: { + new_label: 'new_value', + }, + }, + updateMask: { + paths: ['labels'], + }, + }); + + console.log(`Updated labels for: ${key.name}`); + return key; + } + + return updateKeyUpdateLabels(); + // [END kms_update_key_update_labels] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/verifyAsymmetricEc.js b/kms/verifyAsymmetricEc.js new file mode 100644 index 0000000000..ce0c3997cf --- /dev/null +++ b/kms/verifyAsymmetricEc.js @@ -0,0 +1,90 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'your-project-id', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '1', + message = 'my message to verify', + signatureBuffer = Buffer.from('...') +) { + // [START kms_verify_asymmetric_signature_ec] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'your-project-id'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '1'; + // const message = 'my message to verify'; + // const signatureBuffer = Buffer.from('...'); + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function verifyAsymmetricSignatureEc() { + // Get public key + const [publicKey] = await client.getPublicKey({ + name: versionName, + }); + + // Create the verifier. The algorithm must match the algorithm of the key. + const crypto = require('crypto'); + const verify = crypto.createVerify('sha256'); + verify.update(message); + verify.end(); + + // Build the key object + const key = { + key: publicKey.pem, + }; + + // Verify the signature using the public key + const verified = verify.verify(key, signatureBuffer); + return verified; + } + + return verifyAsymmetricSignatureEc(); + // [END kms_verify_asymmetric_signature_ec] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/verifyAsymmetricRsa.js b/kms/verifyAsymmetricRsa.js new file mode 100644 index 0000000000..d380355c42 --- /dev/null +++ b/kms/verifyAsymmetricRsa.js @@ -0,0 +1,91 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'your-project-id', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '1', + message = 'my message to verify', + signatureBuffer = Buffer.from('...') +) { + // [START kms_verify_asymmetric_signature_rsa] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'your-project-id'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '1'; + // const message = 'my message to verify'; + // const signatureBuffer = Buffer.from('...'); + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the key name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function verifyAsymmetricSignatureRsa() { + // Get public key + const [publicKey] = await client.getPublicKey({ + name: versionName, + }); + + // Create the verifier. The algorithm must match the algorithm of the key. + const crypto = require('crypto'); + const verify = crypto.createVerify('sha256'); + verify.update(message); + verify.end(); + + // Build the key object + const key = { + key: publicKey.pem, + padding: crypto.constants.RSA_PKCS1_PSS_PADDING, + }; + + // Verify the signature using the public key + const verified = verify.verify(key, signatureBuffer); + return verified; + } + + return verifyAsymmetricSignatureRsa(); + // [END kms_verify_asymmetric_signature_rsa] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +} diff --git a/kms/verifyMac.js b/kms/verifyMac.js new file mode 100644 index 0000000000..fa880d493c --- /dev/null +++ b/kms/verifyMac.js @@ -0,0 +1,80 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +'use strict'; + +async function main( + projectId = 'your-project-id', + locationId = 'us-east1', + keyRingId = 'my-key-ring', + keyId = 'my-key', + versionId = '123', + data = Buffer.from('...'), + signature = Buffer.from('...') +) { + // [START kms_verify_mac] + // + // TODO(developer): Uncomment these variables before running the sample. + // + // const projectId = 'your-project-id'; + // const locationId = 'us-east1'; + // const keyRingId = 'my-key-ring'; + // const keyId = 'my-key'; + // const versionId = '123'; + // const data = Buffer.from('...'); + // const signature = Buffer.from('...'); + + // Imports the Cloud KMS library + const {KeyManagementServiceClient} = require('@google-cloud/kms'); + + // Instantiates a client + const client = new KeyManagementServiceClient(); + + // Build the version name + const versionName = client.cryptoKeyVersionPath( + projectId, + locationId, + keyRingId, + keyId, + versionId + ); + + async function verifyMac() { + // Verify the data with Cloud KMS + const [verifyResponse] = await client.macVerify({ + name: versionName, + data: data, + mac: signature, + }); + + console.log(`Verified: ${verifyResponse.success}`); + return verifyResponse; + } + + return verifyMac(); + // [END kms_verify_mac] +} +module.exports.main = main; + +/* c8 ignore next 10 */ +if (require.main === module) { + main(...process.argv.slice(2)).catch(err => { + console.error(err.message); + process.exitCode = 1; + }); + process.on('unhandledRejection', err => { + console.error(err.message); + process.exitCode = 1; + }); +}