• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2010 The Android Open Source Project
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *      http://www.apache.org/licenses/LICENSE-2.0
9   *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  #include <utils/ObbFile.h>
18  #include <utils/String8.h>
19  
20  #include <getopt.h>
21  #include <stdio.h>
22  #include <stdlib.h>
23  #include <string.h>
24  
25  using namespace android;
26  
27  static const char* gProgName = "obbtool";
28  static const char* gProgVersion = "1.0";
29  
30  static int wantUsage = 0;
31  static int wantVersion = 0;
32  
33  #define SALT_LEN 8
34  
35  #define ADD_OPTS "n:v:os:"
36  static const struct option longopts[] = {
37      {"help",       no_argument, &wantUsage,   1},
38      {"version",    no_argument, &wantVersion, 1},
39  
40      /* Args for "add" */
41      {"name",       required_argument, NULL, 'n'},
42      {"version",    required_argument, NULL, 'v'},
43      {"overlay",    optional_argument, NULL, 'o'},
44      {"salt",       required_argument, NULL, 's'},
45  
46      {NULL, 0, NULL, '\0'}
47  };
48  
49  class PackageInfo {
50  public:
PackageInfo()51      PackageInfo()
52              : packageName(NULL)
53              , packageVersion(-1)
54              , overlay(false)
55              , salted(false)
56      {
57          memset(&salt, 0, sizeof(salt));
58      }
59  
60      char* packageName;
61      int packageVersion;
62      bool overlay;
63      bool salted;
64      unsigned char salt[SALT_LEN];
65  };
66  
67  /*
68   * Print usage info.
69   */
usage(void)70  void usage(void)
71  {
72      fprintf(stderr, "Opaque Binary Blob (OBB) Tool\n\n");
73      fprintf(stderr, "Usage:\n");
74      fprintf(stderr,
75          " %s a[dd] [ OPTIONS ] FILENAME\n"
76          "   Adds an OBB signature to the file.\n\n", gProgName);
77      fprintf(stderr,
78          "   Options:\n"
79          "     -n <package name>      sets the OBB package name (required)\n"
80          "     -v <OBB version>       sets the OBB version (required)\n"
81          "     -o                     sets the OBB overlay flag\n"
82          "     -s <8 byte hex salt>   sets the crypto key salt (if encrypted)\n"
83          "\n");
84      fprintf(stderr,
85          " %s r[emove] FILENAME\n"
86          "   Removes the OBB signature from the file.\n\n", gProgName);
87      fprintf(stderr,
88          " %s i[nfo] FILENAME\n"
89          "   Prints the OBB signature information of a file.\n\n", gProgName);
90  }
91  
doAdd(const char * filename,struct PackageInfo * info)92  void doAdd(const char* filename, struct PackageInfo* info) {
93      ObbFile *obb = new ObbFile();
94      if (obb->readFrom(filename)) {
95          fprintf(stderr, "ERROR: %s: OBB signature already present\n", filename);
96          return;
97      }
98  
99      obb->setPackageName(String8(info->packageName));
100      obb->setVersion(info->packageVersion);
101      obb->setOverlay(info->overlay);
102      if (info->salted) {
103          obb->setSalt(info->salt, SALT_LEN);
104      }
105  
106      if (!obb->writeTo(filename)) {
107          fprintf(stderr, "ERROR: %s: couldn't write OBB signature: %s\n",
108                  filename, strerror(errno));
109          return;
110      }
111  
112      fprintf(stderr, "OBB signature successfully written\n");
113  }
114  
doRemove(const char * filename)115  void doRemove(const char* filename) {
116      ObbFile *obb = new ObbFile();
117      if (!obb->readFrom(filename)) {
118          fprintf(stderr, "ERROR: %s: no OBB signature present\n", filename);
119          return;
120      }
121  
122      if (!obb->removeFrom(filename)) {
123          fprintf(stderr, "ERROR: %s: couldn't remove OBB signature\n", filename);
124          return;
125      }
126  
127      fprintf(stderr, "OBB signature successfully removed\n");
128  }
129  
doInfo(const char * filename)130  void doInfo(const char* filename) {
131      ObbFile *obb = new ObbFile();
132      if (!obb->readFrom(filename)) {
133          fprintf(stderr, "ERROR: %s: couldn't read OBB signature\n", filename);
134          return;
135      }
136  
137      printf("OBB info for '%s':\n", filename);
138      printf("Package name: %s\n", obb->getPackageName().string());
139      printf("     Version: %d\n", obb->getVersion());
140      printf("       Flags: 0x%08x\n", obb->getFlags());
141      printf("     Overlay: %s\n", obb->isOverlay() ? "true" : "false");
142      printf("        Salt: ");
143  
144      size_t saltLen;
145      const unsigned char* salt = obb->getSalt(&saltLen);
146      if (salt != NULL) {
147          for (int i = 0; i < SALT_LEN; i++) {
148              printf("%02x", salt[i]);
149          }
150          printf("\n");
151      } else {
152          printf("<empty>\n");
153      }
154  }
155  
fromHex(char h,unsigned char * b)156  bool fromHex(char h, unsigned char *b) {
157      if (h >= '0' && h <= '9') {
158          *b = h - '0';
159          return true;
160      } else if (h >= 'a' && h <= 'f') {
161          *b = h - 'a' + 10;
162          return true;
163      } else if (h >= 'A' && h <= 'F') {
164          *b = h - 'A' + 10;
165          return true;
166      }
167      return false;
168  }
169  
hexToByte(char h1,char h2,unsigned char * b)170  bool hexToByte(char h1, char h2, unsigned char* b) {
171      unsigned char first, second;
172      if (!fromHex(h1, &first)) return false;
173      if (!fromHex(h2, &second)) return false;
174      *b = (first << 4) | second;
175      return true;
176  }
177  
178  /*
179   * Parse args.
180   */
main(int argc,char * const argv[])181  int main(int argc, char* const argv[])
182  {
183      int opt;
184      int option_index = 0;
185      struct PackageInfo package_info;
186  
187      int result = 1;    // pessimistically assume an error.
188  
189      if (argc < 2) {
190          wantUsage = 1;
191          goto bail;
192      }
193  
194      while ((opt = getopt_long(argc, argv, ADD_OPTS, longopts, &option_index)) != -1) {
195          switch (opt) {
196          case 0:
197              if (longopts[option_index].flag)
198                  break;
199              fprintf(stderr, "'%s' requires an argument\n", longopts[option_index].name);
200              wantUsage = 1;
201              goto bail;
202          case 'n':
203              package_info.packageName = optarg;
204              break;
205          case 'v': {
206              char* end;
207              package_info.packageVersion = strtol(optarg, &end, 10);
208              if (*optarg == '\0' || *end != '\0') {
209                  fprintf(stderr, "ERROR: invalid version; should be integer!\n\n");
210                  wantUsage = 1;
211                  goto bail;
212              }
213              break;
214          }
215          case 'o':
216              package_info.overlay = true;
217              break;
218          case 's':
219              if (strlen(optarg) != SALT_LEN * 2) {
220                  fprintf(stderr, "ERROR: salt must be 8 bytes in hex (e.g., ABCD65031337D00D)\n\n");
221                  wantUsage = 1;
222                  goto bail;
223              }
224  
225              package_info.salted = true;
226  
227              unsigned char b;
228              for (int i = 0, j = 0; i < SALT_LEN; i++, j+=2) {
229                  if (!hexToByte(optarg[j], optarg[j+1], &b)) {
230                      fprintf(stderr, "ERROR: salt must be in hex (e.g., ABCD65031337D00D)\n");
231                      wantUsage = 1;
232                      goto bail;
233                  }
234                  package_info.salt[i] = b;
235              }
236              break;
237          case '?':
238              wantUsage = 1;
239              goto bail;
240          }
241      }
242  
243      if (wantVersion) {
244          fprintf(stderr, "%s %s\n", gProgName, gProgVersion);
245      }
246  
247      if (wantUsage) {
248          goto bail;
249      }
250  
251  #define CHECK_OP(name) \
252      if (strncmp(op, name, opsize)) { \
253          fprintf(stderr, "ERROR: unknown function '%s'!\n\n", op); \
254          wantUsage = 1; \
255          goto bail; \
256      }
257  
258      if (optind < argc) {
259          const char* op = argv[optind++];
260          const int opsize = strlen(op);
261  
262          if (optind >= argc) {
263              fprintf(stderr, "ERROR: filename required!\n\n");
264              wantUsage = 1;
265              goto bail;
266          }
267  
268          const char* filename = argv[optind++];
269  
270          switch (op[0]) {
271          case 'a':
272              CHECK_OP("add");
273              if (package_info.packageName == NULL) {
274                  fprintf(stderr, "ERROR: arguments required 'packageName' and 'version'\n");
275                  goto bail;
276              }
277              doAdd(filename, &package_info);
278              break;
279          case 'r':
280              CHECK_OP("remove");
281              doRemove(filename);
282              break;
283          case 'i':
284              CHECK_OP("info");
285              doInfo(filename);
286              break;
287          default:
288              fprintf(stderr, "ERROR: unknown command '%s'!\n\n", op);
289              wantUsage = 1;
290              goto bail;
291          }
292      }
293  
294  bail:
295      if (wantUsage) {
296          usage();
297          result = 2;
298      }
299  
300      return result;
301  }
302