1/* 2 * Copyright (C) 2014 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//-------------------------------------------------------------------------------------------------- 18// 19// Module Name: GeneratePassword.cc 20// 21// Based on an IMEI and serverId input, the algorithm for generating the OMADM client password 22// and server password actually has following three steps, 23// 24// Step 1 Generate the client password key and server password key: 25// char[] clientPasswordDict = new char[] { 0x0e, 0x06, 0x10,0x0c, 0x0a, 0x0e, 0x05, 0x0c, 26// 0x12, 0x0a, 0x0b, 0x06, 0x0d, 0x0e, 0x05 }; 27// char[] serverPasswordDict = new char[] { 0x0a, 0x06, 0x0e,0x0e, 0x0a, 0x0b, 0x06, 0x0e, 28// 0x0b, 0x04, 0x04, 0x07, 0x11, 0x0c, 0x0c }; 29// 30// It defines a client password dictionary and a server password dictionary which contain 31// 15 numbers, we use client password dictionary to generate client password key and server 32// password dictionary to generate server password key. Suppose IMEI string length is n, for 33// each character in IMEI string {imei[i], 0<= i <n-3}, we generate two serial numbers using 34// following calculation, 35// 36// Serial1 += imei[i + 3] * dict[i]; 37// Serial2 += imei[i + 3] * imei[i + 2]*dict[i]; 38// 39// Note: Serial numbers are in decimal. 40// Hence we get a password KEY which is Serial1+"-"+Serial2. 41// 42// Step 2 Generate Temporary passwords: 43// We generate a MD5 digest from IMEI+KEY+serverId, then we pick No. 2,7,8,12,25,30 characters 44// from MD5 DigestStr , let is be md5key. Convert IMEI to 36 radix number, let it be newImei 45// which is always 10 characters, then we get a temporary password which is md5key+newImei. 46// 47// Step 3 Shuffle the temporary password: 48// The last step is to shuffle the temporary password got from Step 2. 49// Since the password length is 16 and n is the length which is equal to 16, 50// let P1,P2,P3,P4,...,P[n/2]-1, P[n/2], P[n/2]+1 , ... , Pn are the characters in the 51// temporary password string, we do following shuffle, 52// 53// move P[n/2]+1 between P[n/2]-1 and P[n/2], 54// .... 55// move Pn before P1. 56// Then we get Pn,P1,Pn-1,P2,....,P[n/2]-1,P[n/2]+1,P[n/2]. 57// Do the same shuffle three times, then after third time shuffle we get the password which 58// is 16 characters string. 59// 60// Usage: GeneratePassword [IMEI] [SERVER_ID] 61// 62// Example: GeneratePassword 000000011234564 motorola 63// 64// Default: IMEI = 123456789012345 65// SERVER_ID = openwave.com 66// 67 68#include <stdio.h> // printf() 69#include <stdlib.h> // exit() malloc() 70#include <string.h> // strcpy() strlen() 71#include "md5.h" 72 73#include "GeneratePassword.H" 74 75/** 76 * Initialize all the client/server password dictionaries and other values. 77 */ 78GeneratePassword::GeneratePassword() { 79 80 clientPasswordDict[0] = 0x0e; 81 clientPasswordDict[1] = 0x06; 82 clientPasswordDict[2] = 0x10; 83 clientPasswordDict[3] = 0x0c; 84 clientPasswordDict[4] = 0x0a; 85 clientPasswordDict[5] = 0x0e; 86 clientPasswordDict[6] = 0x05; 87 clientPasswordDict[7] = 0x0c; 88 clientPasswordDict[8] = 0x12; 89 clientPasswordDict[9] = 0x0a; 90 clientPasswordDict[10] = 0x0b; 91 clientPasswordDict[11] = 0x06; 92 clientPasswordDict[12] = 0x0d; 93 clientPasswordDict[13] = 0x0e; 94 clientPasswordDict[14] = 0x05; 95 96 serverPasswordDict[0] = 0x0a; 97 serverPasswordDict[1] = 0x06; 98 serverPasswordDict[2] = 0x0e; 99 serverPasswordDict[3] = 0x0e; 100 serverPasswordDict[4] = 0x0a; 101 serverPasswordDict[5] = 0x0b; 102 serverPasswordDict[6] = 0x06; 103 serverPasswordDict[7] = 0x0e; 104 serverPasswordDict[8] = 0x0b; 105 serverPasswordDict[9] = 0x04; 106 serverPasswordDict[10] = 0x04; 107 serverPasswordDict[11] = 0x07; 108 serverPasswordDict[12] = 0x11; 109 serverPasswordDict[13] = 0x0c; 110 serverPasswordDict[14] = 0x0c; 111 112 hexTable[0] = '0'; 113 hexTable[1] = '1'; 114 hexTable[2] = '2'; 115 hexTable[3] = '3'; 116 hexTable[4] = '4'; 117 hexTable[5] = '5'; 118 hexTable[6] = '6'; 119 hexTable[7] = '7'; 120 hexTable[8] = '8'; 121 hexTable[9] = '9'; 122 hexTable[10] = 'a'; 123 hexTable[11] = 'b'; 124 hexTable[12] = 'c'; 125 hexTable[13] = 'd'; 126 hexTable[14] = 'e'; 127 hexTable[15] = 'f'; 128 129 imei = "123456789012345"; 130 serverId = "openwave.com"; 131 132 char * tmpIMEI = "123456789012345"; 133 char * tmpServerId = "openwave.com"; 134 135 int len = sizeof(char) * strlen(tmpIMEI) + 1; 136 imei = (char *) malloc(len); 137 memset(imei, '\0', (len)); 138 strcpy(imei, tmpIMEI); 139 140 len = sizeof(char) * strlen(tmpServerId) + 1; 141 serverId = (char *) malloc(len); 142 memset(serverId, '\0', (len)); 143 strcpy(serverId, tmpServerId); 144 145 MD5_HASH_LENGTH = 16; 146} 147 148/** 149 * Free all dynamic allocated memories. 150 */ 151GeneratePassword::~GeneratePassword() { 152 153 if (imei != NULL) { 154 free(imei); 155 imei = NULL; 156 } 157 158 if (serverId != NULL) { 159 free(serverId); 160 serverId = NULL; 161 } 162} 163 164/** 165 * Sets the sever ID for password generation 166 * 167 * @param serverId the serverId that represent a DM server 168 */ 169void GeneratePassword::setServerId(const char * sid) { 170 if (serverId != NULL) { 171 free(serverId); 172 serverId = NULL; 173 } 174 175 int len = sizeof(char) * strlen(sid) + 1; 176 serverId = (char *) malloc(len); 177 memset(serverId, '\0', len); 178 strcpy(serverId, sid); 179} 180 181/** 182 * Sets the IMEI for password generation 183 * 184 * @param aIMEI a phone identification number 185 */ 186void GeneratePassword::setIMEI(const char * aIMEI) { 187 188 if (imei != NULL) { 189 free(imei); 190 imei = NULL; 191 } 192 193 int len = sizeof(char) * strlen(aIMEI) + 1; 194 imei = (char *) malloc(len); 195 memset(imei, '\0', len); 196 strcpy(imei, aIMEI); 197} 198 199/** 200 * Returns the IMEI number. 201 * 202 * @return a phone identification number 203 */ 204char * GeneratePassword::getIMEI() { 205 return imei; 206} 207 208/** 209 * Returns the server ID 210 * 211 * @return serverId the serverId that represent a DM server 212 */ 213char * GeneratePassword::getServerId() { 214 return serverId; 215} 216 217/** 218 * Generate a client password key with a predefined client password dictionary 219 * based on the IMEI. 220 * 221 * @param imei the imei use to generate the key 222 * @return the client password key 223 */ 224char * GeneratePassword::generateClientPasswordKey(char * imei) { 225 return generateKeyFromDict(imei, clientPasswordDict); 226} 227 228/** 229 * Generate a server password key with a predefined server password dictionary 230 * based on the IMEI. 231 * 232 * @param imei the imei use to generate the key 233 * @return the server password key 234 */ 235char * GeneratePassword::generateServerPasswordKey(char * imei) { 236 return generateKeyFromDict(imei, serverPasswordDict); 237} 238 239/** 240 * Generate a client password using a generated client password key, the IMEI, and 241 * the server ID. 242 * 243 * @return the client password 244 */ 245char * GeneratePassword::generateClientPassword() { 246 char * key = generateClientPasswordKey(imei); 247 return generatePassword(imei, serverId, key); 248} 249 250/** 251 * Generate a server password using a generated server password key, the IMEI, and 252 * the server ID. 253 * 254 * @return the server password 255 */ 256char * GeneratePassword::generateServerPassword() { 257 char * key = generateServerPasswordKey(imei); 258 return generatePassword(imei, serverId, key); 259} 260 261/** 262 * Generate a client password using a generated client password key, the IMEI, and 263 * the server ID. 264 * 265 * @param imei a phone identification number 266 * @param serverId the serverId that represent a DM server 267 * @return the client password 268 */ 269char * GeneratePassword::generateClientPassword(char * imei, char * serverId) { 270 char * key = generateClientPasswordKey(imei); 271 return generatePassword(imei, serverId, key); 272} 273 274/** 275 * Generate a server password using a generated server password key, the IMEI, and 276 * the server ID. 277 * 278 * @param imei a phone identification number 279 * @param serverId the serverId that represent a DM server 280 * @return the server password 281 */ 282char * GeneratePassword::generateServerPassword(char * imei, char * serverId) { 283 char * key = generateServerPasswordKey(imei); 284 return generatePassword(imei, serverId, key); 285} 286 287/** 288 * Generate a key with given IMEI and password dictionary. 289 * Suppose IMEI string length is n, for each character in IMEI string {imei[i], 0<= i <n-3}, 290 * we generate two serial numbers using following calculation, 291 * 292 * Serial1 += imei[i + 3] * dict[i]; 293 * Serial2 += imei[i + 3] * imei[i + 2]*dict[i]; 294 * 295 * Note: Serial numbers are in decimal. 296 * Hence we get a password KEY which is Serial1+"-"+Serial2. 297 * 298 * @param imei a phone indentification number 299 * @param dict[] a password dictionary 300 * @return a password key 301 */ 302char * GeneratePassword::generateKeyFromDict(char * imei, char dict[]) { 303 int i; 304 int length; 305 long serial1 = 0; 306 long serial2 = 0; 307 char * serial1_str; 308 char * serial2_str; 309 char * key; 310 311 length = strlen(imei); 312 313 for (i = 0; i < length - 3; i++) { 314 serial1 += imei[i + 3] * dict[i]; 315 serial2 += imei[i + 3] * imei[i + 2] * dict[i]; 316 } 317 318 serial1_str = (char *) malloc(sizeof(char) * (24)); 319 serial2_str = (char *) malloc(sizeof(char) * (24)); 320 sprintf(serial1_str, "%d", serial1); 321 sprintf(serial2_str, "%d", serial2); 322 323 key = (char *) malloc(sizeof(char) * (strlen(serial1_str) + strlen(serial2_str) + 2)); 324 memset(key, '\0', (sizeof(char) * (strlen(serial1_str) + strlen(serial2_str) + 2))); 325 326 strcat(key, (const char *)serial1_str ); 327 strcat(key, "-"); 328 strcat(key, (const char *)serial2_str ); 329 330 free(serial1_str); 331 serial1_str = NULL; 332 free(serial2_str); 333 serial2_str = NULL; 334 335 return key; 336} 337 338/** 339 * Convert an array of characters that represents a large number to a decimal number type 340 * 341 * @param input the array of characters thar represents a large number 342 * @return the decimal number 343 */ 344long long GeneratePassword::convertChar2Long(char * input) 345{ 346 char ch[2]; 347 int i; 348 long long tmp; 349 tmp = 0; 350 351 for (i=0 ; i < strlen((const char *)input) ; i++ ) { 352 ch[0]=*(input+i); 353 ch[1]='\0'; 354 tmp = (long long) ( ( (tmp) * 10) + atol((const char *)ch) ); 355 } 356 return tmp; 357} 358 359/** 360 * Convert an array of characters that represents a number in decimal based to 36 based. 361 * 362 * @param target_imei the array of characters thar represents a number in decimal based 363 * @param the 36 based number represented by array of characters. 364 */ 365char * GeneratePassword::get36BasedIMEI(char * target_imei) { 366 367 char NumericBaseData[]= "0123456789abcdefghijklmnopqrstuvwxyz"; 368 char tmp_IMEI[11]; 369 long long Quotient; 370 long Remainder; 371 int i; 372 char tmpchar; 373 374 char * IMEI36 = (char *) malloc(sizeof(char) * ( 10 + 1 )); 375 memset(IMEI36, '\0', (sizeof(char) * (10 + 1))); 376 377 long long IMEI = 0; 378 IMEI = convertChar2Long(target_imei); 379 380 i=0; 381 while ( IMEI > 0 ) { 382 Quotient = (long long)(IMEI/36); 383 Remainder = (long)(IMEI%36); 384 tmp_IMEI[i++] = NumericBaseData[Remainder]; 385 IMEI = Quotient; 386 } 387 tmp_IMEI[i]='\0'; 388 389 //If the length is <10 pad the remaining chracter to '0' to make the length 10 390 if( strlen(tmp_IMEI) < 10 ) { 391 for (i=strlen(tmp_IMEI); i<10 ; i++) { 392 tmp_IMEI[i]='0'; 393 } 394 tmp_IMEI[i]='\0'; 395 } 396 397 for( i=0 ; i < strlen(tmp_IMEI)/2 ; i++ ) { 398 tmpchar = tmp_IMEI[i]; 399 tmp_IMEI[i] = tmp_IMEI[ strlen(tmp_IMEI)-i-1]; 400 tmp_IMEI[ strlen(tmp_IMEI)-i-1] = tmpchar; 401 } 402 403 memcpy(IMEI36,tmp_IMEI,strlen(tmp_IMEI)); 404 return IMEI36; 405} 406 407/** 408 * Shuffle an array of characters. 409 * 410 * let P1,P2,P3,P4,...,P[n/2]-1, P[n/2], P[n/2]+1 , ... , Pn 411 * are the characters in the string, we do following shuffle, 412 * 413 * move P[n/2]+1 between P[n/2]-1 and P[n/2], 414 * .... 415 * move Pn before P1. 416 * Then we get 417 * Pn,P1,Pn-1,P2,....,P[n/2]-1,P[n/2]+1,P[n/2]. 418 * 419 * @param buffer the string to be shuffle 420 */ 421void GeneratePassword::shuffle(char & buffer) { 422 423 int length; 424 int secondHalfPos; 425 int insertPos; 426 char * buf; 427 char tmpchar; 428 int i; 429 int j; 430 431 insertPos = 0; 432 i=0; 433 j=0; 434 buf = & buffer; 435 length = strlen((char *)buf); 436 secondHalfPos = (length / 2); 437 438 for ( i= secondHalfPos ; i < length ; i++ ) { 439 tmpchar = (char)buf[i]; 440 insertPos = (length - i - 1); 441 for ( j = i ; j > insertPos ; j-- ) { 442 buf[j] = buf[j-1]; 443 } 444 buf[j] = tmpchar; 445 } 446} 447 448/** 449 * Convert the input data from a decimal based number to Heximal based number. 450 * 451 * @param data the decimal based number to be covert 452 * @return the Heximal based number 453 */ 454char * GeneratePassword::encodeHex(char data[]) { 455 456 int i; 457 char tmpChar; 458 int len = MD5_HASH_LENGTH; 459 printf("LEN: %d\n", len); 460 int size = len * 2 + 1; 461 char * output = (char *) malloc(sizeof(char) * size); 462 memset(output, '\0', (sizeof(char) * size)); 463 464 for ( i = 0; i < len ; i++) { 465 tmpChar = data[i]; 466 output[2*i] = hexTable[ (tmpChar & 0x0F) ]; // Get low 4 bits 467 output[(2*i)+1] = hexTable[ ((tmpChar >> 4) & 0x0F ) ]; // Get high 4 bits 468 } 469 output[2*i] = '\0'; 470 471 return output; 472} 473 474 475/** 476 * Generate a password with given IMEI, serverID, and key. 477 * We generate a MD5 digest from IMEI+KEY+serverId, then we pick No. 2,7,8,12,25,30 characters 478 * from MD5 DigestStr , let is be md5key. Convert IMEI to 36 radix number, let it be newImei 479 * which is always 10 characters, then we get a temporary password which is md5key+newImei. 480 * Finally, we shuffle the temporary password three time. 481 * 482 * @param imei the phone identification number 483 * @param serverId the server ID of a DM server. 484 * @param key the key needs to generate password 485 * @return a password 486 */ 487char * GeneratePassword::generatePassword(char * imei, char * serverId, char * key) { 488 489 char * MD5DigestStr = (char *) malloc(sizeof(char) * (strlen ((const char *)imei) + strlen(key) + strlen(serverId) +1)); 490 memset( MD5DigestStr , '\0', (sizeof(char) * ( strlen ((const char *)imei) + strlen(key) + strlen(serverId) +1 ) ) ); 491 492 strcpy( MD5DigestStr , (const char *)imei ); 493 strcat( MD5DigestStr , key ); 494 strcat( MD5DigestStr , serverId ); 495 496 printf("Before MD5: %s\n", MD5DigestStr); 497 498 MD5_CTX md5_context; 499 500 char md5hash[MD5_HASH_LENGTH + 1]; /* Add 1 character for NULL */ 501 memset(md5hash, '\0', (sizeof(char) * (MD5_HASH_LENGTH + 1))); 502 503 smlMD5Init(&md5_context); 504 smlMD5Update(&md5_context, (unsigned char *)MD5DigestStr,strlen(MD5DigestStr)); 505 smlMD5Final((unsigned char*)md5hash, &md5_context); 506 md5hash[MD5_HASH_LENGTH] = 0; 507 508 free(MD5DigestStr ); 509 MD5DigestStr =NULL; 510 511 printf("MD5 HASH: %s\n", md5hash); 512 513 char * MD5DigestStr32 = encodeHex(md5hash); 514 515 printf("Digest Str: %s\n", MD5DigestStr32); 516 517 // Pick only no. 2,7,8,12,25,30 characters from MD5 Digest String 518 519 MD5DigestStr = (char *) malloc(sizeof(char) * ( 6 + 1 )); 520 memset(MD5DigestStr, '\0', (sizeof(char) * ( 6 + 1))); 521 522 MD5DigestStr[0] = MD5DigestStr32[2]; 523 MD5DigestStr[1] = MD5DigestStr32[7]; 524 MD5DigestStr[2] = MD5DigestStr32[8]; 525 MD5DigestStr[3] = MD5DigestStr32[12]; 526 MD5DigestStr[4] = MD5DigestStr32[25]; 527 MD5DigestStr[5] = MD5DigestStr32[30]; 528 529 free(MD5DigestStr32 ); 530 MD5DigestStr32 =NULL; 531 532 //Convert IMEI to 36(base) radixnumber to generate NewIMEI 533 534 char * IMEI36 = (char *) malloc(sizeof(char) * ( 10 + 1 )); 535 memset(IMEI36, '\0', (sizeof(char) * (10 + 1))); 536 537 IMEI36 = get36BasedIMEI(imei); 538 539 //Create Password 540 541 int PWLength = strlen (MD5DigestStr) + strlen((const char *)IMEI36); //Length will be 16 542 543 char * password = (char *) malloc(sizeof(char) * ( PWLength + 1)); 544 memset( password , '\0', (sizeof(char) * ( PWLength + 1 ) ) ); //this will be of 16 + 1 545 546 strcpy( password , MD5DigestStr ); 547 strcat( password , (const char *)IMEI36 ); 548 549 free(MD5DigestStr ); 550 MD5DigestStr =NULL; 551 552 free(IMEI36); 553 IMEI36 =NULL; 554 555 free(MD5DigestStr32 ); 556 MD5DigestStr32 =NULL; 557 558 printf("BUFFER: %s\n", password); 559 560 shuffle(*password); 561 shuffle(*password); 562 shuffle(*password); 563 564 free( key ); 565 key=NULL; 566 567 return password; 568} 569