使用 GREP11 API 执行加密操作

IBM Cloud® Hyper Protect Crypto Services 提供了通过 gRPC 执行的企业 PKCS #11 (EP11) API(也称为 GREP11 API),以远程访问 Hyper Protect Crypto Services 服务实例来进行数据加密和管理。

检索 IBM Cloud 凭证

要使用该 API,您需要生成您的服务和认证凭证。 要收集凭证,请执行以下操作:

  1. 生成 IBM Cloud IAM 访问令牌
  2. 检索用于唯一标识 Hyper Protect Crypto Services 服务实例的实例标识

生成 GREP11 API 请求

为了远程访问 Hyper Protect Crypto Services 上的云 HSM 以执行加密操作,需要生成 GREP11 API 请求,并通过 API 调用传递 GREP11 API 端点 URL,服务标识 API 密钥和 IAM 端点。

对于 Hyper Protect Crypto Services 标准套餐,您还可以为 GREP11 API 启用相互 TLS 以添加另一个认证层。 有关更多信息,请参阅 为 EP11 连接启用第二层认证

示例:使用 GenerateRandomRequest() 函数生成随机数据

GREP11 API 支持使用 gRPC 库的编程语言。 为您提供了两个样本 GitHub 存储库,用于测试 GREP11 API:

可以使用以下 Golang 代码示例通过调用 GenerateRandom 函数来生成随机数据。

此示例假定通过 import 语句 (例如 gRPChttp 包) 包含额外的必需 Golang 包。 import pb "github.com/IBM-Cloud/hpcs-grep11-go/grpc" 语句由 GREP11 用于执行 API 函数调用。

import pb "github.com/IBM-Cloud/hpcs-grep11-go/grpc"

// Data structure and supporting methods used for GREP11 authentication
// IAMPerRPCCredentials type defines the fields required for IBM Cloud IAM authentication
// This type implements the gRPC PerRPCCredentials interface

type IAMPerRPCCredentials struct {
	expiration  time.Time
	updateLock  sync.Mutex
	AccessToken string // Required if APIKey nor Endpoint are specified - IBM Cloud IAM access token
	APIKey      string // Required if AccessToken is not specified - IBM Cloud API key
	Endpoint    string // Required if AccessToken is not specified - IBM Cloud IAM endpoint
}

// GetRequestMetadata is used by GRPC for authentication
func (cr *IAMPerRPCCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
	// Set token if empty or Set token if expired
	if len(cr.APIKey) != 0 && len(cr.Endpoint) != 0 && time.Now().After(cr.expiration) {
		if err := cr.getToken(ctx); err != nil {
			return nil, err
		}
	}

	return map[string]string{
		"authorization":    cr.AccessToken,
	}, nil
}

// RequireTransportSecurity is used by gRPC for authentication
func (cr *IAMPerRPCCredentials) RequireTransportSecurity() bool {
	return true
}

// getToken obtains a bearer token and the expiration
func (cr *IAMPerRPCCredentials) getToken(ctx context.Context) (err error) {
	cr.updateLock.Lock()
	defer cr.updateLock.Unlock()

	// Check if another thread has updated the token
	if time.Now().Before(cr.expiration) {
		return nil
	}

	var req *http.Request
	client := http.Client{}
	requestBody := []byte("grant_type=urn:ibm:params:oauth:grant-type:apikey&apikey=" + cr.APIKey)

	req, err = http.NewRequest("POST", cr.Endpoint+"/identity/token", bytes.NewBuffer(requestBody))
	if err != nil {
		return err
	}

	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
	req = req.WithContext(ctx)
	resp, err := client.Do(req)
	if err != nil {
		return err
	}

	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return fmt.Errorf("failed to read response body: %s", err)
	}
	defer resp.Body.Close()

	iamToken := struct {
		AccessToken string `json:"access_token"`
		ExpiresIn   int32  `json:"expires_in"`
	}{}

	err = json.Unmarshal(respBody, &iamToken)
	if err != nil {
		return fmt.Errorf("error unmarshaling response body: %s", err)
	}

	cr.AccessToken = fmt.Sprintf("Bearer %s", iamToken.AccessToken)
	cr.expiration = time.Now().Add((time.Duration(iamToken.ExpiresIn - 60)) * time.Second)

	return nil
}

// Generating a GREP11 API function call

// The following IBM Cloud items need to be changed prior to running the sample program
const address = "<grep11_server_address>"

var callOpts = []grpc.DialOption{
  grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})),
  grpc.WithPerRPCCredentials(&util.IAMPerRPCCredentials{
    APIKey:   "<ibm_cloud_apikey>",
    Endpoint: "https://iam.cloud.ibm.com",
  }),
}

conn, err := grpc.Dial(address, callOpts...)
if err != nil {
		panic(fmt.Errorf("Could not connect to server: %s", err))
}
defer conn.Close()

cryptoClient := pb.NewCryptoClient(conn)

rngTemplate := &pb.GenerateRandomRequest{
		Len: (uint64)(ep11.AES_BLOCK_SIZE),
}

// Generate 16 bytes of random data for the initialization vector
rng, err := cryptoClient.GenerateRandom(context.Background(), rngTemplate)
if err != nil {
		panic(fmt.Errorf("GenerateRandom Error: %s", err))
}
iv := rng.Rnd[:ep11.AES_BLOCK_SIZE]
fmt.Println("Generated IV")

在此示例中,更新以下变量:

  • <grep11_server_address> 替换为 GREP11 API 端点的值。 要查找服务端点 URL,请从供应的服务实例 UI 中单击 概述 > 连接 > Enterprise PKCS #11 端点 URL。 或者,您可以动态 检索 API 端点 URL。 返回的值包含以下内容。 根据是使用公用网络还是 专用网络,请使用 ep11 部分中返回的公用或专用服务端点值。

    {
      "instance_id": "<instance_ID>",
      "kms": {
        "public": "<instance_ID>.api.<region>.hs-crypto.appdomain.cloud",
        "private":"<instance_ID>.api.private.<region>.hs-crypto.appdomain.cloud"
      },
      "ep11": {
        "public": "<instance_ID>.ep11.<region>.hs-crypto.appdomain.cloud",
        "private":"<instance_ID>.ep11.private.<region>.hs-crypto.appdomain.cloud"
      }
    }
    

    如果在某些区域中的 2024 年 4 月 12 日之后创建实例,那么可能需要使用新格式为 <instance_ID>.ep11.<REGION>.hs-crypto.appdomain.cloud 的新 API 端点。 可用性日期因区域而异。 有关受支持区域,可用性日期和新端点 URL 的更多信息,请参阅 新端点

  • <ibm_cloud_apikey> 替换为您创建的服务标识 API 密钥。 可通过遵循 管理服务标识 API 密钥中的指示信息来创建服务标识 API 密钥。

如果成功处理样本请求,那么将返回长度为 16 个字节的随机数据,如 ep11.AES_BLOCKSIZE 中所指定。

可以在以下位置找到先前的认证示例以及更多 Golang 代码示例:

下一步

您已准备好开始管理加密密钥和数据。 要了解有关使用 Hyper Protect Crypto Services 的云 HSM 功能来管理数据的更多信息,请查看 GREP11 API 参考文档