더 안전한 데이터 사용

Android Jetpack의 일부인 보안 라이브러리는 저장 데이터 읽기 및 쓰기와 관련된 보안 권장사항의 구현과 키 생성 및 인증을 제공합니다.

라이브러리는 빌더 패턴을 사용하여 다음 보안 수준에 안전한 기본 설정을 제공합니다.

  • 뛰어난 암호화와 우수한 성능 사이에서 균형을 이루는 강력한 보안. 이 보안 수준은 은행 및 채팅 앱, 인증서 취소 확인을 실행하는 기업 앱과 같은 소비자 앱에 적합합니다.
  • 최대 보안. 이 보안 수준은 키 액세스를 제공하는 데 하드웨어 지원 키 저장소와 사용자 정보가 필요한 앱에 적합합니다.

이 가이드에서는 보안 라이브러리의 권장 보안 구성을 사용하는 방법과 파일 및 공유 환경설정에 저장된 암호화된 데이터를 쉽고 안전하게 읽고 쓰는 방법을 보여줍니다.

키 관리

보안 라이브러리는 키 관리를 위해 2파트 시스템을 사용합니다.

  • 하나 이상의 키를 포함하여 파일 또는 공유 환경설정 데이터를 암호화하는 키 세트. 키 세트 자체는 SharedPreferences에 저장됩니다.

  • 모든 키 세트를 암호화하는 마스터 키. 이 키는 Android 키 저장소 시스템을 사용하여 저장됩니다.

라이브러리에 포함된 클래스

보안 라이브러리에는 다음 클래스가 포함되어 더 안전한 저장 데이터를 제공합니다.

EncryptedFile

FileInputStreamFileOutputStream의 맞춤 구현을 제공하여 앱에서 더 안전하게 스트리밍 읽기 및 쓰기 작업을 할 수 있습니다.

파일 스트림에서 안전한 읽기 및 쓰기 작업을 제공하기 위해 보안 라이브러리는 연결된 데이터와 함께 스트리밍 인증 암호화(AEAD) 프리미티브를 사용합니다. GitHub의 Tink 라이브러리 문서에서 이 프리미티브를 자세히 알아보세요.

EncryptedSharedPreferences

SharedPreferences 클래스를 래핑하고 다음 두 가지 메서드를 사용하여 키와 값을 자동으로 암호화합니다.

  • 가 결정론적 암호화 알고리즘을 사용하여 암호화되므로 키를 암호화하고 올바르게 찾을 수 있습니다.
  • AES-256 GCM을 사용하여 암호화되고 비결정론적입니다.

다음 섹션에서는 이러한 클래스를 사용하여 파일 및 공유 환경설정으로 일반 작업을 실행하는 방법을 보여줍니다.

파일 읽기

다음 코드 스니펫은 EncryptedFile을 사용하여 파일의 콘텐츠를 더 안전하게 읽는 방법을 보여줍니다.

Kotlin

    // Although you can define your own key generation parameter specification, it's
    // recommended that you use the value specified here.
    val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
    val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

    val fileToRead = "my_sensitive_data.txt"
    lateinit var byteStream: ByteArrayOutputStream
    val encryptedFile = EncryptedFile.Builder(
        File(directory, fileToRead),
        context,
        masterKeyAlias,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()

    val contents = encryptedFile.bufferedReader().useLines { lines ->
        lines.fold("") { working, line ->
            "$working\n$line"
        }
    }
    

자바

    // Although you can define your own key generation parameter specification, it's
    // recommended that you use the value specified here.
    KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC;
    String masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

    String fileToRead = "my_sensitive_data.txt";
    ByteArrayOutputStream byteStream;

    EncryptedFile encryptedFile = new EncryptedFile.Builder(
            File(directory, fileToRead),
            context,
            masterKeyAlias,
            EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build();

    StringBuffer stringBuffer = new StringBuffer();
    try (BufferedReader reader =
                 new BufferedReader(new FileReader(encryptedFile))) {

        String line = reader.readLine();
        while (line != null) {
            stringBuffer.append(line).append('\n');
            line = reader.readLine();
        }
    } catch (IOException e) {
        // Error occurred opening raw file for reading.
    } finally {
        String contents = stringBuffer.toString();
    }
    

파일 쓰기

다음 코드 스니펫은 EncryptedFile을 사용하여 파일의 콘텐츠를 더 안전하게 쓰는 방법을 보여줍니다.

Kotlin

    // Although you can define your own key generation parameter specification, it's
    // recommended that you use the value specified here.
    val keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC
    val masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec)

    // Creates a file with this name, or replaces an existing file
    // that has the same name. Note that the file name cannot contain
    // path separators.
    val fileToWrite = "my_sensitive_data.txt"
    val encryptedFile = EncryptedFile.Builder(
        File(directory, fileToWrite),
        context,
        masterKeyAlias,
        EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
    ).build()

    encryptedFile.bufferedWriter().use { writer ->
        writer.write("MY SUPER-SECRET INFORMATION")
    }
    

자바

    // Although you can define your own key generation parameter specification, it's
    // recommended that you use the value specified here.
    KeyGenParameterSpec keyGenParameterSpec = MasterKeys.AES256_GCM_SPEC;
    String masterKeyAlias = MasterKeys.getOrCreate(keyGenParameterSpec);

    // Creates a file with this name, or replaces an existing file
    // that has the same name. Note that the file name cannot contain
    // path separators.
    String fileToWrite = "my_sensitive_data.txt";
    try {
        EncryptedFile encryptedFile = new EncryptedFile.Builder(
                new File(directory, fileToWrite),
                context,
                masterKeyAlias,
                EncryptedFile.FileEncryptionScheme.AES256_GCM_HKDF_4KB
        ).build();

        // Write to a file.
        BufferedWriter writer = new BufferedWriter(new FileWriter(encryptedFile));
        writer.write("MY SUPER-SECRET INFORMATION");
    } catch (GeneralSecurityException gse) {
        // Error occurred getting or creating keyset.
    } catch (IOException ex) {
        // Error occurred opening file for writing.
    }
    

추가 보안이 필요한 사용 사례의 경우 다음 단계를 완료하세요.

  1. KeyGenParameterSpec.Builder 개체를 만들어 setUserAuthenticationRequired()true를, setUserAuthenticationValidityDurationSeconds()에 0보다 큰 값을 전달합니다.
  2. createConfirmDeviceCredentialIntent()를 사용하여 사용자 인증 정보를 입력하라는 메시지를 사용자에게 표시합니다. 키 사용을 위한 사용자 인증을 요청하는 방법을 자세히 알아보세요.

  3. onActivityResult()를 재정의하여 확인된 사용자 인증 정보 콜백을 가져옵니다.

자세한 내용은 키 사용을 위한 사용자 인증 요청을 참조하세요.

공유 환경설정 수정

다음 코드 스니펫은 EncryptedSharedPreferences를 사용하여 사용자의 공유 환경설정을 더 안전하게 수정하는 방법을 보여줍니다.

Kotlin

    val sharedPreferences = EncryptedSharedPreferences
        .create(
        fileName,
        masterKeyAlias,
        context,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )

    val sharedPrefsEditor = sharedPreferences.edit()
    

자바

    EncryptedSharedPreferences sharedPreferences = EncryptedSharedPreferences
            .create(
                    fileName,
                    masterKeyAlias,
                    context,
                    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
                    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
            );

    SharedPreferences.Editor sharedPrefsEditor = sharedPreferences.edit();