You've already forked TrickyStore
mirror of
https://github.com/5ec1cff/TrickyStore.git
synced 2025-09-06 06:37:07 +00:00
support generate key
This commit is contained in:
5
service/proguard-rules.pro
vendored
5
service/proguard-rules.pro
vendored
@@ -26,3 +26,8 @@
|
||||
-assumenosideeffects class io.github.a13e300.tricky_store.Logger {
|
||||
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.**
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package io.github.a13e300.tricky_store
|
||||
|
||||
import android.content.pm.IPackageManager
|
||||
import android.os.FileObserver
|
||||
import android.os.ServiceManager
|
||||
import io.github.a13e300.tricky_store.keystore.CertHack
|
||||
import java.io.File
|
||||
|
||||
object Config {
|
||||
val targetPackages = mutableSetOf<String>()
|
||||
private val hackPackages = mutableSetOf<String>()
|
||||
private val generatePackages = mutableSetOf<String>()
|
||||
private val DEFAULT_TARGET_PACKAGES = listOf(
|
||||
"com.google.android.gms",
|
||||
"icu.nullptr.nativetest",
|
||||
@@ -14,11 +17,16 @@ object Config {
|
||||
)
|
||||
|
||||
private fun updateTargetPackages(f: File?) = runCatching {
|
||||
targetPackages.clear()
|
||||
f?.readLines()?.mapNotNullTo(targetPackages) {
|
||||
if (it.isNotBlank() && !it.startsWith("#")) it else null
|
||||
hackPackages.clear()
|
||||
generatePackages.clear()
|
||||
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 {
|
||||
Logger.e("failed to update target files", it)
|
||||
}
|
||||
@@ -65,4 +73,25 @@ object Config {
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package io.github.a13e300.tricky_store
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.pm.IPackageManager
|
||||
import android.hardware.security.keymint.SecurityLevel
|
||||
import android.os.IBinder
|
||||
import android.os.Parcel
|
||||
import android.os.ServiceManager
|
||||
import android.system.keystore2.IKeystoreService
|
||||
import android.system.keystore2.KeyDescriptor
|
||||
import android.system.keystore2.KeyEntryResponse
|
||||
import io.github.a13e300.tricky_store.binder.BinderInterceptor
|
||||
import io.github.a13e300.tricky_store.keystore.CertHack
|
||||
@@ -13,17 +14,14 @@ import io.github.a13e300.tricky_store.keystore.Utils
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@SuppressLint("BlockedPrivateApi")
|
||||
object KeystoreInterceptor : BinderInterceptor() {
|
||||
private val targetTransaction = IKeystoreService.Stub::class.java.getDeclaredField("TRANSACTION_getKeyEntry").apply { isAccessible = true }.getInt(null) // 2
|
||||
object KeystoreInterceptor : BinderInterceptor() {
|
||||
private val getKeyEntryTransaction =
|
||||
getTransactCode(IKeystoreService.Stub::class.java, "getKeyEntry") // 2
|
||||
|
||||
private var iPm: IPackageManager? = null
|
||||
private lateinit var keystore: IBinder
|
||||
|
||||
private fun getPm(): IPackageManager? {
|
||||
if (iPm == null) {
|
||||
iPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"))
|
||||
}
|
||||
return iPm
|
||||
}
|
||||
private var teeInterceptor: SecurityLevelInterceptor? = null
|
||||
private var strongBoxInterceptor: SecurityLevelInterceptor? = null
|
||||
|
||||
override fun onPreTransact(
|
||||
target: IBinder,
|
||||
@@ -33,12 +31,26 @@ object KeystoreInterceptor : BinderInterceptor() {
|
||||
callingPid: Int,
|
||||
data: Parcel
|
||||
): Result {
|
||||
if (code == targetTransaction && CertHack.canHack() && Config.targetPackages.isNotEmpty()) {
|
||||
Logger.d("intercept pre $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()}")
|
||||
kotlin.runCatching {
|
||||
val ps = getPm()?.getPackagesForUid(callingUid)
|
||||
if (ps?.any { it in Config.targetPackages } == true) return Continue
|
||||
}.onFailure { Logger.e("failed to get packages", it) }
|
||||
if (code == getKeyEntryTransaction) {
|
||||
if (CertHack.canHack()) {
|
||||
Logger.d("intercept pre $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()}")
|
||||
if (Config.needGenerate(callingUid))
|
||||
kotlin.runCatching {
|
||||
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
|
||||
}
|
||||
@@ -53,7 +65,7 @@ object KeystoreInterceptor : BinderInterceptor() {
|
||||
reply: Parcel?,
|
||||
resultCode: Int
|
||||
): Result {
|
||||
if (code != targetTransaction || reply == null) return Skip
|
||||
if (target != keystore || code != getKeyEntryTransaction || reply == null) return Skip
|
||||
val p = Parcel.obtain()
|
||||
Logger.d("intercept post $target uid=$callingUid pid=$callingPid dataSz=${data.dataSize()} replySz=${reply.dataSize()}")
|
||||
try {
|
||||
@@ -61,7 +73,7 @@ object KeystoreInterceptor : BinderInterceptor() {
|
||||
val response = reply.readTypedObject(KeyEntryResponse.CREATOR)
|
||||
val chain = Utils.getCertificateChain(response)
|
||||
if (chain != null) {
|
||||
val newChain = CertHack.engineGetCertificateChain(chain)
|
||||
val newChain = CertHack.hackCertificateChain(chain)
|
||||
Utils.putCertificateChain(response, newChain)
|
||||
p.writeNoException()
|
||||
p.writeTypedObject(response, 0)
|
||||
@@ -98,8 +110,31 @@ object KeystoreInterceptor : BinderInterceptor() {
|
||||
}
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,38 @@
|
||||
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.system.keystore2.KeyDescriptor;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.bouncycastle.asn1.ASN1Boolean;
|
||||
import org.bouncycastle.asn1.ASN1Encodable;
|
||||
import org.bouncycastle.asn1.ASN1EncodableVector;
|
||||
import org.bouncycastle.asn1.ASN1Enumerated;
|
||||
import org.bouncycastle.asn1.ASN1Integer;
|
||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
||||
import org.bouncycastle.asn1.ASN1OctetString;
|
||||
import org.bouncycastle.asn1.ASN1Sequence;
|
||||
import org.bouncycastle.asn1.ASN1TaggedObject;
|
||||
import org.bouncycastle.asn1.DERNull;
|
||||
import org.bouncycastle.asn1.DEROctetString;
|
||||
import org.bouncycastle.asn1.DERSequence;
|
||||
import org.bouncycastle.asn1.DERSet;
|
||||
import org.bouncycastle.asn1.DERTaggedObject;
|
||||
import org.bouncycastle.asn1.x500.X500Name;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
import org.bouncycastle.asn1.x509.KeyUsage;
|
||||
import org.bouncycastle.cert.X509CertificateHolder;
|
||||
import org.bouncycastle.cert.X509v3CertificateBuilder;
|
||||
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.PEMParser;
|
||||
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
|
||||
@@ -25,25 +41,46 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
|
||||
import org.bouncycastle.util.io.pem.PemReader;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
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.CertificateFactory;
|
||||
import java.security.cert.CertificateParsingException;
|
||||
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.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
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.UtilKt;
|
||||
|
||||
public final class CertHack {
|
||||
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 int ATTESTATION_PACKAGE_INFO_PACKAGE_NAME_INDEX = 0;
|
||||
|
||||
private static final CertificateFactory certificateFactory;
|
||||
|
||||
@@ -55,11 +92,31 @@ public final class CertHack {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
}
|
||||
private static final int ATTESTATION_PACKAGE_INFO_VERSION_INDEX = 1;
|
||||
|
||||
public static boolean canHack() {
|
||||
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) {
|
||||
keyboxes.clear();
|
||||
if (data == null) {
|
||||
@@ -92,7 +149,9 @@ public final class CertHack {
|
||||
} else {
|
||||
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");
|
||||
} catch (Throwable t) {
|
||||
@@ -100,26 +159,7 @@ public final class CertHack {
|
||||
}
|
||||
}
|
||||
|
||||
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 Certificate[] engineGetCertificateChain(Certificate[] caList) {
|
||||
public static Certificate[] hackCertificateChain(Certificate[] caList) {
|
||||
if (caList == null) throw new UnsupportedOperationException("caList is null!");
|
||||
try {
|
||||
X509Certificate leaf = (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(caList[0].getEncoded()));
|
||||
@@ -158,14 +198,10 @@ public final class CertHack {
|
||||
holder.getNotBefore(),
|
||||
holder.getNotAfter(),
|
||||
holder.getSubject(),
|
||||
k.privateKey.getPublicKeyInfo()
|
||||
k.pemKeyPair.getPublicKeyInfo()
|
||||
);
|
||||
signer = new JcaContentSignerBuilder(leaf.getSigAlgName())
|
||||
.build(
|
||||
new JcaPEMKeyConverter()
|
||||
.getPrivateKey(k.privateKey.getPrivateKeyInfo()
|
||||
)
|
||||
);
|
||||
.build(k.keyPair.getPrivate());
|
||||
|
||||
byte[] verifiedBootKey = null;
|
||||
byte[] verifiedBootHash = null;
|
||||
@@ -221,4 +257,286 @@ public final class CertHack {
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package io.github.a13e300.tricky_store.keystore;
|
||||
|
||||
import android.system.keystore2.KeyEntryResponse;
|
||||
import android.system.keystore2.KeyMetadata;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -58,12 +59,16 @@ public class Utils {
|
||||
}
|
||||
|
||||
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;
|
||||
response.metadata.certificate = chain[0].getEncoded();
|
||||
metadata.certificate = chain[0].getEncoded();
|
||||
var output = new ByteArrayOutputStream();
|
||||
for (int i = 1; i < chain.length; i++) {
|
||||
output.write(chain[i].getEncoded());
|
||||
}
|
||||
response.metadata.certificateChain = output.toByteArray();
|
||||
metadata.certificateChain = output.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
40
service/src/main/java/io/github/a13e300/tricky_store/util.kt
Normal file
40
service/src/main/java/io/github/a13e300/tricky_store/util.kt
Normal 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)
|
||||
@@ -5,6 +5,8 @@ import android.os.IBinder;
|
||||
public interface IPackageManager {
|
||||
String[] getPackagesForUid(int uid);
|
||||
|
||||
PackageInfo getPackageInfo(String packageName, long flags, int userId);
|
||||
|
||||
class Stub {
|
||||
public static IPackageManager asInterface(IBinder binder) {
|
||||
throw new RuntimeException("");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package android.system.keystore2;
|
||||
|
||||
import android.hardware.security.keymint.KeyParameter;
|
||||
|
||||
public class Authorization {
|
||||
public KeyParameter keyParameter;
|
||||
public int securityLevel = 0;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,15 @@
|
||||
package android.system.keystore2;
|
||||
|
||||
import android.os.IBinder;
|
||||
|
||||
public interface IKeystoreService {
|
||||
String DESCRIPTOR = "android.system.keystore2.IKeystoreService";
|
||||
|
||||
class Stub {
|
||||
IKeystoreSecurityLevel getSecurityLevel(int securityLevel);
|
||||
|
||||
class Stub {
|
||||
public static IKeystoreService asInterface(IBinder b) {
|
||||
throw new RuntimeException("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,19 +11,15 @@ public class KeyDescriptor implements Parcelable {
|
||||
public int domain = 0;
|
||||
public long nspace = 0;
|
||||
|
||||
protected KeyDescriptor(Parcel in) {
|
||||
throw new RuntimeException("");
|
||||
}
|
||||
|
||||
public static final Creator<KeyDescriptor> CREATOR = new Creator<KeyDescriptor>() {
|
||||
@Override
|
||||
public KeyDescriptor createFromParcel(Parcel in) {
|
||||
return new KeyDescriptor(in);
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyDescriptor[] newArray(int size) {
|
||||
return new KeyDescriptor[size];
|
||||
throw new RuntimeException();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -6,13 +6,9 @@ import android.os.Parcelable;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class KeyEntryResponse implements Parcelable {
|
||||
// public IKeystoreSecurityLevel iSecurityLevel;
|
||||
public IKeystoreSecurityLevel iSecurityLevel;
|
||||
public KeyMetadata metadata;
|
||||
|
||||
protected KeyEntryResponse(Parcel in) {
|
||||
throw new RuntimeException("");
|
||||
}
|
||||
|
||||
public static final Creator<KeyEntryResponse> CREATOR = new Creator<KeyEntryResponse>() {
|
||||
@Override
|
||||
public KeyEntryResponse createFromParcel(Parcel in) {
|
||||
|
||||
@@ -6,17 +6,13 @@ import android.os.Parcelable;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class KeyMetadata implements Parcelable {
|
||||
// public Authorization[] authorizations;
|
||||
public Authorization[] authorizations;
|
||||
public byte[] certificate;
|
||||
public byte[] certificateChain;
|
||||
public KeyDescriptor key;
|
||||
public int keySecurityLevel = 0;
|
||||
public long modificationTimeMs = 0;
|
||||
|
||||
protected KeyMetadata(Parcel in) {
|
||||
throw new RuntimeException("");
|
||||
}
|
||||
|
||||
public static final Creator<KeyMetadata> CREATOR = new Creator<KeyMetadata>() {
|
||||
@Override
|
||||
public KeyMetadata createFromParcel(Parcel in) {
|
||||
|
||||
Reference in New Issue
Block a user