apk-info-zip 1.1.0

A library for correctly unpacking APK files that use the BadPack technique
Documentation
//! Describes signatures contained in the `APK Signature Block`.

use serde::Serialize;

/// Describe used signature scheme in APK
///
/// Basic overview: <https://source.android.com/docs/security/features/apksigning>
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
pub enum Signature {
    /// Default signature scheme based on JAR signing
    ///
    /// See: <https://source.android.com/docs/security/features/apksigning/v2#v1-verification>
    #[serde(rename = "v1")]
    V1(Vec<CertificateInfo>),

    /// APK signature scheme v2
    ///
    /// See: <https://source.android.com/docs/security/features/apksigning/v2>
    #[serde(rename = "v2")]
    V2(Vec<CertificateInfo>),

    /// APK signature scheme v3
    ///
    /// See: <https://source.android.com/docs/security/features/apksigning/v3>
    #[serde(rename = "v3")]
    V3(Vec<CertificateInfo>),

    /// APK signature scheme v3.1
    ///
    /// See: <https://source.android.com/docs/security/features/apksigning/v3-1>
    #[serde(rename = "v31")]
    V31(Vec<CertificateInfo>),

    /// APK signature scheme v3.2
    ///
    /// See: <https://source.android.com/docs/security/features/apksigning/v3-2>
    #[serde(rename = "v32")]
    V32(Vec<CertificateInfo>),

    /// Some useful information from apk channel block
    #[serde(rename = "apk_channel_block")]
    ApkChannelBlock(String),

    /// Stamp Signing Block v1
    ///
    /// See: <https://xrefandroid.com/android-16.0.0_r2/xref/tools/apksig/src/main/java/com/android/apksig/internal/apk/stamp/SourceStampConstants.java#23>
    #[serde(rename = "stamp_block_v1")]
    StampBlockV1(CertificateInfo),

    /// Stamp Signing Block v2
    ///
    /// See: <https://xrefandroid.com/android-16.0.0_r2/xref/tools/apksig/src/main/java/com/android/apksig/internal/apk/stamp/SourceStampConstants.java#24>
    #[serde(rename = "stamp_block_v2")]
    StampBlockV2(CertificateInfo),

    /// Some Chinese packer
    ///
    /// See: <https://github.com/mcxiaoke/packer-ng-plugin/blob/ffbe05a2d27406f3aea574d083cded27f0742160/common/src/main/java/com/mcxiaoke/packer/common/PackerCommon.java#L20>
    ///
    /// Example: `75a606291d88a6c04ca9d4edfbc1b4352cf8a0aee31130f913ceee72f2dcbbbd`
    #[serde(rename = "packer_next_gen_v2")]
    PackerNextGenV2(Vec<u8>),

    /// Google Play Frosting Metadata
    ///
    /// We just highlight the presence of the block, because the full structure is unknown to anyone in public space
    ///
    /// For more details you can inspect: <https://github.com/avast/apkverifier/blob/master/signingblock/frosting.go#L23>
    #[serde(rename = "google_play_frosting")]
    GooglePlayFrosting,

    /// Some apk protector/parser, idk, seen in the wild
    ///
    /// The channel information in the ID-Value pair
    ///
    /// See: <https://edgeone.ai/document/58005>
    #[serde(rename = "vasdolly_v2")]
    VasDollyV2(String),

    /// ByteDance build config, seen in Toutiao (`com.ss.android.article.news`)
    ///
    /// Usually a JSON object with feature flags, returned as is.
    #[serde(rename = "bytedance")]
    ByteDance(String),
}

impl Signature {
    /// Sort key: signature schemes first, then source stamps, then the rest.
    pub(crate) fn order(&self) -> u8 {
        match self {
            Signature::V1(_) => 0,
            Signature::V2(_) => 1,
            Signature::V3(_) => 2,
            Signature::V31(_) => 3,
            Signature::V32(_) => 4,
            Signature::StampBlockV1(_) => 5,
            Signature::StampBlockV2(_) => 6,
            _ => 7,
        }
    }

    pub fn name(&self) -> String {
        match &self {
            Signature::V1(_) => "v1".to_owned(),
            Signature::V2(_) => "v2".to_owned(),
            Signature::V3(_) => "v3".to_owned(),
            Signature::V31(_) => "v3.1".to_owned(),
            Signature::V32(_) => "v3.2".to_owned(),
            Signature::ApkChannelBlock(_) => "APK Channel block".to_owned(),
            Signature::StampBlockV1(_) => "Stamp Block v1".to_owned(),
            Signature::StampBlockV2(_) => "Stamp Block v2".to_owned(),
            Signature::PackerNextGenV2(_) => "Packer NG v2".to_owned(),
            Signature::GooglePlayFrosting => "Google Play Frosting".to_owned(),
            Signature::VasDollyV2(_) => "v2-VasDolly".to_owned(),
            Signature::ByteDance(_) => "ByteDance".to_owned(),
        }
    }
}

/// Represents detailed information about an APK signing certificate.
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize)]
pub struct CertificateInfo {
    /// The serial number of the certificate.
    pub serial_number: String,

    /// The subject of the certificate (typically the entity that signed the APK).
    pub subject: String,

    /// The issuer of the certificate
    pub issuer: String,

    /// The date and time when the certificate becomes valid.
    pub valid_from: String,

    /// The date and time when the certificate expires.
    pub valid_until: String,

    /// The type of signature algorithm used (e.g., RSA, ECDSA).
    pub signature_type: String,

    /// MD5 fingerprint of the certificate.
    pub md5_fingerprint: String,

    /// SHA-1 fingerprint of the certificate.
    pub sha1_fingerprint: String,

    /// SHA-256 fingerprint of the certificate.
    pub sha256_fingerprint: String,
}