Android Keystore — είναι ένας μηχανισμός συστήματος Android για ασφαλή αποθήκευση κρυπτογραφικών κλειδιών σε απομόνωση υλικού. Το σύστημα χρησιμοποιεί Trusted Execution Environment (TEE) σε συσκευές με ARM TrustZone ή αφιερωμένο Secure Element για προστασία κλειδιών σε επίπεδο τσιπ. Σύμφωνα με το Android Open Source Project, το Keystore υποστηρίζει τους αλγόριθμους RSA, EC, AES και HMAC με δημιουργία κλειδιών απευθείας στο ασφαλές περιβάλλον.
Κύρια
Android Keystore — είναι ένας κρυπτογραφικός πάροχος (provider) που υλοποιήθηκε στο Android από API 1 (Android 1.0), αλλά η πλήρης υποστήριξη υλικού εμφανίστηκε με Android 4.3 (API 18). Το Keystore λύνει το πρόβλημα της ασφαλούς αποθήκευσης ιδιωτικών κλειδιών έτσι ώστε ακόμα και σε περίπτωση διακυβεύους του λειτουργικού συστήματος, ο επιτιθέμενος δεν μπορεί να εξάγει τα κλειδιά σε ανοικτή μορφή.
Η αρχιτεκτονική του Android Keystore αποτελείται από τρία επίπεδα: εφαρμοστικό API (java.security.KeyStore), υπηρεσία συστήματος (keystore daemon) και επίπεδο υλικού (Keymaster HAL). Η εφαρμογή έχει πρόσβαση μέσω του τυπικού API Java Cryptography Architecture (JCA), και η υπηρεσία συστήματος διαβιβάζει τα αιτήματα στο Keymaster που λειτουργεί σε TEE.
Όλες οι κρυπτογραφικές λειτουργίες με κλειδιά (υπογραφή, αποκρυπτογράφηση) εκτελούνται εντός TEE ή Secure Element. Τα κλειδιά ποτέ δεν εγκαταλείπουν το ασφαλές περιβάλλον — η εφαρμογή λαμβάνει μόνο ένα ψευδώνυμο (alias) για αναφορά στο κλειδί. Αυτή είναι μια ουσιώδης διαφορά από τα λογισμικά KeyStore, όπου τα κλειδιά είναι δυνατικά προσβάσιμα στη μνήμη της διεργασίας.
Το τυπικό JKS (Java KeyStore) ή BKS (Bouncy Castle) αποθηκεύει τα κλειδιά σε αρχεία που προστατεύονται με κωδικό. Το Android Keystore αποθηκεύει τα κλειδιά σε απομόνωση υλικού, όπου προστατεύονται ακόμα και από τον χρήστη root. Το JKS είναι ευάλωτο σε άμεση πρόσβαση στο σύστημα αρχείων, το Android Keystore — όχι.
Άλλη διαφορά: στο Android Keystore τα κλειδιά έχουν αυστηρές παραμέτρους χρήσης (purpose — μόνο sign/verify/encrypt/decrypt) που καθορίζονται κατά τη δημιουργία. Δεν μπορούν να αλλαχτούν αργότερα, πράγμα που αποτρέπει την κακή χρήση του κλειδιού.
Κατά τη δημιουργία ενός νέου κλειδιού, η εφαρμογή καλεί τον KeyPairGenerator ή τον KeyGenerator με KeyGenParameterSpec, που περιέχει όλες τις παραμέτρους του μελλοντικού κλειδιού. Το σύστημα μεταβιβάζει το αίτημα στο Keymaster HAL, που δημιουργεί το κλειδί εντός TEE και επιστρέφει ένα ψευδώνυμο.
Η μέθοδος KeyGenParameterSpec.Builder δέχεται υποχρεωτικές παραμέτρους: όνομα κλειδιού στο Keystore, σκοπό (PURPOSE_SIGN, PURPOSE_ENCRYPT), αλγόριθμο (RSA, EC, AES). Προσθέτως: digest (SHA-256), padding (PKCS7), userAuthenticationRequired (βιομετρία), keyValidityStart/End (χρονικοί περιορισμοί).
Μετά τη ρύθμιση των παραμέτρων, η KeyPairGenerator.generateKeyPair() επιστρέφει KeyPair, όπου το PrivateKey είναι ένα αντικείμενο που αναθέτει λειτουργίες στο Keymaster. Το δημόσιο κλειδί μπορεί να εξαχθεί, το ιδιωτικό — όχι. Υπάρχει μόνο εντός TEE.
import java.security.KeyPairGenerator
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
fun generateKey(alias: String) {
val spec = KeyGenParameterSpec.Builder(alias,
KeyProperties.PURPOSE_SIGN or KeyProperties.PURPOSE_VERIFY
).setDigests(KeyProperties.DIGEST_SHA256)
.setSignaturePaddings(KeyProperties.SIGN_PADDING_RSA_PKCS1)
.setUserAuthenticationRequired(true)
.build()
val kpGen = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_RSA,
"AndroidKeyStore"
)
kpGen.initialize(spec)
kpGen.generateKeyPair()
}
Το Signature για ECDSA ή RSA-PSS δημιουργείται μέσω του τυπικού API: Signature.getInstance(algorithm).initSign(privateKey). Η λειτουργία υπογραφής εκτελείται σε TEE: η εφαρμογή στέλνει δεδομένα, το Keymaster τα υπογράφει μέσω υλικού και επιστρέφει την υπογραφή. Το κλειδί και τα δεδομένα δεν αναμειγνύονται στην κοινή μνήμη.
Για βιομετρική προστασία, απαιτείται η ταυτοποίηση του χρήστη μέσω BiometricPrompt πριν από την υπογραφή. Χωρίς επιτυχή ταυτοποίηση, το Keymaster δεν εκτελεί τη λειτουργία, επιστρέφοντας CryptoAuthenticationException.
import java.security.KeyStore
import java.security.Signature
import androidx.biometric.BiometricPrompt
fun signWithBiometric(alias: String) {
val ks = KeyStore.getInstance("AndroidKeyStore")
ks.load(null)
val entry = ks.getEntry(alias, null) as KeyStore.PrivateKeyEntry
val signature = Signature.getInstance("SHA256withRSA")
signature.initSign(entry.privateKey)
// BiometricPrompt με CryptoObject(signature) ζητάει FaceID/PIN
}
Το Android υποστηρίζει δύο τρόπους αποθήκευσης κλειδιών: λογισμικό (σε συσκευές χωρίς TEE) και υλικού (σε συσκευές με TEE ή Secure Element). Ο τρόπος εξαρτάται από τις δυνατότητες του SoC και την έκδοση Android.
Σε συσκευές χωρίς Trusted Execution Environment (πριν Android 4.3 ή οικονομικά SoC) τα κλειδιά αποθηκεύονται σε κρυπτογραφημένη μορφή χρησιμοποιώντας ένα κυρίαρχο κλειδί που προέρχεται από τον κωδικό οθόνης κλειδώματος. Αυτός ο τρόπος είναι λιγότερο ασφαλής — τα κλειδιά είναι προσβάσιμα στη μνήμη της διεργασίας κατά τη διάρκεια κρυπτογραφικών λειτουργιών.
Το επίπεδο προστασίας βασίζεται στην κρυπτογράφηση του αρχείου KeyStore με AES-256-GCM. Το κλειδί κρυπτογράφησης δημιουργείται βάσει του κωδικού ή PIN του χρήστη μέσω Scrypt (PBKDF2 με μεγάλο αριθμό επαναλήψεων).
Σε συγχρονες συσκευές χρησιμοποιείται Keymaster 4.x σε TEE (ARM TrustZone). Τα κλειδιά δημιουργούνται, αποθηκεύονται και χρησιμοποιούνται αποκλειστικά εντός TrustZone. Ακόμα και ο πυρήνας Linux δεν έχει πρόσβαση σε ιδιωτικά κλειδιά — μόνο το Keymaster HAL μπορεί να εκτελεί λειτουργίες.
Secure Element (π.χ. eSE στο Samsung Knox ή StrongBox στο Google Pixel 3+) — είναι ένα ξεχωριστό τσιπ με δικό του προσεργαστή και μνήμη. Είναι πιστοποιημένο κατά Common Criteria EAL 4+ και παρέχει μέγιστο επίπεδο προστασίας, συμπεριλαμβανομένης της προστασίας από φυσική αποσυναρμολόγηση.
| Τύπος | Θέση αποθήκευσης | Επίπεδο προστασίας | Διαθέσιμο από API |
|---|---|---|---|
| Software | Αρχείο /data/misc/keystore | Μέτριο (AES-256) | API 1+ |
| Keymaster 3 | TEE (TrustZone) | Υψηλό | API 23+ |
| Keymaster 4 | TEE + Secure I/O | Πολύ υψηλό | API 28+ |
| StrongBox | Υλικό Secure Element | Μέγιστο | API 28+, προαιρετικά |
Το Android Keystore είναι ενσωματωμένο στην Java Cryptography Architecture (JCA). Για πρόσβαση στον πάροχο, χρησιμοποιείται το τυπικό KeyStore.getInstance("AndroidKeyStore"). Το API είναι διαθέσιμο από API 18.
Η μέθοδος KeyStore.load(null) φορτώνει το κοντεινέσερ KeyStore της τρέχουσας εφαρμογής. Δεν απαιτείται κωδικός — το Android χρησιμοποιεί το πλαίσιο της εφαρμογής και το UID για διαχωρισμό πρόσβασης. Κάθε εφαρμογή βλέπει μόνο τις δικές της εγγραφές, εκτός εάν χρησιμοποιείται κοινό UID.
Οι μέθοδοι setEntry και getEntry λειτουργούν με KeyStore.PrivateKeyEntry, SecretKeyEntry ή TrustedCertificateEntry. Η παράμετρος ProtectionParameter είναι πάντα null για Android Keystore (η προστασία είναι υλοποιημένη σε επίπεδο συστήματος).
import java.security.KeyStore
import java.security.cert.Certificate
import android.security.keystore.KeyProtection
fun storeSecretKey(alias: String, key: SecretKey) {
val ks = KeyStore.getInstance("AndroidKeyStore")
ks.load(null)
val prot = KeyProtection.Builder(
KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT
).setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
.setUserAuthenticationRequired(true)
.build()
ks.setEntry(alias, KeyStore.SecretKeyEntry(key), prot)
}
Με το KeyCharacteristics μπορείτε να καθορίσετε σε ποιο περιβάλλον αποθηκεύεται το κλειδί: λογισμικό KeyStore, TEE ή StrongBox. Η μέθοδος getKeyCharacteristics() επιστρέφει ένα σύνολο σημαιών: FLAG_HARDWARE (keymaster), FLAG_SECURE_ELEMENT (StrongBox), FLAG_TRUSTED_USER_PRESENCE_REQUIRED (βιομετρία).
Το Android Keystore υποστηρίζει ευρύ σύνολο κρυπτογραφικών αλγορίθμων, χωρισμένο σε τρεις κατηγορίες: ασυμμετρικοί, συμμετρικοί και MAC. Η υποστήριξη για συγκεκριμένους αλγορίθμους εξαρτάται από την έκδοση Keymaster HAL.
RSA (1024–4096 bit) — για υπογραφή (PKCS1, PSS) και κρυπτογράφηση (OAEP, PKCS1). EC (P-224, P-256, P-384, P-521) — για υπογραφή ECDSA και συμφωνία ECDH. AES (128, 256 bit) — για συμμετρική κρυπτογράφηση σε λειτουργίες CBC, CTR, GCM. HMAC (SHA1, SHA256, SHA512) — για ταυτοποίηση μηνυμάτων.
Για κάθε κλειδί καθορίζεται setPurposes, που περιορίζει τις δυνατές λειτουργίες. Ένα κλειδί RSA με PURPOSE_SIGN δεν μπορεί να χρησιμοποιηθεί για κρυπτογράφηση, ακόμα και αν ο επιτιθέμενος έχει πρόσβαση στο API. Αυτή είναι η επιβολή χρήσης κλειδιού σε επίπεδο υλικού.
Το Keymaster περιλαμβάνει απαριθμητή αποτυχημένων προσπαθειών βιομετρικής ταυτοποίησης. Μετά από έναν καθορισμένο αριθμό αποτυχημένων προσπαθειών (ρυθμίζεται μέσω setInvalidatedByBiometricEnrollment) το κλειδί καθίσταται μη προσβάσιμο και απαιτεί διαγραφή/αναγέννηση. Κατά τη διαγραφή όλων των βιομετρικών προτύπων, όλα τα κλειδιά με userAuthenticationRequired=true ακυρώνονται αυτόματα.
Επίσης υποστηρίζεται το Key Attestation (Android 8.1+): κατόπιν αιτήματος της εφαρμογής, το Keymaster υπογράφει ένα πιστοποιητικό με πληροφορίες σχετικά με τα χαρακτηριστικά του κλειδιού (υλικού/λογισμικού, αλγόριθμου, purges). Ο διακομιστής μπορεί να επαληθεύσει αυτό το πιστοποιητικό για να επιβεβαιώσει ότι το κλειδί δημιουργήθηκε σε αξιόπιστο περιβάλλον.
Συχνές Ερωτήσεις
Java KeyStore αποθηκεύει τα κλειδιά σε ένα αρχείο που προστατεύεται με κωδικό (JKS, BKS). Το Android Keystore χρησιμοποιεί απομόνωση υλικού TEE ή Secure Element. Το Java KeyStore είναι ευάλωτο σε πρόσβαση root, το Android Keystore — όχι, επειδή τα ιδιωτικά κλειδιά ποτέ δεν εγκαταλείπουν το ασφαλές περιβάλλον.
Ναι, μέσω KeyStore.setEntry με KeyProtection. Ωστόσο, το εισαγόμενο κλειδί δεν θα έχει προστασία υλικού — θα αποθηκευτεί στο λογισμικό Keystore, κρυπτογραφημένο με το κυρίαρχο κλειδί. Για μέγιστη ασφάλεια, να δημιουργείτε πάντα τα κλειδιά εντός του Keystore.
Χρησιμοποιήστε KeyChain.isBoundKeyAlgorithm ή ελέγξτε τα KeyCharacteristics μετά τη δημιουργία κλειδιού. Η παρουσία FLAG_HARDWARE στα χαρακτηριστικά σημαίνει ότι το κλειδί δημιουργήθηκε σε TEE. Μπορείτε επίσης να ελέγξτε το android.security.keystore.isHardwareBacked().
Κατά την κατάργηση της εφαρμογής, το Android αφαιρεί όλα τα κλειδιά της από το Keystore. Τα δεδομένα χάνονται αμετάκλητα. Κατά την επανεγκατάσταση, η εφαρμογή πρέπει να δημιουργήσει νέα κλειδιά. Το αντίγραφο ασφαλείας κλειδιών μέσω TEE είναι αδύνατο για αρχιτεκτονικούς λόγους.
Σε κλειδωμένη συσκευή, το Keymaster δεν εκτελεί καμία λειτουργία. Τα κλειδιά με userAuthenticationRequired=true απαιτούν κάθε φορά βιομετρική επιβεβαίωση. Ακόμα και με πρόσβαση root, ο επιτιθέμενος δεν μπορεί να καλέσει απευθείας το Keymaster — μόνο μέσω της υπηρεσίας Android Keystore.
Περίληψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης