首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用KMS解密S3中的SES消息

用KMS解密S3中的SES消息
EN

Stack Overflow用户
提问于 2022-08-14 05:35:07
回答 1查看 31关注 0票数 0

我正试图解密存储在S3中的KMS加密AWS消息。

所有操作都很好(从s3获取对象和元数据,用KMS解密密钥),直到我尝试用解密密钥解密内容为止:

代码语言:javascript
复制
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { KMSClient, DecryptCommand } from '@aws-sdk/client-kms';
import { createDecipheriv } from 'crypto';

const s3 = new S3Client( {
    // ...credentials
} );

const kms = new KMSClient( {
    // ...credentials
} );

const getFromS3AndDecrypt = ( Bucket, Key ) => {

    // GetObject command
    const command = new GetObjectCommand( {
        Bucket,
        Key,
    } );
    
    // Get the object from S3
    const { Metadata, Body } = await s3.send( command );

    // Convert to Buffer
    const body = await streamToBuffer( Body );

    // Get KMS Metadata
    var {
        [ 'x-amz-key-v2' ]: kmsKeyBase64,
        [ 'x-amz-iv' ]: iv,
        [ 'x-amz-tag-len' ]: tagLenBits = 0,
        [ 'x-amz-cek-alg' ]: algo,
        [ 'x-amz-matdesc' ]: matdesc,
    } = Metadata;

    // Convert tagLenBits to Bytes
    const tagLen = tagLenBits / 8;

    // Get encryption context
    const encryptionContext = JSON.parse( matdesc );

    // Get algorithm
    switch ( algo ) {

        case 'AES/GCM/NoPadding':
            algo = `aes-256-gcm`;
            break;

        case 'AES/CBC/PKCS5Padding':
            algo = `aes-256-cbc`;
            break;

        default:
            throw new Error( `Unsupported algorithm ${ algo }` );

    }

    // Convert kmsKey to Buffer
    const kmsKeyBuffer = Buffer.from( kmsKeyBase64, 'base64' );

    // DecryptCommand
    const kmsCommand = new DecryptCommand( {
        CiphertextBlob: kmsKeyBuffer,
        EncryptionContext: encryptionContext,
    } );

    // Decrypt the key with KMS
    const { Plaintext } = await kmsClient.send( kmsCommand );

    // Create decipher with key and iv
    const decipher = createDecipheriv( algo, Buffer.from( Plaintext ), Buffer.from( iv ), {
        authTagLength: 16,
    } );

    // Body without authTag
    const data = body.slice( 0, - tagLen );

    if  ( tagLen !== 0 ) {
        
        // authTag
        const tag = body.slice( - tagLen );

        // Set authTag
        decipher.setAuthTag( tag );

    }

    // Decrypt data
    var decrypted = decipher.update( data, 'binary', 'utf8' );
    
    decrypted += decipher.final( 'utf8' );

    return decrypted;

};

// Turn @aws-sdk/client-s3 stream response into buffer @see https://github.com/aws/aws-sdk-js-v3/issues/1877#issuecomment-755387549
const streamToBuffer = ( stream ) => new Promise( ( resolve, reject ) => {
        
    const chunks = [];
    
    stream.on( 'data', ( chunk ) => chunks.push( chunk ) );
    
    stream.on( 'error', reject );
    
    stream.on( 'end', () => resolve( Buffer.concat( chunks ) ) );
    
} );

当调用decipher.final时,我会得到一个Unsupported state or unable to authenticate data错误。

这似乎要么是因为所使用的authTag与加密数据时使用的不匹配,要么是因为输入和输出编码不匹配。

EN

回答 1

Stack Overflow用户

发布于 2022-08-14 10:12:20

iv和明文key都已被base64编码,因此需要将编码传递给Buffer

代码语言:javascript
复制
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { KMSClient, DecryptCommand } from '@aws-sdk/client-kms';
import { createDecipheriv } from 'crypto';

const s3 = new S3Client( {
    // ...credentials
} );

const kms = new KMSClient( {
    // ...credentials
} );

const getFromS3AndDecrypt = ( Bucket, Key ) => {

    const { Metadata, Body } = await s3.send( new GetObjectCommand( {
        Bucket,
        Key,
    } ) );

    const body = await streamToString( Body );

    const { Plaintext } = await kms.send( new DecryptCommand( {
        CiphertextBlob: Buffer.from( Metadata[ 'x-amz-key-v2' ], 'base64' ),
        EncryptionContext: JSON.parse( Metadata[ 'x-amz-matdesc' ] ),
    } ) );

    const key = Buffer.from( Plaintext, 'base64' );

    const iv = Buffer.from( Metadata[ 'x-amz-iv' ], 'base64' );

    const tag = body.slice( -16 );

    const data = body.slice( 0, -16 );

    const decipher = createDecipheriv( 'aes-256-gcm', key, iv );

    decipher.setAuthTag( tag );

    var decrypted = decipher.update( data, 'binary', 'utf8' );

    decrypted += decipher.final( 'utf8' );

    return decrypted;

};

// Turn @aws-sdk/client-s3 stream response into buffer @see https://github.com/aws/aws-sdk-js-v3/issues/1877#issuecomment-755387549
const streamToString = ( stream ) => new Promise( ( resolve, reject ) => {
        
    const chunks = [];
    
    stream.on( 'data', ( chunk ) => chunks.push( chunk ) );
    
    stream.on( 'error', reject );
    
    stream.on( 'end', () => resolve( Buffer.concat( chunks ) ) );
    
} );
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73349334

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档