use javax.crypto.Cipher for raw signing

- using Cipher "RSA/ECB/NoPadding" to do raw sign
 - also add .gitignore
pull/20/head
cfig 7 years ago
parent 02be1f4b9e
commit ec00936463
No known key found for this signature in database
GPG Key ID: B104C307F0FDABB7

2
.gitignore vendored

@ -0,0 +1,2 @@
.idea
.gradle

@ -133,7 +133,7 @@
| +--------------------------------+-------------------------+ | +--------------------------------+-------------------------+
| | Padding | align by block_size | | | Padding | align by block_size |
+------+--------------------------------+-------------------------+ --> + (block_size * n) +------+--------------------------------+-------------------------+ --> + (block_size * n)
+---------------------------------------+-------------------------+ +---------------------------------------+-------------------------+
| | | | | |
| | | | | |
@ -141,7 +141,7 @@
| | | | | |
| | | | | |
+--------------------------------------- -------------------------+ +--------------------------------------- -------------------------+
+---------------------------------------+-------------------------+ --> partition_size - block_size +---------------------------------------+-------------------------+ --> partition_size - block_size
| Padding | block_size - 64 | | Padding | block_size - 64 |
+---------------------------------------+-------------------------+ --> partition_size - 64 +---------------------------------------+-------------------------+ --> partition_size - 64

@ -35,9 +35,10 @@ Then put your boot.img at **$(CURDIR)/boot.img**, then start gradle 'unpack' tas
Your get the flattened kernel and /root filesystem under **$(CURDIR)/build/unzip\_boot**: Your get the flattened kernel and /root filesystem under **$(CURDIR)/build/unzip\_boot**:
build/unzip_boot/ build/unzip_boot/
├── bootimg.json ├── boot.img.avb.json (AVB only)
├── bootimg.json (boot image info)
├── kernel ├── kernel
├── second ├── second (2nd bootloader, if exists)
└── root └── root
Then you can edit the actual file contents, like rootfs or kernel. Then you can edit the actual file contents, like rootfs or kernel.
@ -76,3 +77,6 @@ https://android.googlesource.com/platform/external/bouncycastle
cpio / fs\_config cpio / fs\_config
https://android.googlesource.com/platform/system/core https://android.googlesource.com/platform/system/core
AVB
https://android.googlesource.com/platform/external/avb/

@ -6,10 +6,10 @@
| - tag | 8 | --> +0 | - tag | 8 | --> +0
| - num_bytes_following | 8 | --> +8 | - num_bytes_following | 8 | --> +8
| - hash algorithm | 8 | --> +16 | - hash algorithm | 8 | --> +16
| - partition name | 32 | | - partition name | 32 |
| - salt length | 4 | | - salt length | 4 |
| - digest length | 4 | | - digest length | 4 |
| - reserved | 60 | | - reserved | 60 |
+--------------------------------+-------------------------+ +--------------------------------+-------------------------+
| Partition name | | | Partition name | |
+--------------------------------+-------------------------+ +--------------------------------+-------------------------+

@ -19,8 +19,8 @@ import static org.junit.Assert.assertEquals;
public class Struct { public class Struct {
private static Logger log = LoggerFactory.getLogger(Struct.class); private static Logger log = LoggerFactory.getLogger(Struct.class);
public ByteOrder byteOrder = ByteOrder.LITTLE_ENDIAN; private ByteOrder byteOrder = ByteOrder.LITTLE_ENDIAN;
public List<Object[]> formats = new ArrayList<>(); private List<Object[]> formats = new ArrayList<>();
public Struct(String formatString) { public Struct(String formatString) {
Matcher m = Pattern.compile("(\\d*)([a-zA-Z])").matcher(formatString); Matcher m = Pattern.compile("(\\d*)([a-zA-Z])").matcher(formatString);
@ -97,11 +97,11 @@ public class Struct {
} }
} }
public Integer calcsize() { public Integer calcSize() {
Integer ret = 0; Integer ret = 0;
for (Object[] format : formats) { for (Object[] format : formats) {
if (format[0] == Byte.class || format[0] == Character.class || format[0] == PadByte.class) { if (format[0] == Byte.class || format[0] == Character.class || format[0] == PadByte.class) {
ret += 1 * (int) format[1]; ret += (int) format[1];
continue; continue;
} }
if (format[0] == Short.class) { if (format[0] == Short.class) {
@ -145,7 +145,8 @@ public class Struct {
for (Object[] format : this.formats) { for (Object[] format : this.formats) {
//return 'null' for padding bytes //return 'null' for padding bytes
if (format[0] == PadByte.class) { if (format[0] == PadByte.class) {
iS.skip((Integer) format[1]); long skipped = iS.skip((Integer) format[1]);
assertEquals((long) (Integer) format[1], skipped);
ret.add(null); ret.add(null);
continue; continue;
} }
@ -233,7 +234,7 @@ public class Struct {
throw new IllegalArgumentException("argument size " + args.length + throw new IllegalArgumentException("argument size " + args.length +
" doesn't match format size " + this.formats.size()); " doesn't match format size " + this.formats.size());
} }
ByteBuffer bf = ByteBuffer.allocate(this.calcsize()); ByteBuffer bf = ByteBuffer.allocate(this.calcSize());
bf.order(this.byteOrder); bf.order(this.byteOrder);
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
Object arg = args[i]; Object arg = args[i];
@ -269,7 +270,7 @@ public class Struct {
log.error("container size " + size + ", value size " + ((byte[]) arg).length); log.error("container size " + size + ", value size " + ((byte[]) arg).length);
throw new IllegalArgumentException("Index[" + i + "] arg [" + arg + "] with type [" + format + "] size overflow"); throw new IllegalArgumentException("Index[" + i + "] arg [" + arg + "] with type [" + format + "] size overflow");
} else { } else {
//perfect match log.debug("perfect match, paddingSize is zero");
} }
continue; continue;
} }
@ -338,22 +339,21 @@ public class Struct {
} else { } else {
throw new IllegalArgumentException("Index[" + i + "] Unsupported arg [" + arg + "] with type [" + format + "]"); throw new IllegalArgumentException("Index[" + i + "] Unsupported arg [" + arg + "] with type [" + format + "]");
} }
continue;
} }
} }
log.debug("Pack Result:" + Helper.Companion.toHexString(bf.array())); log.debug("Pack Result:" + Helper.Companion.toHexString(bf.array()));
return bf.array(); return bf.array();
} }
public static class UnsignedInt { private static class UnsignedInt {
} }
public static class UnsignedLong { private static class UnsignedLong {
} }
public static class UnsignedShort { private static class UnsignedShort {
} }
public static class PadByte { private static class PadByte {
} }
} }

@ -29,7 +29,7 @@ class Avb {
partition_name: String, partition_name: String,
rollback_index: Long, rollback_index: Long,
common_algorithm: String, common_algorithm: String,
common_key_path: String) { inReleaseString: String?) {
var original_image_size = 0L var original_image_size = 0L
//required libavb version //required libavb version
if (use_persistent_digest || do_not_use_ab) { if (use_persistent_digest || do_not_use_ab) {
@ -81,7 +81,6 @@ class Avb {
if (!use_persistent_digest) hd.digest = digest if (!use_persistent_digest) hd.digest = digest
log.info("encoded hash descriptor:" + Hex.encodeHexString(hd.encode())) log.info("encoded hash descriptor:" + Hex.encodeHexString(hd.encode()))
val vbmeta_blob = generateVbMetaBlob(common_algorithm, val vbmeta_blob = generateVbMetaBlob(common_algorithm,
common_key_path,
null, null,
arrayOf(hd as Descriptor), arrayOf(hd as Descriptor),
null, null,
@ -89,15 +88,8 @@ class Avb {
0, 0,
null, null,
null, null,
null, 0,
false, inReleaseString)
null,
false,
null,
null,
null,
false,
0)
log.debug("vbmeta_blob: " + Helper.toHexString(vbmeta_blob)) log.debug("vbmeta_blob: " + Helper.toHexString(vbmeta_blob))
if (hd.image_size % BLOCK_SIZE != 0L) { if (hd.image_size % BLOCK_SIZE != 0L) {
@ -124,41 +116,33 @@ class Avb {
footer.originalImageSize = original_image_size footer.originalImageSize = original_image_size
footer.vbMetaOffset = vbmeta_offset footer.vbMetaOffset = vbmeta_offset
footer.vbMetaSize = vbmeta_blob.size.toLong() footer.vbMetaSize = vbmeta_blob.size.toLong()
val footer_blob = footer.encode() val footerBob = footer.encode()
val footer_blob_with_padding = Helper.join( val footerBlobWithPadding = Helper.join(
Struct("${BLOCK_SIZE - Footer.SIZE}x").pack(null), footer_blob) Struct("${BLOCK_SIZE - Footer.SIZE}x").pack(null), footerBob)
log.info("footer:" + Helper.toHexString(footer_blob)) log.info("footer:" + Helper.toHexString(footerBob))
log.info(footer.toString()) log.info(footer.toString())
FileOutputStream(image_file, true).use { fos -> FileOutputStream(image_file, true).use { fos ->
fos.write(footer_blob_with_padding) fos.write(footerBlobWithPadding)
} }
} }
fun generateVbMetaBlob(algorithm_name: String, fun generateVbMetaBlob(algorithm_name: String,
key_path: String?,
public_key_metadata_path: String?, public_key_metadata_path: String?,
descriptors: Array<Descriptor>, descriptors: Array<Descriptor>,
chain_partitions: String?, chain_partitions: String?,
inRollbackIndex: Long, inRollbackIndex: Long,
inFlags: Long, inFlags: Long,
props: String?, props: String?,
props_from_file: String?,
kernel_cmdlines: String?, kernel_cmdlines: String?,
setup_rootfs_from_kernel: Boolean, required_libavb_version_minor: Int,
ht_desc_to_setup: String?, inReleaseString: String?): ByteArray {
include_descriptors_from_image: Boolean,
signing_helper: String?,
signing_helper_with_files: String?,
release_string: String?,
append_to_release_string: Boolean,
required_libavb_version_minor: Int): ByteArray {
//encoded descriptors //encoded descriptors
var encodedDesc: ByteArray = byteArrayOf() var encodedDesc: ByteArray = byteArrayOf()
descriptors.forEach { encodedDesc = Helper.join(encodedDesc, it.encode()) } descriptors.forEach { encodedDesc = Helper.join(encodedDesc, it.encode()) }
//algorithm //algorithm
val alg = Algorithms.get(algorithm_name)!! val alg = Algorithms.get(algorithm_name)!!
//encoded pubkey //encoded pubkey
val encodedKey = Blob.encodePubKey(alg, Files.readAllBytes(Paths.get(key_path))) val encodedKey = Blob.encodePubKey(alg)
//3 - whole aux blob //3 - whole aux blob
val auxBlob = Blob.getAuxDataBlob(encodedDesc, encodedKey) val auxBlob = Blob.getAuxDataBlob(encodedDesc, encodedKey)
@ -179,6 +163,9 @@ class Avb {
signature_offset = alg.hash_num_bytes.toLong() signature_offset = alg.hash_num_bytes.toLong()
signature_size = alg.signature_num_bytes.toLong() signature_size = alg.signature_num_bytes.toLong()
descriptors_offset = 0
descriptors_size = encodedDesc.size.toLong()
public_key_offset = descriptors_size public_key_offset = descriptors_size
public_key_size = encodedKey.size.toLong() public_key_size = encodedKey.size.toLong()
@ -186,15 +173,16 @@ class Avb {
public_key_metadata_size = 0 public_key_metadata_size = 0
public_key_metadata_offset = public_key_offset + public_key_size public_key_metadata_offset = public_key_offset + public_key_size
descriptors_offset = 0
descriptors_size = encodedDesc.size.toLong()
rollback_index = inRollbackIndex rollback_index = inRollbackIndex
flags = inFlags flags = inFlags
if (inReleaseString != null) {
log.info("Using preset release string: $inReleaseString")
this.release_string = inReleaseString
}
}.encode() }.encode()
//2 - auth blob //2 - auth blob
var authBlob = Blob.getAuthBlob(headerBlob, auxBlob, algorithm_name, key_path) var authBlob = Blob.getAuthBlob(headerBlob, auxBlob, algorithm_name)
return Helper.join(headerBlob, authBlob, auxBlob) return Helper.join(headerBlob, authBlob, auxBlob)
} }
@ -322,12 +310,12 @@ class Avb {
return ai return ai
} }
fun packVbMeta(key_path: String, info: AVBInfo? = null): ByteArray { fun packVbMeta(info: AVBInfo? = null): ByteArray {
val ai = info ?: ObjectMapper().readValue(File(getJsonFileName("vbmeta.img")), AVBInfo::class.java) val ai = info ?: ObjectMapper().readValue(File(getJsonFileName("vbmeta.img")), AVBInfo::class.java)
val alg = Algorithms.get(ai.header!!.algorithm_type.toInt())!! val alg = Algorithms.get(ai.header!!.algorithm_type.toInt())!!
val encodedDesc = ai.auxBlob!!.encodeDescriptors() val encodedDesc = ai.auxBlob!!.encodeDescriptors()
//encoded pubkey //encoded pubkey
val encodedKey = Blob.encodePubKey(alg, Files.readAllBytes(Paths.get(key_path))) val encodedKey = Blob.encodePubKey(alg, Files.readAllBytes(Paths.get(alg.defaultKey)))
//3 - whole aux blob //3 - whole aux blob
var auxBlob = byteArrayOf() var auxBlob = byteArrayOf()
@ -348,6 +336,9 @@ class Avb {
authentication_data_block_size = Helper.round_to_multiple( authentication_data_block_size = Helper.round_to_multiple(
(alg.hash_num_bytes + alg.signature_num_bytes).toLong(), 64) (alg.hash_num_bytes + alg.signature_num_bytes).toLong(), 64)
descriptors_offset = 0
descriptors_size = encodedDesc.size.toLong()
hash_offset = 0 hash_offset = 0
hash_size = alg.hash_num_bytes.toLong() hash_size = alg.hash_num_bytes.toLong()
@ -360,15 +351,12 @@ class Avb {
//TODO: support pubkey metadata //TODO: support pubkey metadata
public_key_metadata_size = 0 public_key_metadata_size = 0
public_key_metadata_offset = public_key_offset + public_key_size public_key_metadata_offset = public_key_offset + public_key_size
descriptors_offset = 0
descriptors_size = encodedDesc.size.toLong()
}.encode() }.encode()
//2 - auth blob //2 - auth blob
var authBlob = byteArrayOf() var authBlob = byteArrayOf()
if (ai.authBlob != null) { if (ai.authBlob != null) {
authBlob = Blob.getAuthBlob(headerBlob, auxBlob, alg.name, key_path) authBlob = Blob.getAuthBlob(headerBlob, auxBlob, alg.name)
} else { } else {
log.info("No auth blob") log.info("No auth blob")
} }
@ -376,8 +364,8 @@ class Avb {
return Helper.join(headerBlob, authBlob, auxBlob) return Helper.join(headerBlob, authBlob, auxBlob)
} }
fun packVbMetaWithPadding(key_path: String, info: AVBInfo? = null) { fun packVbMetaWithPadding(info: AVBInfo? = null) {
val rawBlob = packVbMeta(key_path, info) val rawBlob = packVbMeta(info)
val paddingSize = Helper.round_to_multiple(rawBlob.size.toLong(), BLOCK_SIZE) - rawBlob.size val paddingSize = Helper.round_to_multiple(rawBlob.size.toLong(), BLOCK_SIZE) - rawBlob.size
val paddedBlob = Helper.join(rawBlob, Struct("${paddingSize}x").pack(null)) val paddedBlob = Helper.join(rawBlob, Struct("${paddingSize}x").pack(null))
log.info("raw vbmeta size ${rawBlob.size}, padding size $paddingSize, total blob size ${paddedBlob.size}") log.info("raw vbmeta size ${rawBlob.size}, padding size $paddingSize, total blob size ${paddedBlob.size}")
@ -391,13 +379,8 @@ class Avb {
val AVB_VERSION_MINOR = 1 val AVB_VERSION_MINOR = 1
val AVB_VERSION_SUB = 0 val AVB_VERSION_SUB = 0
//Keep in sync with libavb/avb_footer.h.
val AVB_FOOTER_VERSION_MAJOR = 1
val AVB_FOOTER_VERSION_MINOR = 0
fun getJsonFileName(image_file: String): String { fun getJsonFileName(image_file: String): String {
val fileName = File(image_file).name val fileName = File(image_file).name
// val jsonFile = fileName.substring(0, fileName.lastIndexOf(".")) + ".json"
val jsonFile = "$fileName.avb.json" val jsonFile = "$fileName.avb.json"
return UnifiedConfig.workDir + jsonFile return UnifiedConfig.workDir + jsonFile
} }

@ -1,5 +1,6 @@
package cfig package cfig
import avb.alg.Algorithms
import cfig.io.Struct import cfig.io.Struct
import com.google.common.math.BigIntegerMath import com.google.common.math.BigIntegerMath
import org.apache.commons.codec.binary.Hex import org.apache.commons.codec.binary.Hex
@ -18,8 +19,14 @@ import java.io.*
import java.math.BigInteger import java.math.BigInteger
import java.math.RoundingMode import java.math.RoundingMode
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Paths
import java.security.KeyFactory
import java.security.PrivateKey
import java.security.spec.PKCS8EncodedKeySpec
import java.util.zip.GZIPInputStream import java.util.zip.GZIPInputStream
import java.util.zip.GZIPOutputStream import java.util.zip.GZIPOutputStream
import javax.crypto.Cipher
class Helper { class Helper {
companion object { companion object {
@ -144,7 +151,7 @@ class Helper {
} }
} }
fun extractImageData(fileName: String, outImgName: String, offset: Long, length: Int) { fun extractFile(fileName: String, outImgName: String, offset: Long, length: Int) {
if (0 == length) { if (0 == length) {
return return
} }
@ -167,7 +174,6 @@ class Helper {
} }
} }
/* /*
read RSA private key read RSA private key
assert exp == 65537 assert exp == 65537
@ -179,15 +185,14 @@ class Helper {
fun encodeRSAkey(key: ByteArray): ByteArray { fun encodeRSAkey(key: ByteArray): ByteArray {
val p2 = PemReader(InputStreamReader(ByteArrayInputStream(key))).readPemObject() val p2 = PemReader(InputStreamReader(ByteArrayInputStream(key))).readPemObject()
Assert.assertEquals("RSA PRIVATE KEY", p2.type) Assert.assertEquals("RSA PRIVATE KEY", p2.type)
val rsa = RSAPrivateKey.getInstance(p2.content) val rsa = RSAPrivateKey.getInstance(p2.content)
Assert.assertEquals(65537.toBigInteger(), rsa.publicExponent) Assert.assertEquals(65537.toBigInteger(), rsa.publicExponent)
val numBits: Int = BigIntegerMath.log2(rsa.modulus, RoundingMode.CEILING) val numBits: Int = BigIntegerMath.log2(rsa.modulus, RoundingMode.CEILING)
log.debug("modulus: " + rsa.modulus) log.debug("modulus: " + rsa.modulus)
log.debug("numBits: " + numBits) log.debug("numBits: $numBits")
val b = BigInteger.valueOf(2).pow(32) val b = BigInteger.valueOf(2).pow(32)
val n0inv = (b - rsa.modulus.modInverse(b)).toLong() val n0inv = (b - rsa.modulus.modInverse(b)).toLong()
log.debug("n0inv = " + n0inv) log.debug("n0inv = $n0inv")
val r = BigInteger.valueOf(2).pow(numBits) val r = BigInteger.valueOf(2).pow(numBits)
val rrModn = (r * r).mod(rsa.modulus) val rrModn = (r * r).mod(rsa.modulus)
log.debug("BB: " + numBits / 8 + ", mod_len: " + rsa.modulus.toByteArray().size + ", rrmodn = " + rrModn.toByteArray().size) log.debug("BB: " + numBits / 8 + ", mod_len: " + rsa.modulus.toByteArray().size + ", rrmodn = " + rrModn.toByteArray().size)
@ -203,9 +208,22 @@ class Helper {
return 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 { fun rawSign(keyPath: String, data: ByteArray): ByteArray {
// openssl rsautl -sign -inkey /Users/yu/work/boot/avb/avb_test_data/testkey_rsa4096.pem -raw val privk = Helper.readPrivateKey(keyPath)
log.debug("Raw sign data: SIZE = " + data.size) 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() var ret = byteArrayOf()
val exe = DefaultExecutor() val exe = DefaultExecutor()
val stdin = ByteArrayInputStream(data) val stdin = ByteArrayInputStream(data)
@ -215,6 +233,7 @@ class Helper {
try { try {
exe.execute(CommandLine.parse("openssl rsautl -sign -inkey $keyPath -raw")) exe.execute(CommandLine.parse("openssl rsautl -sign -inkey $keyPath -raw"))
ret = stdout.toByteArray() ret = stdout.toByteArray()
log.debug("Raw signature size = " + ret.size)
} catch (e: ExecuteException) { } catch (e: ExecuteException) {
log.error("Execute error") log.error("Execute error")
} finally { } finally {
@ -238,6 +257,12 @@ class Helper {
} }
} }
@Throws(Exception::class)
fun readPrivateKey(filename: String): PrivateKey {
val spec = PKCS8EncodedKeySpec(Files.readAllBytes(Paths.get(filename)))
return KeyFactory.getInstance("RSA").generatePrivate(spec)
}
private val log = LoggerFactory.getLogger("Helper") private val log = LoggerFactory.getLogger("Helper")
} }
} }

@ -201,20 +201,20 @@ class Parser {
log.info(imgArgs.toString()) log.info(imgArgs.toString())
log.info(imgInfo.toString()) log.info(imgInfo.toString())
Helper.extractImageData(imgArgs.output, imgArgs.kernel, imgInfo.kernelPosition.toLong(), imgInfo.kernelLength) Helper.extractFile(imgArgs.output, imgArgs.kernel, imgInfo.kernelPosition.toLong(), imgInfo.kernelLength)
log.info("kernel dumped to ${imgArgs.kernel}") log.info("kernel dumped to ${imgArgs.kernel}")
imgArgs.ramdisk?.let { ramdisk -> imgArgs.ramdisk?.let { ramdisk ->
log.info("ramdisk dumped to ${imgArgs.ramdisk}") log.info("ramdisk dumped to ${imgArgs.ramdisk}")
Helper.extractImageData(imgArgs.output, ramdisk, imgInfo.ramdiskPosition.toLong(), imgInfo.ramdiskLength) Helper.extractFile(imgArgs.output, ramdisk, imgInfo.ramdiskPosition.toLong(), imgInfo.ramdiskLength)
Helper.unGnuzipFile(ramdisk, workDir + "ramdisk.img") Helper.unGnuzipFile(ramdisk, workDir + "ramdisk.img")
unpackRamdisk(imgArgs) unpackRamdisk(imgArgs)
} }
imgArgs.second?.let { second -> imgArgs.second?.let { second ->
Helper.extractImageData(imgArgs.output, second, imgInfo.secondBootloaderPosition.toLong(), imgInfo.secondBootloaderLength) Helper.extractFile(imgArgs.output, second, imgInfo.secondBootloaderPosition.toLong(), imgInfo.secondBootloaderLength)
log.info("second bootloader dumped to ${imgArgs.second}") log.info("second bootloader dumped to ${imgArgs.second}")
} }
imgArgs.dtbo?.let { dtbo -> imgArgs.dtbo?.let { dtbo ->
Helper.extractImageData(imgArgs.output, dtbo, imgInfo.recoveryDtboPosition.toLong(), imgInfo.recoveryDtboLength) Helper.extractFile(imgArgs.output, dtbo, imgInfo.recoveryDtboPosition.toLong(), imgInfo.recoveryDtboLength)
log.info("dtbo dumped to ${imgArgs.dtbo}") log.info("dtbo dumped to ${imgArgs.dtbo}")
} }
val cfg = UnifiedConfig.fromArgs(imgArgs, imgInfo) val cfg = UnifiedConfig.fromArgs(imgArgs, imgInfo)
@ -226,10 +226,6 @@ class Parser {
companion object { companion object {
private val log = LoggerFactory.getLogger("Parser")!! private val log = LoggerFactory.getLogger("Parser")!!
fun readValues(iS: InputStream, vararg key: Any) {
}
fun readShort(iS: InputStream): Short { fun readShort(iS: InputStream): Short {
val bf = ByteBuffer.allocate(128) val bf = ByteBuffer.allocate(128)
bf.order(ByteOrder.LITTLE_ENDIAN) bf.order(ByteOrder.LITTLE_ENDIAN)

@ -1,5 +1,6 @@
package cfig package cfig
import avb.AVBInfo
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.File import java.io.File
@ -15,7 +16,7 @@ fun main(args: Array<String>) {
Avb().parseVbMeta(args[1]) Avb().parseVbMeta(args[1])
} }
"pack" -> { "pack" -> {
Avb().packVbMetaWithPadding("/Users/yu/work/boot/avb/avb_test_data/testkey_rsa4096.pem") Avb().packVbMetaWithPadding()
} }
"sign" -> { "sign" -> {
log.info("vbmeta is already signed") log.info("vbmeta is already signed")
@ -27,10 +28,13 @@ fun main(args: Array<String>) {
if (File(UnifiedConfig.workDir).exists()) File(UnifiedConfig.workDir).deleteRecursively() if (File(UnifiedConfig.workDir).exists()) File(UnifiedConfig.workDir).deleteRecursively()
File(UnifiedConfig.workDir).mkdirs() File(UnifiedConfig.workDir).mkdirs()
Parser().parseAndExtract(fileName = args[1], avbtool = args[3]) Parser().parseAndExtract(fileName = args[1], avbtool = args[3])
Avb().parseVbMeta(args[1])
if (File("vbmeta.img").exists()) { if (UnifiedConfig.readBack()[2] is ImgInfo.AvbSignature) {
Avb().parseVbMeta("vbmeta.img") log.info("continue to analyze vbmeta info in " + args[1])
Avb().parseVbMeta(args[1])
if (File("vbmeta.img").exists()) {
Avb().parseVbMeta("vbmeta.img")
}
} }
} }
"pack" -> { "pack" -> {
@ -38,15 +42,10 @@ fun main(args: Array<String>) {
} }
"sign" -> { "sign" -> {
Signer.sign(avbtool = args[3], bootSigner = args[4]) Signer.sign(avbtool = args[3], bootSigner = args[4])
val readBack = UnifiedConfig.readBack()
val readBack = ObjectMapper().readValue(File(UnifiedConfig.workDir + "bootimg.json"), if ((readBack[0] as ImgArgs).verifyType == ImgArgs.VerifyType.AVB) {
UnifiedConfig::class.java).toArgs()
val imgArgs = readBack[0] as ImgArgs
val info = readBack[1] as ImgInfo
if (imgArgs.verifyType == ImgArgs.VerifyType.AVB) {
if (File("vbmeta.img").exists()) { if (File("vbmeta.img").exists()) {
val sig = ObjectMapper().readValue( val sig = readBack[2] as ImgInfo.AvbSignature
Signer.mapToJson(info.signature as LinkedHashMap<*, *>), ImgInfo.AvbSignature::class.java)
val newBootImgInfo = Avb().parseVbMeta(args[1] + ".signed") val newBootImgInfo = Avb().parseVbMeta(args[1] + ".signed")
val hashDesc = newBootImgInfo.auxBlob!!.hashDescriptors[0] val hashDesc = newBootImgInfo.auxBlob!!.hashDescriptors[0]
val origVbMeta = ObjectMapper().readValue(File(Avb.getJsonFileName("vbmeta.img")), val origVbMeta = ObjectMapper().readValue(File(Avb.getJsonFileName("vbmeta.img")),
@ -60,7 +59,7 @@ fun main(args: Array<String>) {
} }
ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(File(Avb.getJsonFileName("vbmeta.img")), origVbMeta) ObjectMapper().writerWithDefaultPrettyPrinter().writeValue(File(Avb.getJsonFileName("vbmeta.img")), origVbMeta)
log.info("vbmeta info updated") log.info("vbmeta info updated")
Avb().packVbMetaWithPadding("/Users/yu/work/boot/avb/avb_test_data/testkey_rsa4096.pem") Avb().packVbMetaWithPadding()
} else { } else {
//no vbmeta provided //no vbmeta provided
} }

@ -1,5 +1,7 @@
package cfig package cfig
import avb.AVBInfo
import avb.alg.Algorithms
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import org.apache.commons.exec.CommandLine import org.apache.commons.exec.CommandLine
import org.apache.commons.exec.DefaultExecutor import org.apache.commons.exec.DefaultExecutor
@ -13,46 +15,51 @@ class Signer {
fun sign(avbtool: String, bootSigner: String) { fun sign(avbtool: String, bootSigner: String) {
log.info("Loading config from ${workDir}bootimg.json") log.info("Loading config from ${workDir}bootimg.json")
val cfg = ObjectMapper().readValue(File(workDir + "bootimg.json"), UnifiedConfig::class.java) val readBack = UnifiedConfig.readBack()
val readBack = cfg.toArgs()
val args = readBack[0] as ImgArgs val args = readBack[0] as ImgArgs
val info = readBack[1] as ImgInfo
when (args.verifyType) { when (args.verifyType) {
ImgArgs.VerifyType.VERIFY -> { ImgArgs.VerifyType.VERIFY -> {
log.info("Signing with verified-boot 1.0 style") log.info("Signing with verified-boot 1.0 style")
val sig = ObjectMapper().readValue( val sig = readBack[2] as ImgInfo.VeritySignature
mapToJson(info.signature as LinkedHashMap<*, *>), ImgInfo.VeritySignature::class.java)
DefaultExecutor().execute(CommandLine.parse("java -jar $bootSigner " + DefaultExecutor().execute(CommandLine.parse("java -jar $bootSigner " +
"${sig.path} ${args.output}.clear ${sig.verity_pk8} ${sig.verity_pem} ${args.output}.signed")) "${sig.path} ${args.output}.clear ${sig.verity_pk8} ${sig.verity_pem} ${args.output}.signed"))
} }
ImgArgs.VerifyType.AVB -> { ImgArgs.VerifyType.AVB -> {
log.info("Adding hash_footer with verified-boot 2.0 style") log.info("Adding hash_footer with verified-boot 2.0 style")
val sig = ObjectMapper().readValue( val sig = readBack[2] as ImgInfo.AvbSignature
mapToJson(info.signature as LinkedHashMap<*, *>), ImgInfo.AvbSignature::class.java)
File(args.output + ".clear").copyTo(File(args.output + ".signed")) File(args.output + ".clear").copyTo(File(args.output + ".signed"))
val cmdlineStr = "$avbtool add_hash_footer " + val ai = ObjectMapper().readValue(File(Avb.getJsonFileName(args.output)), AVBInfo::class.java)
val signKey = Algorithms.get(sig.algorithm!!)
var cmdlineStr = "$avbtool add_hash_footer " +
"--image ${args.output}.signed " + "--image ${args.output}.signed " +
"--partition_size ${sig.imageSize} " + "--partition_size ${sig.imageSize} " +
"--salt ${sig.salt} " + "--salt ${sig.salt} " +
"--partition_name ${sig.partName} " + "--partition_name ${sig.partName} " +
"--hash_algorithm ${sig.hashAlgorithm} " + "--hash_algorithm ${sig.hashAlgorithm} " +
"--algorithm ${sig.algorithm} " + "--algorithm ${sig.algorithm}"
"--key avb/avb_test_data/testkey_rsa4096.pem" if (signKey!!.defaultKey.isNotBlank()) {
cmdlineStr += "--key $signKey"
}
log.warn(cmdlineStr) log.warn(cmdlineStr)
DefaultExecutor().execute(CommandLine.parse(cmdlineStr)) val cmdLine = CommandLine.parse(cmdlineStr)
cmdLine.addArgument("--internal_release_string")
cmdLine.addArgument(ai.header!!.release_string, false)
DefaultExecutor().execute(cmdLine)
verifyAVBIntegrity(args, avbtool) verifyAVBIntegrity(args, avbtool)
File(args.output + ".clear").copyTo(File(args.output + ".signed2")) File(args.output + ".clear").copyTo(File(args.output + ".signed2"))
val alg = Algorithms.get(ai.header!!.algorithm_type.toInt())
Avb().add_hash_footer(args.output + ".signed2", Avb().add_hash_footer(args.output + ".signed2",
sig.imageSize!!.toLong(), sig.imageSize!!.toLong(),
false, false, false,
false,
salt = sig.salt, salt = sig.salt,
hash_algorithm = sig.hashAlgorithm!!, hash_algorithm = sig.hashAlgorithm!!,
partition_name = sig.partName!!, partition_name = sig.partName!!,
rollback_index = 0, rollback_index = ai.header!!.rollback_index,
common_algorithm = sig.algorithm!!, common_algorithm = sig.algorithm!!,
common_key_path = "avb/avb_test_data/testkey_rsa4096.pem") inReleaseString = ai.header!!.release_string)
} }
} }
} }

@ -1,7 +1,9 @@
package cfig package cfig
import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import org.slf4j.LoggerFactory import org.slf4j.LoggerFactory
import java.io.File
@JsonInclude(JsonInclude.Include.NON_NULL) @JsonInclude(JsonInclude.Include.NON_NULL)
data class UnifiedConfig( data class UnifiedConfig(
@ -136,5 +138,25 @@ data class UnifiedConfig(
return ret return ret
} }
fun readBack(): Array<Any?> {
var ret: Array<Any?> = arrayOfNulls(3)
val readBack = ObjectMapper().readValue(File(workDir + "bootimg.json"),
UnifiedConfig::class.java).toArgs()
val imgArgs = readBack[0] as ImgArgs
val info = readBack[1] as ImgInfo
if (imgArgs.verifyType == ImgArgs.VerifyType.AVB) {
val sig = ObjectMapper().readValue(
Signer.mapToJson(info.signature as LinkedHashMap<*, *>), ImgInfo.AvbSignature::class.java)
ret[2] = sig
} else {
val sig2 = ObjectMapper().readValue(
Signer.mapToJson(info.signature as LinkedHashMap<*, *>), ImgInfo.VeritySignature::class.java)
ret[2] = sig2
}
ret[0] = imgArgs
ret[1] = info
return ret
}
} }
} }

@ -1,7 +1,7 @@
package cfig package avb
import avb.*
import avb.desc.* import avb.desc.*
import cfig.Helper
/* /*
a wonderfaul base64 encoder/decoder: https://cryptii.com/base64-to-hex a wonderfaul base64 encoder/decoder: https://cryptii.com/base64-to-hex

@ -12,6 +12,18 @@ import java.security.MessageDigest
class Blob { class Blob {
companion object { companion object {
fun encodePubKey(alg: Algorithm): ByteArray {
var encodedKey = byteArrayOf()
if (alg.public_key_num_bytes > 0) {
encodedKey = Helper.encodeRSAkey(Files.readAllBytes((Paths.get(alg.defaultKey))))
log.info("encodePubKey(): size = ${alg.public_key_num_bytes}, algorithm key size: ${encodedKey.size}")
Assert.assertEquals(alg.public_key_num_bytes, encodedKey.size)
} else {
log.info("encodePubKey(): No key to encode for algorithm " + alg.name)
}
return encodedKey
}
fun encodePubKey(alg: Algorithm, key: ByteArray): ByteArray { fun encodePubKey(alg: Algorithm, key: ByteArray): ByteArray {
var encodedKey = byteArrayOf() var encodedKey = byteArrayOf()
if (alg.public_key_num_bytes > 0) { if (alg.public_key_num_bytes > 0) {
@ -35,8 +47,7 @@ class Blob {
fun getAuthBlob(header_data_blob: ByteArray, fun getAuthBlob(header_data_blob: ByteArray,
aux_data_blob: ByteArray, aux_data_blob: ByteArray,
algorithm_name: String, algorithm_name: String): ByteArray {
key_path: String?): ByteArray {
val alg = Algorithms.get(algorithm_name)!! val alg = Algorithms.get(algorithm_name)!!
val authBlockSize = Helper.round_to_multiple((alg.hash_num_bytes + alg.signature_num_bytes).toLong(), 64) val authBlockSize = Helper.round_to_multiple((alg.hash_num_bytes + alg.signature_num_bytes).toLong(), 64)
if (authBlockSize == 0L) { if (authBlockSize == 0L) {
@ -53,7 +64,7 @@ class Blob {
update(header_data_blob) update(header_data_blob)
update(aux_data_blob) update(aux_data_blob)
}.digest() }.digest()
binarySignature = Helper.rawSign(key_path!!, Helper.join(alg.padding, binaryHash)) binarySignature = Helper.rawSign(alg.defaultKey.replace(".pem", ".pk8"), Helper.join(alg.padding, binaryHash))
} }
val authData = Helper.join(binaryHash, binarySignature) val authData = Helper.join(binaryHash, binarySignature)
return Helper.join(authData, Struct("${authBlockSize - authData.size}x").pack(0)) return Helper.join(authData, Struct("${authBlockSize - authData.size}x").pack(0))

@ -20,7 +20,7 @@ data class Footer constructor(
private const val FORMAT_STRING = "!4s2L3Q${RESERVED}x" private const val FORMAT_STRING = "!4s2L3Q${RESERVED}x"
init { init {
Assert.assertEquals(SIZE, Struct(FORMAT_STRING).calcsize()) Assert.assertEquals(SIZE, Struct(FORMAT_STRING).calcSize())
} }
} }

@ -84,7 +84,7 @@ data class Header(
const val FORMAT_STRING = ("!4s2L2QL11QL${REVERSED0}x47sx" + "${REVERSED}x") const val FORMAT_STRING = ("!4s2L2QL11QL${REVERSED0}x47sx" + "${REVERSED}x")
init { init {
Assert.assertEquals(SIZE, Struct(FORMAT_STRING).calcsize()) Assert.assertEquals(SIZE, Struct(FORMAT_STRING).calcSize())
} }
} }
} }

@ -7,4 +7,5 @@ data class Algorithm(
val hash_num_bytes: Int = 0, val hash_num_bytes: Int = 0,
val signature_num_bytes: Int = 0, val signature_num_bytes: Int = 0,
val public_key_num_bytes: Int = 0, val public_key_num_bytes: Int = 0,
val padding: ByteArray = byteArrayOf()) val padding: ByteArray = byteArrayOf(),
val defaultKey: String ="")

@ -34,7 +34,8 @@ class Algorithms {
byteArrayOf(0x00), byteArrayOf(0x00),
intArrayOf(0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20))) 0x00, 0x04, 0x20)),
defaultKey = "avb/avb_test_data/testkey_rsa2048.pem")
val SHA256_RSA4096 = Algorithm( val SHA256_RSA4096 = Algorithm(
name = "SHA256_RSA4096", name = "SHA256_RSA4096",
@ -50,7 +51,8 @@ class Algorithms {
intArrayOf(0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20) 0x00, 0x04, 0x20)
) ),
defaultKey = "avb/avb_test_data/testkey_rsa4096.pem"
) )
val SHA256_RSA8192 = Algorithm( val SHA256_RSA8192 = Algorithm(
@ -66,7 +68,8 @@ class Algorithms {
0x00, 0x00,
intArrayOf(0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05,
0x00, 0x04, 0x20))) 0x00, 0x04, 0x20)),
defaultKey = "avb/avb_test_data/testkey_rsa8192.pem")
val SHA512_RSA2048 = Algorithm( val SHA512_RSA2048 = Algorithm(
name = "SHA512_RSA2048", name = "SHA512_RSA2048",
@ -81,7 +84,8 @@ class Algorithms {
0x00, 0x00,
intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40))) 0x00, 0x04, 0x40)),
defaultKey = "avb/avb_test_data/testkey_rsa2048.pem")
val SHA512_RSA4096 = Algorithm( val SHA512_RSA4096 = Algorithm(
name = "SHA512_RSA4096", name = "SHA512_RSA4096",
@ -96,7 +100,8 @@ class Algorithms {
0x00, 0x00,
intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40))) 0x00, 0x04, 0x40)),
defaultKey = "avb/avb_test_data/testkey_rsa4096.pem")
val SHA512_RSA8192 = Algorithm( val SHA512_RSA8192 = Algorithm(
name = "SHA512_RSA8192", name = "SHA512_RSA8192",
@ -112,7 +117,8 @@ class Algorithms {
0x00, 0x00,
intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, intArrayOf(0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05,
0x00, 0x04, 0x40))) 0x00, 0x04, 0x40)),
defaultKey = "avb/avb_test_data/testkey_rsa8192.pem")
algMap[NONE.name] = NONE algMap[NONE.name] = NONE

@ -45,7 +45,7 @@ class KernelCmdlineDescriptor(
const val flagHashTreeDisabled = 2 const val flagHashTreeDisabled = 2
init { init {
Assert.assertEquals(SIZE, Struct(FORMAT_STRING).calcsize()) Assert.assertEquals(SIZE, Struct(FORMAT_STRING).calcSize())
} }
} }
} }

@ -101,7 +101,7 @@ class UnknownDescriptor(var data: ByteArray = byteArrayOf()) : Descriptor(0, 0,
} }
init { init {
Assert.assertEquals(SIZE, Struct(FORMAT).calcsize()) Assert.assertEquals(SIZE, Struct(FORMAT).calcSize())
} }
} }
} }

@ -0,0 +1 @@
org.slf4j.simpleLogger.defaultLogLevel = info

@ -0,0 +1,78 @@
import avb.alg.Algorithms
import cfig.Helper
import org.apache.commons.codec.binary.Hex
import org.bouncycastle.jce.provider.BouncyCastleProvider
import org.junit.Assert.*
import org.junit.Test
import java.security.KeyFactory
import java.security.KeyPairGenerator
import java.security.Security
import java.security.Signature
import java.security.spec.PKCS8EncodedKeySpec
import java.security.spec.X509EncodedKeySpec
import javax.crypto.Cipher
class HelperTest {
@Test
fun rawSignTest() {
val data = Hex.decodeHex("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004206317a4c8d86accc8258c1ac23ef0ebd18bc33010d7afb43b241802646360b4ab")
val expectedSig = "28e17bc57406650ed78785fd558e7c1861cc4014c900d72b61c03cdbab1039e713b5bb19b556d04d276b46aae9b8a3999ccbac533a1cce00f83cfb83e2beb35ed7329f71ffec04fc2839a9b44e50abd66ea6c3d3bea6705e93e9139ecd0331170db18eba36a85a78bc49a5447260a30ed19d956cb2f8a71f6b19e57fdca43e052d1bb7840bf4c3efb47111f4d77764236d2e013fbf3b2577e4a3e01c9d166a5e890ef96210882e6e88ceca2fe3a2201f4961210d4ec6167f5dfd0e038e4a146f960caecab7d15ba65f6edcf5dbd25f5af543cfb8da4338bdbc872eec3f8e72aa8db679099e70952d3f7176c0b9111bf20ad1390eab1d09a859105816fdf92fbb"
val privkFile = "../" + Algorithms.get("SHA256_RSA2048")!!.defaultKey.replace("pem", "pk8")
val encData = Helper.rawSign(privkFile, data)
assertEquals(expectedSig, Hex.encodeHexString(encData))
}
@Test
fun rawSignOpenSslTest() {
val data = Hex.decodeHex("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004206317a4c8d86accc8258c1ac23ef0ebd18bc33010d7afb43b241802646360b4ab")
val expectedSig = "28e17bc57406650ed78785fd558e7c1861cc4014c900d72b61c03cdbab1039e713b5bb19b556d04d276b46aae9b8a3999ccbac533a1cce00f83cfb83e2beb35ed7329f71ffec04fc2839a9b44e50abd66ea6c3d3bea6705e93e9139ecd0331170db18eba36a85a78bc49a5447260a30ed19d956cb2f8a71f6b19e57fdca43e052d1bb7840bf4c3efb47111f4d77764236d2e013fbf3b2577e4a3e01c9d166a5e890ef96210882e6e88ceca2fe3a2201f4961210d4ec6167f5dfd0e038e4a146f960caecab7d15ba65f6edcf5dbd25f5af543cfb8da4338bdbc872eec3f8e72aa8db679099e70952d3f7176c0b9111bf20ad1390eab1d09a859105816fdf92fbb"
val sig = Helper.rawSignOpenSsl("../" + Algorithms.get("SHA256_RSA2048")!!.defaultKey, data)
assertEquals(expectedSig, Hex.encodeHexString(sig))
}
@Test
fun test3() {
val data = Hex.decodeHex("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff003031300d0609608648016503040201050004206317a4c8d86accc8258c1ac23ef0ebd18bc3301033")
val signature = Signature.getInstance("NONEwithRSA")
val k = Helper.readPrivateKey("../" + Algorithms.get("SHA256_RSA2048")!!.defaultKey.replace("pem", "pk8"))
signature.initSign(k)
signature.update(data)
println("data size " + data.size)
println(signature.provider)
val sig = signature.sign()
// assertEquals(expectedSig, Hex.encodeHexString(sig))
}
@Test
fun testCipher() {
Security.addProvider(BouncyCastleProvider())
for (p in Security.getProviders()) {
println(p.toString())
for (entry in p.entries) {
println("\t" + entry.key.toString() + " -> " + entry.value)
}
println()
}
}
@Test
fun testKeys() {
val kp = KeyPairGenerator.getInstance("rsa")
.apply { this.initialize(2048) }
.generateKeyPair()
val pk8Spec = PKCS8EncodedKeySpec(kp.private.encoded) //kp.private.format == PKCS#8
val x509Spec = X509EncodedKeySpec(kp.public.encoded) //kp.public.format == X.509
val kf = KeyFactory.getInstance("rsa")
val privk = kf.generatePrivate(pk8Spec)
val pubk = kf.generatePublic(x509Spec)
val cipher = Cipher.getInstance("RSA").apply {
this.init(Cipher.ENCRYPT_MODE, privk)
this.update("Good".toByteArray())
}
val encryptedText = Hex.encodeHexString(cipher.doFinal())
println(encryptedText)
}
}

@ -1,7 +1,5 @@
import cfig.Avb
import cfig.Helper import cfig.Helper
import cfig.io.Struct import cfig.io.Struct
import org.junit.Assert
import org.junit.Test import org.junit.Test
import org.junit.Assert.* import org.junit.Assert.*
@ -10,11 +8,13 @@ import java.io.ByteArrayInputStream
class StructTest { class StructTest {
@Test @Test
fun constructTest() { fun constructTest() {
assertEquals(16, Struct("<2i4b4b").calcsize()) assertEquals(16, Struct("<2i4b4b").calcSize())
assertEquals(16, Struct("<Q8b").calcsize()) assertEquals(16, Struct("<Q8b").calcSize())
assertEquals(2, Struct(">h").calcsize()) assertEquals(2, Struct(">h").calcSize())
assertEquals(3, Struct(">3s").calcsize()) assertEquals(3, Struct(">3s").calcSize())
assertEquals(4, Struct("!Hh").calcsize()) assertEquals(4, Struct("!Hh").calcSize())
Struct("<2i4b4b").dump()
try { try {
Struct("abcd") Struct("abcd")

Loading…
Cancel
Save