Golang解析android 備份文件

我參考了一個stackoverflow上的一個項目,java解android備份文件。然后譯成了golang代碼。
總結(jié):
java語言本身雖然很老,但是人家?guī)於喟?,但是人家的流還真是好用
想念java的第x天。

整體的備份文件:xx.ab 分為兩部分

  • 不加密部分
  • 加密部分

分析

加密部分

我所解析的一個文件信息

    magic            string  
    version          int
    compress         int
    encryptionAlg    string
    userSaltHex      string
    ckSaltHex        string
    round            int
    userIvHex        string
    masterKeyBlobHex string

一些debug信息,方便了解上述具體內(nèi)容
···
agic: ANDROID BACKUP
Version: 3
Compressed: 1
Algorithm: AES-256
IV: 1539D61DC22C13259102B5F20B7E9C3D
MK: EC78A761EDAE9E578A1CAE125331BF0C1D9178781C1D997711867EE7717EC30B
MK checksum: 944120ED555A34C6559D1793A322B5B59CED1AB8B19275DB7A482984B06ED4A7
key bytes: EC78A761EDAE9E578A1CAE125331BF0C1D9178781C1D997711867EE7717EC30B
salt bytes: D12A67D559DE5B025E7D0C5D41E27A49C9E7E9502F755E23B3E964969E0AA83DD70235E41C5A72BFD2EA0E2112E36E4827AB54F20FDEFC62F353CD557983378B
Calculated MK checksum (use UTF-8: true): 944120ED555A34C6559D1793A322B5B59CED1AB8B19275DB7A482984B06ED4A7
···

按行來說明

  1. magic 有標(biāo)題的作用
  2. 版本 只支持1-4 v2版本以上要用
  3. 是否壓縮
  4. 采用的加密算法
  5. 鹽1 userSalt
  6. 鹽2 ckSalt
  7. rounds
  8. userIvHex
  9. masterkeyBlob 這就是用來加密的密鑰了

2 的一點說明

  • 在版本號>2的情況下,用UTF-8存儲信息

3 的一點說明

  • 如果是壓縮過的,那么只能用壓縮流進行解

9 的一點說明

  • 這一段由IV+密鑰共同組成

數(shù)組的第一個元素代表了IV的長度

加密部分

之后的內(nèi)容,全都是采用加密并壓縮過的密鑰流來處理,但是這里有一個蛋疼的問題,我讀*.ab文件,讀了前9行后,把之后的內(nèi)容解密,遇到了解密的bug,前面的內(nèi)容正常,后面就GG了。然后,我的辦法是,把這部份內(nèi)容寫入一個單獨的文件中。再進行解密。

處理成Go的難點

  • go中是否有加密流
  • go中是否有壓縮流
  • go中密鑰生成(填充,是否是java BC專有庫)與java是否一致

最后分析的結(jié)果(也許go的流我還不熟)

  • go中無aes cbc加密流
  • go中無壓縮流(java.util.zip.InflaterInputStream 對應(yīng)go里的啥?)
  • 手寫pkcs#5 padding
  • 密鑰生成,go沒有jce怎么搞?

解決方案

go無aes cbc加密流的搞法

先說一下go中cipher 的特點,cbc模式下,這貨會保留上一次加密的狀態(tài),也就是說,

var 加密機
加密.文本1
加密.文本2
//與下面的操作等價
var 加密機
加密.(文本1+文件2)

之前我也有一個誤區(qū),就是流加密不等于塊加密。我錯了,其實流加密,就是每次讀一定的字節(jié)數(shù)罷了,然后再讀一定的字節(jié)數(shù),與上一次的結(jié)果進行相應(yīng)模式下的操作,如,cbc異或啦。
而塊加密,則是直接把要加密的所有內(nèi)容一次性讀入內(nèi)存中。
那么,我用go,可每次只讀16B的內(nèi)容加密,好省內(nèi)存呀!還方便最后一次去填充!

func (tool *Filetool) temp2() {
    println("cbc方式讀")
    fi, _ := os.Open(tool.temp1file)
    defer fi.Close()
    aesBlockEncrypter, _ := aes.NewCipher(tool.realkey)
    aesEncrypter := cipher.NewCBCDecrypter(aesBlockEncrypter, tool.realIV)
    fo, _ := os.Create(tool.temp2file)

    defer fo.Close()
    //tmp := make([]byte, 16)
    read := make([]byte, 16)
    write := make([]byte, 16)
    frist:=true

    var n int
    for {
        n, _ = fi.Read(read)
        if n == 0 {
            fo.Write(PKCS5UnPadding(write))
            break
        } else if !frist {
            fo.Write(write)
        } else {
            frist=false
        }
        aesEncrypter.CryptBlocks(write, read)
        //copy(tmp, write)
    }
}

go中無壓縮流

這個真的很蛋疼,只能把解密之后的內(nèi)容寫入一個文件,然后再解密。

func (tool *Filetool) final() {
    inputFile, _ := os.Open(tool.temp2file) //變量指向os.Open打開的文件時生成的文件句柄
    zf, err := zlib.NewReader(inputFile)
    if err != nil {
        return
    }
    defer zf.Close()
    //tarFilePath = filepath.Join(t.parseBackupTask.backupPath, fmt.Sprintf("backup_%d.tar", api.GetEvidenceID()))
    //os.MkdirAll(filepath.Dir(path), os.ModePerm)
    tarFile:=tool.outfileh
    if err != nil {
        return
    }
    defer tarFile.Close()
    io.Copy(tarFile, zf)
}

完整代碼等我有空再傳吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容