unify helpers and remove codacy

for/win
cfig 4 years ago
parent ea73a704b3
commit 30a5a0cbad
No known key found for this signature in database
GPG Key ID: B104C307F0FDABB7

@ -1,3 +0,0 @@
---
exclude_paths:
- 'aosp/**'

@ -1,6 +1,5 @@
# Android_boot_image_editor
[![Build Status](https://travis-ci.org/cfig/Android_boot_image_editor.svg?branch=master)](https://travis-ci.org/cfig/Android_boot_image_editor)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/fa6a49bb22b84307b12e7a8878867c1e)](https://app.codacy.com/manual/cfig97/Android_boot_image_editor?utm_source=github.com&utm_medium=referral&utm_content=cfig/Android_boot_image_editor&utm_campaign=Badge_Grade_Dashboard)
[![License](http://img.shields.io/:license-apache-blue.svg?style=flat-square)](http://www.apache.org/licenses/LICENSE-2.0.html)
A tool for reverse engineering Android ROM images. (working on ![Linux](doc/linux24.png)(Ubuntu 18.04+) and ![Mac](doc/apple24.png))

@ -206,7 +206,7 @@ static AvbIOResult read_from_partitionX(AvbOps *,
//seek
if (lseek(fd, offset, SEEK_SET) != offset) {
fprintf(stderr,
"[%s()]: Error seeking to pos %lld in file %s: %s\n",
"[%s()]: Error seeking to pos %ld in file %s: %s\n",
__FUNCTION__,
offset,
partitionFile.c_str(),
@ -215,7 +215,7 @@ static AvbIOResult read_from_partitionX(AvbOps *,
return AVB_IO_RESULT_ERROR_IO;
}
ssize_t num_read = read(fd, buffer, num_bytes);
if (num_read < 0) {
if (num_read < 0 || num_read != num_bytes) {
fprintf(stderr,
"[%s()]: Error reading %zd bytes from pos %" PRId64 " in file %s: %s\n",
__FUNCTION__,
@ -333,7 +333,7 @@ bool CfigAvbOps::preload_partition(std::string partition) {
auto *buffer = static_cast<uint8_t *>(malloc(file_size));
ssize_t num_read = read(fd, buffer, file_size);
if (num_read != file_size) {
if (num_read < 0 || num_read != file_size) {
fprintf(stderr,
"[%s()]: Error reading %lld bytes from file '%s': %s\n",
__FUNCTION__,

@ -2,8 +2,11 @@ package avb.blob
import avb.alg.Algorithms
import cfig.helper.Helper
import cfig.helper.KeyHelper2
import cfig.io.Struct3
import org.slf4j.LoggerFactory
import java.nio.file.Files
import java.nio.file.Paths
import java.security.MessageDigest
@OptIn(ExperimentalUnsignedTypes::class)
@ -32,7 +35,8 @@ data class AuthBlob(
update(header_data_blob)
update(aux_data_blob)
}.digest()
binarySignature = Helper.rawSign(alg.defaultKey.replace(".pem", ".pk8"), Helper.join(alg.padding, binaryHash))
val k = KeyHelper2.parseRsaPk8(Files.readAllBytes(Paths.get(alg.defaultKey.replace(".pem", ".pk8"))))
binarySignature = KeyHelper2.rawSign(k, Helper.join(alg.padding, binaryHash))
}
val authData = Helper.join(binaryHash, binarySignature)
return Helper.join(authData, Struct3("${authBlockSize - authData.size}x").pack(0))

@ -3,6 +3,8 @@ package avb.blob
import avb.alg.Algorithm
import avb.desc.*
import cfig.helper.Helper
import cfig.helper.KeyHelper
import cfig.helper.KeyHelper2
import cfig.io.Struct3
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import org.slf4j.LoggerFactory
@ -94,7 +96,7 @@ class AuxBlob(
if (key == null) {
algKey = Files.readAllBytes((Paths.get(alg.defaultKey)))
}
encodedKey = Helper.encodeRSAkey(algKey!!)
encodedKey = KeyHelper.encodeRSAkey(algKey!!)
log.info("encodePubKey(): size = ${alg.public_key_num_bytes}, algorithm key size: ${encodedKey.size}")
assert(alg.public_key_num_bytes == encodedKey.size)
} else {

@ -14,6 +14,7 @@ import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.lang.NumberFormatException
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.security.MessageDigest
@ -291,7 +292,7 @@ class Common {
ret
}
}
} catch (e: Exception) {
} catch (e: NumberFormatException) {
log.warn("can not parse osVersion from $osVersion")
10
}

@ -1,6 +1,5 @@
package cfig.helper
import cfig.KeyUtil
import cfig.io.Struct3
import com.google.common.math.BigIntegerMath
import org.apache.commons.codec.binary.Hex
@ -137,77 +136,6 @@ class Helper {
}
}
/*
read RSA private key
assert exp == 65537
num_bits = log2(modulus)
@return: AvbRSAPublicKeyHeader formatted bytearray
https://android.googlesource.com/platform/external/avb/+/master/libavb/avb_crypto.h#158
from avbtool::encode_rsa_key()
*/
fun encodeRSAkey(key: ByteArray): ByteArray {
val rsa = KeyUtil.parsePemPrivateKey(ByteArrayInputStream(key))
assert(65537.toBigInteger() == rsa.publicExponent)
val numBits: Int = BigIntegerMath.log2(rsa.modulus, RoundingMode.CEILING)
log.debug("modulus: " + rsa.modulus)
log.debug("numBits: $numBits")
val b = BigInteger.valueOf(2).pow(32)
val n0inv = (b - rsa.modulus.modInverse(b)).toLong()
log.debug("n0inv = $n0inv")
val r = BigInteger.valueOf(2).pow(numBits)
val rrModn = (r * r).mod(rsa.modulus)
log.debug("BB: " + numBits / 8 + ", mod_len: " + rsa.modulus.toByteArray().size + ", rrmodn = " + rrModn.toByteArray().size)
val unsignedModulo = rsa.modulus.toByteArray().sliceArray(1..numBits / 8) //remove sign byte
log.debug("unsigned modulo: " + Hex.encodeHexString(unsignedModulo))
val ret = Struct3("!II${numBits / 8}b${numBits / 8}b").pack(
numBits,
n0inv,
unsignedModulo,
rrModn.toByteArray())
log.debug("rrmodn: " + Hex.encodeHexString(rrModn.toByteArray()))
log.debug("RSA: " + Hex.encodeHexString(ret))
return ret
}
//inspired by
// https://stackoverflow.com/questions/40242391/how-can-i-sign-a-raw-message-without-first-hashing-it-in-bouncy-castle
// "specifying Cipher.ENCRYPT mode or Cipher.DECRYPT mode doesn't make a difference;
// both simply perform modular exponentiation"
fun rawSign(keyPath: String, data: ByteArray): ByteArray {
val privk = KeyUtil.parsePk8PrivateKey(Files.readAllBytes(Paths.get(keyPath)))
val cipher = Cipher.getInstance("RSA/ECB/NoPadding").apply {
this.init(Cipher.ENCRYPT_MODE, privk)
this.update(data)
}
return cipher.doFinal()
}
fun rawSignOpenSsl(keyPath: String, data: ByteArray): ByteArray {
log.debug("raw input: " + Hex.encodeHexString(data))
log.debug("Raw sign data size = ${data.size}, key = $keyPath")
var ret = byteArrayOf()
val exe = DefaultExecutor()
val stdin = ByteArrayInputStream(data)
val stdout = ByteArrayOutputStream()
val stderr = ByteArrayOutputStream()
exe.streamHandler = PumpStreamHandler(stdout, stderr, stdin)
try {
exe.execute(CommandLine.parse("openssl rsautl -sign -inkey $keyPath -raw"))
ret = stdout.toByteArray()
log.debug("Raw signature size = " + ret.size)
} catch (e: ExecuteException) {
log.error("Execute error")
} finally {
log.debug("OUT: " + Hex.encodeHexString(stdout.toByteArray()))
log.debug("ERR: " + String(stderr.toByteArray()))
}
if (ret.isEmpty()) throw RuntimeException("raw sign failed")
return ret
}
fun pyAlg2java(alg: String): String {
return when (alg) {
"sha1" -> "sha-1"
@ -401,7 +329,6 @@ class Helper {
return result
}
private val log = LoggerFactory.getLogger("Helper")
}
}

@ -0,0 +1,93 @@
package cfig.helper
import cfig.io.Struct3
import com.google.common.math.BigIntegerMath
import org.apache.commons.codec.binary.Hex
import org.bouncycastle.util.io.pem.PemReader
import org.slf4j.LoggerFactory
import java.io.ByteArrayInputStream
import java.io.InputStream
import java.io.InputStreamReader
import java.math.BigInteger
import java.math.RoundingMode
import java.security.Security
class KeyHelper {
companion object {
private val log = LoggerFactory.getLogger(KeyHelper::class.java)
@Throws(IllegalArgumentException::class)
fun parsePemPubkey(inputStream: InputStream): org.bouncycastle.asn1.pkcs.RSAPublicKey {
val p = PemReader(InputStreamReader(inputStream)).readPemObject()
if ("RSA PUBLIC KEY" != p.type) {
throw IllegalArgumentException("input is not valid 'RSA PUBLIC KEY'")
}
return org.bouncycastle.asn1.pkcs.RSAPublicKey.getInstance(p.content)
}
@Throws(IllegalArgumentException::class)
fun parsePemPrivateKeyBC(inputStream: InputStream): org.bouncycastle.asn1.pkcs.RSAPrivateKey {
val p = PemReader(InputStreamReader(inputStream)).readPemObject()
if ("RSA PRIVATE KEY" != p.type) {
throw IllegalArgumentException("input is not valid 'RSA PRIVATE KEY'")
}
return org.bouncycastle.asn1.pkcs.RSAPrivateKey.getInstance(p.content)
}
// fun parsePemPrivateKey(inputStream: InputStream): java.security.PrivateKey {
// val rsa = BC.parsePemPrivateKeyBC(inputStream)
// return generateRsaPrivateKey(rsa.modulus, rsa.privateExponent)
// }
/*
read RSA private key
assert exp == 65537
num_bits = log2(modulus)
@return: AvbRSAPublicKeyHeader formatted bytearray
https://android.googlesource.com/platform/external/avb/+/master/libavb/avb_crypto.h#158
from avbtool::encode_rsa_key()
*/
fun encodeRSAkey(key: ByteArray): ByteArray {
val rsa = parsePemPrivateKeyBC(ByteArrayInputStream(key))
assert(65537.toBigInteger() == rsa.publicExponent)
val numBits: Int = BigIntegerMath.log2(rsa.modulus, RoundingMode.CEILING)
log.debug("modulus: " + rsa.modulus)
log.debug("numBits: $numBits")
val b = BigInteger.valueOf(2).pow(32)
val n0inv = (b - rsa.modulus.modInverse(b)).toLong()
log.debug("n0inv = $n0inv")
val r = BigInteger.valueOf(2).pow(numBits)
val rrModn = (r * r).mod(rsa.modulus)
log.debug("BB: " + numBits / 8 + ", mod_len: " + rsa.modulus.toByteArray().size + ", rrmodn = " + rrModn.toByteArray().size)
val unsignedModulo = rsa.modulus.toByteArray().sliceArray(1..numBits / 8) //remove sign byte
log.debug("unsigned modulo: " + Hex.encodeHexString(unsignedModulo))
val ret = Struct3("!II${numBits / 8}b${numBits / 8}b").pack(
numBits,
n0inv,
unsignedModulo,
rrModn.toByteArray())
log.debug("rrmodn: " + Hex.encodeHexString(rrModn.toByteArray()))
log.debug("RSA: " + Hex.encodeHexString(ret))
return ret
}
fun listAll() {
Security.getProviders().forEach {
val sb = StringBuilder("Provider: " + it.name + "{")
it.stringPropertyNames().forEach { key ->
sb.append(" (k=" + key + ",v=" + it.getProperty(key) + "), ")
}
sb.append("}")
log.info(sb.toString())
}
var i = 0
for (item in Security.getAlgorithms("Cipher")) {
log.info("Cipher: $i -> $item")
i++
}
}
}
}

@ -0,0 +1,187 @@
package cfig.helper
import org.apache.commons.codec.binary.Hex
import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor
import org.apache.commons.exec.ExecuteException
import org.apache.commons.exec.PumpStreamHandler
import org.slf4j.LoggerFactory
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.math.BigInteger
import java.security.*
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.RSAPrivateKeySpec
import java.security.spec.RSAPublicKeySpec
import java.security.spec.X509EncodedKeySpec
import java.util.*
import javax.crypto.Cipher
class KeyHelper2 {
companion object {
private val log = LoggerFactory.getLogger(KeyHelper2::class.java)
fun parseRsaPk8(inputData: ByteArray): java.security.PrivateKey {
val spec = PKCS8EncodedKeySpec(inputData)
return KeyFactory.getInstance("RSA").generatePrivate(spec)
}
fun parseRsaKey(keyText: String): PrivateKey {
val publicKeyPEM = keyText
.replace("-----BEGIN RSA PRIVATE KEY-----", "")
.replace(System.lineSeparator().toRegex(), "")
.replace("\n", "")
.replace("\r", "")
.replace("-----END RSA PRIVATE KEY-----", "")
log.warn("trimmed key")
log.warn(publicKeyPEM)
val encoded: ByteArray = Base64.getDecoder().decode(publicKeyPEM)
val keySpec = X509EncodedKeySpec(encoded)
return KeyFactory.getInstance("RSA").generatePrivate(keySpec)
}
fun parsePemPubkey(keyText: String): java.security.interfaces.RSAPublicKey {
val publicKeyPEM = keyText
.replace("-----BEGIN PUBLIC KEY-----", "")
.replace(System.lineSeparator().toRegex(), "")
.replace("\n", "")
.replace("\r", "")
.replace("-----END PUBLIC KEY-----", "")
val encoded: ByteArray = Base64.getDecoder().decode(publicKeyPEM)
val keySpec = X509EncodedKeySpec(encoded)
return KeyFactory.getInstance("RSA").generatePublic(keySpec) as java.security.interfaces.RSAPublicKey
}
fun parsePemPubCert(keyText: String) {
val publicKeyPEM = keyText
.replace("-----BEGIN CERTIFICATE-----", "")
.replace(System.lineSeparator().toRegex(), "")
.replace("\n", "")
.replace("\r", "")
.replace("-----END CERTIFICATE-----", "")
val encoded: ByteArray = Base64.getDecoder().decode(publicKeyPEM)
val keySpec = X509EncodedKeySpec(encoded)
// return KeyFactory.getInstance("RSA").generatePublic(keySpec) as java.security.interfaces.RSAPublicKey
}
/*
in: modulus, expo
out: PublicKey
*/
fun generateRsaPublicKey(modulus: BigInteger, publicExponent: BigInteger): java.security.PublicKey {
return KeyFactory.getInstance("RSA").generatePublic(RSAPublicKeySpec(modulus, publicExponent))
}
/*
in: modulus, expo
out: PrivateKey
*/
fun generateRsaPrivateKey(modulus: BigInteger, privateExponent: BigInteger): java.security.PrivateKey {
return KeyFactory.getInstance("RSA").generatePrivate(RSAPrivateKeySpec(modulus, privateExponent))
}
//inspired by
// https://stackoverflow.com/questions/40242391/how-can-i-sign-a-raw-message-without-first-hashing-it-in-bouncy-castle
// "specifying Cipher.ENCRYPT mode or Cipher.DECRYPT mode doesn't make a difference;
// both simply perform modular exponentiation"
fun rawSign(privk: java.security.PrivateKey, data: ByteArray): ByteArray {
return Cipher.getInstance("RSA/ECB/NoPadding").let { cipher ->
cipher.init(Cipher.ENCRYPT_MODE, privk)
cipher.update(data)
cipher.doFinal()
}
}
fun rawSignOpenSsl(keyPath: String, data: ByteArray): ByteArray {
log.debug("raw input: " + Hex.encodeHexString(data))
log.debug("Raw sign data size = ${data.size}, key = $keyPath")
var ret = byteArrayOf()
val exe = DefaultExecutor()
val stdin = ByteArrayInputStream(data)
val stdout = ByteArrayOutputStream()
val stderr = ByteArrayOutputStream()
exe.streamHandler = PumpStreamHandler(stdout, stderr, stdin)
try {
exe.execute(CommandLine.parse("openssl rsautl -sign -inkey $keyPath -raw"))
ret = stdout.toByteArray()
log.debug("Raw signature size = " + ret.size)
} catch (e: ExecuteException) {
log.error("Execute error")
} finally {
log.debug("OUT: " + Hex.encodeHexString(stdout.toByteArray()))
log.debug("ERR: " + String(stderr.toByteArray()))
}
if (ret.isEmpty()) throw RuntimeException("raw sign failed")
return ret
}
fun pyAlg2java(alg: String): String {
return when (alg) {
"sha1" -> "sha-1"
"sha224" -> "sha-224"
"sha256" -> "sha-256"
"sha384" -> "sha-384"
"sha512" -> "sha-512"
else -> throw IllegalArgumentException("unknown algorithm: [$alg]")
}
}
/*
openssl dgst -sha256 <file>
*/
fun sha256(inData: ByteArray): ByteArray {
return MessageDigest.getInstance("SHA-256").digest(inData)
}
fun rsa(inData: ByteArray, inKey: java.security.PrivateKey): ByteArray {
return Cipher.getInstance("RSA").let {
it.init(Cipher.ENCRYPT_MODE, inKey)
it.doFinal(inData)
}
}
fun sha256rsa(inData: ByteArray, inKey: java.security.PrivateKey): ByteArray {
return rsa(sha256(inData), inKey)
}
fun sign(inData: ByteArray, privateKey: PrivateKey): String {
val signature = Signature.getInstance("SHA256withRSA").let {
it.initSign(privateKey)
it.update(inData)
it.sign()
}
return Base64.getEncoder().encodeToString(signature)
}
fun verify(inData: ByteArray, signature: ByteArray, pubKey: PublicKey): Boolean {
return Signature.getInstance("SHA256withRSA").let {
it.initVerify(pubKey)
it.update(inData)
it.verify(signature)
}
}
fun verify(inData: ByteArray, base64Signature: String, pubKey: PublicKey): Boolean {
val signatureBytes = Base64.getDecoder().decode(base64Signature)
return Signature.getInstance("SHA256withRSA").let {
it.initVerify(pubKey)
it.update(inData)
it.verify(signatureBytes)
}
}
fun verify2(inData: ByteArray, encrypedHash: ByteArray, inKey: java.security.PublicKey): Boolean {
val calcHash = sha256(inData)
val decrypedHash = Cipher.getInstance("RSA").let {
it.init(Cipher.DECRYPT_MODE, inKey)
it.doFinal(encrypedHash)
}
return calcHash.contentEquals(decrypedHash)
}
}
}

@ -0,0 +1,341 @@
package cfig.helper
import org.apache.commons.exec.CommandLine
import org.bouncycastle.util.encoders.Hex
import org.slf4j.LoggerFactory
import java.io.ByteArrayInputStream
import java.io.File
import java.io.FileOutputStream
import java.lang.RuntimeException
import java.util.*
class OpenSslHelper {
enum class KeyFormat {
PEM, //header + metadata + base64 der
DER // der format
}
interface IKey {
val name: String
val data: ByteArray
fun writeTo(fileName: String) {
FileOutputStream(fileName, false).use {
it.write(data)
}
}
}
class PK1Key(val format: KeyFormat = KeyFormat.PEM,
override val data: ByteArray = byteArrayOf(),
override val name: String = "RSA Private") : IKey {
/*
PEM private key -> PEM/DER public key
*/
fun getPublicKey(pubKeyFormat: KeyFormat): PK1PubKey {
if (format != KeyFormat.PEM) {
throw IllegalArgumentException("can not handle $format private key")
}
val ret = Helper.powerRun("openssl rsa -in - -pubout -outform ${pubKeyFormat.name}",
ByteArrayInputStream(data))
log.info("privateToPublic:stderr: ${String(ret[1])}")
return PK1PubKey(format = pubKeyFormat, data = ret[0])
}
/*
file based:
openssl rsa -in private.pem -pubout -out public.pem
stream based:
openssl rsa -in - -pubout
*/
fun getPk8PublicKey(): Pk8PubKey {
if (this.format != KeyFormat.PEM) {
throw java.lang.IllegalArgumentException("Only PEM key is supported")
}
val ret = Helper.powerRun2("openssl rsa -in - -pubout",
ByteArrayInputStream(data))
if (ret[0] as Boolean) {
log.info("getPk8PublicKey:error: ${String(ret[2] as ByteArray)}")
return Pk8PubKey(KeyFormat.PEM, ret[1] as ByteArray)
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw RuntimeException()
}
}
/*
file based:
openssl pkcs8 -nocrypt -in $(rsa_key) -topk8 -outform DER -out $(pk8_key)
stream based:
openssl pkcs8 -nocrypt -in - -topk8 -outform DER
*/
fun toPk8(pk8Format: KeyFormat): PK8RsaKey {
val ret = Helper.powerRun("openssl pkcs8 -nocrypt -in - -topk8 -outform ${pk8Format.name}",
ByteArrayInputStream(data))
log.info("toPk8Private:stderr: ${String(ret[1])}")
return PK8RsaKey(format = pk8Format, data = ret[0])
}
fun toCsr(): Csr {
val info = "/C=CN/ST=Shanghai/L=Shanghai/O=XXX/OU=infra/CN=gerrit/emailAddress=webmaster@XX.com"
val cmdLine = CommandLine.parse("openssl req -new -key - -subj").apply {
this.addArgument("$info", true)
}
val ret = Helper.powerRun3(cmdLine, ByteArrayInputStream(data))
if (ret[0] as Boolean) {
log.info("toCsr:error: ${String(ret[2] as ByteArray)}")
return Csr(data = ret[1] as ByteArray)
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw RuntimeException()
}
}
fun toV1Cert(): Crt {
//full command:
// openssl x509 -req -in 2017key.csr -signkey 2017key.rsa.pem -out theCert.crt -days 180
//send RSA key as input stream:
// openssl x509 -req -in 2017key.csr -signkey - -out theCert.crt -days 180
//send RSA key as input stream, crt as output stream:
// openssl x509 -req -in 2017key.csr -signkey - -days 180
val csr = this.toCsr()
val tmpFile = File.createTempFile("pk1.", ".csr")
tmpFile.writeBytes(csr.data)
tmpFile.deleteOnExit()
val ret = Helper.powerRun2("openssl x509 -req -in ${tmpFile.path} -signkey - -days 180",
ByteArrayInputStream(data))
if (ret[0] as Boolean) {
log.info("toCrt:error: ${String(ret[2] as ByteArray)}")
return Crt(ret[1] as ByteArray)
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw RuntimeException()
}
}
companion object {
/*
-> PEM RSA private key
*/
fun generate(keyLength: Int): PK1Key {
val ret = Helper.powerRun("openssl genrsa $keyLength", null)
log.info("generateRSA:stderr: ${String(ret[1])}")
return PK1Key(format = KeyFormat.PEM, data = ret[0])
}
}
}
class PK8RsaKey(val format: KeyFormat = KeyFormat.PEM,
override val data: ByteArray = byteArrayOf(),
override val name: String = "PK8 Private") : IKey {
/*
file based:
openssl pkcs8 -nocrypt -in $(pk8_key) -inform DER -out $(rsa_key).converted.tmp
openssl rsa -in $(rsa_key).converted.tmp -out $(rsa_key).converted
stream based:
openssl pkcs8 -nocrypt -in - -inform DER
openssl rsa -in - -out -
*/
fun toPk1(): PK1Key {
if (this.format != KeyFormat.PEM) {
throw IllegalArgumentException("Only pk8+pem can be converted to RSA")
}
val ret = Helper.powerRun2("openssl rsa -in -",
ByteArrayInputStream(data))
if (ret[0] as Boolean) {
log.info("toRsaPrivate:error: ${String(ret[2] as ByteArray)}")
return PK1Key(KeyFormat.PEM, ret[1] as ByteArray)
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw RuntimeException()
}
}
/*
openssl pkcs8 -nocrypt -in - -inform DER
*/
fun transform(inFormat: KeyFormat, outFormat: KeyFormat): PK8RsaKey {
val ret = Helper.powerRun2("openssl pkcs8 -nocrypt -in - -inform ${inFormat.name} -outform ${outFormat.name}",
ByteArrayInputStream(data))
if (ret[0] as Boolean) {
log.info("transform:error: ${String(ret[2] as ByteArray)}")
return PK8RsaKey(data = ret[1] as ByteArray)
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw IllegalArgumentException()
}
}
/*
file based:
openssl rsa -in pkcs8.pem -pubout -out public_pkcs8.pem
stream based:
openssl rsa -in - -pubout
*/
fun getPublicKey(): Pk8PubKey {
if (this.format != KeyFormat.PEM) {
throw java.lang.IllegalArgumentException("Only PEM key is supported")
}
val ret = Helper.powerRun2("openssl rsa -in - -pubout",
ByteArrayInputStream(data))
if (ret[0] as Boolean) {
log.info("getPublicKey:error: ${String(ret[2] as ByteArray)}")
return Pk8PubKey(KeyFormat.PEM, ret[1] as ByteArray)
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw RuntimeException()
}
}
}
class PK1PubKey(
val format: KeyFormat = KeyFormat.PEM,
override val data: ByteArray = byteArrayOf(),
override val name: String = "RSA Public"
) : IKey
class Pk8PubKey(
val format: KeyFormat = KeyFormat.PEM,
override val data: ByteArray = byteArrayOf(),
override val name: String = "Pk8 Public"
) : IKey
class Csr(override val name: String = "CSR", override val data: ByteArray = byteArrayOf()) : IKey
class Jks(override val name: String = "Java Keystore", override val data: ByteArray = byteArrayOf()) : IKey {
//keytool -list -v -deststorepass $(thePassword) -keystore $(jks_file)
fun check(passWord: String = "somepassword") {
val tmpFile = File.createTempFile("tmp.", ".jks").apply { this.deleteOnExit() }
tmpFile.writeBytes(this.data)
val ret = Helper.powerRun2("keytool -list -v -deststorepass $passWord -keystore $tmpFile",
null)
if (ret[0] as Boolean) {
log.info("Jks.check:stdout: ${String(ret[1] as ByteArray)}")
log.info("Jks.check:error: ${String(ret[2] as ByteArray)}")
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw RuntimeException()
}
}
}
class Crt(val data: ByteArray = byteArrayOf()) {
//Result: trustedCertEntry
//keytool -importcert -file 2017key.crt -deststorepass somepassword -srcstorepass somepassword -keystore 2017key.2.jks
fun toJks(paramSrcPass: String = "somepassword", paramDstPass: String = "somepassword"): Jks {
val crtFile = File.createTempFile("tmp.", ".crt").apply { this.deleteOnExit() }
crtFile.writeBytes(this.data)
val outFile = File.createTempFile("tmp.", ".jks").apply { this.delete() }
val ret = Helper.powerRun2("keytool -importcert -file ${crtFile.path}" +
" -deststorepass $paramDstPass -srcstorepass $paramSrcPass " +
" -keystore ${outFile.path}",
ByteArrayInputStream("yes\n".toByteArray()))
if (ret[0] as Boolean) {
log.info("toJks:error: ${String(ret[2] as ByteArray)}")
log.info("toJks:stdout: ${String(ret[1] as ByteArray)}")
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw RuntimeException()
}
if (!outFile.exists()) {
throw RuntimeException()
}
val outData = outFile.readBytes()
outFile.delete()
return Jks(data = outData)
}
}
class Pfx(override val name: String = "androiddebugkey",
var thePassword: String = "somepassword",
override var data: ByteArray = byteArrayOf()) : IKey {
fun generate(pk1: PK1Key, crt: Crt) {
val pk1File = File.createTempFile("tmp.", ".file").apply { this.deleteOnExit() }
pk1File.writeBytes(pk1.data)
val crtFile = File.createTempFile("tmp.", ".file").apply { this.deleteOnExit() }
crtFile.writeBytes(crt.data)
//openssl pkcs12 -export -out $(pfx_cert) -inkey $(rsa_key) -in $(crt_file) -password pass:$(thePassword) -name $(thePfxName)
val cmd = "openssl pkcs12 -export " +
" -inkey ${pk1File.path} " +
" -in ${crtFile.path} " +
" -password pass:${this.thePassword} -name ${this.name}"
val ret = Helper.powerRun2(cmd, null)
if (ret[0] as Boolean) {
log.info("toPfx:error: ${String(ret[2] as ByteArray)}")
log.info("toPfx:stdout: ${Hex.toHexString(ret[1] as ByteArray)}")
this.data = ret[1] as ByteArray
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw RuntimeException()
}
}
//Zkeytool -importkeystore -deststorepass $(thePassword) -destkeystore $(jks_file) -srckeystore $(pfx_cert) -srcstoretype PKCS12 -srcstorepass $(thePassword)
fun toJks(): Jks {
val jksFile = File.createTempFile("tmp.", ".file").apply { this.delete() }
val thisFile = File.createTempFile("tmp.", ".file").apply { this.deleteOnExit() }
thisFile.writeBytes(this.data)
val cmd = "keytool -importkeystore " +
" -srcstorepass $thePassword -deststorepass $thePassword " +
" -destkeystore ${jksFile.path} " +
" -srckeystore $thisFile -srcstoretype PKCS12"
val ret = Helper.powerRun2(cmd, null)
if (ret[0] as Boolean) {
log.info("toJks:error: " + String(ret[2] as ByteArray))
log.info("toJks:stdout: " + String(ret[1] as ByteArray))
this.data = ret[1] as ByteArray
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw RuntimeException()
}
val outDate = jksFile.readBytes()
jksFile.delete()
return Jks(this.name, outDate)
}
}
companion object {
private val log = LoggerFactory.getLogger(OpenSslHelper::class.java)
fun decodePem(keyText: String): ByteArray {
val publicKeyPEM = keyText
.replace("-----BEGIN .*-----".toRegex(), "")
.replace(System.lineSeparator().toRegex(), "")
.replace("\n", "")
.replace("\r", "")
.replace("-----END .*-----".toRegex(), "")
return Base64.getDecoder().decode(publicKeyPEM)
}
fun toPfx(password: String = "somepassword", keyName: String = "androiddebugkey", pk1: PK1Key, crt: Crt) {
val pk1File = File.createTempFile("tmp.", ".file").apply { this.deleteOnExit() }
pk1File.writeBytes(pk1.data)
val crtFile = File.createTempFile("tmp.", ".file").apply { this.deleteOnExit() }
crtFile.writeBytes(crt.data)
//openssl pkcs12 -export -out $(pfx_cert) -inkey $(rsa_key) -in $(crt_file) -password pass:$(thePassword) -name $(thePfxName)
val cmd = "openssl pkcs12 -export -inkey ${pk1File.path} -in ${crtFile.path} -password pass:$password -name $keyName"
val ret = Helper.powerRun2(cmd, null)
if (ret[0] as Boolean) {
log.info("toPfx:error: ${String(ret[2] as ByteArray)}")
log.info("toPfx:stdout: ${Hex.toHexString(ret[1] as ByteArray)}")
} else {
log.error("stdout: " + String(ret[1] as ByteArray))
log.error("stderr: " + String(ret[2] as ByteArray))
throw RuntimeException()
}
}
}
}

@ -1,14 +1,12 @@
import avb.alg.Algorithms
import cfig.KeyUtil
import cfig.helper.Helper
import cfig.helper.KeyHelper2
import com.google.common.math.BigIntegerMath
import org.apache.commons.codec.binary.Hex
import org.apache.commons.compress.compressors.lz4.FramedLZ4CompressorInputStream
import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.junit.Assert.assertEquals
import org.junit.Test
import org.slf4j.LoggerFactory
import java.io.*
import java.math.BigInteger
import java.math.RoundingMode
import java.nio.file.Files
@ -31,7 +29,8 @@ class HelperTest {
val data = Hex.decodeHex("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004206317a4c8d86accc8258c1ac23ef0ebd18bc33010d7afb43b241802646360b4ab")
val expectedSig = "28e17bc57406650ed78785fd558e7c1861cc4014c900d72b61c03cdbab1039e713b5bb19b556d04d276b46aae9b8a3999ccbac533a1cce00f83cfb83e2beb35ed7329f71ffec04fc2839a9b44e50abd66ea6c3d3bea6705e93e9139ecd0331170db18eba36a85a78bc49a5447260a30ed19d956cb2f8a71f6b19e57fdca43e052d1bb7840bf4c3efb47111f4d77764236d2e013fbf3b2577e4a3e01c9d166a5e890ef96210882e6e88ceca2fe3a2201f4961210d4ec6167f5dfd0e038e4a146f960caecab7d15ba65f6edcf5dbd25f5af543cfb8da4338bdbc872eec3f8e72aa8db679099e70952d3f7176c0b9111bf20ad1390eab1d09a859105816fdf92fbb"
val privkFile = "../" + Algorithms.get("SHA256_RSA2048")!!.defaultKey.replace("pem", "pk8")
val encData = Helper.rawSign(privkFile, data)
val k = KeyHelper2.parseRsaPk8(Files.readAllBytes(Paths.get(privkFile)))
val encData = KeyHelper2.rawSign(k, data)
assertEquals(expectedSig, Hex.encodeHexString(encData))
}
@ -39,8 +38,7 @@ class HelperTest {
fun rawSignOpenSslTest() {
val data = Hex.decodeHex("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004206317a4c8d86accc8258c1ac23ef0ebd18bc33010d7afb43b241802646360b4ab")
val expectedSig = "28e17bc57406650ed78785fd558e7c1861cc4014c900d72b61c03cdbab1039e713b5bb19b556d04d276b46aae9b8a3999ccbac533a1cce00f83cfb83e2beb35ed7329f71ffec04fc2839a9b44e50abd66ea6c3d3bea6705e93e9139ecd0331170db18eba36a85a78bc49a5447260a30ed19d956cb2f8a71f6b19e57fdca43e052d1bb7840bf4c3efb47111f4d77764236d2e013fbf3b2577e4a3e01c9d166a5e890ef96210882e6e88ceca2fe3a2201f4961210d4ec6167f5dfd0e038e4a146f960caecab7d15ba65f6edcf5dbd25f5af543cfb8da4338bdbc872eec3f8e72aa8db679099e70952d3f7176c0b9111bf20ad1390eab1d09a859105816fdf92fbb"
val sig = Helper.rawSignOpenSsl("../" + Algorithms.get("SHA256_RSA2048")!!.defaultKey, data)
val sig = KeyHelper2.rawSignOpenSsl("../" + Algorithms.get("SHA256_RSA2048")!!.defaultKey, data)
assertEquals(expectedSig, Hex.encodeHexString(sig))
}

@ -1 +1 @@
Subproject commit 23b636091aa768f141266dafa14f89fb4417eb5a
Subproject commit d95de4b8d5d5fa7d36f3696e14be23d22fcdf7f5

@ -4,19 +4,14 @@
#
import subprocess
"""
"""
def run(cmd):
print(cmd)
subprocess.check_call(cmd, shell = True)
run("touch vbmeta.img")
run("gradle pull")
run("gradle unpack")
run('vim build/unzip_boot/vbmeta.avb.json -c ":19s/0/2/g" -c ":wq"')
run('vim -u NONE -N build/unzip_boot/vbmeta.avb.json -c ":19s/0/2/g" -c ":wq"')
run("gradle pack")
run("gradle flash")

Loading…
Cancel
Save