support generate key

This commit is contained in:
5ec1cff
2024-07-16 09:15:08 +08:00
parent 812d2911b2
commit 994d531304
21 changed files with 1047 additions and 71 deletions

View File

@@ -26,3 +26,8 @@
-assumenosideeffects class io.github.a13e300.tricky_store.Logger { -assumenosideeffects class io.github.a13e300.tricky_store.Logger {
public static void d(java.lang.String); public static void d(java.lang.String);
} }
# keep these or bouncycastle will not work
-keep class org.bouncycastle.jcajce.provider.** { *; }
-keep class org.bouncycastle.jce.provider.** { *; }
-dontwarn javax.naming.**

View File

@@ -1,11 +1,14 @@
package io.github.a13e300.tricky_store package io.github.a13e300.tricky_store
import android.content.pm.IPackageManager
import android.os.FileObserver import android.os.FileObserver
import android.os.ServiceManager
import io.github.a13e300.tricky_store.keystore.CertHack import io.github.a13e300.tricky_store.keystore.CertHack
import java.io.File import java.io.File
object Config { object Config {
val targetPackages = mutableSetOf<String>() private val hackPackages = mutableSetOf<String>()
private val generatePackages = mutableSetOf<String>()
private val DEFAULT_TARGET_PACKAGES = listOf( private val DEFAULT_TARGET_PACKAGES = listOf(
"com.google.android.gms", "com.google.android.gms",
"icu.nullptr.nativetest", "icu.nullptr.nativetest",
@@ -14,11 +17,16 @@ object Config {
) )
private fun updateTargetPackages(f: File?) = runCatching { private fun updateTargetPackages(f: File?) = runCatching {
targetPackages.clear() hackPackages.clear()
f?.readLines()?.mapNotNullTo(targetPackages) { generatePackages.clear()
if (it.isNotBlank() && !it.startsWith("#")) it else null f?.readLines()?.forEach {
if (it.isNotBlank() && !it.startsWith("#")) {
val n = it.trim()
if (n.endsWith("!")) generatePackages.add(n.removeSuffix("!").trim())
else hackPackages.add(n)
}
} }
Logger.i("update target packages: $targetPackages") Logger.i("update hack packages: $hackPackages, generate packages=$generatePackages")
}.onFailure { }.onFailure {
Logger.e("failed to update target files", it) Logger.e("failed to update target files", it)
} }
@@ -65,4 +73,25 @@ object Config {
} }
ConfigObserver.startWatching() ConfigObserver.startWatching()
} }
private var iPm: IPackageManager? = null
fun getPm(): IPackageManager? {
if (iPm == null) {
iPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"))
}
return iPm
}
fun needHack(callingUid: Int) = kotlin.runCatching {
if (hackPackages.isEmpty()) return false
val ps = getPm()?.getPackagesForUid(callingUid)
ps?.any { it in hackPackages }
}.onFailure { Logger.e("failed to get packages", it) }.getOrNull() ?: false
fun needGenerate(callingUid: Int) = kotlin.runCatching {
if (generatePackages.isEmpty()) return false
val ps = getPm()?.getPackagesForUid(callingUid)
ps?.any { it in generatePackages }
}.onFailure { Logger.e("failed to get packages", it) }.getOrNull() ?: false
} }

View File

@@ -1,11 +1,12 @@
package io.github.a13e300.tricky_store package io.github.a13e300.tricky_store
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.pm.IPackageManager import android.hardware.security.keymint.SecurityLevel
import android.os.IBinder import android.os.IBinder
import android.os.Parcel import android.os.Parcel
import android.os.ServiceManager import android.os.ServiceManager
import android.system.keystore2.IKeystoreService import android.system.keystore2.IKeystoreService
import android.system.keystore2.KeyDescriptor
import android.system.keystore2.KeyEntryResponse import android.system.keystore2.KeyEntryResponse
import io.github.a13e300.tricky_store.binder.BinderInterceptor import io.github.a13e300.tricky_store.binder.BinderInterceptor
import io.github.a13e300.tricky_store.keystore.CertHack import io.github.a13e300.tricky_store.keystore.CertHack
@@ -13,17 +14,14 @@ import io.github.a13e300.tricky_store.keystore.Utils
import kotlin.system.exitProcess import kotlin.system.exitProcess
@SuppressLint("BlockedPrivateApi") @SuppressLint("BlockedPrivateApi")
object KeystoreInterceptor : BinderInterceptor() { object KeystoreInterceptor : BinderInterceptor() {
private val targetTransaction = IKeystoreService.Stub::class.java.getDeclaredField("TRANSACTION_getKeyEntry").apply { isAccessible = true }.getInt(null) // 2 private val getKeyEntryTransaction =
getTransactCode(IKeystoreService.Stub::class.java, "getKeyEntry") // 2
private var iPm: IPackageManager? = null private lateinit var keystore: IBinder
private fun getPm(): IPackageManager? { private var teeInterceptor: SecurityLevelInterceptor? = null
if (iPm == null) { private var strongBoxInterceptor: SecurityLevelInterceptor? = null
iPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"))
}
return iPm
}
override fun onPreTransact( override fun onPreTransact(
target: IBinder, target: IBinder,
@@ -33,12 +31,26 @@ object KeystoreInterceptor : BinderInterceptor() {
callingPid: Int, callingPid: Int,
data: Parcel data: Parcel
): Result { ): Result {
if (code == targetTransaction && CertHack.canHack() && Config.targetPackages.isNotEmpty()) { if (code == getKeyEntryTransaction) {
Logger.d("intercept pre $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()}") if (CertHack.canHack()) {
kotlin.runCatching { Logger.d("intercept pre $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()}")
val ps = getPm()?.getPackagesForUid(callingUid) if (Config.needGenerate(callingUid))
if (ps?.any { it in Config.targetPackages } == true) return Continue kotlin.runCatching {
}.onFailure { Logger.e("failed to get packages", it) } data.enforceInterface(IKeystoreService.DESCRIPTOR)
val descriptor =
data.readTypedObject(KeyDescriptor.CREATOR) ?: return@runCatching
val response =
SecurityLevelInterceptor.getKeyResponse(callingUid, descriptor.alias)
?: return@runCatching
Logger.i("use generated key $callingUid ${descriptor.alias}")
val p = Parcel.obtain()
p.writeNoException()
p.writeTypedObject(response, 0)
return OverrideReply(0, p)
}
else if (Config.needHack(callingUid)) return Continue
return Skip
}
} }
return Skip return Skip
} }
@@ -53,7 +65,7 @@ object KeystoreInterceptor : BinderInterceptor() {
reply: Parcel?, reply: Parcel?,
resultCode: Int resultCode: Int
): Result { ): Result {
if (code != targetTransaction || reply == null) return Skip if (target != keystore || code != getKeyEntryTransaction || reply == null) return Skip
val p = Parcel.obtain() val p = Parcel.obtain()
Logger.d("intercept post $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()} replySz=${reply.dataSize()}") Logger.d("intercept post $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()} replySz=${reply.dataSize()}")
try { try {
@@ -61,7 +73,7 @@ object KeystoreInterceptor : BinderInterceptor() {
val response = reply.readTypedObject(KeyEntryResponse.CREATOR) val response = reply.readTypedObject(KeyEntryResponse.CREATOR)
val chain = Utils.getCertificateChain(response) val chain = Utils.getCertificateChain(response)
if (chain != null) { if (chain != null) {
val newChain = CertHack.engineGetCertificateChain(chain) val newChain = CertHack.hackCertificateChain(chain)
Utils.putCertificateChain(response, newChain) Utils.putCertificateChain(response, newChain)
p.writeNoException() p.writeNoException()
p.writeTypedObject(response, 0) p.writeTypedObject(response, 0)
@@ -98,8 +110,31 @@ object KeystoreInterceptor : BinderInterceptor() {
} }
return false return false
} }
val ks = IKeystoreService.Stub.asInterface(b)
val tee = kotlin.runCatching { ks.getSecurityLevel(SecurityLevel.TRUSTED_ENVIRONMENT) }
.getOrNull()
val strongBox =
kotlin.runCatching { ks.getSecurityLevel(SecurityLevel.STRONGBOX) }.getOrNull()
keystore = b
Logger.i("register for Keystore $keystore!")
registerBinderInterceptor(bd, b, this) registerBinderInterceptor(bd, b, this)
b.linkToDeath(Killer, 0) keystore.linkToDeath(Killer, 0)
if (tee != null) {
Logger.i("register for TEE SecurityLevel $tee!")
val interceptor = SecurityLevelInterceptor(tee)
registerBinderInterceptor(bd, tee.asBinder(), interceptor)
teeInterceptor = interceptor
} else {
Logger.i("no TEE SecurityLevel found!")
}
if (strongBox != null) {
Logger.i("register for StrongBox SecurityLevel $tee!")
val interceptor = SecurityLevelInterceptor(strongBox)
registerBinderInterceptor(bd, strongBox.asBinder(), interceptor)
strongBoxInterceptor = interceptor
} else {
Logger.i("no StrongBox SecurityLevel found!")
}
return true return true
} }

View File

@@ -0,0 +1,141 @@
package io.github.a13e300.tricky_store
import android.hardware.security.keymint.KeyParameter
import android.hardware.security.keymint.KeyParameterValue
import android.hardware.security.keymint.SecurityLevel
import android.hardware.security.keymint.Tag
import android.os.IBinder
import android.os.Parcel
import android.system.keystore2.Authorization
import android.system.keystore2.IKeystoreSecurityLevel
import android.system.keystore2.KeyDescriptor
import android.system.keystore2.KeyEntryResponse
import android.system.keystore2.KeyMetadata
import io.github.a13e300.tricky_store.binder.BinderInterceptor
import io.github.a13e300.tricky_store.keystore.CertHack
import io.github.a13e300.tricky_store.keystore.CertHack.KeyGenParameters
import io.github.a13e300.tricky_store.keystore.Utils
import java.security.KeyPair
import java.security.cert.Certificate
import java.util.concurrent.ConcurrentHashMap
class SecurityLevelInterceptor(private val original: IKeystoreSecurityLevel) : BinderInterceptor() {
companion object {
private val generateKeyTransaction =
getTransactCode(IKeystoreSecurityLevel.Stub::class.java, "generateKey")
private val keys = ConcurrentHashMap<Key, Info>()
fun getKeyResponse(uid: Int, alias: String): KeyEntryResponse? =
keys[Key(uid, alias)]?.response
}
data class Key(val uid: Int, val alias: String)
data class Info(val keyPair: KeyPair, val response: KeyEntryResponse)
override fun onPreTransact(
target: IBinder,
code: Int,
flags: Int,
callingUid: Int,
callingPid: Int,
data: Parcel
): Result {
if (code == generateKeyTransaction && Config.needGenerate(callingUid)) {
Logger.i("intercept key gen uid=$callingUid pid=$callingPid")
kotlin.runCatching {
data.enforceInterface(IKeystoreSecurityLevel.DESCRIPTOR)
val keyDescriptor =
data.readTypedObject(KeyDescriptor.CREATOR) ?: return@runCatching
val attestationKeyDescriptor = data.readTypedObject(KeyDescriptor.CREATOR)
val params = data.createTypedArray(KeyParameter.CREATOR)!!
// val aFlags = data.readInt()
// val entropy = data.createByteArray()
val kgp = KeyGenParameters(params)
if (kgp.attestationChallenge != null) {
if (attestationKeyDescriptor != null) {
Logger.e("warn: attestation key not supported now")
} else {
val pair = CertHack.generateKeyPair(callingUid, keyDescriptor, kgp)
?: return@runCatching
val response = buildResponse(pair.second, kgp, keyDescriptor)
keys[Key(callingUid, keyDescriptor.alias)] = Info(pair.first, response)
val p = Parcel.obtain()
p.writeNoException()
p.writeTypedObject(response.metadata, 0)
return OverrideReply(0, p)
}
}
}.onFailure {
Logger.e("parse key gen request", it)
}
}
return Skip
}
private fun buildResponse(
chain: List<Certificate>,
params: KeyGenParameters,
descriptor: KeyDescriptor
): KeyEntryResponse {
val response = KeyEntryResponse()
val metadata = KeyMetadata()
Utils.putCertificateChain(metadata, chain.toTypedArray<Certificate>())
val d = KeyDescriptor()
d.domain = descriptor.domain
d.nspace = descriptor.nspace
metadata.key = d
val authorizations = ArrayList<Authorization>()
var a: Authorization
for (i in params.purpose) {
a = Authorization()
a.keyParameter = KeyParameter()
a.keyParameter.tag = Tag.PURPOSE
a.keyParameter.value = KeyParameterValue.keyPurpose(i)
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
authorizations.add(a)
}
for (i in params.digest) {
a = Authorization()
a.keyParameter = KeyParameter()
a.keyParameter.tag = Tag.DIGEST
a.keyParameter.value = KeyParameterValue.digest(i)
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
authorizations.add(a)
}
a = Authorization()
a.keyParameter = KeyParameter()
a.keyParameter.tag = Tag.ALGORITHM
a.keyParameter.value = KeyParameterValue.algorithm(params.algorithm)
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
authorizations.add(a)
a = Authorization()
a.keyParameter = KeyParameter()
a.keyParameter.tag = Tag.KEY_SIZE
a.keyParameter.value = KeyParameterValue.integer(params.keySize)
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
authorizations.add(a)
a = Authorization()
a.keyParameter = KeyParameter()
a.keyParameter.tag = Tag.EC_CURVE
a.keyParameter.value = KeyParameterValue.ecCurve(params.ecCurve)
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
authorizations.add(a)
a = Authorization()
a.keyParameter = KeyParameter()
a.keyParameter.tag = Tag.NO_AUTH_REQUIRED
a.keyParameter.value = KeyParameterValue.boolValue(true) // TODO: copy
a.securityLevel = SecurityLevel.TRUSTED_ENVIRONMENT
authorizations.add(a)
// TODO: ORIGIN
//OS_VERSION
//OS_PATCHLEVEL
//VENDOR_PATCHLEVEL
//BOOT_PATCHLEVEL
//CREATION_DATETIME
//USER_ID
metadata.authorizations = authorizations.toTypedArray<Authorization>()
response.metadata = metadata
response.iSecurityLevel = original
return response
}
}

View File

@@ -1,22 +1,38 @@
package io.github.a13e300.tricky_store.keystore; package io.github.a13e300.tricky_store.keystore;
import android.content.pm.PackageManager;
import android.hardware.security.keymint.Algorithm;
import android.hardware.security.keymint.EcCurve;
import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.Tag;
import android.security.keystore.KeyProperties; import android.security.keystore.KeyProperties;
import android.system.keystore2.KeyDescriptor;
import android.util.Pair;
import androidx.annotation.Nullable;
import org.bouncycastle.asn1.ASN1Boolean; import org.bouncycastle.asn1.ASN1Boolean;
import org.bouncycastle.asn1.ASN1Encodable; import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Enumerated; import org.bouncycastle.asn1.ASN1Enumerated;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString; import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.ASN1Sequence; import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1TaggedObject; import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DEROctetString; import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERTaggedObject; import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder; import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
@@ -25,25 +41,46 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.util.io.pem.PemReader; import org.bouncycastle.util.io.pem.PemReader;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader; import java.io.StringReader;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateFactory; import java.security.cert.CertificateFactory;
import java.security.cert.CertificateParsingException; import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import javax.security.auth.x500.X500Principal;
import io.github.a13e300.tricky_store.Config;
import io.github.a13e300.tricky_store.Logger; import io.github.a13e300.tricky_store.Logger;
import io.github.a13e300.tricky_store.UtilKt;
public final class CertHack { public final class CertHack {
private static final ASN1ObjectIdentifier OID = new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17"); private static final ASN1ObjectIdentifier OID = new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17");
record KeyBox(PEMKeyPair privateKey, List<Certificate> certificates) {} private static final int ATTESTATION_APPLICATION_ID_PACKAGE_INFOS_INDEX = 0;
private static final int ATTESTATION_APPLICATION_ID_SIGNATURE_DIGESTS_INDEX = 1;
private static final Map<String, KeyBox> keyboxes = new HashMap<>(); private static final Map<String, KeyBox> keyboxes = new HashMap<>();
private static final int ATTESTATION_PACKAGE_INFO_PACKAGE_NAME_INDEX = 0;
private static final CertificateFactory certificateFactory; private static final CertificateFactory certificateFactory;
@@ -55,11 +92,31 @@ public final class CertHack {
throw new RuntimeException(t); throw new RuntimeException(t);
} }
} }
private static final int ATTESTATION_PACKAGE_INFO_VERSION_INDEX = 1;
public static boolean canHack() { public static boolean canHack() {
return !keyboxes.isEmpty(); return !keyboxes.isEmpty();
} }
private static PEMKeyPair parseKeyPair(String key) throws Throwable {
try (PEMParser parser = new PEMParser(new StringReader(key))) {
return (PEMKeyPair) parser.readObject();
}
}
private static Certificate parseCert(String cert) throws Throwable {
try (PemReader reader = new PemReader(new StringReader(cert))) {
return certificateFactory.generateCertificate(new ByteArrayInputStream(reader.readPemObject().getContent()));
}
}
private static byte[] getByteArrayFromAsn1(ASN1Encodable asn1Encodable) throws CertificateParsingException {
if (!(asn1Encodable instanceof DEROctetString derOctectString)) {
throw new CertificateParsingException("Expected DEROctetString");
}
return derOctectString.getOctets();
}
public static void readFromXml(String data) { public static void readFromXml(String data) {
keyboxes.clear(); keyboxes.clear();
if (data == null) { if (data == null) {
@@ -92,7 +149,9 @@ public final class CertHack {
} else { } else {
algo = KeyProperties.KEY_ALGORITHM_RSA; algo = KeyProperties.KEY_ALGORITHM_RSA;
} }
keyboxes.put(algo, new KeyBox(parseKeyPair(privateKey), certificateChain)); var pemKp = parseKeyPair(privateKey);
var kp = new JcaPEMKeyConverter().getKeyPair(pemKp);
keyboxes.put(algo, new KeyBox(pemKp, kp, certificateChain));
} }
Logger.i("update " + numberOfKeyboxes + " keyboxes"); Logger.i("update " + numberOfKeyboxes + " keyboxes");
} catch (Throwable t) { } catch (Throwable t) {
@@ -100,26 +159,7 @@ public final class CertHack {
} }
} }
private static PEMKeyPair parseKeyPair(String key) throws Throwable { public static Certificate[] hackCertificateChain(Certificate[] caList) {
try (PEMParser parser = new PEMParser(new StringReader(key))) {
return (PEMKeyPair) parser.readObject();
}
}
private static Certificate parseCert(String cert) throws Throwable {
try (PemReader reader = new PemReader(new StringReader(cert))) {
return certificateFactory.generateCertificate(new ByteArrayInputStream(reader.readPemObject().getContent()));
}
}
private static byte[] getByteArrayFromAsn1(ASN1Encodable asn1Encodable) throws CertificateParsingException {
if (!(asn1Encodable instanceof DEROctetString derOctectString)) {
throw new CertificateParsingException("Expected DEROctetString");
}
return derOctectString.getOctets();
}
public static Certificate[] engineGetCertificateChain(Certificate[] caList) {
if (caList == null) throw new UnsupportedOperationException("caList is null!"); if (caList == null) throw new UnsupportedOperationException("caList is null!");
try { try {
X509Certificate leaf = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(caList[0].getEncoded())); X509Certificate leaf = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(caList[0].getEncoded()));
@@ -158,14 +198,10 @@ public final class CertHack {
holder.getNotBefore(), holder.getNotBefore(),
holder.getNotAfter(), holder.getNotAfter(),
holder.getSubject(), holder.getSubject(),
k.privateKey.getPublicKeyInfo() k.pemKeyPair.getPublicKeyInfo()
); );
signer = new JcaContentSignerBuilder(leaf.getSigAlgName()) signer = new JcaContentSignerBuilder(leaf.getSigAlgName())
.build( .build(k.keyPair.getPrivate());
new JcaPEMKeyConverter()
.getPrivateKey(k.privateKey.getPrivateKeyInfo()
)
);
byte[] verifiedBootKey = null; byte[] verifiedBootKey = null;
byte[] verifiedBootHash = null; byte[] verifiedBootHash = null;
@@ -221,4 +257,286 @@ public final class CertHack {
} }
return caList; return caList;
} }
public static Pair<KeyPair, List<Certificate>> generateKeyPair(int uid, KeyDescriptor descriptor, KeyGenParameters params) {
Logger.i("Requested KeyPair with alias: " + descriptor.alias);
KeyPair rootKP;
X500Name issuer;
int size = params.keySize;
KeyPair kp = null;
KeyBox keyBox = null;
try {
var algo = params.algorithm;
if (algo == Algorithm.EC) {
Logger.d("GENERATING EC KEYPAIR OF SIZE " + size);
kp = buildECKeyPair(params);
keyBox = keyboxes.get(KeyProperties.KEY_ALGORITHM_EC);
} else if (algo == Algorithm.RSA) {
Logger.d("GENERATING RSA KEYPAIR OF SIZE " + size);
kp = buildRSAKeyPair(params);
keyBox = keyboxes.get(KeyProperties.KEY_ALGORITHM_RSA);
}
if (keyBox == null) {
Logger.e("UNSUPPORTED ALGORITHM: " + algo);
return null;
}
rootKP = keyBox.keyPair;
issuer = new X509CertificateHolder(
keyBox.certificates.get(0).getEncoded()
).getSubject();
X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(issuer,
params.certificateSerial,
params.certificateNotBefore,
params.certificateNotAfter,
params.certificateSubject,
kp.getPublic()
);
KeyUsage keyUsage = new KeyUsage(KeyUsage.keyCertSign);
certBuilder.addExtension(Extension.keyUsage, true, keyUsage);
certBuilder.addExtension(createExtension(params, uid));
ContentSigner contentSigner;
if (algo == Algorithm.EC) {
contentSigner = new JcaContentSignerBuilder("SHA256withECDSA").build(rootKP.getPrivate());
} else {
contentSigner = new JcaContentSignerBuilder("SHA256withRSA").build(rootKP.getPrivate());
}
X509CertificateHolder certHolder = certBuilder.build(contentSigner);
var leaf = new JcaX509CertificateConverter().getCertificate(certHolder);
List<Certificate> chain = new ArrayList<>(keyBox.certificates);
chain.add(0, leaf);
Logger.d("Successfully generated X500 Cert for alias: " + descriptor.alias);
return new Pair<>(kp, chain);
} catch (Throwable t) {
Logger.e("", t);
}
return null;
}
private static KeyPair buildECKeyPair(KeyGenParameters params) throws Exception {
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
Security.addProvider(new BouncyCastleProvider());
ECGenParameterSpec spec = new ECGenParameterSpec(params.ecCurveName);
KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDSA", BouncyCastleProvider.PROVIDER_NAME);
kpg.initialize(spec);
return kpg.generateKeyPair();
}
private static KeyPair buildRSAKeyPair(KeyGenParameters params) throws Exception {
Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
Security.addProvider(new BouncyCastleProvider());
RSAKeyGenParameterSpec spec = new RSAKeyGenParameterSpec(
params.keySize, params.rsaPublicExponent);
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
kpg.initialize(spec);
return kpg.generateKeyPair();
}
private static ASN1Encodable[] fromIntList(List<Integer> list) {
ASN1Encodable[] result = new ASN1Encodable[list.size()];
for (int i = 0; i < list.size(); i++) {
result[i] = new ASN1Integer(list.get(i));
}
return result;
}
private static Extension createExtension(KeyGenParameters params, int uid) {
try {
SecureRandom random = new SecureRandom();
byte[] key = new byte[32];
byte[] hash = UtilKt.getBootHashFromProp();
random.nextBytes(key);
if (hash == null || hash.length != 32) {
hash = new byte[32];
random.nextBytes(hash);
}
ASN1Encodable[] rootOfTrustEncodables = {new DEROctetString(key), ASN1Boolean.TRUE,
new ASN1Enumerated(0), new DEROctetString(hash)};
ASN1Sequence rootOfTrustSeq = new DERSequence(rootOfTrustEncodables);
var Apurpose = new DERSet(fromIntList(params.purpose));
var Aalgorithm = new ASN1Integer(params.algorithm);
var AkeySize = new ASN1Integer(params.keySize);
var Adigest = new DERSet(fromIntList(params.digest));
var AecCurve = new ASN1Integer(params.ecCurve);
var AnoAuthRequired = DERNull.INSTANCE;
// To be loaded
var AosVersion = new ASN1Integer(UtilKt.getOsVersion());
var AosPatchLevel = new ASN1Integer(UtilKt.getPatchLevel());
// TODO hex3l: add applicationID to attestation
var AapplicationID = createApplicationId(uid);
var AbootPatchlevel = new ASN1Integer(UtilKt.getPatchLevelLong());
var AvendorPatchLevel = new ASN1Integer(UtilKt.getPatchLevelLong());
var AcreationDateTime = new ASN1Integer(System.currentTimeMillis());
var Aorigin = new ASN1Integer(0);
var purpose = new DERTaggedObject(true, 1, Apurpose);
var algorithm = new DERTaggedObject(true, 2, Aalgorithm);
var keySize = new DERTaggedObject(true, 3, AkeySize);
var digest = new DERTaggedObject(true, 5, Adigest);
var ecCurve = new DERTaggedObject(true, 10, AecCurve);
var noAuthRequired = new DERTaggedObject(true, 503, AnoAuthRequired);
var creationDateTime = new DERTaggedObject(true, 701, AcreationDateTime);
var origin = new DERTaggedObject(true, 702, Aorigin);
var rootOfTrust = new DERTaggedObject(true, 704, rootOfTrustSeq);
var osVersion = new DERTaggedObject(true, 705, AosVersion);
var osPatchLevel = new DERTaggedObject(true, 706, AosPatchLevel);
var applicationID = new DERTaggedObject(true, 709, AapplicationID);
var vendorPatchLevel = new DERTaggedObject(true, 718, AvendorPatchLevel);
var bootPatchLevel = new DERTaggedObject(true, 719, AbootPatchlevel);
ASN1Encodable[] teeEnforcedEncodables = {purpose, algorithm, keySize, digest, ecCurve,
noAuthRequired, creationDateTime, origin, rootOfTrust, osVersion, osPatchLevel, applicationID, vendorPatchLevel, bootPatchLevel};
ASN1OctetString keyDescriptionOctetStr = getAsn1OctetString(teeEnforcedEncodables, params);
return new Extension(new ASN1ObjectIdentifier("1.3.6.1.4.1.11129.2.1.17"), false, keyDescriptionOctetStr);
} catch (Throwable t) {
Logger.e("", t);
}
return null;
}
private static ASN1OctetString getAsn1OctetString(ASN1Encodable[] teeEnforcedEncodables, KeyGenParameters params) throws IOException {
ASN1Integer attestationVersion = new ASN1Integer(100);
ASN1Enumerated attestationSecurityLevel = new ASN1Enumerated(1);
ASN1Integer keymasterVersion = new ASN1Integer(100);
ASN1Enumerated keymasterSecurityLevel = new ASN1Enumerated(1);
ASN1OctetString attestationChallenge = new DEROctetString(params.attestationChallenge);
ASN1OctetString uniqueId = new DEROctetString("".getBytes());
ASN1Sequence softwareEnforced = new DERSequence();
ASN1Sequence teeEnforced = new DERSequence(teeEnforcedEncodables);
ASN1Encodable[] keyDescriptionEncodables = {attestationVersion, attestationSecurityLevel, keymasterVersion,
keymasterSecurityLevel, attestationChallenge, uniqueId, softwareEnforced, teeEnforced};
ASN1Sequence keyDescriptionHackSeq = new DERSequence(keyDescriptionEncodables);
return new DEROctetString(keyDescriptionHackSeq);
}
private static DEROctetString createApplicationId(int uid) throws Throwable {
var pm = Config.INSTANCE.getPm();
if (pm == null) {
throw new IllegalStateException("createApplicationId: pm not found!");
}
var packages = pm.getPackagesForUid(uid);
var size = packages.length;
ASN1Encodable[] packageInfoAA = new ASN1Encodable[size];
Set<Digest> signatures = new HashSet<>();
var dg = MessageDigest.getInstance("SHA-256");
for (int i = 0; i < size; i++) {
var name = packages[i];
var info = pm.getPackageInfo(name, PackageManager.GET_SIGNATURES, uid / 100000);
ASN1Encodable[] arr = new ASN1Encodable[2];
arr[ATTESTATION_PACKAGE_INFO_PACKAGE_NAME_INDEX] =
new DEROctetString(packages[i].getBytes(StandardCharsets.UTF_8));
arr[ATTESTATION_PACKAGE_INFO_VERSION_INDEX] = new ASN1Integer(info.getLongVersionCode());
packageInfoAA[i] = new DERSequence(arr);
for (var s : info.signatures) {
signatures.add(new Digest(dg.digest(s.toByteArray())));
}
}
ASN1Encodable[] signaturesAA = new ASN1Encodable[signatures.size()];
var i = 0;
for (var d : signatures) {
signaturesAA[i] = new DEROctetString(d.digest);
i++;
}
ASN1Encodable[] applicationIdAA = new ASN1Encodable[2];
applicationIdAA[ATTESTATION_APPLICATION_ID_PACKAGE_INFOS_INDEX] =
new DERSet(packageInfoAA);
applicationIdAA[ATTESTATION_APPLICATION_ID_SIGNATURE_DIGESTS_INDEX] =
new DERSet(signaturesAA);
return new DEROctetString(new DERSequence(applicationIdAA).getEncoded());
}
record Digest(byte[] digest) {
@Override
public boolean equals(@Nullable Object o) {
if (o instanceof Digest d)
return Arrays.equals(digest, d.digest);
return false;
}
@Override
public int hashCode() {
return Arrays.hashCode(digest);
}
}
record KeyBox(PEMKeyPair pemKeyPair, KeyPair keyPair, List<Certificate> certificates) {
}
public static class KeyGenParameters {
public int keySize;
public int algorithm;
public BigInteger certificateSerial;
public Date certificateNotBefore;
public Date certificateNotAfter;
public X500Name certificateSubject;
public BigInteger rsaPublicExponent;
public int ecCurve;
public String ecCurveName;
public List<Integer> purpose = new ArrayList<>();
public List<Integer> digest = new ArrayList<>();
public byte[] attestationChallenge;
public KeyGenParameters(KeyParameter[] params) {
for (var kp : params) {
var p = kp.value;
switch (kp.tag) {
case Tag.KEY_SIZE -> keySize = p.getInteger();
case Tag.ALGORITHM -> algorithm = p.getAlgorithm();
case Tag.CERTIFICATE_SERIAL -> certificateSerial = new BigInteger(p.getBlob());
case Tag.CERTIFICATE_NOT_BEFORE ->
certificateNotBefore = new Date(p.getDateTime());
case Tag.CERTIFICATE_NOT_AFTER ->
certificateNotAfter = new Date(p.getDateTime());
case Tag.CERTIFICATE_SUBJECT ->
certificateSubject = new X500Name(new X500Principal(p.getBlob()).getName());
case Tag.RSA_PUBLIC_EXPONENT -> rsaPublicExponent = new BigInteger(p.getBlob());
case Tag.EC_CURVE -> {
ecCurve = p.getEcCurve();
ecCurveName = getEcCurveName(ecCurve);
}
case Tag.PURPOSE -> {
purpose.add(p.getKeyPurpose());
}
case Tag.DIGEST -> {
digest.add(p.getDigest());
}
case Tag.ATTESTATION_CHALLENGE -> attestationChallenge = p.getBlob();
}
}
}
private static String getEcCurveName(int curve) {
String res;
switch (curve) {
case EcCurve.CURVE_25519 -> res = "CURVE_25519";
case EcCurve.P_224 -> res = "secp224r1";
case EcCurve.P_256 -> res = "secp256r1";
case EcCurve.P_384 -> res = "secp384r1";
case EcCurve.P_521 -> res = "secp521r1";
default -> throw new IllegalArgumentException("unknown curve");
}
return res;
}
}
} }

View File

@@ -1,6 +1,7 @@
package io.github.a13e300.tricky_store.keystore; package io.github.a13e300.tricky_store.keystore;
import android.system.keystore2.KeyEntryResponse; import android.system.keystore2.KeyEntryResponse;
import android.system.keystore2.KeyMetadata;
import android.util.Log; import android.util.Log;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
@@ -58,12 +59,16 @@ public class Utils {
} }
public static void putCertificateChain(KeyEntryResponse response, Certificate[] chain) throws Throwable { public static void putCertificateChain(KeyEntryResponse response, Certificate[] chain) throws Throwable {
putCertificateChain(response.metadata, chain);
}
public static void putCertificateChain(KeyMetadata metadata, Certificate[] chain) throws Throwable {
if (chain == null || chain.length == 0) return; if (chain == null || chain.length == 0) return;
response.metadata.certificate = chain[0].getEncoded(); metadata.certificate = chain[0].getEncoded();
var output = new ByteArrayOutputStream(); var output = new ByteArrayOutputStream();
for (int i = 1; i < chain.length; i++) { for (int i = 1; i < chain.length; i++) {
output.write(chain[i].getEncoded()); output.write(chain[i].getEncoded());
} }
response.metadata.certificateChain = output.toByteArray(); metadata.certificateChain = output.toByteArray();
} }
} }

View File

@@ -0,0 +1,40 @@
package io.github.a13e300.tricky_store
import android.os.Build
import android.os.SystemProperties
fun getTransactCode(clazz: Class<*>, method: String) =
clazz.getDeclaredField("TRANSACTION_$method").apply { isAccessible = true }
.getInt(null) // 2
@OptIn(ExperimentalStdlibApi::class)
val bootHashFromProp by lazy {
val b = SystemProperties.get("ro.boot.vbmeta.digest", null) ?: return@lazy null
if (b.length != 64) return@lazy null
b.hexToByteArray()
}
val patchLevel by lazy {
Build.VERSION.SECURITY_PATCH.convertPatchLevel(false)
}
val patchLevelLong by lazy {
Build.VERSION.SECURITY_PATCH.convertPatchLevel(true)
}
// FIXME
val osVersion by lazy {
when (Build.VERSION.SDK_INT) {
Build.VERSION_CODES.UPSIDE_DOWN_CAKE -> 140000
Build.VERSION_CODES.TIRAMISU -> 130000
Build.VERSION_CODES.S_V2 -> 120100
Build.VERSION_CODES.S -> 120000
else -> 0
}
}
fun String.convertPatchLevel(long: Boolean) = kotlin.runCatching {
val l = split("-")
if (long) l[0].toInt() * 10000 + l[1].toInt() * 100 + l[2].toInt()
else l[0].toInt() * 100 + l[1].toInt()
}.onFailure { Logger.e("invalid patch level $this !", it) }.getOrDefault(202404)

View File

@@ -5,6 +5,8 @@ import android.os.IBinder;
public interface IPackageManager { public interface IPackageManager {
String[] getPackagesForUid(int uid); String[] getPackagesForUid(int uid);
PackageInfo getPackageInfo(String packageName, long flags, int userId);
class Stub { class Stub {
public static IPackageManager asInterface(IBinder binder) { public static IPackageManager asInterface(IBinder binder) {
throw new RuntimeException(""); throw new RuntimeException("");

View File

@@ -0,0 +1,9 @@
package android.hardware.security.keymint;
public @interface Algorithm {
int AES = 32;
int EC = 3;
int HMAC = 128;
int RSA = 1;
int TRIPLE_DES = 33;
}

View File

@@ -0,0 +1,10 @@
package android.hardware.security.keymint;
/* loaded from: classes2.dex */
public @interface EcCurve {
public static final int CURVE_25519 = 4;
public static final int P_224 = 0;
public static final int P_256 = 1;
public static final int P_384 = 2;
public static final int P_521 = 3;
}

View File

@@ -0,0 +1,32 @@
package android.hardware.security.keymint;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
public class KeyParameter implements Parcelable {
public static final Creator<KeyParameter> CREATOR = new Creator<>() {
@Override
public KeyParameter createFromParcel(Parcel in) {
throw new RuntimeException();
}
@Override
public KeyParameter[] newArray(int size) {
throw new RuntimeException();
}
};
public int tag = 0;
public KeyParameterValue value;
@Override
public int describeContents() {
throw new RuntimeException();
}
@Override
public void writeToParcel(@NonNull Parcel parcel, int i) {
throw new RuntimeException();
}
}

View File

@@ -0,0 +1,239 @@
package android.hardware.security.keymint;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.NonNull;
/* loaded from: classes2.dex */
public final class KeyParameterValue implements Parcelable {
public static final int algorithm = 1;
public static final int blob = 14;
public static final int blockMode = 2;
public static final int boolValue = 10;
public static final int dateTime = 13;
public static final int digest = 4;
public static final int ecCurve = 5;
public static final int hardwareAuthenticatorType = 8;
public static final int integer = 11;
public static final int invalid = 0;
public static final int keyPurpose = 7;
public static final int longInteger = 12;
public static final int origin = 6;
public static final int paddingMode = 3;
public static final int securityLevel = 9;
public static final Creator<KeyParameterValue> CREATOR = new Creator<KeyParameterValue>() {
@Override
public KeyParameterValue createFromParcel(Parcel in) {
throw new RuntimeException();
}
@Override
public KeyParameterValue[] newArray(int size) {
throw new RuntimeException();
}
};
public KeyParameterValue() {
throw new RuntimeException();
}
protected KeyParameterValue(Parcel in) {
throw new RuntimeException();
}
public static KeyParameterValue invalid(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue algorithm(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue blockMode(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue paddingMode(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue digest(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue ecCurve(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue origin(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue keyPurpose(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue hardwareAuthenticatorType(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue securityLevel(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue boolValue(boolean _value) {
throw new RuntimeException();
}
public static KeyParameterValue integer(int _value) {
throw new RuntimeException();
}
public static KeyParameterValue longInteger(long _value) {
throw new RuntimeException();
}
public static KeyParameterValue dateTime(long _value) {
throw new RuntimeException();
}
public static KeyParameterValue blob(byte[] _value) {
throw new RuntimeException();
}
public int getTag() {
throw new RuntimeException();
}
public int getInvalid() {
throw new RuntimeException();
}
public void setInvalid(int _value) {
throw new RuntimeException();
}
public int getAlgorithm() {
throw new RuntimeException();
}
public void setAlgorithm(int _value) {
throw new RuntimeException();
}
public int getBlockMode() {
throw new RuntimeException();
}
public void setBlockMode(int _value) {
throw new RuntimeException();
}
public int getPaddingMode() {
throw new RuntimeException();
}
public void setPaddingMode(int _value) {
throw new RuntimeException();
}
public int getDigest() {
throw new RuntimeException();
}
public void setDigest(int _value) {
throw new RuntimeException();
}
public int getEcCurve() {
throw new RuntimeException();
}
public void setEcCurve(int _value) {
throw new RuntimeException();
}
public int getOrigin() {
throw new RuntimeException();
}
public void setOrigin(int _value) {
throw new RuntimeException();
}
public int getKeyPurpose() {
throw new RuntimeException();
}
public void setKeyPurpose(int _value) {
throw new RuntimeException();
}
public int getHardwareAuthenticatorType() {
throw new RuntimeException();
}
public void setHardwareAuthenticatorType(int _value) {
throw new RuntimeException();
}
public int getSecurityLevel() {
throw new RuntimeException();
}
public void setSecurityLevel(int _value) {
throw new RuntimeException();
}
public boolean getBoolValue() {
throw new RuntimeException();
}
public void setBoolValue(boolean _value) {
throw new RuntimeException();
}
public int getInteger() {
throw new RuntimeException();
}
public void setInteger(int _value) {
throw new RuntimeException();
}
public long getLongInteger() {
throw new RuntimeException();
}
public void setLongInteger(long _value) {
throw new RuntimeException();
}
public long getDateTime() {
throw new RuntimeException();
}
public void setDateTime(long _value) {
throw new RuntimeException();
}
public byte[] getBlob() {
throw new RuntimeException();
}
public void setBlob(byte[] _value) {
throw new RuntimeException();
}
@Override
public int describeContents() {
throw new RuntimeException();
}
@Override
public void writeToParcel(@NonNull Parcel parcel, int i) {
throw new RuntimeException();
}
}

View File

@@ -0,0 +1,11 @@
package android.hardware.security.keymint;
public @interface KeyPurpose {
int AGREE_KEY = 6;
int ATTEST_KEY = 7;
int DECRYPT = 1;
int ENCRYPT = 0;
int SIGN = 2;
int VERIFY = 3;
int WRAP_KEY = 5;
}

View File

@@ -0,0 +1,8 @@
package android.hardware.security.keymint;
public @interface SecurityLevel {
int KEYSTORE = 100;
int SOFTWARE = 0;
int STRONGBOX = 2;
int TRUSTED_ENVIRONMENT = 1;
}

View File

@@ -0,0 +1,70 @@
package android.hardware.security.keymint;
public @interface Tag {
int ACTIVE_DATETIME = 1610613136;
int ALGORITHM = 268435458;
int ALLOW_WHILE_ON_BODY = 1879048698;
int APPLICATION_DATA = -1879047492;
int APPLICATION_ID = -1879047591;
int ASSOCIATED_DATA = -1879047192;
int ATTESTATION_APPLICATION_ID = -1879047483;
int ATTESTATION_CHALLENGE = -1879047484;
int ATTESTATION_ID_BRAND = -1879047482;
int ATTESTATION_ID_DEVICE = -1879047481;
int ATTESTATION_ID_IMEI = -1879047478;
int ATTESTATION_ID_MANUFACTURER = -1879047476;
int ATTESTATION_ID_MEID = -1879047477;
int ATTESTATION_ID_MODEL = -1879047475;
int ATTESTATION_ID_PRODUCT = -1879047480;
int ATTESTATION_ID_SECOND_IMEI = -1879047469;
int ATTESTATION_ID_SERIAL = -1879047479;
int AUTH_TIMEOUT = 805306873;
int BLOCK_MODE = 536870916;
int BOOTLOADER_ONLY = 1879048494;
int BOOT_PATCHLEVEL = 805307087;
int CALLER_NONCE = 1879048199;
int CERTIFICATE_NOT_AFTER = 1610613745;
int CERTIFICATE_NOT_BEFORE = 1610613744;
int CERTIFICATE_SERIAL = -2147482642;
int CERTIFICATE_SUBJECT = -1879047185;
int CONFIRMATION_TOKEN = -1879047187;
int CREATION_DATETIME = 1610613437;
int DEVICE_UNIQUE_ATTESTATION = 1879048912;
int DIGEST = 536870917;
int EARLY_BOOT_ONLY = 1879048497;
int EC_CURVE = 268435466;
int HARDWARE_TYPE = 268435760;
int IDENTITY_CREDENTIAL_KEY = 1879048913;
int INCLUDE_UNIQUE_ID = 1879048394;
int INVALID = 0;
int KEY_SIZE = 805306371;
int MAC_LENGTH = 805307371;
int MAX_BOOT_LEVEL = 805307378;
int MAX_USES_PER_BOOT = 805306772;
int MIN_MAC_LENGTH = 805306376;
int MIN_SECONDS_BETWEEN_OPS = 805306771;
int NONCE = -1879047191;
int NO_AUTH_REQUIRED = 1879048695;
int ORIGIN = 268436158;
int ORIGINATION_EXPIRE_DATETIME = 1610613137;
int OS_PATCHLEVEL = 805307074;
int OS_VERSION = 805307073;
int PADDING = 536870918;
int PURPOSE = 536870913;
int RESET_SINCE_ID_ROTATION = 1879049196;
int ROLLBACK_RESISTANCE = 1879048495;
int ROOT_OF_TRUST = -1879047488;
int RSA_OAEP_MGF_DIGEST = 536871115;
int RSA_PUBLIC_EXPONENT = 1342177480;
int STORAGE_KEY = 1879048914;
int TRUSTED_CONFIRMATION_REQUIRED = 1879048700;
int TRUSTED_USER_PRESENCE_REQUIRED = 1879048699;
int UNIQUE_ID = -1879047485;
int UNLOCKED_DEVICE_REQUIRED = 1879048701;
int USAGE_COUNT_LIMIT = 805306773;
int USAGE_EXPIRE_DATETIME = 1610613138;
int USER_AUTH_TYPE = 268435960;
int USER_ID = 805306869;
int USER_SECURE_ID = -1610612234;
int VENDOR_PATCHLEVEL = 805307086;
}

View File

@@ -0,0 +1,8 @@
package android.system.keystore2;
import android.hardware.security.keymint.KeyParameter;
public class Authorization {
public KeyParameter keyParameter;
public int securityLevel = 0;
}

View File

@@ -0,0 +1,20 @@
package android.system.keystore2;
import android.hardware.security.keymint.KeyParameter;
import android.os.IBinder;
import android.os.IInterface;
import androidx.annotation.Nullable;
public interface IKeystoreSecurityLevel extends IInterface {
String DESCRIPTOR = "android.system.keystore2.IKeystoreSecurityLevel";
KeyMetadata generateKey(KeyDescriptor key, @Nullable KeyDescriptor attestationKey,
KeyParameter[] params, int flags, byte[] entropy);
class Stub {
public static IKeystoreSecurityLevel asInterface(IBinder b) {
throw new RuntimeException();
}
}
}

View File

@@ -1,9 +1,15 @@
package android.system.keystore2; package android.system.keystore2;
import android.os.IBinder;
public interface IKeystoreService { public interface IKeystoreService {
String DESCRIPTOR = "android.system.keystore2.IKeystoreService"; String DESCRIPTOR = "android.system.keystore2.IKeystoreService";
class Stub { IKeystoreSecurityLevel getSecurityLevel(int securityLevel);
class Stub {
public static IKeystoreService asInterface(IBinder b) {
throw new RuntimeException("");
}
} }
} }

View File

@@ -11,19 +11,15 @@ public class KeyDescriptor implements Parcelable {
public int domain = 0; public int domain = 0;
public long nspace = 0; public long nspace = 0;
protected KeyDescriptor(Parcel in) {
throw new RuntimeException("");
}
public static final Creator<KeyDescriptor> CREATOR = new Creator<KeyDescriptor>() { public static final Creator<KeyDescriptor> CREATOR = new Creator<KeyDescriptor>() {
@Override @Override
public KeyDescriptor createFromParcel(Parcel in) { public KeyDescriptor createFromParcel(Parcel in) {
return new KeyDescriptor(in); throw new RuntimeException();
} }
@Override @Override
public KeyDescriptor[] newArray(int size) { public KeyDescriptor[] newArray(int size) {
return new KeyDescriptor[size]; throw new RuntimeException();
} }
}; };

View File

@@ -6,13 +6,9 @@ import android.os.Parcelable;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
public class KeyEntryResponse implements Parcelable { public class KeyEntryResponse implements Parcelable {
// public IKeystoreSecurityLevel iSecurityLevel; public IKeystoreSecurityLevel iSecurityLevel;
public KeyMetadata metadata; public KeyMetadata metadata;
protected KeyEntryResponse(Parcel in) {
throw new RuntimeException("");
}
public static final Creator<KeyEntryResponse> CREATOR = new Creator<KeyEntryResponse>() { public static final Creator<KeyEntryResponse> CREATOR = new Creator<KeyEntryResponse>() {
@Override @Override
public KeyEntryResponse createFromParcel(Parcel in) { public KeyEntryResponse createFromParcel(Parcel in) {

View File

@@ -6,17 +6,13 @@ import android.os.Parcelable;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
public class KeyMetadata implements Parcelable { public class KeyMetadata implements Parcelable {
// public Authorization[] authorizations; public Authorization[] authorizations;
public byte[] certificate; public byte[] certificate;
public byte[] certificateChain; public byte[] certificateChain;
public KeyDescriptor key; public KeyDescriptor key;
public int keySecurityLevel = 0; public int keySecurityLevel = 0;
public long modificationTimeMs = 0; public long modificationTimeMs = 0;
protected KeyMetadata(Parcel in) {
throw new RuntimeException("");
}
public static final Creator<KeyMetadata> CREATOR = new Creator<KeyMetadata>() { public static final Creator<KeyMetadata> CREATOR = new Creator<KeyMetadata>() {
@Override @Override
public KeyMetadata createFromParcel(Parcel in) { public KeyMetadata createFromParcel(Parcel in) {