func()

in fakekms/symmetric_rpcs.go [42:170]


func (f *fakeKMS) RawEncrypt(ctx context.Context, req *kmspb.RawEncryptRequest) (*kmspb.RawEncryptResponse, error) {
	if err := allowlist("name", "plaintext", "plaintext_crc32c", "additional_authenticated_data", "additional_authenticated_data_crc32c", "initialization_vector", "initialization_vector_crc32c").check(req); err != nil {
		return nil, err
	}

	name, err := parseCryptoKeyVersionName(req.Name)
	if err != nil {
		return nil, err
	}

	ckv, err := f.cryptoKeyVersion(name)
	if err != nil {
		return nil, err
	}

	if ckv.pb.State != kmspb.CryptoKeyVersion_ENABLED {
		return nil, errFailedPrecondition("key version %s is not enabled", name)
	}

	def, _ := algorithmDef(ckv.pb.Algorithm)
	if def.Purpose != kmspb.CryptoKey_RAW_ENCRYPT_DECRYPT {
		return nil, errFailedPrecondition("keys with algorithm %s may not be used for raw encryption",
			nameForValue(kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm_name, int32(ckv.pb.Algorithm)))
	}

	if req.Plaintext == nil {
		return nil, errInvalidArgument("plaintext is empty")
	}
	var plaintext []byte = req.Plaintext

	if len(plaintext) > maxPlaintextSize {
		return nil, errInvalidArgument("len(plaintext)=%d, want len(plaintext)<=%d", len(plaintext), maxPlaintextSize)
	}

	plaintextChecksum := crc32c(plaintext)
	if req.PlaintextCrc32C != nil && plaintextChecksum.Value != req.PlaintextCrc32C.Value {
		return nil, errInvalidArgument("invalid plaintext checksum")
	}

	var nonce []byte
	// Validate request fields.
	switch ckv.pb.Algorithm {
	case kmspb.CryptoKeyVersion_AES_128_GCM, kmspb.CryptoKeyVersion_AES_256_GCM:
		if req.InitializationVector != nil {
			return nil, errInvalidArgument("cannot specify iv when using AES-GCM")
		}
		nonce = make([]byte, 12)
		if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
			return nil, err
		}

		aadChecksum := crc32c(req.AdditionalAuthenticatedData)
		if req.AdditionalAuthenticatedData != nil &&
			req.AdditionalAuthenticatedDataCrc32C != nil &&
			aadChecksum.Value != req.AdditionalAuthenticatedDataCrc32C.Value {
			return nil, errInvalidArgument("invalid aad checksum")
		}
	case kmspb.CryptoKeyVersion_AES_128_CTR,
		kmspb.CryptoKeyVersion_AES_256_CTR,
		kmspb.CryptoKeyVersion_AES_128_CBC,
		kmspb.CryptoKeyVersion_AES_256_CBC:
		if req.AdditionalAuthenticatedData != nil {
			return nil, errInvalidArgument("cannot specify aad when using %s",
				nameForValue(kmspb.CryptoKeyVersion_CryptoKeyVersionAlgorithm_name, int32(ckv.pb.Algorithm)))
		}
		if req.InitializationVector != nil {
			if len(req.InitializationVector) > maxIvSize {
				return nil, errInvalidArgument("len(iv)=%d, want len(iv)<=%d", len(req.InitializationVector), maxIvSize)
			}
			nonce = req.InitializationVector
		} else {
			nonce = make([]byte, 16)
			if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
				return nil, err
			}
		}
	default:
		return nil, errInternal("unhandled algorithm")
	}

	var key []byte
	var ok bool
	if key, ok = ckv.keyMaterial.([]byte); !ok {
		return nil, err
	}

	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, errInternal("AES cipher creation failed: %v", err)
	}

	var ciphertext []byte
	var tagLen int32
	switch ckv.pb.Algorithm {
	case kmspb.CryptoKeyVersion_AES_128_GCM, kmspb.CryptoKeyVersion_AES_256_GCM:
		aesgcm, err := cipher.NewGCM(block)
		if err != nil {
			return nil, errInternal("GCM cipher creation failed: %v", err)
		}
		ciphertext = aesgcm.Seal(nil, nonce, plaintext, req.AdditionalAuthenticatedData)
		tagLen = defaultTagLength
	case kmspb.CryptoKeyVersion_AES_128_CTR, kmspb.CryptoKeyVersion_AES_256_CTR:
		ciphertext = make([]byte, len(plaintext))
		aesctr := cipher.NewCTR(block, nonce)
		aesctr.XORKeyStream(ciphertext, plaintext)
	case kmspb.CryptoKeyVersion_AES_128_CBC, kmspb.CryptoKeyVersion_AES_256_CBC:
		if len(plaintext)%block.BlockSize() != 0 {
			return nil, errInvalidArgument("len(plaintext)=%d, want len(plaintext) mod %d == 0", len(plaintext), block.BlockSize())
		}
		ciphertext = make([]byte, len(plaintext))
		aescbc := cipher.NewCBCEncrypter(block, nonce)
		aescbc.CryptBlocks(ciphertext, plaintext)
	default:
		return nil, errInternal("unhandled algorithm")
	}

	return &kmspb.RawEncryptResponse{
		Name:                       req.Name,
		Ciphertext:                 ciphertext,
		CiphertextCrc32C:           crc32c(ciphertext),
		InitializationVector:       nonce,
		InitializationVectorCrc32C: crc32c(nonce),
		TagLength:                  tagLen,
		VerifiedPlaintextCrc32C:    req.PlaintextCrc32C != nil,
		VerifiedAdditionalAuthenticatedDataCrc32C: req.AdditionalAuthenticatedDataCrc32C != nil,
		VerifiedInitializationVectorCrc32C:        req.InitializationVectorCrc32C != nil,
		ProtectionLevel:                           ckv.pb.ProtectionLevel,
	}, nil
}