Key Management Service 키를 활용한 암호화 예제

Key Management Service 키를 활용한 암호화 예제

KMS에서 생성한 키를 사용하여 봉투 암호화(Envelope Encryption) 및 데이터 서명/검증을 구현하기 위한 Java 코드 예제입니다.

참고
아래의 코드는 Samsung Cloud Platform KMS에 대한 이해를 돕기 위한 단순 참고용 예시입니다. KMS 기능 수행에 필요한 함수만 기술했기 때문에 그대로 실행하면 Error가 발생합니다. 반드시 사용자의 실제 시나리오에 맞게 수정하여 활용하세요.

봉투 암호화

봉투 암호화 시나리오를 제시하고 시나리오에 따라 작성된 Java, Go, Python 예제 코드와 결과값을 확인할 수 있습니다.

시나리오

  1. 비밀번호 정보를 봉투 암호화 방식으로 암호화하기 위해 Data Key를 발급 받습니다.
  2. 발급 받은 Data Key 정보를 사용해 비밀번호를 암호화합니다.
  3. 암호화된 비밀번호, 암호화된 Data Key 정보를 봉투 암호화하여 JSON 파일로 저장합니다.

Java 예제 코드

제시된 시나리오에 따라 작성된 Java 예제 코드입니다.

// URI
static String KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }};
// END POINT
static String KMS_API_DECRYPT = "/v1/kms/openapi/decrypt/%s";
static String KMS_API_CREATE_DATAKEY = "/v1/kms/openapi/datakey/%s";
// KEY ID
static String KEY_ID = {{마스터 키 ID}};
 
createEnvelop() {
    // 새로운 데이터 키 생성을 요청
    String encryptedDataKey = getDataKey();
    // 암호화를 할 데이터
    String example_json_data = "{\"PASSWORD\":\"SECRET_CREDENTIAL\"}";
    // 암호화된 데이터 봉투(Envelop encryption)
    String envelope = encryptData(example_json_data, encryptedDataKey);
    // 이 예제 코드에서는 암호화된 데이터 봉투를 파일로 저장
    File envelopeFile = new File("envelope.json");
}
 
getDataKey() {
    String endPoint = String.format(KMS_API_CREATE_DATAKEY, KEY_ID);
    String url = KMS_API_BASE_URI + endPoint;
    JSONObject data = new JSONObject();
    data.put("key_type", "plaintext");
    JSONObject respJsonObject = callApi(endPoint, data.toJSONString());
    return respJsonObject.get("ciphertext").toString();
}
 
encryptData() {
    Map<String, String> envelope = new HashMap<>();
    // 데이터 키 복호화
    String dataKey = decryptDataKey(encryptedDataKey);
    // 생성된 데이터 키를 AES-CBC 방식으로 암호화
    // Cipher Class 사용 (사용자가 기 사용 중인 암호화 알고리즘 사용 가능)
    SecretKey secretKey = new SecretKeySpec(decodeBase64(dataKey), "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey);
    byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
    byte[] cipherText = cipher.doFinal(obj.toString().getBytes());
 
    envelope.put("encryptedKey", encryptedDataKey);
    envelope.put("cipherText", encodeBase64(cipherText));
    envelope.put("iv", encodeBase64(iv));
 
    return JSONValue.toJSONString(envelope);
}
 
decryptDataKey() {
    String endPoint = String.format(KMS_API_DECRYPT, KEY_ID);
    JSONObject data = new JSONObject();
    data.put("cipherText", sealedKey);
    JSONObject respJsonObject = callApi(endPoint, data.toJSONString());
    String plaintext = (respJsonObject.get("plaintext")).toString();
    return plaintext;
}

Go 예제 코드

제시된 시나리오에 따라 작성된 Go 예제 코드입니다.

// URI
const KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }}
  
// END POINT
const KMS_API_DECRYPT = "/v1/kms/openapi/decrypt/%s"
const KMS_API_CREATE_DATAKEY = "/v1/kms/openapi/datakey/%s"
  
// KEY ID
const KEY_ID = {{마스터 키 ID}}
  
createEnvelop() {
        // 새로운 데이터 키 생성을 요청
        encryptedDataKey := getDataKey()
        // 암호화를 할 데이터
        example_json_data := "{\"PASSWORD\":\"SECRET_CREDENTIAL\"}"
        // 암호화된 데이터 봉투(Envelop encryption)
        envelope := encryptData(example_json_data, encryptedDataKey)
        // 이 예제 코드에서는 암호화된 데이터 봉투를 파일로 저장
        file, _ := os.Create("envelope.json")
        defer file.Close()
        file.WriteString(envelope)
}
  
getDataKey() {
        endPoint := fmt.Sprintf(KMS_API_CREATE_DATAKEY, KEY_ID)
        data := map[string]interface{}{
            "key_type": "plaintext",
        }
        jsonData, _ := json.Marshal(data)
        respJsonObject := callApi(endPoint, jsonData)
        info := &KMSDatakeyInfo{}
        json.Unmarshal([]byte(respJsonObject), info)
  
        return info.DataKey
}
  
encryptData() {
        envelope := make(map[string]string)
        // 데이터 키 복호화
        dataKey := decryptDataKey(encryptedDataKey)
        secretKey, _ := base64.StdEncoding.DecodeString(dataKey)
        // 생성된 데이터 키를 AES-CBC 방식으로 암호화
        // Cipher Class 사용
        block, _ := aes.NewCipher(secretKey)
        cipherText := make([]byte, aes.BlockSize+len(example_json_data))
        iv := cipherText[:aes.BlockSize]
        if _, err := io.ReadFull(rand.Reader, iv); err != nil {
               panic(err)
        }
  
        mode := cipher.NewCFBEncrypter(block, iv)
        mode.XORKeyStream(cipherText[aes.BlockSize:], []byte(example_json_data))
  
        envelope["encryptedKey"] = encryptedDataKey
        envelope["cipherText"] = base64.StdEncoding.EncodeToString(cipherText)
        envelope["iv"] = base64.StdEncoding.EncodeToString(iv)
  
        jsonString, _ := json.Marshal(envelope)
  
        return string(jsonString)
}
  
decryptDataKey() {
        endPoint := fmt.Sprintf(KMS_API_DECRYPT, KEY_ID)
        data := map[string]interface{}{
               "cipherText": sealedKey,
        }
        jsonData, _ := json.Marshal(data)
        respJsonObject := callApi(endPoint, jsonData)
        info := &KMSDecryptInfo{}
        json.Unmarshal([]byte(respJsonObject), info)
  
        return info.DecryptedData
  
}

Python 예제 코드

제시된 시나리오에 따라 작성된 Python 예제 코드입니다.

# URI
KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }}
  
# END POINT
KMS_API_DECRYPT = "/v1/kms/openapi/decrypt/"
KMS_API_CREATE_DATAKEY = "/v1/kms/openapi/datakey/"
  
# KEY ID
KEY_ID = {{마스터 키 ID}}
    
create_envelop()
    # 새로운 데이터 키 생성을 요청
    encrypted_data_key = get_dataKey()
  
    # 암호화를 할 데이터
    example_json_data = {"PASSWORDTEST":"SECRET_CREDENTIALTEST"}
    json_data_str = json.dumps(example_json_data)
     
    # 암호화된 데이터 봉투(Envelop encryption)
    envelope = encrypt_data(json_data_str,encrypted_data_key)
  
    # 이 예제 코드에서는 암호화된 데이터 봉투를 파일로 저장
    with open("envelope.json", "w") as file:
        file.write(envelope)
  
    
get_dataKey()
    end_point = f"{KMS_API_CREATE_DATAKEY}{KEY_ID}"
    data = {
        "key_type": "plaintext"
    }
    response_object = call_api(end_point, data)
  
    data_key = response_object.get("ciphertext", "")
  
    return data_key
  
  
encrypt_data()
    envelope = {}
    # 데이터 키 복호화
    dataKey = decrypt_data_key(encrypted_data_key)
    decoded_data_key = base64.b64decode(dataKey)
  
    # 생성된 데이터 키를 AES-CBC 방식으로 암호화
    # Cipher Class 사용
    iv = get_random_bytes(16)
    cipher = AES.new(decoded_data_key, AES.MODE_CBC, iv)
    data_to_encrypt = obj
    data_bytes = data_to_encrypt.encode()
    padded_data = pad(data_bytes, AES.block_size)
    cipher_text = cipher.encrypt(padded_data).hex()
  
    envelope["encryptedKey"] = encrypted_data_key
    envelope["cipherText"] = cipher_text
    envelope["iv"] = base64.b64encode(iv).decode()
    
    return json.dumps(envelope)
  
decrypt_data_key()
    end_point = f"{KMS_API_DECRYPT}{KEY_ID}"
    data = {}
    data["cipherText"] = sealed_key
    resp_json_object = call_api(end_point,data)
    plaintext = resp_json_object.get("decryptedData")
    return plaintext

예제 코드 결과값

예제 코드의 결과값을 표시합니다.

  {
        "cipherText":"d3S81rzaGAl8U12LlKSlRbDekPlGuibTntXX962KCjBIKuXdPOG8N8vk3Jet8lyG",
        "iv":"0kP7QKZ6BUeQPlThk4tySA==",
        "encryptedKey":"vault:v1:KJjjLtGHTbaV5N8LWC5O9eMDCaJVeff5SM\/MAYseugjiqiXFVgdXaKXg6kym0NmjHkO\/wLPsa+YK0aVk"
    }

봉투 암호화 사용

봉투 암호화 사용 시나리오를 제시하고 시나리오에 따라 작성된 Java, Go, Python 예제 코드와 결과값을 확인할 수 있습니다.

시나리오

  1. 암호화된 봉투 파일의 Data Key를 복호화합니다.
  2. 복호화된 Data Key로 봉투 파일의 암호화 데이터를 복호화합니다.

Java 예제 코드

제시된 시나리오에 따라 작성된 Java 예제 코드입니다.

// URI
static String KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }};
// END POINT
static String KMS_API_DECRYPT = "/v1/kms/openapi/decrypt/%s";
// KEY ID
static String KEY_ID = {{마스터 키 ID}};;
 
 
getData() {
    // 암호화된 데이터 봉투(Envelop encryption)
    String envelope = new String(Files.readAllBytes(Paths.get("envelope.json")));
    JSONParser parser = new JSONParser();
    JSONObject envelopeJson = (JSONObject) parser.parse(envelope);
    String encryptedDataKey = envelopeJson.get("encryptedKey").toString();
    String cipherText = envelopeJson.get("cipherText").toString();
    String iv = envelopeJson.get("iv").toString();
 
    return decryptData(cipherText, encryptedDataKey, iv);
}
     
decryptData() {
    String dataKey = decryptDataKey(encryptedDataKey);
    IvParameterSpec ivParameterSpec = new IvParameterSpec(decodeBase64(iv));
    SecretKey secretKey = new SecretKeySpec(decodeBase64(dataKey), "AES");
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
    byte[] plaintext = cipher.doFinal(decodeBase64(cipherText));
 
    return new String(plaintext);
}
 
decryptDataKey() {
    String endPoint = String.format(KMS_API_DECRYPT, KEY_ID);
    JSONObject data = new JSONObject();
    data.put("cipherText", sealedKey);
    JSONObject respJsonObject = callApi(endPoint, data.toJSONString());
    String plaintext = (respJsonObject.get("plaintext")).toString();
    return plaintext;
}

Go 예제 코드

제시된 시나리오에 따라 작성된 Go 예제 코드입니다.

// URI
const KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }}
 
// END POINT
const KMS_API_DECRYPT = "/v1/kms/openapi/decrypt/%s"
 
// KEY ID
const KEY_ID = {{마스터 키 ID}}
 
getData() {
    // 암호화된 데이터 봉투(Envelop encryption) 불러오기
    jsonData, _ := os.ReadFile("envelope.json")
    var envelope map[string]interface{}
    if err := json.Unmarshal(jsonData, &envelope); err != nil {
           fmt.Println("JSON 파싱 오류:", err)
           os.Exit(1)
    }
    encryptedDataKey := envelope["encryptedKey"].(string)
    cipherText := envelope["cipherText"].(string)
    iv := envelope["iv"].(string)
   
    return decryptData(cipherText, encryptedDataKey, iv)
}
  
decryptData() {
    dataKey := decryptDataKey(encryptedDataKey)
    ciphertext, _ := base64.StdEncoding.DecodeString(cipherText)
    dataKeyBytes, _ := base64.StdEncoding.DecodeString(dataKey)
    decodedData := ciphertext[aes.BlockSize:]
    ivparam := ciphertext[:aes.BlockSize]
    block, _ := aes.NewCipher(dataKeyBytes)
   
    mode := cipher.NewCFBDecrypter(block, ivparam)
    mode.XORKeyStream(decodedData, decodedData)
    decryptedData := string(decodedData)
   
    return decryptedData
}
  
decryptDataKey() {
    endPoint := fmt.Sprintf(KMS_API_DECRYPT, KEY_ID)
    data := map[string]interface{}{
           "cipherText": sealedKey,
    }
    jsonData, _ := json.Marshal(data)
    respJsonObject := callApi(endPoint, jsonData)
    info := &KMSDecryptInfo{}
    json.Unmarshal([]byte(respJsonObject), info)
  
    return info.DecryptedData
}

Python 예제 코드

제시된 시나리오에 따라 작성된 Python 예제 코드입니다.

# URI
KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }}
  
# END POINT
KMS_API_DECRYPT = "/v1/kms/openapi/decrypt/"
  
# KEY ID
KEY_ID = {{마스터 키 ID}}
    
get_data()
    # 암호화된 데이터 봉투(Envelop encryption) 열기
    with open("envelope.json", "r") as file:
        envelope = file.read()
    envelope_json = json.loads(envelope)
    encrypted_data_key = envelope_json["encryptedKey"]
    cipher_text = envelope_json["cipherText"]
    iv = envelope_json["iv"]
    return decrypt_data(cipher_text, encrypted_data_key, iv)
  
decrypt_data()
    data_key = decrypt_data_key(encrypted_data_key)
    iv_bytes = base64.b64decode(iv)
    decoded_data_key = base64.b64decode(data_key)
    cipher_txt = bytes.fromhex(cipher_text)
  
    cipher = AES.new(decoded_data_key, AES.MODE_CBC, iv_bytes)
    plain_text_bytes = unpad(cipher.decrypt(cipher_txt), AES.block_size)
    plain_text = plain_text_bytes.decode('utf-8')
    return plain_text
    
decrypt_data_key()
    end_point = f"{KMS_API_DECRYPT}{KEY_ID}"
    data = {}
    data["cipherText"] = sealed_key
    resp_json_object = call_api(end_point,data)
    plaintext = resp_json_object.get("decryptedData")
    return plaintext

예제 코드 결과값

예제 코드의 결과값을 표시합니다.

  {"PASSWORD":"SECRET_CREDENTIAL"}

데이터 서명 사용

데이터의 무결성을 보증하기 위한 데이터 서명 사용 시나리오를 제시하고 시나리오에 따라 작성된 Java, Go, Python 예제 코드와 결과값을 확인할 수 있습니다.

시나리오

  1. 서명할 데이터를 OpenAPI로 호출하여 서명합니다.
  2. 서명된 데이터는 봉투화하여 json 파일로 저장합니다.

Java 예제 코드

제시된 시나리오에 따라 작성된 Java 예제 코드입니다.

// URI
static String KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }};
 
// END POINT
static String KMS_API_SIGN = "/v1/kms/openapi/sign/%s";
 
// KEY ID
static String KEY_ID = {{마스터 키 ID}};
 
signEnvelop() {
    // 서명 데이터 봉투(Envelop encryption)
    String envelope = sign();
    // 이 예제 코드에서는 서명 데이터 봉투를 파일로 저장
    File envelopeFile = new File("signEnvelope.json");
    OutputStream os = new BufferedOutputStream(new FileOutputStream(envelopeFile));
 
    try {
        os.write(envelope.getBytes());
    } finally {
        os.close();
    }
}
 
sign() {
    Map<String, String> envelope = new HashMap<>();
 
    String example_credential = "SCP KMS Sign Test!!!";
    String endPoint = String.format(KMS_API_SIGN, KEY_ID);
    JSONObject data = new JSONObject();
    data.put("input", encodeToBase64(example_credential));
 
    JSONObject respJsonObject = callApi(endPoint, data.toJSONString());
 
    envelope.put("signature", respJsonObject.get("signature").toString());
    if(respJsonObject.get("batch_results") != null) {
 
        envelope.put("batch_results", respJsonObject.get("batch_results").toString());
    }
 
    return JSONValue.toJSONString(envelope);
}

Go 예제 코드

제시된 시나리오에 따라 작성된 Go 예제 코드입니다.

// URI
const KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }}
  
// END POINT
const KMS_API_SIGN = "/v1/kms/openapi/sign/%s"
  
// KEY ID
const KEY_ID = {{마스터 키 ID}}
  
signEnvelop() {
    // 서명 데이터 봉투(Envelop encryption)
    envelope := sign()
    // 이 예제 코드에서는 서명 데이터 봉투를 파일로 저장
    file, _ := os.Create("signEnvelope.json")
    defer file.Close()
    file.WriteString(envelope)
}
  
sign() {
    envelope := make(map[string]string)
    example_credential := "SCP KMS Sign Test!!!"
    endPoint := fmt.Sprintf(KMS_API_SIGN, KEY_ID)
    data := map[string]interface{}{
        "input": base64.StdEncoding.EncodeToString([]byte(example_credential)),
    }
    jsonData, _ := json.Marshal(data)
    respJsonObject := callApi(endPoint, jsonData)
    info := &KMSSignInfo{}
    json.Unmarshal([]byte(respJsonObject), info)
   
    envelope["signature"] = info.Signature
   
    jsonString, _ := json.Marshal(envelope)
   
    return string(jsonString)
}

Python 예제 코드

제시된 시나리오에 따라 작성된 Python 예제 코드입니다.

# URI
KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }}
  
# END POINT
KMS_API_SIGN = "/v1/kms/openapi/sign/"
  
# KEY ID
KEY_ID = {{마스터 키 ID}}
    
sign_envelop()
    # 서명 데이터 봉투(Envelop encryption)
    envelope = sign()
  
    # 이 예제 코드에서는 서명 데이터 봉투를 파일로 저장
    with open("signEnvelope.json", "w") as file:
        file.write(envelope)
  
    
sign()
    envelope = {}
  
    example_credential = "SCP KMS Sign Test!!!"
    end_point = f"{KMS_API_SIGN}{KEY_ID}"
    credential_bytes = example_credential.encode('utf-8')
  
    data = {
        "input": base64.b64encode(credential_bytes).decode('utf-8')
    }
  
    resp_json_object = call_api(end_point,data)
  
    envelope["signature"] = resp_json_object.get("signature")
 
    return json.dumps(envelope)

예제 코드 결과값

예제 코드의 결과값을 표시합니다.

  {
    "signature":"vault:v1:qHGf4ALkTao1Yy\/lpSbLQ2l8YVpsHWBP6ic3Ux1BKSodQQxnEIrjPyUwXXQ1NZfGSVxdeVe5Y6kb0nUPNADQpzkOh9\/e8T\/QCOs9==",
    "projectId":"PROJECT-qWrHRJX5sZnTkopcr9N1dk"
}

데이터 검증 사용

데이터의 무결성을 검증하기 위한 검증 사용 시나리오를 제시하고 시나리오에 따라 작성된 Java, Go, Python 예제 코드와 결과값을 확인할 수 있습니다.

시나리오

  1. 서명된 봉투 파일의 서명값을 가져옵니다.
  2. 서명된 데이터를 검증하여 결과값을 출력합니다.

Java 예제 코드

제시된 시나리오에 따라 작성된 Java 예제 코드입니다.

// URI
static String KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }};
 
// END POINT
static String KMS_API_VERIFY = "/v1/kms/openapi/verify/%s";
 
// KEY ID
static String KEY_ID = {{마스터 키 ID}};
 
getSign() {
    // 서명 데이터 봉투(Envelop encryption)
    String envelope = new String(Files.readAllBytes(Paths.get("signEnvelope.json")));
    JSONParser parser = new JSONParser();
    JSONObject envelopeJson = (JSONObject) parser.parse(envelope);
    String signature = envelopeJson.get("signature").toString();
 
    return verify(signature);
}
 
verify() {
    String endPoint = String.format(KMS_API_VERIFY, KEY_ID);
    JSONObject data = new JSONObject();
    data.put("input", "U0NQIEtNUyBTaWduIFRlc3QhISE=");
    data.put("signature", signature);
    JSONObject respJsonObject = callApi(endPoint, data.toJSONString());
    String valid = (respJsonObject.get("valid")).toString();
    return valid;
}

Go 예제 코드

제시된 시나리오에 따라 작성된 Go 예제 코드입니다.

// URI
const KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }}
  
// END POINT
const KMS_API_VERIFY = "/v1/kms/openapi/verify/%s"
  
// KEY ID
const KEY_ID = {{마스터 키 ID}}
  
getSign() {
    // 서명 데이터 봉투(Envelop encryption) 불러오기
    jsonData, _ := os.ReadFile("signEnvelope.json")
    var envelope map[string]interface{}
    if err := json.Unmarshal(jsonData, &envelope); err != nil {
           fmt.Println("JSON 파싱 오류:", err)
           os.Exit(1)
    }
    signature := envelope["signature"].(string)
  
    return verify(signature)
}
  
verify() {
    endPoint := fmt.Sprintf(KMS_API_VERIFY, KEY_ID)
    data := map[string]interface{}{
           "input":          "U0NQIEtNUyBTaWduIFRlc3QhISE=",
           "signature":      signature,
    }
    jsonData, _ := json.Marshal(data)
    respJsonObject := callApi(endPoint, jsonData)
    info := &KMSVerifyInfo{}
    json.Unmarshal([]byte(respJsonObject), info)
   
    return info.Valid
}

Python 예제 코드

제시된 시나리오에 따라 작성된 Python 예제 코드입니다.

# URI
KMS_API_BASE_URI = {{ OpenAPI 가이드의 URL 참조 }}
  
# END POINT
KMS_API_VERIFY = "/v1/kms/openapi/verify/"
  
# KEY ID
KEY_ID = {{마스터 키 ID}}
    
get_sign()
    # 서명 데이터 봉투(Envelop encryption) 열기
    with open("signEnvelope.json", "r") as file:
        envelope = file.read()
    envelope_json = json.loads(envelope)
    signature = envelope_json["signature"]
 
    return verify(signature)
  
    
verify()
    end_point = f"{KMS_API_VERIFY}{KEY_ID}"
 
    data = {
        "input": "U0NQIEtNUyBTaWduIFRlc3QhISE=",
        "signature": signature
    }
 
    resp_json_object = call_api(end_point,data)
    valid = resp_json_object.get("valid")
 
    return valid

예제 코드 결과값

예제 코드의 결과값을 표시합니다.

  {
    "valid": true
}
How-to guides
Release Note