Home | History | Annotate | Download | only in static
      1 <div id="pageData-name" class="pageData">CRX Package Format</div>
      2 <div id="pageData-showTOC" class="pageData">true</div>
      3 
      4 <p>
      5 CRX files are ZIP files with a special header and the <code>.crx</code> file
      6 extension.
      7 </p>
      8 
      9 <h2>Package header</h2>
     10 
     11 <p>
     12 The header contains the author's public key and the extension's signature. 
     13 The signature is generated from the ZIP file using SHA-1 with the
     14 author's private key. The header requires a little-endian byte ordering with 
     15 4-byte alignment. The following table describes the fields of
     16 the <code>.crx</code> header in order:
     17 </p>
     18 
     19 <table>
     20   <tr>
     21     <th>Field</th><th>Type</th><th>Length</th><th>Value</th><th>Description</th>
     22   </tr>
     23   <tr>
     24     <td><em>magic number</em></td><td>char[]</td><td>32 bits</td><td>Cr24</td>
     25     <td>
     26       Chrome requires this constant at the beginning of every <code>.crx</code>
     27       package.
     28     </td>
     29   </tr>
     30   <tr>
     31     <td><em>version</em></td><td>unsigned&nbsp;int</td><td>32 bits</td><td>2</td>
     32     <td>The version of the <code>*.crx</code> file format used (currently 2).</td> 
     33   </tr>
     34   <tr>
     35     <td><em>public key length</em></td><td>unsigned&nbsp;int</td><td>32 bits</td>
     36     <td><i>pubkey.length</i></td>
     37     <td>
     38       The length of the RSA public key in <em>bytes</em>.
     39     </td>
     40   </tr>
     41   <tr>
     42     <td><em>signature length</em></td><td>unsigned&nbsp;int</td><td>32 bits</td>
     43     <td><i>sig.length</i></td>
     44     <td>
     45       The length of the signature in <em>bytes</em>.
     46     </td>
     47   </tr>
     48   <tr>
     49     <td><em>public key</em></td><td>byte[]</td><td><i>pubkey.length</i></i></td>
     50     <td><i>pubkey.contents</i></td>
     51     <td>
     52       The contents of the author's RSA public key, formatted as an X509 
     53       SubjectPublicKeyInfo block.
     54     </td>
     55   </tr>
     56   <tr>
     57     <td><em>signature</em></td><td>byte[]</td><td><i>sig.length</i></td>
     58     <td><i>sig.contents</i></td>
     59     <td>
     60       The signature of the ZIP content using the author's private key. The
     61       signature is created using the RSA algorithm with the SHA-1 hash function.
     62     </td>
     63   </tr>
     64 </table>
     65 
     66 <h2>Extension contents</h2>
     67 
     68 <p>
     69 The extension's ZIP file is appended to the <code>*.crx</code> package after the
     70 header. This should be the same ZIP file that the signature in the header
     71 was generated from.
     72 </p>
     73 
     74 <h2>Example</h2>
     75 
     76 <p>
     77 The following is an example hex dump from the beginning of a <code>.crx</code> 
     78 file.
     79 </p>
     80 
     81 <pre>
     82 43 72 32 34   # "Cr24" -- the magic number
     83 02 00 00 00   # 2 -- the crx format version number
     84 A2 00 00 00   # 162 -- length of public key in bytes
     85 80 00 00 00   # 128 -- length of signature in bytes
     86 ...........   # the contents of the public key
     87 ...........   # the contents of the signature
     88 ...........   # the contents of the zip file
     89 
     90 </pre>
     91 
     92 <h2 id="scripts">Packaging scripts</h2>
     93 <p>
     94 Members of the community have written the following scripts to package 
     95 <code>.crx</code> files.
     96 </p>
     97 
     98 <h3 id="ruby">Ruby</h3>
     99 <blockquote>
    100 <a href="http://github.com/Constellation/crxmake">github: crxmake</a>
    101 </blockquote>
    102 
    103 <h3>Bash</h3>
    104 <pre>
    105 #!/bin/bash -e
    106 #
    107 # Purpose: Pack a Chromium extension directory into crx format
    108 
    109 if test $# -ne 2; then
    110   echo "Usage: crxmake.sh &lt;extension dir&gt; &lt;pem path&gt;"
    111   exit 1
    112 fi
    113 
    114 dir=$1
    115 key=$2
    116 name=$(basename "$dir")
    117 crx="$name.crx"
    118 pub="$name.pub"
    119 sig="$name.sig"
    120 zip="$name.zip"
    121 trap 'rm -f "$pub" "$sig" "$zip"' EXIT
    122 
    123 # zip up the crx dir
    124 cwd=$(pwd -P)
    125 (cd "$dir" && zip -qr -9 -X "$cwd/$zip" .)
    126 
    127 # signature
    128 openssl sha1 -sha1 -binary -sign "$key" < "$zip" > "$sig"
    129 
    130 # public key
    131 openssl rsa -pubout -outform DER < "$key" > "$pub" 2>/dev/null
    132 
    133 byte_swap () {
    134   # Take "abcdefgh" and return it as "ghefcdab"
    135   echo "${1:6:2}${1:4:2}${1:2:2}${1:0:2}"
    136 }
    137 
    138 crmagic_hex="4372 3234" # Cr24
    139 version_hex="0200 0000" # 2
    140 pub_len_hex=$(byte_swap $(printf '%08x\n' $(ls -l "$pub" | awk '{print $5}')))
    141 sig_len_hex=$(byte_swap $(printf '%08x\n' $(ls -l "$sig" | awk '{print $5}')))
    142 (
    143   echo "$crmagic_hex $version_hex $pub_len_hex $sig_len_hex" | xxd -r -p
    144   cat "$pub" "$sig" "$zip"
    145 ) > "$crx"
    146 echo "Wrote $crx"
    147 </pre>
    148 
    149