├── 20200212 ├── AndroidBase64.java ├── Cipher.java ├── ContextHolder.java ├── Mac.java ├── MessageDigest.java └── MyUtil.java ├── 8.1.0_r1.zip └── README.md /20200212/AndroidBase64.java: -------------------------------------------------------------------------------- 1 | package javax.crypto; 2 | 3 | /* 4 | * Copyright (C) 2010 The Android Open Source Project 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | import java.io.UnsupportedEncodingException; 19 | /** 20 | * Utilities for encoding and decoding the Base64 representation of 21 | * binary data. See RFCs 2045 and 3548. 24 | */ 25 | public class AndroidBase64 { 26 | /** 27 | * Default values for encoder/decoder flags. 28 | */ 29 | public static final int DEFAULT = 0; 30 | /** 31 | * Encoder flag bit to omit the padding '=' characters at the end 32 | * of the output (if any). 33 | */ 34 | public static final int NO_PADDING = 1; 35 | /** 36 | * Encoder flag bit to omit all line terminators (i.e., the output 37 | * will be on one long line). 38 | */ 39 | public static final int NO_WRAP = 2; 40 | /** 41 | * Encoder flag bit to indicate lines should be terminated with a 42 | * CRLF pair instead of just an LF. Has no effect if {@code 43 | * NO_WRAP} is specified as well. 44 | */ 45 | public static final int CRLF = 4; 46 | /** 47 | * Encoder/decoder flag bit to indicate using the "URL and 48 | * filename safe" variant of Base64 (see RFC 3548 section 4) where 49 | * {@code -} and {@code _} are used in place of {@code +} and 50 | * {@code /}. 51 | */ 52 | public static final int URL_SAFE = 8; 53 | public static final int NO_CLOSE = 16; 54 | // -------------------------------------------------------- 55 | // shared code 56 | // -------------------------------------------------------- 57 | /* package */ static abstract class Coder { 58 | public byte[] output; 59 | public int op; 60 | /** 61 | * Encode/decode another block of input data. this.output is 62 | * provided by the caller, and must be big enough to hold all 63 | * the coded data. On exit, this.opwill be set to the length 64 | * of the coded data. 65 | * 66 | * @param finish true if this is the final call to process for 67 | * this object. Will finalize the coder state and 68 | * include any final bytes in the output. 69 | * 70 | * @return true if the input so far is good; false if some 71 | * error has been detected in the input stream.. 72 | */ 73 | public abstract boolean process(byte[] input, int offset, int len, boolean finish); 74 | /** 75 | * @return the maximum number of bytes a call to process() 76 | * could produce for the given number of input bytes. This may 77 | * be an overestimate. 78 | */ 79 | public abstract int maxOutputSize(int len); 80 | } 81 | // -------------------------------------------------------- 82 | // decoding 83 | // -------------------------------------------------------- 84 | /** 85 | * Decode the Base64-encoded data in input and return the data in 86 | * a new byte array. 87 | * 88 | *

The padding '=' characters at the end are considered optional, but 89 | * if any are present, there must be the correct number of them. 90 | * 91 | * @param str the input String to decode, which is converted to 92 | * bytes using the default charset 93 | * @param flags controls certain features of the decoded output. 94 | * Pass {@code DEFAULT} to decode standard Base64. 95 | * 96 | * @throws IllegalArgumentException if the input contains 97 | * incorrect padding 98 | */ 99 | public static byte[] decode(String str, int flags) { 100 | return decode(str.getBytes(), flags); 101 | } 102 | /** 103 | * Decode the Base64-encoded data in input and return the data in 104 | * a new byte array. 105 | * 106 | *

The padding '=' characters at the end are considered optional, but 107 | * if any are present, there must be the correct number of them. 108 | * 109 | * @param input the input array to decode 110 | * @param flags controls certain features of the decoded output. 111 | * Pass {@code DEFAULT} to decode standard Base64. 112 | * 113 | * @throws IllegalArgumentException if the input contains 114 | * incorrect padding 115 | */ 116 | public static byte[] decode(byte[] input, int flags) { 117 | return decode(input, 0, input.length, flags); 118 | } 119 | /** 120 | * Decode the Base64-encoded data in input and return the data in 121 | * a new byte array. 122 | * 123 | *

The padding '=' characters at the end are considered optional, but 124 | * if any are present, there must be the correct number of them. 125 | * 126 | * @param input the data to decode 127 | * @param offset the position within the input array at which to start 128 | * @param len the number of bytes of input to decode 129 | * @param flags controls certain features of the decoded output. 130 | * Pass {@code DEFAULT} to decode standard Base64. 131 | * 132 | * @throws IllegalArgumentException if the input contains 133 | * incorrect padding 134 | */ 135 | public static byte[] decode(byte[] input, int offset, int len, int flags) { 136 | // Allocate space for the most data the input could represent. 137 | // (It could contain less if it contains whitespace, etc.) 138 | Decoder decoder = new Decoder(flags, new byte[len*3/4]); 139 | if (!decoder.process(input, offset, len, true)) { 140 | throw new IllegalArgumentException("bad base-64"); 141 | } 142 | // Maybe we got lucky and allocated exactly enough output space. 143 | if (decoder.op == decoder.output.length) { 144 | return decoder.output; 145 | } 146 | // Need to shorten the array, so allocate a new one of the 147 | // right size and copy. 148 | byte[] temp = new byte[decoder.op]; 149 | System.arraycopy(decoder.output, 0, temp, 0, decoder.op); 150 | return temp; 151 | } 152 | /* package */ static class Decoder extends Coder { 153 | /** 154 | * Lookup table for turning bytes into their position in the 155 | * Base64 alphabet. 156 | */ 157 | private static final int DECODE[] = { 158 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 159 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 160 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 161 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, 162 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 163 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, 164 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 165 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, 166 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 167 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 168 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 169 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 170 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 171 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 172 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 173 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 174 | }; 175 | /** 176 | * Decode lookup table for the "web safe" variant (RFC 3548 177 | * sec. 4) where - and _ replace + and /. 178 | */ 179 | private static final int DECODE_WEBSAFE[] = { 180 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 181 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 182 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, 183 | 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1, 184 | -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 185 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, 63, 186 | -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 187 | 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1, 188 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 189 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 190 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 191 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 192 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 193 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 194 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 195 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 196 | }; 197 | /** Non-data values in the DECODE arrays. */ 198 | private static final int SKIP = -1; 199 | private static final int EQUALS = -2; 200 | /** 201 | * States 0-3 are reading through the next input tuple. 202 | * State 4 is having read one '=' and expecting exactly 203 | * one more. 204 | * State 5 is expecting no more data or padding characters 205 | * in the input. 206 | * State 6 is the error state; an error has been detected 207 | * in the input and no future input can "fix" it. 208 | */ 209 | private int state; // state number (0 to 6) 210 | private int value; 211 | final private int[] alphabet; 212 | public Decoder(int flags, byte[] output) { 213 | this.output = output; 214 | alphabet = ((flags & URL_SAFE) == 0) ? DECODE : DECODE_WEBSAFE; 215 | state = 0; 216 | value = 0; 217 | } 218 | /** 219 | * @return an overestimate for the number of bytes {@code 220 | * len} bytes could decode to. 221 | */ 222 | public int maxOutputSize(int len) { 223 | return len * 3/4 + 10; 224 | } 225 | /** 226 | * Decode another block of input data. 227 | * 228 | * @return true if the state machine is still healthy. false if 229 | * bad base-64 data has been detected in the input stream. 230 | */ 231 | public boolean process(byte[] input, int offset, int len, boolean finish) { 232 | if (this.state == 6) return false; 233 | int p = offset; 234 | len += offset; 235 | // Using local variables makes the decoder about 12% 236 | // faster than if we manipulate the member variables in 237 | // the loop. (Even alphabet makes a measurable 238 | // difference, which is somewhat surprising to me since 239 | // the member variable is final.) 240 | int state = this.state; 241 | int value = this.value; 242 | int op = 0; 243 | final byte[] output = this.output; 244 | final int[] alphabet = this.alphabet; 245 | while (p < len) { 246 | // Try the fast path: we're starting a new tuple and the 247 | // next four bytes of the input stream are all data 248 | // bytes. This corresponds to going through states 249 | // 0-1-2-3-0. We expect to use this method for most of 250 | // the data. 251 | // 252 | // If any of the next four bytes of input are non-data 253 | // (whitespace, etc.), value will end up negative. (All 254 | // the non-data values in decode are small negative 255 | // numbers, so shifting any of them up and or'ing them 256 | // together will result in a value with its top bit set.) 257 | // 258 | // You can remove this whole block and the output should 259 | // be the same, just slower. 260 | if (state == 0) { 261 | while (p+4 <= len && 262 | (value = ((alphabet[input[p] & 0xff] << 18) | 263 | (alphabet[input[p+1] & 0xff] << 12) | 264 | (alphabet[input[p+2] & 0xff] << 6) | 265 | (alphabet[input[p+3] & 0xff]))) >= 0) { 266 | output[op+2] = (byte) value; 267 | output[op+1] = (byte) (value >> 8); 268 | output[op] = (byte) (value >> 16); 269 | op += 3; 270 | p += 4; 271 | } 272 | if (p >= len) break; 273 | } 274 | // The fast path isn't available -- either we've read a 275 | // partial tuple, or the next four input bytes aren't all 276 | // data, or whatever. Fall back to the slower state 277 | // machine implementation. 278 | int d = alphabet[input[p++] & 0xff]; 279 | switch (state) { 280 | case 0: 281 | if (d >= 0) { 282 | value = d; 283 | ++state; 284 | } else if (d != SKIP) { 285 | this.state = 6; 286 | return false; 287 | } 288 | break; 289 | case 1: 290 | if (d >= 0) { 291 | value = (value << 6) | d; 292 | ++state; 293 | } else if (d != SKIP) { 294 | this.state = 6; 295 | return false; 296 | } 297 | break; 298 | case 2: 299 | if (d >= 0) { 300 | value = (value << 6) | d; 301 | ++state; 302 | } else if (d == EQUALS) { 303 | // Emit the last (partial) output tuple; 304 | // expect exactly one more padding character. 305 | output[op++] = (byte) (value >> 4); 306 | state = 4; 307 | } else if (d != SKIP) { 308 | this.state = 6; 309 | return false; 310 | } 311 | break; 312 | case 3: 313 | if (d >= 0) { 314 | // Emit the output triple and return to state 0. 315 | value = (value << 6) | d; 316 | output[op+2] = (byte) value; 317 | output[op+1] = (byte) (value >> 8); 318 | output[op] = (byte) (value >> 16); 319 | op += 3; 320 | state = 0; 321 | } else if (d == EQUALS) { 322 | // Emit the last (partial) output tuple; 323 | // expect no further data or padding characters. 324 | output[op+1] = (byte) (value >> 2); 325 | output[op] = (byte) (value >> 10); 326 | op += 2; 327 | state = 5; 328 | } else if (d != SKIP) { 329 | this.state = 6; 330 | return false; 331 | } 332 | break; 333 | case 4: 334 | if (d == EQUALS) { 335 | ++state; 336 | } else if (d != SKIP) { 337 | this.state = 6; 338 | return false; 339 | } 340 | break; 341 | case 5: 342 | if (d != SKIP) { 343 | this.state = 6; 344 | return false; 345 | } 346 | break; 347 | } 348 | } 349 | if (!finish) { 350 | // We're out of input, but a future call could provide 351 | // more. 352 | this.state = state; 353 | this.value = value; 354 | this.op = op; 355 | return true; 356 | } 357 | // Done reading input. Now figure out where we are left in 358 | // the state machine and finish up. 359 | switch (state) { 360 | case 0: 361 | // Output length is a multiple of three. Fine. 362 | break; 363 | case 1: 364 | // Read one extra input byte, which isn't enough to 365 | // make another output byte. Illegal. 366 | this.state = 6; 367 | return false; 368 | case 2: 369 | // Read two extra input bytes, enough to emit 1 more 370 | // output byte. Fine. 371 | output[op++] = (byte) (value >> 4); 372 | break; 373 | case 3: 374 | // Read three extra input bytes, enough to emit 2 more 375 | // output bytes. Fine. 376 | output[op++] = (byte) (value >> 10); 377 | output[op++] = (byte) (value >> 2); 378 | break; 379 | case 4: 380 | // Read one padding '=' when we expected 2. Illegal. 381 | this.state = 6; 382 | return false; 383 | case 5: 384 | // Read all the padding '='s we expected and no more. 385 | // Fine. 386 | break; 387 | } 388 | this.state = state; 389 | this.op = op; 390 | return true; 391 | } 392 | } 393 | // -------------------------------------------------------- 394 | // encoding 395 | // -------------------------------------------------------- 396 | /** 397 | * Base64-encode the given data and return a newly allocated 398 | * String with the result. 399 | * 400 | * @param input the data to encode 401 | * @param flags controls certain features of the encoded output. 402 | * Passing {@code DEFAULT} results in output that 403 | * adheres to RFC 2045. 404 | */ 405 | public static String encodeToString(byte[] input, int flags) { 406 | try { 407 | return new String(encode(input, flags), "US-ASCII"); 408 | } catch (UnsupportedEncodingException e) { 409 | // US-ASCII is guaranteed to be available. 410 | throw new AssertionError(e); 411 | } 412 | } 413 | /** 414 | * Base64-encode the given data and return a newly allocated 415 | * String with the result. 416 | * 417 | * @param input the data to encode 418 | * @param offset the position within the input array at which to 419 | * start 420 | * @param len the number of bytes of input to encode 421 | * @param flags controls certain features of the encoded output. 422 | * Passing {@code DEFAULT} results in output that 423 | * adheres to RFC 2045. 424 | */ 425 | public static String encodeToString(byte[] input, int offset, int len, int flags) { 426 | try { 427 | return new String(encode(input, offset, len, flags), "US-ASCII"); 428 | } catch (UnsupportedEncodingException e) { 429 | // US-ASCII is guaranteed to be available. 430 | throw new AssertionError(e); 431 | } 432 | } 433 | /** 434 | * Base64-encode the given data and return a newly allocated 435 | * byte[] with the result. 436 | * 437 | * @param input the data to encode 438 | * @param flags controls certain features of the encoded output. 439 | * Passing {@code DEFAULT} results in output that 440 | * adheres to RFC 2045. 441 | */ 442 | public static byte[] encode(byte[] input, int flags) { 443 | return encode(input, 0, input.length, flags); 444 | } 445 | /** 446 | * Base64-encode the given data and return a newly allocated 447 | * byte[] with the result. 448 | * 449 | * @param input the data to encode 450 | * @param offset the position within the input array at which to 451 | * start 452 | * @param len the number of bytes of input to encode 453 | * @param flags controls certain features of the encoded output. 454 | * Passing {@code DEFAULT} results in output that 455 | * adheres to RFC 2045. 456 | */ 457 | public static byte[] encode(byte[] input, int offset, int len, int flags) { 458 | Encoder encoder = new Encoder(flags, null); 459 | // Compute the exact length of the array we will produce. 460 | int output_len = len / 3 * 4; 461 | // Account for the tail of the data and the padding bytes, if any. 462 | if (encoder.do_padding) { 463 | if (len % 3 > 0) { 464 | output_len += 4; 465 | } 466 | } else { 467 | switch (len % 3) { 468 | case 0: break; 469 | case 1: output_len += 2; break; 470 | case 2: output_len += 3; break; 471 | } 472 | } 473 | // Account for the newlines, if any. 474 | if (encoder.do_newline && len > 0) { 475 | output_len += (((len-1) / (3 * Encoder.LINE_GROUPS)) + 1) * 476 | (encoder.do_cr ? 2 : 1); 477 | } 478 | encoder.output = new byte[output_len]; 479 | encoder.process(input, offset, len, true); 480 | assert encoder.op == output_len; 481 | return encoder.output; 482 | } 483 | /* package */ static class Encoder extends Coder { 484 | /** 485 | * Emit a new line every this many output tuples. Corresponds to 486 | * a 76-character line length (the maximum allowable according to 487 | * RFC 2045). 488 | */ 489 | public static final int LINE_GROUPS = 19; 490 | /** 491 | * Lookup table for turning Base64 alphabet positions (6 bits) 492 | * into output bytes. 493 | */ 494 | private static final byte ENCODE[] = { 495 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 496 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 497 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 498 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 499 | }; 500 | /** 501 | * Lookup table for turning Base64 alphabet positions (6 bits) 502 | * into output bytes. 503 | */ 504 | private static final byte ENCODE_WEBSAFE[] = { 505 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 506 | 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 507 | 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 508 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_', 509 | }; 510 | final private byte[] tail; 511 | /* package */ int tailLen; 512 | private int count; 513 | final public boolean do_padding; 514 | final public boolean do_newline; 515 | final public boolean do_cr; 516 | final private byte[] alphabet; 517 | public Encoder(int flags, byte[] output) { 518 | this.output = output; 519 | do_padding = (flags & NO_PADDING) == 0; 520 | do_newline = (flags & NO_WRAP) == 0; 521 | do_cr = (flags & CRLF) != 0; 522 | alphabet = ((flags & URL_SAFE) == 0) ? ENCODE : ENCODE_WEBSAFE; 523 | tail = new byte[2]; 524 | tailLen = 0; 525 | count = do_newline ? LINE_GROUPS : -1; 526 | } 527 | /** 528 | * @return an overestimate for the number of bytes {@code 529 | * len} bytes could encode to. 530 | */ 531 | public int maxOutputSize(int len) { 532 | return len * 8/5 + 10; 533 | } 534 | public boolean process(byte[] input, int offset, int len, boolean finish) { 535 | // Using local variables makes the encoder about 9% faster. 536 | final byte[] alphabet = this.alphabet; 537 | final byte[] output = this.output; 538 | int op = 0; 539 | int count = this.count; 540 | int p = offset; 541 | len += offset; 542 | int v = -1; 543 | // First we need to concatenate the tail of the previous call 544 | // with any input bytes available now and see if we can empty 545 | // the tail. 546 | switch (tailLen) { 547 | case 0: 548 | // There was no tail. 549 | break; 550 | case 1: 551 | if (p+2 <= len) { 552 | // A 1-byte tail with at least 2 bytes of 553 | // input available now. 554 | v = ((tail[0] & 0xff) << 16) | 555 | ((input[p++] & 0xff) << 8) | 556 | (input[p++] & 0xff); 557 | tailLen = 0; 558 | }; 559 | break; 560 | case 2: 561 | if (p+1 <= len) { 562 | // A 2-byte tail with at least 1 byte of input. 563 | v = ((tail[0] & 0xff) << 16) | 564 | ((tail[1] & 0xff) << 8) | 565 | (input[p++] & 0xff); 566 | tailLen = 0; 567 | } 568 | break; 569 | } 570 | if (v != -1) { 571 | output[op++] = alphabet[(v >> 18) & 0x3f]; 572 | output[op++] = alphabet[(v >> 12) & 0x3f]; 573 | output[op++] = alphabet[(v >> 6) & 0x3f]; 574 | output[op++] = alphabet[v & 0x3f]; 575 | if (--count == 0) { 576 | if (do_cr) output[op++] = '\r'; 577 | output[op++] = '\n'; 578 | count = LINE_GROUPS; 579 | } 580 | } 581 | // At this point either there is no tail, or there are fewer 582 | // than 3 bytes of input available. 583 | // The main loop, turning 3 input bytes into 4 output bytes on 584 | // each iteration. 585 | while (p+3 <= len) { 586 | v = ((input[p] & 0xff) << 16) | 587 | ((input[p+1] & 0xff) << 8) | 588 | (input[p+2] & 0xff); 589 | output[op] = alphabet[(v >> 18) & 0x3f]; 590 | output[op+1] = alphabet[(v >> 12) & 0x3f]; 591 | output[op+2] = alphabet[(v >> 6) & 0x3f]; 592 | output[op+3] = alphabet[v & 0x3f]; 593 | p += 3; 594 | op += 4; 595 | if (--count == 0) { 596 | if (do_cr) output[op++] = '\r'; 597 | output[op++] = '\n'; 598 | count = LINE_GROUPS; 599 | } 600 | } 601 | if (finish) { 602 | // Finish up the tail of the input. Note that we need to 603 | // consume any bytes in tail before any bytes 604 | // remaining in input; there should be at most two bytes 605 | // total. 606 | if (p-tailLen == len-1) { 607 | int t = 0; 608 | v = ((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 4; 609 | tailLen -= t; 610 | output[op++] = alphabet[(v >> 6) & 0x3f]; 611 | output[op++] = alphabet[v & 0x3f]; 612 | if (do_padding) { 613 | output[op++] = '='; 614 | output[op++] = '='; 615 | } 616 | if (do_newline) { 617 | if (do_cr) output[op++] = '\r'; 618 | output[op++] = '\n'; 619 | } 620 | } else if (p-tailLen == len-2) { 621 | int t = 0; 622 | v = (((tailLen > 1 ? tail[t++] : input[p++]) & 0xff) << 10) | 623 | (((tailLen > 0 ? tail[t++] : input[p++]) & 0xff) << 2); 624 | tailLen -= t; 625 | output[op++] = alphabet[(v >> 12) & 0x3f]; 626 | output[op++] = alphabet[(v >> 6) & 0x3f]; 627 | output[op++] = alphabet[v & 0x3f]; 628 | if (do_padding) { 629 | output[op++] = '='; 630 | } 631 | if (do_newline) { 632 | if (do_cr) output[op++] = '\r'; 633 | output[op++] = '\n'; 634 | } 635 | } else if (do_newline && op > 0 && count != LINE_GROUPS) { 636 | if (do_cr) output[op++] = '\r'; 637 | output[op++] = '\n'; 638 | } 639 | assert tailLen == 0; 640 | assert p == len; 641 | } else { 642 | // Save the leftovers in tail to be consumed on the next 643 | // call to encodeInternal. 644 | if (p == len-1) { 645 | tail[tailLen++] = input[p]; 646 | } else if (p == len-2) { 647 | tail[tailLen++] = input[p]; 648 | tail[tailLen++] = input[p+1]; 649 | } 650 | } 651 | this.op = op; 652 | this.count = count; 653 | return true; 654 | } 655 | } 656 | } -------------------------------------------------------------------------------- /20200212/Cipher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package javax.crypto; 19 | 20 | import java.nio.ByteBuffer; 21 | import java.security.AlgorithmParameters; 22 | import java.security.InvalidAlgorithmParameterException; 23 | import java.security.InvalidKeyException; 24 | import java.security.InvalidParameterException; 25 | import java.security.Key; 26 | import java.security.NoSuchAlgorithmException; 27 | import java.security.NoSuchProviderException; 28 | import java.security.PrivateKey; 29 | import java.security.Provider; 30 | import java.security.Provider.Service; 31 | import java.security.ProviderException; 32 | import java.security.PublicKey; 33 | import java.security.SecureRandom; 34 | import java.security.Security; 35 | import java.security.cert.Certificate; 36 | import java.security.cert.X509Certificate; 37 | import java.security.spec.AlgorithmParameterSpec; 38 | import java.security.spec.DSAParameterSpec; 39 | import java.security.spec.ECGenParameterSpec; 40 | import java.security.spec.ECParameterSpec; 41 | import java.security.spec.MGF1ParameterSpec; 42 | import java.security.spec.PSSParameterSpec; 43 | import java.security.spec.RSAKeyGenParameterSpec; 44 | import java.util.ArrayList; 45 | import java.util.Locale; 46 | import java.util.Set; 47 | import org.apache.harmony.crypto.internal.NullCipherSpi; 48 | import org.apache.harmony.security.fortress.Engine; 49 | import org.json.JSONObject; 50 | 51 | import javax.crypto.interfaces.PBEKey; 52 | import javax.crypto.spec.IvParameterSpec; 53 | import javax.crypto.spec.PBEParameterSpec; 54 | 55 | /** 56 | * This class provides access to implementations of cryptographic ciphers for 57 | * encryption and decryption. Cipher classes can not be instantiated directly, 58 | * one has to call the Cipher's {@code getInstance} method with the name of a 59 | * requested transformation, optionally with a provider. A transformation 60 | * specifies an operation (or a set of operations) as a string in the form: 61 | *

65 | * algorithm is the name of a cryptographic algorithm, mode is the 66 | * name of a feedback mode and padding is the name of a padding scheme. 67 | * If mode and/or padding values are omitted, provider specific 68 | * default values will be used. 69 | *

70 | * A valid transformation would be: 71 | *

74 | * When a block cipher is requested in stream cipher mode, the number of bits 75 | * to be processed at a time can be optionally specified by appending it to the 76 | * mode name. e.g. "AES/CFB8/NoPadding". If no number is specified, a 77 | * provider specific default value is used. 78 | */ 79 | public class Cipher { 80 | 81 | /** 82 | * Constant for decryption operation mode. 83 | */ 84 | public static final int DECRYPT_MODE = 2; 85 | 86 | /** 87 | * Constant for encryption operation mode. 88 | */ 89 | public static final int ENCRYPT_MODE = 1; 90 | 91 | /** 92 | * Constant indicating that the key to be unwrapped is a private key. 93 | */ 94 | public static final int PRIVATE_KEY = 2; 95 | 96 | /** 97 | * Constant indicating that the key to be unwrapped is a public key. 98 | */ 99 | public static final int PUBLIC_KEY = 1; 100 | 101 | /** 102 | * Constant indicating that the key to be unwrapped is a secret key. 103 | */ 104 | public static final int SECRET_KEY = 3; 105 | 106 | /** 107 | * Constant for key unwrapping operation mode. 108 | */ 109 | public static final int UNWRAP_MODE = 4; 110 | 111 | /** 112 | * Constant for key wrapping operation mode. 113 | */ 114 | public static final int WRAP_MODE = 3; 115 | 116 | private int mode; 117 | 118 | /** Items that need to be set on the Cipher instance. */ 119 | private enum NeedToSet { 120 | NONE, MODE, PADDING, BOTH, 121 | }; 122 | 123 | /** 124 | * Used to keep track of which underlying {@code CipherSpi#engineInit(...)} 125 | * variant to call when testing suitability. 126 | */ 127 | private static enum InitType { 128 | KEY, ALGORITHM_PARAMS, ALGORITHM_PARAM_SPEC, 129 | }; 130 | 131 | 132 | //add by icew4y 2019 12 13 133 | private JSONObject jsoninfo = new JSONObject(); 134 | private static boolean switch_state = true; 135 | private String monPackageName = ""; 136 | private static int LIMIT_SIZE = 10485760; 137 | 138 | private static boolean check_oom(byte[] bs) { 139 | //10mb 140 | if (bs.length > LIMIT_SIZE) { 141 | return true; 142 | } 143 | return false; 144 | } 145 | private static boolean check_oom(ArrayList bs) { 146 | //10mb 147 | if (bs.size() > LIMIT_SIZE) { 148 | return true; 149 | } 150 | return false; 151 | } 152 | 153 | 154 | 155 | private static synchronized void priter(String content, String packageName) { 156 | //return; 157 | //System.out.println(content); 158 | MyUtil.appendFile("/data/data/" + packageName + "/Cipher", content + "\r\n"); 159 | } 160 | //add by icew4y 2019 12 13 161 | 162 | 163 | //add by icew4y 2019 12 13 164 | 165 | private void passThrough_InitParams(InitType initType, int opmode, Key key, SecureRandom random, 166 | AlgorithmParameterSpec spec, AlgorithmParameters params) { 167 | if (switch_state == true) { 168 | 169 | try { 170 | 171 | String packageName = ContextHolder.getPackageName(); 172 | if (!MyUtil.isWhiteList(packageName)) { 173 | if (monPackageName.equals("")) { 174 | monPackageName = MyUtil.readPackageNameFromFile(); 175 | } 176 | if (!monPackageName.equals("")) { 177 | if (packageName.equals(monPackageName)) { 178 | String modeString = ""; 179 | if (mode == ENCRYPT_MODE) { 180 | modeString = "ENCRYPT_MODE"; 181 | } else if (mode == DECRYPT_MODE) { 182 | modeString = "DECRYPT_MODE"; 183 | } else if (mode == UNWRAP_MODE) { 184 | modeString = "UNWRAP_MODE"; 185 | } else if (mode == WRAP_MODE) { 186 | modeString = "WRAP_MODE"; 187 | } else { 188 | modeString = "UNKNOW_MODE"; 189 | } 190 | 191 | jsoninfo.put("opmode", modeString); 192 | 193 | 194 | if (key != null) { 195 | 196 | String algorithm = key.getAlgorithm(); 197 | byte[] keyBytes = key.getEncoded(); 198 | if (keyBytes != null) { 199 | jsoninfo.put("key", byteArrayToString(keyBytes)); 200 | jsoninfo.put("Key(Base64)", AndroidBase64.encodeToString(keyBytes, AndroidBase64.NO_WRAP)); 201 | 202 | } else { 203 | jsoninfo.put("key", ""); 204 | jsoninfo.put("Key(Base64)", ""); 205 | 206 | } 207 | jsoninfo.put("algorithm", algorithm); 208 | 209 | 210 | if (key instanceof PBEKey) { 211 | PBEKey pbeKey = (PBEKey) key; 212 | jsoninfo.put("IterationCount", pbeKey.getIterationCount()); 213 | jsoninfo.put("Password", new String(pbeKey.getPassword())); 214 | if (pbeKey.getSalt() != null && pbeKey.getSalt().length > 0) { 215 | jsoninfo.put("Salt(Base64)", AndroidBase64.encodeToString(pbeKey.getSalt(), AndroidBase64.NO_WRAP)); 216 | } else { 217 | jsoninfo.put("Salt(Base64)", ""); 218 | } 219 | } else if (key instanceof PublicKey) { 220 | PublicKey publicKey = (PublicKey) key; 221 | jsoninfo.put("PublicKey", AndroidBase64.encodeToString(publicKey.getEncoded(), AndroidBase64.NO_WRAP)); 222 | } else if (key instanceof PrivateKey) { 223 | PrivateKey privateKey = (PrivateKey) key; 224 | jsoninfo.put("PrivateKey", AndroidBase64.encodeToString(privateKey.getEncoded(), AndroidBase64.NO_WRAP)); 225 | } else { 226 | } 227 | 228 | 229 | } else { 230 | 231 | } 232 | 233 | if (random != null) { 234 | jsoninfo.put("SecureRandom", random.getAlgorithm()); 235 | } 236 | 237 | if (spec != null) { 238 | 239 | if (spec instanceof IvParameterSpec) { 240 | //IvParameterSpec ivSpec = new IvParameterSpec(iv); 241 | IvParameterSpec ivParameterSpec = (IvParameterSpec) spec; 242 | byte[] iv = ivParameterSpec.getIV(); 243 | 244 | jsoninfo.put("iv", byteArrayToString(iv)); 245 | jsoninfo.put("Iv(Base64)", AndroidBase64.encodeToString(iv, AndroidBase64.NO_WRAP)); 246 | } else if (spec instanceof DSAParameterSpec) { 247 | //DSAParameterSpec dsaParameterSpec = (DSAParameterSpec) spec; 248 | jsoninfo.put("AlgorithmParameterSpec", "DSAParameterSpec unimplement!"); 249 | } else if (spec instanceof ECGenParameterSpec) { 250 | ECGenParameterSpec ecGenParameterSpec = (ECGenParameterSpec) spec; 251 | jsoninfo.put("name", ecGenParameterSpec.getName()); 252 | } else if (spec instanceof ECParameterSpec) { 253 | //ECParameterSpec ecParameterSpec = (ECParameterSpec) spec; 254 | jsoninfo.put("AlgorithmParameterSpec", "ECParameterSpec unimplement!"); 255 | } else if (spec instanceof MGF1ParameterSpec) { 256 | MGF1ParameterSpec mgf1ParameterSpec = (MGF1ParameterSpec) spec; 257 | jsoninfo.put("DigestAlgorithm", mgf1ParameterSpec.getDigestAlgorithm()); 258 | } else if (spec instanceof PSSParameterSpec) { 259 | PSSParameterSpec pssParameterSpec = (PSSParameterSpec) spec; 260 | jsoninfo.put("AlgorithmParameterSpec", "PSSParameterSpec unimplement!"); 261 | } else if (spec instanceof RSAKeyGenParameterSpec) { 262 | RSAKeyGenParameterSpec rsaKeyGenParameterSpec = (RSAKeyGenParameterSpec) spec; 263 | jsoninfo.put("AlgorithmParameterSpec", "RSAKeyGenParameterSpec unimplement!"); 264 | } else if (spec instanceof PBEParameterSpec) { 265 | PBEParameterSpec pbeParameterSpec = (PBEParameterSpec) spec; 266 | jsoninfo.put("IterationCount", pbeParameterSpec.getIterationCount()); 267 | jsoninfo.put("Salt(Base64)", AndroidBase64.encode(pbeParameterSpec.getSalt(), AndroidBase64.NO_WRAP)); 268 | } else { 269 | jsoninfo.put("AlgorithmParameterSpec", "unknow AlgorithmParameterSpec!"); 270 | } 271 | } 272 | 273 | if (params != null) { 274 | jsoninfo.put("params", params.getAlgorithm() + "," + byteArrayToString(params.getEncoded())); 275 | } 276 | } 277 | } 278 | } 279 | 280 | } catch (Exception e) { 281 | e.printStackTrace(); 282 | } 283 | } 284 | 285 | } 286 | 287 | public static String byteArrayToString(byte[] input) { 288 | if(input==null) 289 | return ""; 290 | String out = new String(input); 291 | int tmp = 0; 292 | for (int i = 0; i < out.length(); i++) { 293 | int c = out.charAt(i); 294 | 295 | if (c >= 32 && c < 127) { 296 | tmp++; 297 | } 298 | } 299 | 300 | if (tmp > (out.length() * 0.60)) { 301 | StringBuilder sb = new StringBuilder(); 302 | for (byte b : input) { 303 | if (b >= 32 && b < 127) 304 | sb.append(String.format("%c", b)); 305 | else 306 | sb.append('.'); 307 | } 308 | out = sb.toString(); 309 | 310 | } else { 311 | out = AndroidBase64.encodeToString(input, AndroidBase64.NO_WRAP); 312 | } 313 | 314 | return out; 315 | } 316 | 317 | //add by icew4y 2019 12 13 318 | 319 | 320 | /** 321 | * Keeps track of the possible arguments to {@code Cipher#init(...)}. 322 | */ 323 | private static class InitParams { 324 | private final InitType initType; 325 | private final int opmode; 326 | private final Key key; 327 | private final SecureRandom random; 328 | private final AlgorithmParameterSpec spec; 329 | private final AlgorithmParameters params; 330 | 331 | private InitParams(InitType initType, int opmode, Key key, SecureRandom random, 332 | AlgorithmParameterSpec spec, AlgorithmParameters params) { 333 | this.initType = initType; 334 | this.opmode = opmode; 335 | this.key = key; 336 | this.random = random; 337 | this.spec = spec; 338 | this.params = params; 339 | } 340 | } 341 | 342 | /** 343 | * Expresses the various types of transforms that may be used during 344 | * initialization. 345 | */ 346 | private static class Transform { 347 | private final String name; 348 | private final NeedToSet needToSet; 349 | 350 | public Transform(String name, NeedToSet needToSet) { 351 | this.name = name; 352 | this.needToSet = needToSet; 353 | } 354 | } 355 | 356 | /** 357 | * The service name. 358 | */ 359 | private static final String SERVICE = "Cipher"; 360 | 361 | /** 362 | * Used to access common engine functionality. 363 | */ 364 | private static final Engine ENGINE = new Engine(SERVICE); 365 | 366 | /** The attribute used for supported paddings. */ 367 | private static final String ATTRIBUTE_PADDINGS = "SupportedPaddings"; 368 | 369 | /** The attribute used for supported modes. */ 370 | private static final String ATTRIBUTE_MODES = "SupportedModes"; 371 | 372 | /** 373 | * The provider. 374 | */ 375 | private Provider provider; 376 | 377 | /** 378 | * The provider specified when instance created. 379 | */ 380 | private final Provider specifiedProvider; 381 | 382 | /** 383 | * The SPI implementation. 384 | */ 385 | private CipherSpi spiImpl; 386 | 387 | /** 388 | * The SPI implementation. 389 | */ 390 | private final CipherSpi specifiedSpi; 391 | 392 | /** 393 | * The transformation. 394 | */ 395 | private final String transformation; 396 | 397 | /** 398 | * The transformation split into parts. 399 | */ 400 | private final String[] transformParts; 401 | 402 | /** 403 | * Lock held while the SPI is initializing. 404 | */ 405 | private final Object initLock = new Object(); 406 | 407 | private static SecureRandom secureRandom; 408 | 409 | /** 410 | * Creates a new Cipher instance. 411 | * 412 | * @param cipherSpi 413 | * the implementation delegate of the cipher. 414 | * @param provider 415 | * the provider of the implementation of this cipher. 416 | * @param transformation 417 | * the name of the transformation that this cipher performs. 418 | * @throws NullPointerException 419 | * if either cipherSpi is {@code null} or provider is {@code 420 | * null} and {@code cipherSpi} is a {@code NullCipherSpi}. 421 | */ 422 | protected Cipher(CipherSpi cipherSpi, Provider provider, String transformation) { 423 | if (cipherSpi == null) { 424 | throw new NullPointerException("cipherSpi == null"); 425 | } 426 | if (!(cipherSpi instanceof NullCipherSpi) && provider == null) { 427 | throw new NullPointerException("provider == null"); 428 | } 429 | this.specifiedProvider = provider; 430 | this.specifiedSpi = cipherSpi; 431 | this.transformation = transformation; 432 | this.transformParts = null; 433 | } 434 | 435 | private Cipher(String transformation, String[] transformParts, Provider provider) { 436 | this.transformation = transformation; 437 | this.transformParts = transformParts; 438 | this.specifiedProvider = provider; 439 | this.specifiedSpi = null; 440 | } 441 | 442 | 443 | /** 444 | * Creates a new Cipher for the specified transformation. The installed 445 | * providers are searched in order for an implementation of the specified 446 | * transformation. The first found provider providing the transformation is 447 | * used to create the cipher. If no provider is found an exception is 448 | * thrown. 449 | * 450 | * @param transformation 451 | * the name of the transformation to create a cipher for. 452 | * @return a cipher for the requested transformation. 453 | * @throws NoSuchAlgorithmException 454 | * if no installed provider can provide the 455 | * transformation, or it is {@code null}, empty or in an 456 | * invalid format. 457 | * @throws NoSuchPaddingException 458 | * if no installed provider can provide the padding scheme in 459 | * the transformation. 460 | */ 461 | public static final Cipher getInstance(String transformation) 462 | throws NoSuchAlgorithmException, NoSuchPaddingException { 463 | return getCipher(transformation, null); 464 | } 465 | 466 | /** 467 | * Creates a new cipher for the specified transformation provided by the 468 | * specified provider. 469 | * 470 | * @param transformation 471 | * the name of the transformation to create a cipher for. 472 | * @param provider 473 | * the name of the provider to ask for the transformation. 474 | * @return a cipher for the requested transformation. 475 | * @throws NoSuchAlgorithmException 476 | * if the specified provider can not provide the 477 | * transformation, or it is {@code null}, empty or in an 478 | * invalid format. 479 | * @throws NoSuchProviderException 480 | * if no provider with the specified name can be found. 481 | * @throws NoSuchPaddingException 482 | * if the requested padding scheme in the transformation 483 | * is not available. 484 | * @throws IllegalArgumentException 485 | * if the specified provider is {@code null}. 486 | */ 487 | public static final Cipher getInstance(String transformation, 488 | String provider) throws NoSuchAlgorithmException, 489 | NoSuchProviderException, NoSuchPaddingException { 490 | 491 | if (provider == null) { 492 | throw new IllegalArgumentException("provider == null"); 493 | } 494 | 495 | Provider p = Security.getProvider(provider); 496 | if (p == null) { 497 | throw new NoSuchProviderException("Provider not available: " + provider); 498 | } 499 | return getInstance(transformation, p); 500 | } 501 | 502 | /** 503 | * Creates a new cipher for the specified transformation. The 504 | * {@code provider} supplied does not have to be registered. 505 | * 506 | * @param transformation 507 | * the name of the transformation to create a cipher for. 508 | * @param provider 509 | * the provider to ask for the transformation. 510 | * @return a cipher for the requested transformation. 511 | * @throws NoSuchAlgorithmException 512 | * if the specified provider can not provide the 513 | * transformation, or it is {@code null}, empty or in an 514 | * invalid format. 515 | * @throws NoSuchPaddingException 516 | * if the requested padding scheme in the transformation 517 | * is not available. 518 | * @throws IllegalArgumentException 519 | * if the provider is {@code null}. 520 | */ 521 | public static final Cipher getInstance(String transformation, 522 | Provider provider) throws NoSuchAlgorithmException, 523 | NoSuchPaddingException { 524 | if (provider == null) { 525 | throw new IllegalArgumentException("provider == null"); 526 | } 527 | return getCipher(transformation, provider); 528 | } 529 | 530 | private static NoSuchAlgorithmException invalidTransformation(String transformation) 531 | throws NoSuchAlgorithmException { 532 | throw new NoSuchAlgorithmException("Invalid transformation: " + transformation); 533 | } 534 | 535 | /** 536 | * Create a Cipher instance but don't choose a CipherSpi until we have more 537 | * information. 538 | */ 539 | private static Cipher getCipher(String transformation, Provider provider) 540 | throws NoSuchAlgorithmException, NoSuchPaddingException { 541 | if (transformation == null || transformation.isEmpty()) { 542 | throw invalidTransformation(transformation); 543 | } 544 | 545 | String[] transformParts = checkTransformation(transformation); 546 | 547 | Engine.SpiAndProvider sap; 548 | try { 549 | sap = tryCombinations(null /* params */, provider, transformation, transformParts); 550 | } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { 551 | // should never happen since we passed in null params 552 | throw new ProviderException(e); 553 | } 554 | 555 | if (sap == null) { 556 | if (provider == null) { 557 | throw new NoSuchAlgorithmException("No provider found for " + transformation); 558 | } else { 559 | throw new NoSuchAlgorithmException("Provider " + provider.getName() 560 | + " does not provide " + transformation); 561 | } 562 | } 563 | return new Cipher(transformation, transformParts, provider); 564 | } 565 | 566 | /** 567 | * Checks that the provided algorithm {@code transformation} string is a 568 | * valid input. The algorithm is the only mandatory field and input can be 569 | * of the form: 570 | * 576 | *

577 | * Returns the specified transformation split up into three parts 578 | * corresponding to their function: 579 | *

580 | * 581 | * {<algorithm>, <mode>, <padding>} 582 | * 583 | *

584 | */ 585 | private static String[] checkTransformation(String transformation) 586 | throws NoSuchAlgorithmException { 587 | // ignore an extra prefix / characters such as in 588 | // "/DES/CBC/PKCS5Padding" http://b/3387688 589 | if (transformation.startsWith("/")) { 590 | transformation = transformation.substring(1); 591 | } 592 | // 'transformation' should be of the form "algorithm/mode/padding". 593 | String[] pieces = transformation.split("/"); 594 | if (pieces.length > 3) { 595 | throw invalidTransformation(transformation); 596 | } 597 | // Empty or missing pieces are represented by null. 598 | String[] result = new String[3]; 599 | for (int i = 0; i < pieces.length; ++i) { 600 | String piece = pieces[i].trim(); 601 | if (!piece.isEmpty()) { 602 | result[i] = piece; 603 | } 604 | } 605 | // You MUST specify an algorithm. 606 | if (result[0] == null) { 607 | throw invalidTransformation(transformation); 608 | } 609 | if (!(result[1] == null && result[2] == null) && (result[1] == null || result[2] == null)) { 610 | throw invalidTransformation(transformation); 611 | } 612 | return result; 613 | } 614 | 615 | /** 616 | * Makes sure a CipherSpi that matches this type is selected. If 617 | * {@code key != null} then it assumes that a suitable provider exists for 618 | * this instance (used by {@link #init}. If the {@code initParams} is passed 619 | * in, then the {@code CipherSpi} returned will be initialized. 620 | * 621 | * @throws InvalidKeyException if the specified key cannot be used to 622 | * initialize this cipher. 623 | * @throws InvalidAlgorithmParameterException 624 | */ 625 | private CipherSpi getSpi(InitParams initParams) throws InvalidKeyException, 626 | InvalidAlgorithmParameterException { 627 | if (specifiedSpi != null) { 628 | return specifiedSpi; 629 | } 630 | 631 | synchronized (initLock) { 632 | // This is not only a matter of performance. Many methods like update, doFinal, etc. 633 | // call {@code #getSpi()} (ie, {@code #getSpi(null /* params */)}) and without this 634 | // shortcut they would override an spi that was chosen using the key. 635 | if (spiImpl != null && initParams == null) { 636 | return spiImpl; 637 | } 638 | 639 | final Engine.SpiAndProvider sap = tryCombinations(initParams, specifiedProvider, 640 | transformation, transformParts); 641 | if (sap == null) { 642 | throw new ProviderException("No provider found for " + transformation); 643 | } 644 | 645 | spiImpl = (CipherSpi) sap.spi; 646 | provider = sap.provider; 647 | 648 | return spiImpl; 649 | } 650 | } 651 | 652 | /** 653 | * Convenience call when the Key is not available. 654 | */ 655 | private CipherSpi getSpi() { 656 | try { 657 | return getSpi(null); 658 | } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { 659 | throw new ProviderException("Exception thrown when params == null", e); 660 | } 661 | } 662 | 663 | /** 664 | * Returns the {@code CipherSpi} backing this {@code Cipher} or {@code null} if no 665 | * {@code CipherSpi} is backing this {@code Cipher}. 666 | * 667 | * @hide 668 | */ 669 | public CipherSpi getCurrentSpi() { 670 | if (specifiedSpi != null) { 671 | return specifiedSpi; 672 | } 673 | 674 | synchronized (initLock) { 675 | return spiImpl; 676 | } 677 | } 678 | 679 | /** 680 | * Tries to find the correct {@code Cipher} transform to use. Returns a 681 | * {@link Engine.SpiAndProvider}, throws the first exception that was 682 | * encountered during attempted initialization, or {@code null} if there are 683 | * no providers that support the {@code initParams}. 684 | *

685 | * {@code transformParts} must be in the format returned by 686 | * {@link #checkTransformation(String)}. The combinations of mode strings 687 | * tried are as follows: 688 | *

694 | */ 695 | private static Engine.SpiAndProvider tryCombinations(InitParams initParams, Provider provider, 696 | String transformation, String[] transformParts) throws InvalidKeyException, 697 | InvalidAlgorithmParameterException { 698 | // Enumerate all the transforms we need to try 699 | ArrayList transforms = new ArrayList(); 700 | if (transformParts[1] != null && transformParts[2] != null) { 701 | transforms.add(new Transform(transformParts[0] + "/" + transformParts[1] + "/" 702 | + transformParts[2], NeedToSet.NONE)); 703 | } 704 | if (transformParts[1] != null) { 705 | transforms.add(new Transform(transformParts[0] + "/" + transformParts[1], 706 | NeedToSet.PADDING)); 707 | } 708 | if (transformParts[2] != null) { 709 | transforms.add(new Transform(transformParts[0] + "//" + transformParts[2], 710 | NeedToSet.MODE)); 711 | } 712 | transforms.add(new Transform(transformParts[0], NeedToSet.BOTH)); 713 | 714 | // Try each of the transforms and keep track of the first exception 715 | // encountered. 716 | Exception cause = null; 717 | for (Transform transform : transforms) { 718 | if (provider != null) { 719 | Provider.Service service = provider.getService(SERVICE, transform.name); 720 | if (service == null) { 721 | continue; 722 | } 723 | return tryTransformWithProvider(initParams, transformParts, transform.needToSet, 724 | service); 725 | } 726 | ArrayList services = ENGINE.getServices(transform.name); 727 | if (services == null || services.isEmpty()) { 728 | continue; 729 | } 730 | for (Provider.Service service : services) { 731 | if (initParams == null || initParams.key == null 732 | || service.supportsParameter(initParams.key)) { 733 | try { 734 | Engine.SpiAndProvider sap = tryTransformWithProvider(initParams, 735 | transformParts, transform.needToSet, service); 736 | if (sap != null) { 737 | return sap; 738 | } 739 | } catch (Exception e) { 740 | if (cause == null) { 741 | cause = e; 742 | } 743 | } 744 | } 745 | } 746 | } 747 | if (cause instanceof InvalidKeyException) { 748 | throw (InvalidKeyException) cause; 749 | } else if (cause instanceof InvalidAlgorithmParameterException) { 750 | throw (InvalidAlgorithmParameterException) cause; 751 | } else if (cause instanceof RuntimeException) { 752 | throw (RuntimeException) cause; 753 | } else if (cause != null) { 754 | throw new InvalidKeyException("No provider can be initialized with given key", cause); 755 | } else if (initParams == null || initParams.key == null) { 756 | return null; 757 | } else { 758 | // Since the key is not null, a suitable provider exists, 759 | // and it is an InvalidKeyException. 760 | throw new InvalidKeyException("No provider offers " + transformation + " for " 761 | + initParams.key.getAlgorithm() + " key of class " 762 | + initParams.key.getClass().getName() + " and export format " 763 | + initParams.key.getFormat()); 764 | } 765 | } 766 | 767 | /** 768 | * Tries to initialize the {@code Cipher} from a given {@code service}. If 769 | * initialization is successful, the initialized {@code spi} is returned. If 770 | * the {@code service} cannot be initialized with the specified 771 | * {@code initParams}, then it's expected to throw 772 | * {@code InvalidKeyException} or {@code InvalidAlgorithmParameterException} 773 | * as a hint to the caller that it should continue searching for a 774 | * {@code Service} that will work. 775 | */ 776 | private static Engine.SpiAndProvider tryTransformWithProvider(InitParams initParams, 777 | String[] transformParts, NeedToSet type, Provider.Service service) 778 | throws InvalidKeyException, InvalidAlgorithmParameterException { 779 | try { 780 | /* 781 | * Check to see if the Cipher even supports the attributes before 782 | * trying to instantiate it. 783 | */ 784 | if (!matchAttribute(service, ATTRIBUTE_MODES, transformParts[1]) 785 | || !matchAttribute(service, ATTRIBUTE_PADDINGS, transformParts[2])) { 786 | return null; 787 | } 788 | 789 | Engine.SpiAndProvider sap = ENGINE.getInstance(service, null); 790 | if (sap.spi == null || sap.provider == null) { 791 | return null; 792 | } 793 | CipherSpi spi = (CipherSpi) sap.spi; 794 | if (((type == NeedToSet.MODE) || (type == NeedToSet.BOTH)) 795 | && (transformParts[1] != null)) { 796 | spi.engineSetMode(transformParts[1]); 797 | } 798 | if (((type == NeedToSet.PADDING) || (type == NeedToSet.BOTH)) 799 | && (transformParts[2] != null)) { 800 | spi.engineSetPadding(transformParts[2]); 801 | } 802 | 803 | if (initParams != null) { 804 | switch (initParams.initType) { 805 | case ALGORITHM_PARAMS: 806 | spi.engineInit(initParams.opmode, initParams.key, initParams.params, 807 | initParams.random); 808 | break; 809 | case ALGORITHM_PARAM_SPEC: 810 | spi.engineInit(initParams.opmode, initParams.key, initParams.spec, 811 | initParams.random); 812 | break; 813 | case KEY: 814 | spi.engineInit(initParams.opmode, initParams.key, initParams.random); 815 | break; 816 | default: 817 | throw new AssertionError("This should never be reached"); 818 | } 819 | } 820 | return sap; 821 | } catch (NoSuchAlgorithmException ignored) { 822 | } catch (NoSuchPaddingException ignored) { 823 | } 824 | return null; 825 | } 826 | 827 | /** 828 | * If the attribute listed exists, check that it matches the regular 829 | * expression. 830 | */ 831 | private static boolean matchAttribute(Service service, String attr, String value) { 832 | if (value == null) { 833 | return true; 834 | } 835 | final String pattern = service.getAttribute(attr); 836 | if (pattern == null) { 837 | return true; 838 | } 839 | final String valueUc = value.toUpperCase(Locale.US); 840 | return valueUc.matches(pattern.toUpperCase(Locale.US)); 841 | } 842 | 843 | /** 844 | * Returns the provider of this cipher instance. 845 | * 846 | * @return the provider of this cipher instance. 847 | */ 848 | public final Provider getProvider() { 849 | getSpi(); 850 | return provider; 851 | } 852 | 853 | /** 854 | * Returns the name of the algorithm of this cipher instance. 855 | *

856 | * This is the name of the transformation argument used in the 857 | * {@code getInstance} call creating this object. 858 | * 859 | * @return the name of the algorithm of this cipher instance. 860 | */ 861 | public final String getAlgorithm() { 862 | return transformation; 863 | } 864 | 865 | /** 866 | * Returns this ciphers block size (in bytes). 867 | * 868 | * @return this ciphers block size. 869 | */ 870 | public final int getBlockSize() { 871 | return getSpi().engineGetBlockSize(); 872 | } 873 | 874 | /** 875 | * Returns the length in bytes an output buffer needs to be when this cipher 876 | * is updated with {@code inputLen} bytes. 877 | * 878 | * @param inputLen 879 | * the number of bytes of the input. 880 | * @return the output buffer length for the input length. 881 | * @throws IllegalStateException 882 | * if this cipher instance is in an invalid state. 883 | */ 884 | public final int getOutputSize(int inputLen) { 885 | if (mode == 0) { 886 | throw new IllegalStateException("Cipher has not yet been initialized"); 887 | } 888 | return getSpi().engineGetOutputSize(inputLen); 889 | } 890 | 891 | /** 892 | * Returns the initialization vector for this cipher instance. 893 | * 894 | * @return the initialization vector for this cipher instance. 895 | */ 896 | public final byte[] getIV() { 897 | return getSpi().engineGetIV(); 898 | } 899 | 900 | /** 901 | * Returns the parameters that where used to create this cipher instance. 902 | *

903 | * These may be a the same parameters that were used to create this cipher 904 | * instance, or may be a combination of default and random parameters, 905 | * depending on the underlying cipher implementation. 906 | * 907 | * @return the parameters that where used to create this cipher instance, or 908 | * {@code null} if this cipher instance does not have any 909 | * parameters. 910 | */ 911 | public final AlgorithmParameters getParameters() { 912 | return getSpi().engineGetParameters(); 913 | } 914 | 915 | /** 916 | * Returns the exemption mechanism associated with this cipher. 917 | * 918 | * @return currently {@code null} 919 | */ 920 | public final ExemptionMechanism getExemptionMechanism() { 921 | //FIXME implement getExemptionMechanism 922 | 923 | // try { 924 | // return ExemptionMechanism.getInstance(transformation, provider); 925 | // } catch (NoSuchAlgorithmException e) { 926 | return null; 927 | // } 928 | 929 | } 930 | 931 | /** 932 | * Checks that the provided {@code mode} is one that is valid for 933 | * {@code Cipher}. 934 | */ 935 | private void checkMode(int mode) { 936 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE && mode != UNWRAP_MODE 937 | && mode != WRAP_MODE) { 938 | throw new InvalidParameterException("Invalid mode: " + mode); 939 | } 940 | } 941 | 942 | /** 943 | * Initializes this cipher instance with the specified key. 944 | *

945 | * The cipher is initialized for the specified operational mode (one of: 946 | * encryption, decryption, key wrapping or key unwrapping) depending on 947 | * {@code opmode}. 948 | *

949 | * If this cipher instance needs any algorithm parameters or random values 950 | * that the specified key can not provide, the underlying implementation of 951 | * this cipher is supposed to generate the required parameters (using its 952 | * provider or random values). 953 | *

954 | * When a cipher instance is initialized by a call to any of the {@code 955 | * init} methods, the state of the instance is overridden, meaning that it 956 | * is equivalent to creating a new instance and calling its {@code init} 957 | * method. 958 | * 959 | * @param opmode 960 | * the operation this cipher instance should be initialized for 961 | * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 962 | * WRAP_MODE} or {@code UNWRAP_MODE}). 963 | * @param key 964 | * the input key for the operation. 965 | * @throws InvalidKeyException 966 | * if the specified key can not be used to initialize this 967 | * cipher instance. 968 | */ 969 | public final void init(int opmode, Key key) throws InvalidKeyException { 970 | if (secureRandom == null) { 971 | // In theory it might be thread-unsafe but in the given case it's OK 972 | // since it does not matter which SecureRandom instance is passed 973 | // to the init() 974 | secureRandom = new SecureRandom(); 975 | } 976 | init(opmode, key, secureRandom); 977 | } 978 | 979 | /** 980 | * Initializes this cipher instance with the specified key and a source of 981 | * randomness. 982 | *

983 | * The cipher is initialized for the specified operational mode (one of: 984 | * encryption, decryption, key wrapping or key unwrapping) depending on 985 | * {@code opmode}. 986 | *

987 | * If this cipher instance needs any algorithm parameters or random values 988 | * that the specified key can not provide, the underlying implementation of 989 | * this cipher is supposed to generate the required parameters (using its 990 | * provider or random values). Random values are generated using {@code 991 | * random}; 992 | *

993 | * When a cipher instance is initialized by a call to any of the {@code 994 | * init} methods, the state of the instance is overridden, means it is 995 | * equivalent to creating a new instance and calling it {@code init} method. 996 | * 997 | * @param opmode 998 | * the operation this cipher instance should be initialized for 999 | * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 1000 | * WRAP_MODE} or {@code UNWRAP_MODE}). 1001 | * @param key 1002 | * the input key for the operation. 1003 | * @param random 1004 | * the source of randomness to use. 1005 | * @throws InvalidKeyException 1006 | * if the specified key can not be used to initialize this 1007 | * cipher instance. 1008 | * @throws InvalidParameterException 1009 | * if the specified opmode is invalid. 1010 | */ 1011 | public final void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { 1012 | checkMode(opmode); 1013 | // FIXME InvalidKeyException 1014 | // if keysize exceeds the maximum allowable keysize 1015 | // (jurisdiction policy files) 1016 | try { 1017 | getSpi(new InitParams(InitType.KEY, opmode, key, random, null, null)); 1018 | } catch (InvalidAlgorithmParameterException e) { 1019 | // Should never happen since we only specified the key. 1020 | throw new ProviderException("Invalid parameters when params == null", e); 1021 | } 1022 | mode = opmode; 1023 | 1024 | //add by icew4y 2019 12 13 1025 | 1026 | passThrough_InitParams(InitType.KEY, opmode, key, random, null, null); 1027 | //System.out.println("MyTag: InitParams -> " + sb.toString()); 1028 | //add by icew4y 2019 12 13 1029 | } 1030 | 1031 | /** 1032 | * Initializes this cipher instance with the specified key and algorithm 1033 | * parameters. 1034 | *

1035 | * The cipher is initialized for the specified operational mode (one of: 1036 | * encryption, decryption, key wrapping or key unwrapping). 1037 | *

1038 | * If this cipher instance needs any algorithm parameters and {@code params} 1039 | * is {@code null}, the underlying implementation of this cipher is supposed 1040 | * to generate the required parameters (using its provider or random 1041 | * values). 1042 | *

1043 | * When a cipher instance is initialized by a call to any of the {@code 1044 | * init} methods, the state of the instance is overridden, means it is 1045 | * equivalent to creating a new instance and calling it {@code init} method. 1046 | * 1047 | * @param opmode 1048 | * the operation this cipher instance should be initialized for 1049 | * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 1050 | * WRAP_MODE} or {@code UNWRAP_MODE}). 1051 | * @param key 1052 | * the input key for the operation. 1053 | * @param params 1054 | * the algorithm parameters. 1055 | * @throws InvalidKeyException 1056 | * if the specified key can not be used to initialize this 1057 | * cipher instance. 1058 | * @throws InvalidAlgorithmParameterException 1059 | * it the specified parameters are inappropriate for this 1060 | * cipher. 1061 | */ 1062 | public final void init(int opmode, Key key, AlgorithmParameterSpec params) 1063 | throws InvalidKeyException, InvalidAlgorithmParameterException { 1064 | if (secureRandom == null) { 1065 | secureRandom = new SecureRandom(); 1066 | } 1067 | init(opmode, key, params, secureRandom); 1068 | } 1069 | 1070 | /** 1071 | * Initializes this cipher instance with the specified key, algorithm 1072 | * parameters and a source of randomness. 1073 | *

1074 | * The cipher is initialized for the specified operational mode (one of: 1075 | * encryption, decryption, key wrapping or key unwrapping) depending on 1076 | * {@code opmode}. 1077 | *

1078 | * If this cipher instance needs any algorithm parameters and {@code params} 1079 | * is {@code null}, the underlying implementation of this cipher is supposed 1080 | * to generate the required parameters (using its provider or random 1081 | * values). Random values are generated using {@code random}; 1082 | *

1083 | * When a cipher instance is initialized by a call to any of the {@code 1084 | * init} methods, the state of the instance is overridden, meaning that it 1085 | * is equivalent to creating a new instance and calling it {@code init} 1086 | * method. 1087 | * 1088 | * @param opmode 1089 | * the operation this cipher instance should be initialized for 1090 | * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 1091 | * WRAP_MODE} or {@code UNWRAP_MODE}). 1092 | * @param key 1093 | * the input key for the operation. 1094 | * @param params 1095 | * the algorithm parameters. 1096 | * @param random 1097 | * the source of randomness to use. 1098 | * @throws InvalidKeyException 1099 | * if the specified key can not be used to initialize this 1100 | * cipher instance. 1101 | * @throws InvalidAlgorithmParameterException 1102 | * it the specified parameters are inappropriate for this 1103 | * cipher. 1104 | * @throws InvalidParameterException 1105 | * if the specified {@code opmode} is invalid. 1106 | */ 1107 | public final void init(int opmode, Key key, AlgorithmParameterSpec params, 1108 | SecureRandom random) throws InvalidKeyException, 1109 | InvalidAlgorithmParameterException { 1110 | checkMode(opmode); 1111 | // FIXME InvalidKeyException 1112 | // if keysize exceeds the maximum allowable keysize 1113 | // (jurisdiction policy files) 1114 | // FIXME InvalidAlgorithmParameterException 1115 | // cryptographic strength exceed the legal limits 1116 | // (jurisdiction policy files) 1117 | getSpi(new InitParams(InitType.ALGORITHM_PARAM_SPEC, opmode, key, random, params, null)); 1118 | mode = opmode; 1119 | 1120 | // add by icew4y 2019 12 13 1121 | passThrough_InitParams(InitType.ALGORITHM_PARAM_SPEC, opmode, key, random, params, null); 1122 | // add by icew4y 2019 12 13 1123 | } 1124 | 1125 | /** 1126 | * Initializes this cipher instance with the specified key and algorithm 1127 | * parameters. 1128 | *

1129 | * The cipher is initialized for the specified operation (one of: 1130 | * encryption, decryption, key wrapping or key unwrapping) depending on 1131 | * {@code opmode}. 1132 | *

1133 | * If this cipher instance needs any algorithm parameters and {@code params} 1134 | * is {@code null}, the underlying implementation of this cipher is supposed 1135 | * to generate the required parameters (using its provider or random 1136 | * values). 1137 | *

1138 | * When a cipher instance is initialized by a call to any of the {@code 1139 | * init} methods, the state of the instance is overridden, meaning that it 1140 | * is equivalent to creating a new instance and calling it {@code init} 1141 | * method. 1142 | * 1143 | * @param opmode 1144 | * the operation this cipher instance should be initialized for 1145 | * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 1146 | * WRAP_MODE} or {@code UNWRAP_MODE}). 1147 | * @param key 1148 | * the input key for the operation. 1149 | * @param params 1150 | * the algorithm parameters. 1151 | * @throws InvalidKeyException 1152 | * if the specified key can not be used to initialize this 1153 | * cipher instance. 1154 | * @throws InvalidAlgorithmParameterException 1155 | * it the specified parameters are inappropriate for this 1156 | * cipher. 1157 | */ 1158 | public final void init(int opmode, Key key, AlgorithmParameters params) 1159 | throws InvalidKeyException, InvalidAlgorithmParameterException { 1160 | if (secureRandom == null) { 1161 | secureRandom = new SecureRandom(); 1162 | } 1163 | init(opmode, key, params, secureRandom); 1164 | } 1165 | 1166 | /** 1167 | * Initializes this cipher instance with the specified key, algorithm 1168 | * parameters and a source of randomness. 1169 | *

1170 | * The cipher will be initialized for the specified operation (one of: 1171 | * encryption, decryption, key wrapping or key unwrapping) depending on 1172 | * {@code opmode}. 1173 | *

1174 | * If this cipher instance needs any algorithm parameters and {@code params} 1175 | * is {@code null}, the underlying implementation of this cipher is supposed 1176 | * to generate the required parameters (using its provider or random 1177 | * values). Random values are generated using {@code random}. 1178 | *

1179 | * When a cipher instance is initialized by a call to any of the {@code 1180 | * init} methods, the state of the instance is overridden, means it is 1181 | * equivalent to creating a new instance and calling it {@code init} method. 1182 | * 1183 | * @param opmode 1184 | * the operation this cipher instance should be initialized for 1185 | * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 1186 | * WRAP_MODE} or {@code UNWRAP_MODE}). 1187 | * @param key 1188 | * the input key for the operation. 1189 | * @param params 1190 | * the algorithm parameters. 1191 | * @param random 1192 | * the source of randomness to use. 1193 | * @throws InvalidKeyException 1194 | * if the specified key can not be used to initialize this 1195 | * cipher instance. 1196 | * @throws InvalidAlgorithmParameterException 1197 | * if the specified parameters are inappropriate for this 1198 | * cipher. 1199 | * @throws InvalidParameterException 1200 | * if the specified {@code opmode} is invalid. 1201 | */ 1202 | public final void init(int opmode, Key key, AlgorithmParameters params, 1203 | SecureRandom random) throws InvalidKeyException, 1204 | InvalidAlgorithmParameterException { 1205 | checkMode(opmode); 1206 | // FIXME InvalidKeyException 1207 | // if keysize exceeds the maximum allowable keysize 1208 | // (jurisdiction policy files) 1209 | // FIXME InvalidAlgorithmParameterException 1210 | // cryptographic strength exceed the legal limits 1211 | // (jurisdiction policy files) 1212 | getSpi(new InitParams(InitType.ALGORITHM_PARAMS, opmode, key, random, null, params)); 1213 | mode = opmode; 1214 | 1215 | // add by icew4y 2019 12 13 1216 | passThrough_InitParams(InitType.ALGORITHM_PARAMS, opmode, key, random, null, params); 1217 | // add by icew4y 2019 12 13 1218 | } 1219 | 1220 | /** 1221 | * Initializes this cipher instance with the public key from the specified 1222 | * certificate. 1223 | *

1224 | * The cipher will be initialized for the specified operation (one of: 1225 | * encryption, decryption, key wrapping or key unwrapping) depending on 1226 | * {@code opmode}. 1227 | *

1228 | * It the type of the certificate is X.509 and the certificate has a key 1229 | * usage extension field marked as critical, the specified {@code 1230 | * opmode} has the be enabled for this key, otherwise an {@code 1231 | * InvalidKeyException} is thrown. 1232 | *

1233 | * If this cipher instance needs any algorithm parameters that the key in 1234 | * the certificate can not provide, the underlying implementation of this 1235 | * cipher is supposed to generate the required parameters (using its 1236 | * provider or random values). 1237 | *

1238 | * When a cipher instance is initialized by a call to any of the {@code 1239 | * init} methods, the state of the instance is overridden, means it is 1240 | * equivalent to creating a new instance and calling it {@code init} method. 1241 | * 1242 | * @param opmode 1243 | * the operation this cipher instance should be initialized for 1244 | * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 1245 | * WRAP_MODE} or {@code UNWRAP_MODE}). 1246 | * @param certificate 1247 | * the certificate. 1248 | * @throws InvalidKeyException 1249 | * if the public key in the certificate can not be used to 1250 | * initialize this cipher instance. 1251 | */ 1252 | public final void init(int opmode, Certificate certificate) 1253 | throws InvalidKeyException { 1254 | if (secureRandom == null) { 1255 | secureRandom = new SecureRandom(); 1256 | } 1257 | init(opmode, certificate, secureRandom); 1258 | } 1259 | 1260 | /** 1261 | * Initializes this cipher instance with the public key from the specified 1262 | * certificate and a source of randomness. 1263 | *

1264 | * The cipher will be initialized for the specified operation (one of: 1265 | * encryption, decryption, key wrapping or key unwrapping) depending on 1266 | * {@code opmode}. 1267 | *

1268 | * It the type of the certificate is X.509 and the certificate has a key 1269 | * usage extension field marked as critical, the specified {@code 1270 | * opmode} has the be enabled for this key, otherwise an {@code 1271 | * InvalidKeyException} is thrown. 1272 | *

1273 | * If this cipher instance needs any algorithm parameters that the key in 1274 | * the certificate can not provide, the underlying implementation of this 1275 | * cipher is supposed to generate the required parameters (using its 1276 | * provider or random values). Random values are generated using {@code 1277 | * random}. 1278 | *

1279 | * When a cipher instance is initialized by a call to any of the {@code 1280 | * init} methods, the state of the instance is overridden, means it is 1281 | * equivalent to creating a new instance and calling it {@code init} method. 1282 | * 1283 | * @param opmode 1284 | * the operation this cipher instance should be initialized for 1285 | * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code 1286 | * WRAP_MODE} or {@code UNWRAP_MODE}). 1287 | * @param certificate 1288 | * the certificate. 1289 | * @param random 1290 | * the source of randomness to be used. 1291 | * @throws InvalidKeyException 1292 | * if the public key in the certificate can not be used to 1293 | * initialize this cipher instance. 1294 | */ 1295 | public final void init(int opmode, Certificate certificate, 1296 | SecureRandom random) throws InvalidKeyException { 1297 | checkMode(opmode); 1298 | if (certificate instanceof X509Certificate) { 1299 | Set ce = ((X509Certificate) certificate).getCriticalExtensionOIDs(); 1300 | boolean critical = false; 1301 | if (ce != null && !ce.isEmpty()) { 1302 | for (String oid : ce) { 1303 | if (oid.equals("2.5.29.15")) { // KeyUsage OID = 2.5.29.15 1304 | critical = true; 1305 | break; 1306 | } 1307 | } 1308 | if (critical) { 1309 | boolean[] keyUsage = ((X509Certificate) certificate).getKeyUsage(); 1310 | // As specified in RFC 3280: 1311 | // Internet X.509 Public Key Infrastructure 1312 | // Certificate and Certificate Revocation List (CRL) Profile. 1313 | // Section 4.2.1.3 Key Usage 1314 | // http://www.ietf.org/rfc/rfc3280.txt 1315 | // 1316 | // KeyUsage ::= BIT STRING {digitalSignature (0), 1317 | // nonRepudiation (1), 1318 | // keyEncipherment (2), 1319 | // dataEncipherment (3), 1320 | // keyAgreement (4), 1321 | // keyCertSign (5), 1322 | // cRLSign (6), 1323 | // encipherOnly (7), 1324 | // decipherOnly (8) } 1325 | if (keyUsage != null) { 1326 | if (opmode == ENCRYPT_MODE && !keyUsage[3]) { 1327 | throw new InvalidKeyException("The public key in the certificate " 1328 | + "cannot be used for ENCRYPT_MODE"); 1329 | } else if (opmode == WRAP_MODE && !keyUsage[2]) { 1330 | throw new InvalidKeyException("The public key in the certificate " 1331 | + "cannot be used for WRAP_MODE"); 1332 | } 1333 | } 1334 | } 1335 | } 1336 | } 1337 | // FIXME InvalidKeyException 1338 | // if keysize exceeds the maximum allowable keysize 1339 | // (jurisdiction policy files) 1340 | final Key key = certificate.getPublicKey(); 1341 | try { 1342 | getSpi(new InitParams(InitType.KEY, opmode, key, random, null, null)); 1343 | } catch (InvalidAlgorithmParameterException e) { 1344 | // Should never happen since we only specified the key. 1345 | throw new ProviderException("Invalid parameters when params == null", e); 1346 | } 1347 | mode = opmode; 1348 | 1349 | // add by icew4y 2019 12 13 1350 | passThrough_InitParams(InitType.KEY, opmode, key, random, null, null); 1351 | // add by icew4y 2019 12 13 1352 | } 1353 | 1354 | /** 1355 | * Continues a multi-part transformation (encryption or decryption). The 1356 | * transformed bytes are returned. 1357 | * 1358 | * @param input 1359 | * the input bytes to transform. 1360 | * @return the transformed bytes in a new buffer, or {@code null} if the 1361 | * input has zero length. 1362 | * @throws IllegalStateException 1363 | * if this cipher instance is not initialized for encryption or 1364 | * decryption. 1365 | * @throws IllegalArgumentException 1366 | * if the input is {@code null}. 1367 | */ 1368 | public final byte[] update(byte[] input) { 1369 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1370 | throw new IllegalStateException(); 1371 | } 1372 | if (input == null) { 1373 | throw new IllegalArgumentException("input == null"); 1374 | } 1375 | if (input.length == 0) { 1376 | return null; 1377 | } 1378 | return getSpi().engineUpdate(input, 0, input.length); 1379 | } 1380 | 1381 | /** 1382 | * Continues a multi-part transformation (encryption or decryption). The 1383 | * transformed bytes are returned. 1384 | * 1385 | * @param input 1386 | * the input bytes to transform. 1387 | * @param inputOffset 1388 | * the offset in the input to start. 1389 | * @param inputLen 1390 | * the length of the input to transform. 1391 | * @return the transformed bytes in a new buffer, or {@code null} if {@code inputLen} is zero. 1392 | * @throws IllegalStateException 1393 | * if this cipher instance is not initialized for encryption or 1394 | * decryption. 1395 | * @throws IllegalArgumentException 1396 | * if {@code input} is {@code null}, or if {@code inputOffset} and 1397 | * {@code inputLen} do not specify a valid chunk in the input 1398 | * buffer. 1399 | */ 1400 | public final byte[] update(byte[] input, int inputOffset, int inputLen) { 1401 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1402 | throw new IllegalStateException(); 1403 | } 1404 | if (input == null) { 1405 | throw new IllegalArgumentException("input == null"); 1406 | } 1407 | checkInputOffsetAndCount(input.length, inputOffset, inputLen); 1408 | if (inputLen == 0) { 1409 | return null; 1410 | } 1411 | return getSpi().engineUpdate(input, inputOffset, inputLen); 1412 | } 1413 | 1414 | private static void checkInputOffsetAndCount(int inputArrayLength, 1415 | int inputOffset, 1416 | int inputLen) { 1417 | if ((inputOffset | inputLen) < 0 1418 | || inputOffset > inputArrayLength 1419 | || inputArrayLength - inputOffset < inputLen) { 1420 | throw new IllegalArgumentException("input.length=" + inputArrayLength 1421 | + "; inputOffset=" + inputOffset 1422 | + "; inputLen=" + inputLen); 1423 | } 1424 | } 1425 | 1426 | /** 1427 | * Continues a multi-part transformation (encryption or decryption). The 1428 | * transformed bytes are stored in the {@code output} buffer. 1429 | *

1430 | * If the size of the {@code output} buffer is too small to hold the result, 1431 | * a {@code ShortBufferException} is thrown. Use 1432 | * {@link Cipher#getOutputSize getOutputSize} to check for the size of the 1433 | * output buffer. 1434 | * 1435 | * @param input 1436 | * the input bytes to transform. 1437 | * @param inputOffset 1438 | * the offset in the input to start. 1439 | * @param inputLen 1440 | * the length of the input to transform. 1441 | * @param output 1442 | * the output buffer. 1443 | * @return the number of bytes placed in output. 1444 | * @throws ShortBufferException 1445 | * if the size of the {@code output} buffer is too small. 1446 | * @throws IllegalStateException 1447 | * if this cipher instance is not initialized for encryption or 1448 | * decryption. 1449 | * @throws IllegalArgumentException 1450 | * if the input is {@code null}, the output is {@code null}, or 1451 | * if {@code inputOffset} and {@code inputLen} do not specify a 1452 | * valid chunk in the input buffer. 1453 | */ 1454 | public final int update(byte[] input, int inputOffset, int inputLen, 1455 | byte[] output) throws ShortBufferException { 1456 | return update(input, inputOffset, inputLen, output, 0); 1457 | } 1458 | 1459 | /** 1460 | * Continues a multi-part transformation (encryption or decryption). The 1461 | * transformed bytes are stored in the {@code output} buffer. 1462 | *

1463 | * If the size of the {@code output} buffer is too small to hold the result, 1464 | * a {@code ShortBufferException} is thrown. Use 1465 | * {@link Cipher#getOutputSize getOutputSize} to check for the size of the 1466 | * output buffer. 1467 | * 1468 | * @param input 1469 | * the input bytes to transform. 1470 | * @param inputOffset 1471 | * the offset in the input to start. 1472 | * @param inputLen 1473 | * the length of the input to transform. 1474 | * @param output 1475 | * the output buffer. 1476 | * @param outputOffset 1477 | * the offset in the output buffer. 1478 | * @return the number of bytes placed in output. 1479 | * @throws ShortBufferException 1480 | * if the size of the {@code output} buffer is too small. 1481 | * @throws IllegalStateException 1482 | * if this cipher instance is not initialized for encryption or 1483 | * decryption. 1484 | * @throws IllegalArgumentException 1485 | * if the input is {@code null}, the output is {@code null}, or 1486 | * if {@code inputOffset} and {@code inputLen} do not specify a 1487 | * valid chunk in the input buffer. 1488 | */ 1489 | public final int update(byte[] input, int inputOffset, int inputLen, 1490 | byte[] output, int outputOffset) throws ShortBufferException { 1491 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1492 | throw new IllegalStateException(); 1493 | } 1494 | if (input == null) { 1495 | throw new IllegalArgumentException("input == null"); 1496 | } 1497 | if (output == null) { 1498 | throw new IllegalArgumentException("output == null"); 1499 | } 1500 | if (outputOffset < 0) { 1501 | throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset); 1502 | } 1503 | checkInputOffsetAndCount(input.length, inputOffset, inputLen); 1504 | if (input.length == 0) { 1505 | return 0; 1506 | } 1507 | return getSpi().engineUpdate(input, inputOffset, inputLen, output, 1508 | outputOffset); 1509 | } 1510 | 1511 | /** 1512 | * Continues a multi-part transformation (encryption or decryption). The 1513 | * {@code input.remaining()} bytes starting at {@code input.position()} are 1514 | * transformed and stored in the {@code output} buffer. 1515 | *

1516 | * If the {@code output.remaining()} is too small to hold the transformed 1517 | * bytes a {@code ShortBufferException} is thrown. Use 1518 | * {@link Cipher#getOutputSize getOutputSize} to check for the size of the 1519 | * output buffer. 1520 | * 1521 | * @param input 1522 | * the input buffer to transform. 1523 | * @param output 1524 | * the output buffer to store the result within. 1525 | * @return the number of bytes stored in the output buffer. 1526 | * @throws ShortBufferException 1527 | * if the size of the {@code output} buffer is too small. 1528 | * @throws IllegalStateException 1529 | * if this cipher instance is not initialized for encryption or 1530 | * decryption. 1531 | * @throws IllegalArgumentException 1532 | * if the input buffer and the output buffer are the identical 1533 | * object. 1534 | */ 1535 | public final int update(ByteBuffer input, ByteBuffer output) 1536 | throws ShortBufferException { 1537 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1538 | throw new IllegalStateException(); 1539 | } 1540 | if (input == output) { 1541 | throw new IllegalArgumentException("input == output"); 1542 | } 1543 | return getSpi().engineUpdate(input, output); 1544 | } 1545 | 1546 | /** 1547 | * Continues a multi-part transformation (encryption or decryption) with 1548 | * Authenticated Additional Data (AAD). AAD may only be added after the 1549 | * {@code Cipher} is initialized and before any data is passed to the 1550 | * instance. 1551 | *

1552 | * This is only usable with cipher modes that support Authenticated 1553 | * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM). 1554 | * 1555 | * @param input bytes of AAD to use with the cipher 1556 | * @throws IllegalStateException 1557 | * if this cipher instance is not initialized for encryption or 1558 | * decryption. 1559 | * @throws IllegalArgumentException 1560 | * if {@code input} is {@code null} 1561 | * @throws UnsupportedOperationException if the cipher does not support AEAD 1562 | * @since 1.7 1563 | */ 1564 | public final void updateAAD(byte[] input) { 1565 | if (input == null) { 1566 | throw new IllegalArgumentException("input == null"); 1567 | } 1568 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1569 | throw new IllegalStateException(); 1570 | } 1571 | if (input.length == 0) { 1572 | return; 1573 | } 1574 | getSpi().engineUpdateAAD(input, 0, input.length); 1575 | } 1576 | 1577 | /** 1578 | * Continues a multi-part transformation (encryption or decryption) with 1579 | * Authenticated Additional Data (AAD). AAD may only be added after the 1580 | * {@code Cipher} is initialized and before any data is passed to the 1581 | * instance. 1582 | *

1583 | * This is only usable with cipher modes that support Authenticated 1584 | * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM). 1585 | * 1586 | * @param input bytes of AAD to use with the cipher 1587 | * @param inputOffset offset within bytes of additional data to add to cipher 1588 | * @param inputLen length of bytes of additional data to add to cipher 1589 | * @throws IllegalStateException 1590 | * if this cipher instance is not initialized for encryption or 1591 | * decryption. 1592 | * @throws IllegalArgumentException 1593 | * if {@code input} is {@code null}, or if {@code inputOffset} and 1594 | * {@code inputLen} do not specify a valid chunk in the input 1595 | * buffer. 1596 | * @throws UnsupportedOperationException if the cipher does not support AEAD 1597 | * @since 1.7 1598 | */ 1599 | public final void updateAAD(byte[] input, int inputOffset, int inputLen) { 1600 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1601 | throw new IllegalStateException(); 1602 | } 1603 | if (input == null) { 1604 | throw new IllegalArgumentException("input == null"); 1605 | } 1606 | checkInputOffsetAndCount(input.length, inputOffset, inputLen); 1607 | if (input.length == 0) { 1608 | return; 1609 | } 1610 | getSpi().engineUpdateAAD(input, inputOffset, inputLen); 1611 | } 1612 | 1613 | /** 1614 | * Continues a multi-part transformation (encryption or decryption) with 1615 | * Authenticated Additional Data (AAD). AAD may only be added after the 1616 | * {@code Cipher} is initialized and before any data is passed to the 1617 | * instance. 1618 | *

1619 | * This is only usable with cipher modes that support Authenticated 1620 | * Encryption with Additional Data (AEAD) such as Galois/Counter Mode (GCM). 1621 | * 1622 | * @param input buffer of AAD to be used 1623 | * @throws IllegalStateException 1624 | * if this cipher instance is not initialized for encryption or 1625 | * decryption. 1626 | * @throws UnsupportedOperationException if the cipher does not support AEAD 1627 | * @since 1.7 1628 | */ 1629 | public final void updateAAD(ByteBuffer input) { 1630 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1631 | throw new IllegalStateException("Cipher is not initialized"); 1632 | } 1633 | if (input == null) { 1634 | throw new IllegalArgumentException("input == null"); 1635 | } 1636 | getSpi().engineUpdateAAD(input); 1637 | } 1638 | 1639 | /** 1640 | * Finishes a multi-part transformation (encryption or decryption). 1641 | *

1642 | * Processes any bytes that may have been buffered in previous {@code 1643 | * update} calls. 1644 | * 1645 | * @return the final bytes from the transformation. 1646 | * @throws IllegalBlockSizeException 1647 | * if the size of the resulting bytes is not a multiple of the 1648 | * cipher block size. 1649 | * @throws BadPaddingException 1650 | * if the padding of the data does not match the padding scheme. 1651 | * @throws IllegalStateException 1652 | * if this cipher instance is not initialized for encryption or 1653 | * decryption. 1654 | */ 1655 | public final byte[] doFinal() throws IllegalBlockSizeException, 1656 | BadPaddingException { 1657 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1658 | throw new IllegalStateException(); 1659 | } 1660 | //return getSpi().engineDoFinal(null, 0, 0); 1661 | 1662 | //add by icew4y 2019 12 13 1663 | byte[] resultData = getSpi().engineDoFinal(null, 0, 0); 1664 | 1665 | if (switch_state == true ) { 1666 | try { 1667 | String packageName = ContextHolder.getPackageName(); 1668 | if (!MyUtil.isWhiteList(packageName)) { 1669 | if (monPackageName.equals("")) { 1670 | monPackageName = MyUtil.readPackageNameFromFile(); 1671 | } 1672 | if (!monPackageName.equals("")) { 1673 | if (packageName.equals(monPackageName)) { 1674 | if (this.specifiedProvider != null) { 1675 | jsoninfo.put("provider", this.specifiedProvider.getName()); 1676 | }else{ 1677 | jsoninfo.put("provider", ""); 1678 | } 1679 | jsoninfo.put("transformation", this.transformation == null ? "" : this.transformation); 1680 | jsoninfo.put("data", "unknow!"); 1681 | jsoninfo.put("Base64Data", "unknow!"); 1682 | jsoninfo.put("doFinal", byteArrayToString(resultData)); 1683 | jsoninfo.put("Base64Cipher", AndroidBase64.encodeToString(resultData, AndroidBase64.NO_WRAP)); 1684 | jsoninfo.put("StackTrace", AndroidBase64.encodeToString(MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace()).getBytes(), AndroidBase64.NO_WRAP)); 1685 | priter("CipherTag:" + jsoninfo.toString(), packageName); 1686 | } 1687 | } 1688 | } 1689 | 1690 | 1691 | 1692 | 1693 | 1694 | } catch (Exception e) { 1695 | e.printStackTrace(); 1696 | } 1697 | } 1698 | 1699 | 1700 | return resultData; 1701 | //add by icew4y 2019 12 13 1702 | } 1703 | 1704 | /** 1705 | * Finishes a multi-part transformation (encryption or decryption). 1706 | *

1707 | * Processes any bytes that may have been buffered in previous {@code 1708 | * update} calls. 1709 | *

1710 | * The final transformed bytes are stored in the {@code output} buffer. 1711 | * 1712 | * @param output 1713 | * the output buffer. 1714 | * @param outputOffset 1715 | * the offset in the output buffer. 1716 | * @return the number of bytes placed in the output buffer. 1717 | * @throws IllegalBlockSizeException 1718 | * if the size of the resulting bytes is not a multiple of the 1719 | * cipher block size. 1720 | * @throws ShortBufferException 1721 | * if the size of the {@code output} buffer is too small. 1722 | * @throws BadPaddingException 1723 | * if the padding of the data does not match the padding scheme. 1724 | * @throws IllegalStateException 1725 | * if this cipher instance is not initialized for encryption or 1726 | * decryption. 1727 | */ 1728 | public final int doFinal(byte[] output, int outputOffset) 1729 | throws IllegalBlockSizeException, ShortBufferException, 1730 | BadPaddingException { 1731 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1732 | throw new IllegalStateException(); 1733 | } 1734 | if (outputOffset < 0) { 1735 | throw new IllegalArgumentException("outputOffset < 0. outputOffset=" + outputOffset); 1736 | } 1737 | return getSpi().engineDoFinal(null, 0, 0, output, outputOffset); 1738 | } 1739 | 1740 | /** 1741 | * Finishes a multi-part transformation (encryption or decryption). 1742 | *

1743 | * Processes the bytes in {@code input} buffer, and any bytes that have been 1744 | * buffered in previous {@code update} calls. 1745 | * 1746 | * @param input 1747 | * the input buffer. 1748 | * @return the final bytes from the transformation. 1749 | * @throws IllegalBlockSizeException 1750 | * if the size of the resulting bytes is not a multiple of the 1751 | * cipher block size. 1752 | * @throws BadPaddingException 1753 | * if the padding of the data does not match the padding scheme. 1754 | * @throws IllegalStateException 1755 | * if this cipher instance is not initialized for encryption or 1756 | * decryption. 1757 | */ 1758 | public final byte[] doFinal(byte[] input) throws IllegalBlockSizeException, 1759 | BadPaddingException { 1760 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1761 | throw new IllegalStateException(); 1762 | } 1763 | //add by icew4y 2019 12 13 1764 | byte[] resultData = getSpi().engineDoFinal(input, 0, input.length); 1765 | 1766 | if (switch_state == true && !check_oom(input)) { 1767 | try { 1768 | String packageName = ContextHolder.getPackageName(); 1769 | if (!MyUtil.isWhiteList(packageName)) { 1770 | if (monPackageName.equals("")) { 1771 | monPackageName = MyUtil.readPackageNameFromFile(); 1772 | } 1773 | if (!monPackageName.equals("")) { 1774 | if (packageName.equals(monPackageName)) { 1775 | if (this.specifiedProvider != null) { 1776 | jsoninfo.put("provider", this.specifiedProvider.getName()); 1777 | }else{ 1778 | jsoninfo.put("provider", ""); 1779 | } 1780 | jsoninfo.put("transformation", this.transformation == null ? "" : this.transformation); 1781 | 1782 | jsoninfo.put("data", byteArrayToString(input)); 1783 | jsoninfo.put("Base64Data", AndroidBase64.encodeToString(input, AndroidBase64.NO_WRAP)); 1784 | jsoninfo.put("doFinal", byteArrayToString(resultData)); 1785 | jsoninfo.put("Base64Cipher", AndroidBase64.encodeToString(resultData, AndroidBase64.NO_WRAP)); 1786 | jsoninfo.put("StackTrace", AndroidBase64.encodeToString(MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace()).getBytes(), AndroidBase64.NO_WRAP)); 1787 | 1788 | priter("CipherTag:" + jsoninfo.toString(), packageName); 1789 | } 1790 | } 1791 | } 1792 | 1793 | } catch (Exception e) { 1794 | e.printStackTrace(); 1795 | } 1796 | } 1797 | 1798 | return resultData; 1799 | //add by icew4y 2019 12 13 1800 | 1801 | 1802 | 1803 | //return getSpi().engineDoFinal(input, 0, input.length); 1804 | } 1805 | 1806 | /** 1807 | * Finishes a multi-part transformation (encryption or decryption). 1808 | *

1809 | * Processes the {@code inputLen} bytes in {@code input} buffer at {@code 1810 | * inputOffset}, and any bytes that have been buffered in previous {@code 1811 | * update} calls. 1812 | * 1813 | * @param input 1814 | * the input buffer. 1815 | * @param inputOffset 1816 | * the offset in the input buffer. 1817 | * @param inputLen 1818 | * the length of the input 1819 | * @return the final bytes from the transformation. 1820 | * @throws IllegalBlockSizeException 1821 | * if the size of the resulting bytes is not a multiple of the 1822 | * cipher block size. 1823 | * @throws BadPaddingException 1824 | * if the padding of the data does not match the padding scheme. 1825 | * @throws IllegalStateException 1826 | * if this cipher instance is not initialized for encryption or 1827 | * decryption. 1828 | * @throws IllegalArgumentException 1829 | * if {@code inputOffset} and {@code inputLen} do not specify an 1830 | * valid chunk in the input buffer. 1831 | */ 1832 | public final byte[] doFinal(byte[] input, int inputOffset, int inputLen) 1833 | throws IllegalBlockSizeException, BadPaddingException { 1834 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1835 | throw new IllegalStateException(); 1836 | } 1837 | checkInputOffsetAndCount(input.length, inputOffset, inputLen); 1838 | //add by icew4y 2019 12 13 1839 | 1840 | 1841 | byte[] resultData = getSpi().engineDoFinal(input, inputOffset, inputLen); 1842 | if (switch_state == true && !check_oom(input)) { 1843 | try { 1844 | String packageName = ContextHolder.getPackageName(); 1845 | if (!MyUtil.isWhiteList(packageName)) { 1846 | if (monPackageName.equals("")) { 1847 | monPackageName = MyUtil.readPackageNameFromFile(); 1848 | } 1849 | if (!monPackageName.equals("")) { 1850 | if (packageName.equals(monPackageName)) { 1851 | if (this.specifiedProvider != null) { 1852 | jsoninfo.put("provider", this.specifiedProvider.getName()); 1853 | } else { 1854 | jsoninfo.put("provider", ""); 1855 | } 1856 | jsoninfo.put("transformation", this.transformation == null ? "" : this.transformation); 1857 | 1858 | byte[] inputdata = new byte[inputLen]; 1859 | System.arraycopy(input, inputOffset, inputdata, 0, inputLen); 1860 | 1861 | jsoninfo.put("data", byteArrayToString(inputdata)); 1862 | jsoninfo.put("Base64Data", AndroidBase64.encodeToString(inputdata, AndroidBase64.NO_WRAP)); 1863 | jsoninfo.put("doFinal", byteArrayToString(resultData)); 1864 | jsoninfo.put("Base64Cipher", AndroidBase64.encodeToString(resultData, AndroidBase64.NO_WRAP)); 1865 | jsoninfo.put("StackTrace", AndroidBase64.encodeToString(MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace()).getBytes(), AndroidBase64.NO_WRAP)); 1866 | 1867 | priter("CipherTag:" + jsoninfo.toString(), packageName); 1868 | } 1869 | } 1870 | } 1871 | 1872 | 1873 | } catch (Exception e) { 1874 | e.printStackTrace(); 1875 | } 1876 | } 1877 | 1878 | 1879 | return resultData; 1880 | //add by icew4y 2019 12 13 1881 | 1882 | //return getSpi().engineDoFinal(input, inputOffset, inputLen); 1883 | } 1884 | 1885 | /** 1886 | * Finishes a multi-part transformation (encryption or decryption). 1887 | *

1888 | * Processes the {@code inputLen} bytes in {@code input} buffer at {@code 1889 | * inputOffset}, and any bytes that have been buffered in previous {@code 1890 | * update} calls. 1891 | * 1892 | * @param input 1893 | * the input buffer. 1894 | * @param inputOffset 1895 | * the offset in the input buffer. 1896 | * @param inputLen 1897 | * the length of the input. 1898 | * @param output 1899 | * the output buffer for the transformed bytes. 1900 | * @return the number of bytes placed in the output buffer. 1901 | * @throws ShortBufferException 1902 | * if the size of the {@code output} buffer is too small. 1903 | * @throws IllegalBlockSizeException 1904 | * if the size of the resulting bytes is not a multiple of the 1905 | * cipher block size. 1906 | * @throws BadPaddingException 1907 | * if the padding of the data does not match the padding scheme. 1908 | * @throws IllegalStateException 1909 | * if this cipher instance is not initialized for encryption or 1910 | * decryption. 1911 | * @throws IllegalArgumentException 1912 | * if {@code inputOffset} and {@code inputLen} do not specify an 1913 | * valid chunk in the input buffer. 1914 | */ 1915 | public final int doFinal(byte[] input, int inputOffset, int inputLen, 1916 | byte[] output) throws ShortBufferException, 1917 | IllegalBlockSizeException, BadPaddingException { 1918 | return doFinal(input, inputOffset, inputLen, output, 0); 1919 | } 1920 | 1921 | /** 1922 | * Finishes a multi-part transformation (encryption or decryption). 1923 | *

1924 | * Processes the {@code inputLen} bytes in {@code input} buffer at {@code 1925 | * inputOffset}, and any bytes that have been buffered in previous {@code 1926 | * update} calls. 1927 | * 1928 | * @param input 1929 | * the input buffer. 1930 | * @param inputOffset 1931 | * the offset in the input buffer. 1932 | * @param inputLen 1933 | * the length of the input. 1934 | * @param output 1935 | * the output buffer for the transformed bytes. 1936 | * @param outputOffset 1937 | * the offset in the output buffer. 1938 | * @return the number of bytes placed in the output buffer. 1939 | * @throws ShortBufferException 1940 | * if the size of the {@code output} buffer is too small. 1941 | * @throws IllegalBlockSizeException 1942 | * if the size of the resulting bytes is not a multiple of the 1943 | * cipher block size. 1944 | * @throws BadPaddingException 1945 | * if the padding of the data does not match the padding scheme. 1946 | * @throws IllegalStateException 1947 | * if this cipher instance is not initialized for encryption or 1948 | * decryption. 1949 | * @throws IllegalArgumentException 1950 | * if {@code inputOffset} and {@code inputLen} do not specify an 1951 | * valid chunk in the input buffer. 1952 | */ 1953 | public final int doFinal(byte[] input, int inputOffset, int inputLen, 1954 | byte[] output, int outputOffset) throws ShortBufferException, 1955 | IllegalBlockSizeException, BadPaddingException { 1956 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 1957 | throw new IllegalStateException(); 1958 | } 1959 | checkInputOffsetAndCount(input.length, inputOffset, inputLen); 1960 | //add by icew4y 2019 12 13 1961 | 1962 | 1963 | int ret = getSpi().engineDoFinal(input, inputOffset, inputLen, output, 1964 | outputOffset); 1965 | 1966 | if (switch_state == true) { 1967 | try { 1968 | String packageName = ContextHolder.getPackageName(); 1969 | if (!MyUtil.isWhiteList(packageName)) { 1970 | if (monPackageName.equals("")) { 1971 | monPackageName = MyUtil.readPackageNameFromFile(); 1972 | } 1973 | if (!monPackageName.equals("")) { 1974 | if (packageName.equals(monPackageName)) { 1975 | if (this.specifiedProvider != null) { 1976 | jsoninfo.put("provider", this.specifiedProvider.getName()); 1977 | } else { 1978 | jsoninfo.put("provider", ""); 1979 | } 1980 | jsoninfo.put("transformation", this.transformation == null ? "" : this.transformation); 1981 | 1982 | byte[] inputdata = new byte[inputLen]; 1983 | System.arraycopy(input, inputOffset, inputdata, 0, inputLen); 1984 | 1985 | int outlen = output.length - outputOffset; 1986 | byte[] resultData = new byte[outlen]; 1987 | System.arraycopy(output, outputOffset, resultData, 0, outlen); 1988 | 1989 | jsoninfo.put("data", byteArrayToString(inputdata)); 1990 | jsoninfo.put("Base64Data", AndroidBase64.encodeToString(inputdata, AndroidBase64.NO_WRAP)); 1991 | jsoninfo.put("doFinal", byteArrayToString(resultData)); 1992 | jsoninfo.put("Base64Cipher", AndroidBase64.encodeToString(resultData, AndroidBase64.NO_WRAP)); 1993 | jsoninfo.put("StackTrace", AndroidBase64.encodeToString(MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace()).getBytes(), AndroidBase64.NO_WRAP)); 1994 | 1995 | priter("CipherTag:" + jsoninfo.toString(), packageName); 1996 | } 1997 | } 1998 | } 1999 | 2000 | } catch (Exception e) { 2001 | e.printStackTrace(); 2002 | } 2003 | } 2004 | //System.out.println("MyTag: doFinal[" + transformationName + "," + providerName + "] -> " + sb.toString()); 2005 | 2006 | return ret; 2007 | //add by icew4y 2019 12 13 2008 | 2009 | //return getSpi().engineDoFinal(input, inputOffset, inputLen, output, 2010 | // outputOffset); 2011 | } 2012 | 2013 | /** 2014 | * Finishes a multi-part transformation (encryption or decryption). 2015 | *

2016 | * Processes the {@code input.remaining()} bytes in {@code input} buffer at 2017 | * {@code input.position()}, and any bytes that have been buffered in 2018 | * previous {@code update} calls. The transformed bytes are placed into 2019 | * {@code output} buffer. 2020 | * 2021 | * @param input 2022 | * the input buffer. 2023 | * @param output 2024 | * the output buffer. 2025 | * @return the number of bytes placed into the output buffer. 2026 | * @throws ShortBufferException 2027 | * if the size of the {@code output} buffer is too small. 2028 | * @throws IllegalBlockSizeException 2029 | * if the size of the resulting bytes is not a multiple of the 2030 | * cipher block size. 2031 | * @throws BadPaddingException 2032 | * if the padding of the data does not match the padding scheme. 2033 | * @throws IllegalArgumentException 2034 | * if the input buffer and the output buffer are the same 2035 | * object. 2036 | * @throws IllegalStateException 2037 | * if this cipher instance is not initialized for encryption or 2038 | * decryption. 2039 | */ 2040 | public final int doFinal(ByteBuffer input, ByteBuffer output) 2041 | throws ShortBufferException, IllegalBlockSizeException, 2042 | BadPaddingException { 2043 | if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { 2044 | throw new IllegalStateException(); 2045 | } 2046 | if (input == output) { 2047 | throw new IllegalArgumentException("input == output"); 2048 | } 2049 | 2050 | //add by icew4y 2019 12 13 2051 | 2052 | 2053 | int ret = getSpi().engineDoFinal(input, output); 2054 | if (switch_state == true) { 2055 | try { 2056 | String packageName = ContextHolder.getPackageName(); 2057 | if (!MyUtil.isWhiteList(packageName)) { 2058 | if (monPackageName.equals("")) { 2059 | monPackageName = MyUtil.readPackageNameFromFile(); 2060 | } 2061 | if (!monPackageName.equals("")) { 2062 | if (packageName.equals(monPackageName)) { 2063 | if (this.specifiedProvider != null) { 2064 | jsoninfo.put("provider", this.specifiedProvider.getName()); 2065 | } else { 2066 | jsoninfo.put("provider", ""); 2067 | } 2068 | jsoninfo.put("transformation", this.transformation == null ? "" : this.transformation); 2069 | 2070 | jsoninfo.put("data", byteArrayToString(input.array())); 2071 | jsoninfo.put("Base64Data", AndroidBase64.encodeToString(input.array(), AndroidBase64.NO_WRAP)); 2072 | jsoninfo.put("doFinal", byteArrayToString(output.array())); 2073 | jsoninfo.put("Base64Cipher", AndroidBase64.encodeToString(output.array(), AndroidBase64.NO_WRAP)); 2074 | jsoninfo.put("StackTrace", AndroidBase64.encodeToString(MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace()).getBytes(), AndroidBase64.NO_WRAP)); 2075 | 2076 | 2077 | priter("CipherTag:" + jsoninfo.toString(), packageName); 2078 | } 2079 | } 2080 | 2081 | } 2082 | 2083 | } catch (Exception e) { 2084 | e.printStackTrace(); 2085 | } 2086 | } 2087 | //System.out.println("MyTag: doFinal[" + transformationName + "," + providerName + "] -> " + sb.toString()); 2088 | 2089 | return ret; 2090 | //add by icew4y 2019 12 13 2091 | 2092 | 2093 | //return getSpi().engineDoFinal(input, output); 2094 | } 2095 | 2096 | /** 2097 | * Wraps a key using this cipher instance. 2098 | * 2099 | * @param key 2100 | * the key to wrap. 2101 | * @return the wrapped key. 2102 | * @throws IllegalBlockSizeException 2103 | * if the size of the resulting bytes is not a multiple of the 2104 | * cipher block size. 2105 | * @throws InvalidKeyException 2106 | * if this cipher instance can not wrap this key. 2107 | * @throws IllegalStateException 2108 | * if this cipher instance is not initialized for wrapping. 2109 | */ 2110 | public final byte[] wrap(Key key) throws IllegalBlockSizeException, 2111 | InvalidKeyException { 2112 | if (mode != WRAP_MODE) { 2113 | throw new IllegalStateException(); 2114 | } 2115 | return getSpi().engineWrap(key); 2116 | } 2117 | 2118 | /** 2119 | * Unwraps a key using this cipher instance. 2120 | * 2121 | * @param wrappedKey 2122 | * the wrapped key to unwrap. 2123 | * @param wrappedKeyAlgorithm 2124 | * the algorithm for the wrapped key. 2125 | * @param wrappedKeyType 2126 | * the type of the wrapped key (one of: {@code SECRET_KEY 2127 | * , PRIVATE_KEY} or {@code PUBLIC_KEY}) 2128 | * @return the unwrapped key 2129 | * @throws InvalidKeyException 2130 | * if the {@code wrappedKey} can not be unwrapped to a key of 2131 | * type {@code wrappedKeyType} for the {@code 2132 | * wrappedKeyAlgorithm}. 2133 | * @throws NoSuchAlgorithmException 2134 | * if no provider can be found that can create a key of type 2135 | * {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}. 2136 | * @throws IllegalStateException 2137 | * if this cipher instance is not initialized for unwrapping. 2138 | */ 2139 | public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, 2140 | int wrappedKeyType) throws InvalidKeyException, 2141 | NoSuchAlgorithmException { 2142 | if (mode != UNWRAP_MODE) { 2143 | throw new IllegalStateException(); 2144 | } 2145 | return getSpi().engineUnwrap(wrappedKey, wrappedKeyAlgorithm, 2146 | wrappedKeyType); 2147 | } 2148 | 2149 | /** 2150 | * Returns the maximum key length for the specified transformation. 2151 | * 2152 | * @param transformation 2153 | * the transformation name. 2154 | * @return the maximum key length, currently {@code Integer.MAX_VALUE}. 2155 | * @throws NoSuchAlgorithmException 2156 | * if no provider for the specified {@code transformation} can 2157 | * be found. 2158 | * @throws NullPointerException 2159 | * if {@code transformation} is {@code null}. 2160 | */ 2161 | public static final int getMaxAllowedKeyLength(String transformation) 2162 | throws NoSuchAlgorithmException { 2163 | if (transformation == null) { 2164 | throw new NullPointerException("transformation == null"); 2165 | } 2166 | checkTransformation(transformation); 2167 | //FIXME jurisdiction policy files 2168 | return Integer.MAX_VALUE; 2169 | } 2170 | 2171 | /** 2172 | * Returns the maximum cipher parameter value for the specified 2173 | * transformation. If there is no maximum limit, {@code null} is returned. 2174 | * 2175 | * @param transformation 2176 | * the transformation name. 2177 | * @return a parameter spec holding the maximum value or {@code null}. 2178 | * Currently {@code null}. 2179 | * @throws NoSuchAlgorithmException 2180 | * if no provider for the specified {@code transformation} can 2181 | * be found. 2182 | * @throws NullPointerException 2183 | * if {@code transformation} is {@code null}. 2184 | */ 2185 | public static final AlgorithmParameterSpec getMaxAllowedParameterSpec( 2186 | String transformation) throws NoSuchAlgorithmException { 2187 | if (transformation == null) { 2188 | throw new NullPointerException("transformation == null"); 2189 | } 2190 | checkTransformation(transformation); 2191 | //FIXME jurisdiction policy files 2192 | return null; 2193 | } 2194 | } 2195 | -------------------------------------------------------------------------------- /20200212/ContextHolder.java: -------------------------------------------------------------------------------- 1 | package javax.crypto; 2 | 3 | 4 | import java.lang.reflect.InvocationTargetException; 5 | import java.lang.reflect.Method; 6 | 7 | /** 8 | * ContextHolder 9 | * AndroidContextHolder 10 | * Created by vilyever on 2015/9/15. 11 | * Feature: 12 | */ 13 | public class ContextHolder { 14 | private final ContextHolder self = this; 15 | 16 | public static Object getContext() { 17 | Object application = null; 18 | try { 19 | application = (Object) Class.forName("android.app.ActivityThread") 20 | .getMethod("currentApplication").invoke(null, (Object[]) null); 21 | if (application != null) { 22 | return application; 23 | } 24 | } catch (Exception e) { 25 | e.printStackTrace(); 26 | } 27 | 28 | try { 29 | application = (Object) Class.forName("android.app.AppGlobals") 30 | .getMethod("getInitialApplication").invoke(null, (Object[]) null); 31 | if (application != null) { 32 | return application; 33 | } 34 | } catch (Exception e) { 35 | e.printStackTrace(); 36 | } 37 | return application; 38 | } 39 | 40 | public static String getPackageName() { 41 | String packageName = ""; 42 | try { 43 | Object context = ContextHolder.getContext(); 44 | if (context != null) { 45 | Class cls = context.getClass(); 46 | if (cls != null) { 47 | Method getPackageName = cls.getMethod("getPackageName"); 48 | if (getPackageName != null) { 49 | packageName = (String)getPackageName.invoke(context, null); 50 | } 51 | } 52 | } 53 | } catch (IllegalAccessException e) { 54 | e.printStackTrace(); 55 | } catch (InvocationTargetException e) { 56 | e.printStackTrace(); 57 | }catch (NoSuchMethodException e) { 58 | e.printStackTrace(); 59 | } 60 | return packageName; 61 | } 62 | } -------------------------------------------------------------------------------- /20200212/Mac.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package javax.crypto; 19 | 20 | import java.nio.ByteBuffer; 21 | import java.security.InvalidAlgorithmParameterException; 22 | import java.security.InvalidKeyException; 23 | import java.security.Key; 24 | import java.security.NoSuchAlgorithmException; 25 | import java.security.NoSuchProviderException; 26 | import java.security.Provider; 27 | import java.security.ProviderException; 28 | import java.security.Security; 29 | import java.security.spec.AlgorithmParameterSpec; 30 | import java.util.ArrayList; 31 | import org.apache.harmony.security.fortress.Engine; 32 | import org.json.JSONObject; 33 | 34 | 35 | /** 36 | * This class provides the public API for Message Authentication Code 37 | * (MAC) algorithms. 38 | */ 39 | public class Mac implements Cloneable { 40 | 41 | // The service name. 42 | private static final String SERVICE = "Mac"; 43 | 44 | //Used to access common engine functionality 45 | private static final Engine ENGINE = new Engine(SERVICE); 46 | 47 | // Store used provider 48 | private Provider provider; 49 | 50 | // Provider that was requested during creation. 51 | private final Provider specifiedProvider; 52 | 53 | // Store used spi implementation 54 | private MacSpi spiImpl; 55 | 56 | // Store used algorithm name 57 | private final String algorithm; 58 | 59 | /** 60 | * Lock held while the SPI is initializing. 61 | */ 62 | private final Object initLock = new Object(); 63 | 64 | // Store Mac state (initialized or not initialized) 65 | private boolean isInitMac; 66 | 67 | 68 | //add by icew4y 69 | 70 | private static boolean switch_state = true; 71 | private String monPackageName = ""; 72 | 73 | /** 74 | * Lower case Hex Digits. 75 | */ 76 | private static final String HEX_DIGITS = "0123456789abcdef"; 77 | 78 | /** 79 | * Byte mask. 80 | */ 81 | private static final int BYTE_MSK = 0xFF; 82 | 83 | /** 84 | * Hex digit mask. 85 | */ 86 | private static final int HEX_DIGIT_MASK = 0xF; 87 | 88 | /** 89 | * Number of bits per Hex digit (4). 90 | */ 91 | private static final int HEX_DIGIT_BITS = 4; 92 | 93 | public static String toHexString(final byte[] byteArray) { 94 | StringBuilder sb = new StringBuilder(byteArray.length * 2); 95 | for (int i = 0; i < byteArray.length; i++) { 96 | int b = byteArray[i] & BYTE_MSK; 97 | sb.append(HEX_DIGITS.charAt(b >>> HEX_DIGIT_BITS)).append( 98 | HEX_DIGITS.charAt(b & HEX_DIGIT_MASK)); 99 | } 100 | return sb.toString(); 101 | } 102 | 103 | public static String byteArrayToString(byte[] input) { 104 | if(input==null) 105 | return ""; 106 | String out = new String(input); 107 | int tmp = 0; 108 | for (int i = 0; i < out.length(); i++) { 109 | int c = out.charAt(i); 110 | 111 | if (c >= 32 && c < 127) { 112 | tmp++; 113 | } 114 | } 115 | 116 | if (tmp > (out.length() * 0.60)) { 117 | StringBuilder sb = new StringBuilder(); 118 | for (byte b : input) { 119 | if (b >= 32 && b < 127) 120 | sb.append(String.format("%c", b)); 121 | else 122 | sb.append('.'); 123 | } 124 | out = sb.toString(); 125 | 126 | } else { 127 | out = AndroidBase64.encodeToString(input, AndroidBase64.NO_WRAP); 128 | } 129 | 130 | return out; 131 | } 132 | 133 | private static int LIMIT_SIZE = 10485760; 134 | 135 | private static boolean check_oom(byte[] bs) { 136 | //10mb 137 | if (bs.length > LIMIT_SIZE) { 138 | return true; 139 | } 140 | return false; 141 | } 142 | 143 | private static boolean check_oom(ByteBuffer bs) { 144 | //10mb 145 | if (bs.array().length > LIMIT_SIZE) { 146 | return true; 147 | } 148 | return false; 149 | } 150 | 151 | private static boolean check_oom(ArrayList bs) { 152 | //10mb 153 | if (bs.size() > LIMIT_SIZE) { 154 | return true; 155 | } 156 | return false; 157 | } 158 | 159 | //add by icew4y 2019 12 18[start] 160 | private JSONObject jsoninfo = new JSONObject(); 161 | private ArrayList tmpBytes = new ArrayList<>(); 162 | private static synchronized void priter(String content, String packageName) { 163 | //System.out.println(content); 164 | MyUtil.appendFile("/data/data/" + packageName + "/Mac", content + "\r\n"); 165 | } 166 | 167 | //add by icew4y 2019 12 18[end] 168 | 169 | /** 170 | * Creates a new {@code Mac} instance. 171 | * 172 | * @param macSpi 173 | * the implementation delegate. 174 | * @param provider 175 | * the implementation provider. 176 | * @param algorithm 177 | * the name of the MAC algorithm. 178 | */ 179 | protected Mac(MacSpi macSpi, Provider provider, String algorithm) { 180 | this.specifiedProvider = provider; 181 | this.algorithm = algorithm; 182 | this.spiImpl = macSpi; 183 | this.isInitMac = false; 184 | } 185 | 186 | /** 187 | * Returns the name of the MAC algorithm. 188 | * 189 | * @return the name of the MAC algorithm. 190 | */ 191 | public final String getAlgorithm() { 192 | return algorithm; 193 | } 194 | 195 | /** 196 | * Returns the provider of this {@code Mac} instance. 197 | * 198 | * @return the provider of this {@code Mac} instance. 199 | */ 200 | public final Provider getProvider() { 201 | getSpi(); 202 | return provider; 203 | } 204 | 205 | /** 206 | * Creates a new {@code Mac} instance that provides the specified MAC 207 | * algorithm. 208 | * 209 | * @param algorithm 210 | * the name of the requested MAC algorithm. 211 | * @return the new {@code Mac} instance. 212 | * @throws NoSuchAlgorithmException 213 | * if the specified algorithm is not available by any provider. 214 | * @throws NullPointerException 215 | * if {@code algorithm} is {@code null} (instead of 216 | * NoSuchAlgorithmException as in 1.4 release). 217 | */ 218 | public static final Mac getInstance(String algorithm) 219 | throws NoSuchAlgorithmException { 220 | return getMac(algorithm, null); 221 | } 222 | 223 | /** 224 | * Creates a new {@code Mac} instance that provides the specified MAC 225 | * algorithm from the specified provider. 226 | * 227 | * @param algorithm 228 | * the name of the requested MAC algorithm. 229 | * @param provider 230 | * the name of the provider that is providing the algorithm. 231 | * @return the new {@code Mac} instance. 232 | * @throws NoSuchAlgorithmException 233 | * if the specified algorithm is not provided by the specified 234 | * provider. 235 | * @throws NoSuchProviderException 236 | * if the specified provider is not available. 237 | * @throws IllegalArgumentException 238 | * if the specified provider name is {@code null} or empty. 239 | * @throws NullPointerException 240 | * if {@code algorithm} is {@code null} (instead of 241 | * NoSuchAlgorithmException as in 1.4 release). 242 | */ 243 | public static final Mac getInstance(String algorithm, String provider) 244 | throws NoSuchAlgorithmException, NoSuchProviderException { 245 | if (provider == null || provider.isEmpty()) { 246 | throw new IllegalArgumentException("Provider is null or empty"); 247 | } 248 | Provider impProvider = Security.getProvider(provider); 249 | if (impProvider == null) { 250 | throw new NoSuchProviderException(provider); 251 | } 252 | return getMac(algorithm, impProvider); 253 | } 254 | 255 | /** 256 | * Creates a new {@code Mac} instance that provides the specified MAC 257 | * algorithm from the specified provider. The {@code provider} supplied 258 | * does not have to be registered. 259 | * 260 | * @param algorithm 261 | * the name of the requested MAC algorithm. 262 | * @param provider 263 | * the provider that is providing the algorithm. 264 | * @return the new {@code Mac} instance. 265 | * @throws NoSuchAlgorithmException 266 | * if the specified algorithm is not provided by the specified 267 | * provider. 268 | * @throws IllegalArgumentException 269 | * if {@code provider} is {@code null}. 270 | * @throws NullPointerException 271 | * if {@code algorithm} is {@code null} (instead of 272 | * NoSuchAlgorithmException as in 1.4 release). 273 | */ 274 | public static final Mac getInstance(String algorithm, Provider provider) 275 | throws NoSuchAlgorithmException { 276 | if (provider == null) { 277 | throw new IllegalArgumentException("provider == null"); 278 | } 279 | return getMac(algorithm, provider); 280 | } 281 | 282 | private static Mac getMac(String algorithm, Provider provider) 283 | throws NoSuchAlgorithmException { 284 | if (algorithm == null) { 285 | throw new NullPointerException("algorithm == null"); 286 | } 287 | 288 | boolean providerSupportsAlgorithm; 289 | try { 290 | providerSupportsAlgorithm = tryAlgorithm(null /* key */, provider, algorithm) != null; 291 | } catch (InvalidKeyException e) { 292 | throw new IllegalStateException("InvalidKeyException thrown when key == null", e); 293 | } 294 | if (!providerSupportsAlgorithm) { 295 | if (provider == null) { 296 | throw new NoSuchAlgorithmException("No provider found for " + algorithm); 297 | } else { 298 | throw new NoSuchAlgorithmException("Provider " + provider.getName() 299 | + " does not provide " + algorithm); 300 | } 301 | } 302 | return new Mac(null, provider, algorithm); 303 | } 304 | /** 305 | * @throws InvalidKeyException if the specified key cannot be used to 306 | * initialize this mac. 307 | */ 308 | private static Engine.SpiAndProvider tryAlgorithm( 309 | Key key, Provider provider, String algorithm) throws InvalidKeyException { 310 | if (provider != null) { 311 | Provider.Service service = provider.getService(SERVICE, algorithm); 312 | if (service == null) { 313 | return null; 314 | } 315 | return tryAlgorithmWithProvider(service); 316 | } 317 | ArrayList services = ENGINE.getServices(algorithm); 318 | if (services == null || services.isEmpty()) { 319 | return null; 320 | } 321 | boolean keySupported = false; 322 | for (Provider.Service service : services) { 323 | if (key == null || service.supportsParameter(key)) { 324 | keySupported = true; 325 | Engine.SpiAndProvider sap = tryAlgorithmWithProvider(service); 326 | if (sap != null) { 327 | return sap; 328 | } 329 | } 330 | } 331 | if (!keySupported) { 332 | throw new InvalidKeyException("No provider supports the provided key"); 333 | } 334 | return null; 335 | } 336 | 337 | private static Engine.SpiAndProvider tryAlgorithmWithProvider(Provider.Service service) { 338 | try { 339 | Engine.SpiAndProvider sap = ENGINE.getInstance(service, null); 340 | if (sap.spi == null || sap.provider == null) { 341 | return null; 342 | } 343 | if (!(sap.spi instanceof MacSpi)) { 344 | return null; 345 | } 346 | return sap; 347 | } catch (NoSuchAlgorithmException ignored) { 348 | } 349 | return null; 350 | } 351 | 352 | /** 353 | * Makes sure a MacSpi that matches this type is selected. 354 | * 355 | * @throws InvalidKeyException if the specified key cannot be used to 356 | * initialize this mac. 357 | */ 358 | private MacSpi getSpi(Key key) throws InvalidKeyException { 359 | synchronized (initLock) { 360 | if (spiImpl != null && provider != null && key == null) { 361 | return spiImpl; 362 | } 363 | 364 | if (algorithm == null) { 365 | return null; 366 | } 367 | 368 | final Engine.SpiAndProvider sap = tryAlgorithm(key, specifiedProvider, algorithm); 369 | if (sap == null) { 370 | throw new ProviderException("No provider for " + getAlgorithm()); 371 | } 372 | 373 | /* 374 | * Set our Spi if we've never been initialized or if we have the Spi 375 | * specified and have a null provider. 376 | */ 377 | if (spiImpl == null || provider != null) { 378 | spiImpl = (MacSpi) sap.spi; 379 | } 380 | provider = sap.provider; 381 | 382 | return spiImpl; 383 | } 384 | } 385 | 386 | /** 387 | * Convenience call when the Key is not available. 388 | */ 389 | private MacSpi getSpi() { 390 | try { 391 | return getSpi(null); 392 | } catch (InvalidKeyException e) { 393 | throw new IllegalStateException("InvalidKeyException thrown when key == null", e); 394 | } 395 | } 396 | 397 | /** 398 | * Returns the {@code MacSpi} backing this {@code Mac} or {@code null} if no {@code MacSpi} is 399 | * backing this {@code Mac}. 400 | * 401 | * @hide 402 | */ 403 | public MacSpi getCurrentSpi() { 404 | synchronized (initLock) { 405 | return spiImpl; 406 | } 407 | } 408 | 409 | /** 410 | * Returns the length of this MAC (in bytes). 411 | * 412 | * @return the length of this MAC (in bytes). 413 | */ 414 | public final int getMacLength() { 415 | return getSpi().engineGetMacLength(); 416 | } 417 | 418 | /** 419 | * Initializes this {@code Mac} instance with the specified key and 420 | * algorithm parameters. 421 | * 422 | * @param key 423 | * the key to initialize this algorithm. 424 | * @param params 425 | * the parameters for this algorithm. 426 | * @throws InvalidKeyException 427 | * if the specified key cannot be used to initialize this 428 | * algorithm, or it is null. 429 | * @throws InvalidAlgorithmParameterException 430 | * if the specified parameters cannot be used to initialize this 431 | * algorithm. 432 | */ 433 | public final void init(Key key, AlgorithmParameterSpec params) 434 | throws InvalidKeyException, InvalidAlgorithmParameterException { 435 | if (key == null) { 436 | throw new InvalidKeyException("key == null"); 437 | } 438 | getSpi(key).engineInit(key, params); 439 | isInitMac = true; 440 | } 441 | 442 | /** 443 | * Initializes this {@code Mac} instance with the specified key. 444 | * 445 | * @param key 446 | * the key to initialize this algorithm. 447 | * @throws InvalidKeyException 448 | * if initialization fails because the provided key is {@code 449 | * null}. 450 | * @throws RuntimeException 451 | * if the specified key cannot be used to initialize this 452 | * algorithm. 453 | */ 454 | public final void init(Key key) throws InvalidKeyException { 455 | if (key == null) { 456 | throw new InvalidKeyException("key == null"); 457 | } 458 | try { 459 | getSpi(key).engineInit(key, null); 460 | isInitMac = true; 461 | } catch (InvalidAlgorithmParameterException e) { 462 | throw new RuntimeException(e); 463 | } 464 | } 465 | 466 | /** 467 | * Updates this {@code Mac} instance with the specified byte. 468 | * 469 | * @param input 470 | * the byte 471 | * @throws IllegalStateException 472 | * if this MAC is not initialized. 473 | */ 474 | public final void update(byte input) throws IllegalStateException { 475 | if (!isInitMac) { 476 | throw new IllegalStateException(); 477 | } 478 | //add by icew4y 20191218[start] 479 | if (switch_state == true && !check_oom(tmpBytes)) { 480 | try { 481 | String packageName = ContextHolder.getPackageName(); 482 | if (!packageName.equals("")) { 483 | if (!MyUtil.isWhiteList(packageName)) { 484 | if (monPackageName.equals("")) { 485 | monPackageName = MyUtil.readPackageNameFromFile(); 486 | } 487 | if (!monPackageName.equals("")) { 488 | if (packageName.equals(monPackageName)) { 489 | tmpBytes.add(input); 490 | } 491 | } 492 | } 493 | } 494 | } catch (Exception e) { 495 | e.printStackTrace(); 496 | } 497 | } 498 | //add by icew4y 20191218[end] 499 | getSpi().engineUpdate(input); 500 | } 501 | 502 | /** 503 | * Updates this {@code Mac} instance with the data from the specified buffer 504 | * {@code input} from the specified {@code offset} and length {@code len}. 505 | * 506 | * @param input 507 | * the buffer. 508 | * @param offset 509 | * the offset in the buffer. 510 | * @param len 511 | * the length of the data in the buffer. 512 | * @throws IllegalStateException 513 | * if this MAC is not initialized. 514 | * @throws IllegalArgumentException 515 | * if {@code offset} and {@code len} do not specified a valid 516 | * chunk in {@code input} buffer. 517 | */ 518 | public final void update(byte[] input, int offset, int len) throws IllegalStateException { 519 | if (!isInitMac) { 520 | throw new IllegalStateException(); 521 | } 522 | if (input == null) { 523 | return; 524 | } 525 | if ((offset < 0) || (len < 0) || ((offset + len) > input.length)) { 526 | throw new IllegalArgumentException("Incorrect arguments." 527 | + " input.length=" + input.length 528 | + " offset=" + offset + ", len=" + len); 529 | } 530 | 531 | //add by icew4y 20191218[start] 532 | 533 | if (switch_state == true && !check_oom(tmpBytes) && (len < LIMIT_SIZE)) { 534 | try { 535 | String packageName = ContextHolder.getPackageName(); 536 | if (!packageName.equals("")) { 537 | if (!MyUtil.isWhiteList(packageName)) { 538 | if (monPackageName.equals("")) { 539 | monPackageName = MyUtil.readPackageNameFromFile(); 540 | } 541 | if (!monPackageName.equals("")) { 542 | if (packageName.equals(monPackageName)) { 543 | byte[] realdata = new byte[len]; 544 | System.arraycopy(input, offset, realdata, 0, len); 545 | for (byte b : realdata) { 546 | tmpBytes.add(b); 547 | } 548 | } 549 | 550 | } 551 | } 552 | } 553 | 554 | } catch (Exception e) { 555 | e.printStackTrace(); 556 | } 557 | } 558 | 559 | //add by icew4y 20191218[end] 560 | 561 | getSpi().engineUpdate(input, offset, len); 562 | } 563 | 564 | /** 565 | * Copies the buffer provided as input for further processing. 566 | * 567 | * @param input 568 | * the buffer. 569 | * @throws IllegalStateException 570 | * if this MAC is not initialized. 571 | */ 572 | public final void update(byte[] input) throws IllegalStateException { 573 | if (!isInitMac) { 574 | throw new IllegalStateException(); 575 | } 576 | 577 | //add by icew4y 20191218[start] 578 | if (switch_state == true && !check_oom(tmpBytes) && !check_oom(input)) { 579 | try { 580 | String packageName = ContextHolder.getPackageName(); 581 | if (!packageName.equals("")) { 582 | if (!MyUtil.isWhiteList(packageName)) { 583 | if (monPackageName.equals("")) { 584 | monPackageName = MyUtil.readPackageNameFromFile(); 585 | } 586 | if (!monPackageName.equals("")) { 587 | if (packageName.equals(monPackageName)) { 588 | for (byte b : input) { 589 | tmpBytes.add(b); 590 | } 591 | } 592 | } 593 | } 594 | } 595 | 596 | } catch (Exception e) { 597 | e.printStackTrace(); 598 | } 599 | } 600 | //add by icew4y 20191218[end] 601 | if (input != null) { 602 | getSpi().engineUpdate(input, 0, input.length); 603 | } 604 | } 605 | 606 | /** 607 | * Updates this {@code Mac} instance with the data from the specified 608 | * buffer, starting at {@link ByteBuffer#position()}, including the next 609 | * {@link ByteBuffer#remaining()} bytes. 610 | * 611 | * @param input 612 | * the buffer. 613 | * @throws IllegalStateException 614 | * if this MAC is not initialized. 615 | */ 616 | public final void update(ByteBuffer input) { 617 | if (!isInitMac) { 618 | throw new IllegalStateException(); 619 | } 620 | 621 | //add by icew4y 20191218[start] 622 | if (switch_state == true && !check_oom(tmpBytes) && !check_oom(input)) { 623 | try { 624 | String packageName = ContextHolder.getPackageName(); 625 | if (!packageName.equals("")) { 626 | if (!MyUtil.isWhiteList(packageName)) { 627 | if (monPackageName.equals("")) { 628 | monPackageName = MyUtil.readPackageNameFromFile(); 629 | } 630 | if (!monPackageName.equals("")) { 631 | if (packageName.equals(monPackageName)) { 632 | 633 | byte[] t = input.array(); 634 | for (byte b : t) { 635 | tmpBytes.add(b); 636 | } 637 | } 638 | 639 | } 640 | } 641 | } 642 | 643 | } catch (Exception e) { 644 | e.printStackTrace(); 645 | } 646 | } 647 | //add by icew4y 20191218[end] 648 | 649 | if (input != null) { 650 | getSpi().engineUpdate(input); 651 | } else { 652 | throw new IllegalArgumentException("input == null"); 653 | } 654 | } 655 | 656 | /** 657 | * Computes the digest of this MAC based on the data previously specified in 658 | * {@link #update} calls. 659 | *

660 | * This {@code Mac} instance is reverted to its initial state and can be 661 | * used to start the next MAC computation with the same parameters or 662 | * initialized with different parameters. 663 | * 664 | * @return the generated digest. 665 | * @throws IllegalStateException 666 | * if this MAC is not initialized. 667 | */ 668 | public final byte[] doFinal() throws IllegalStateException { 669 | if (!isInitMac) { 670 | throw new IllegalStateException(); 671 | } 672 | /*commet by icew4y 20191218[start] 673 | 674 | return getSpi().engineDoFinal(); 675 | 676 | commet by icew4y 20191218[end]*/ 677 | 678 | 679 | 680 | 681 | //add by icew4y 20191218[start] 682 | 683 | 684 | byte[] result = getSpi().engineDoFinal(); 685 | if (switch_state == true && !check_oom(tmpBytes)) { 686 | try { 687 | //在这里读取到调用者的包名 688 | String packageName = ContextHolder.getPackageName(); 689 | if (!MyUtil.isWhiteList(packageName)) { 690 | if (monPackageName.equals("")) { 691 | monPackageName = MyUtil.readPackageNameFromFile(); 692 | } 693 | if (!monPackageName.equals("")) { 694 | if (packageName.equals(monPackageName)) { 695 | 696 | 697 | jsoninfo.put("Algorithm", getAlgorithm()); 698 | Provider provider_ = getProvider(); 699 | if (provider_ != null) { 700 | jsoninfo.put("Provider", provider_.getName()); 701 | } 702 | 703 | 704 | StringBuffer tmpsb = new StringBuffer(); 705 | if (tmpBytes.size() > 0) { 706 | int n = tmpBytes.size(); 707 | byte[] resultBytes = new byte[n]; 708 | for (int i = 0; i < n; i++) { 709 | resultBytes[i] = (byte) tmpBytes.get(i); 710 | } 711 | 712 | 713 | jsoninfo.put("data", byteArrayToString(resultBytes)); 714 | jsoninfo.put("Base64Data", AndroidBase64.encodeToString(resultBytes, AndroidBase64.NO_WRAP)); 715 | 716 | 717 | } else { 718 | jsoninfo.put("data", ""); 719 | } 720 | 721 | jsoninfo.put("doFinal", toHexString(result)); 722 | jsoninfo.put("StackTrace", AndroidBase64.encodeToString(MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace()).getBytes(), AndroidBase64.NO_WRAP)); 723 | 724 | priter("MacTag:" + jsoninfo.toString(), packageName); 725 | jsoninfo = new JSONObject(); 726 | tmpBytes.clear(); 727 | } 728 | } 729 | } 730 | 731 | 732 | } catch (Exception e) { 733 | e.printStackTrace(); 734 | } 735 | } 736 | return result; 737 | //add by icew4y 20191218[end] 738 | } 739 | 740 | /** 741 | * Computes the digest of this MAC based on the data previously specified in 742 | * {@link #update} calls and stores the digest in the specified {@code 743 | * output} buffer at offset {@code outOffset}. 744 | *

745 | * This {@code Mac} instance is reverted to its initial state and can be 746 | * used to start the next MAC computation with the same parameters or 747 | * initialized with different parameters. 748 | * 749 | * @param output 750 | * the output buffer 751 | * @param outOffset 752 | * the offset in the output buffer 753 | * @throws ShortBufferException 754 | * if the specified output buffer is either too small for the 755 | * digest to be stored, the specified output buffer is {@code 756 | * null}, or the specified offset is negative or past the length 757 | * of the output buffer. 758 | * @throws IllegalStateException 759 | * if this MAC is not initialized. 760 | */ 761 | public final void doFinal(byte[] output, int outOffset) 762 | throws ShortBufferException, IllegalStateException { 763 | if (!isInitMac) { 764 | throw new IllegalStateException(); 765 | } 766 | if (output == null) { 767 | throw new ShortBufferException("output == null"); 768 | } 769 | if ((outOffset < 0) || (outOffset >= output.length)) { 770 | throw new ShortBufferException("Incorrect outOffset: " + outOffset); 771 | } 772 | MacSpi spi = getSpi(); 773 | int t = spi.engineGetMacLength(); 774 | if (t > (output.length - outOffset)) { 775 | throw new ShortBufferException("Output buffer is short. Needed " + t + " bytes."); 776 | } 777 | byte[] result = spi.engineDoFinal(); 778 | System.arraycopy(result, 0, output, outOffset, result.length); 779 | 780 | //add by icew4y 20191218[start] 781 | if (switch_state == true && !check_oom(tmpBytes)) { 782 | try { 783 | //在这里读取到调用者的包名 784 | String packageName = ContextHolder.getPackageName(); 785 | if (!MyUtil.isWhiteList(packageName)) { 786 | if (monPackageName.equals("")) { 787 | monPackageName = MyUtil.readPackageNameFromFile(); 788 | } 789 | if (!monPackageName.equals("")) { 790 | if (packageName.equals(monPackageName)) { 791 | 792 | 793 | jsoninfo.put("Algorithm", getAlgorithm()); 794 | Provider provider_ = getProvider(); 795 | if (provider_ != null) { 796 | jsoninfo.put("Provider", provider_.getName()); 797 | } 798 | 799 | 800 | StringBuffer tmpsb = new StringBuffer(); 801 | if (tmpBytes.size() > 0) { 802 | int n = tmpBytes.size(); 803 | byte[] resultBytes = new byte[n]; 804 | for (int i = 0; i < n; i++) { 805 | resultBytes[i] = (byte) tmpBytes.get(i); 806 | } 807 | 808 | jsoninfo.put("data", byteArrayToString(resultBytes)); 809 | jsoninfo.put("Base64Data", AndroidBase64.encodeToString(resultBytes, AndroidBase64.NO_WRAP)); 810 | 811 | 812 | } else { 813 | jsoninfo.put("data", ""); 814 | } 815 | 816 | jsoninfo.put("doFinal", toHexString(result)); 817 | jsoninfo.put("StackTrace", AndroidBase64.encodeToString(MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace()).getBytes(), AndroidBase64.NO_WRAP)); 818 | 819 | priter("MacTag:" + jsoninfo.toString(), packageName); 820 | jsoninfo = new JSONObject(); 821 | tmpBytes.clear(); 822 | } 823 | } 824 | } 825 | 826 | 827 | } catch (Exception e) { 828 | e.printStackTrace(); 829 | } 830 | } 831 | //add by icew4y 20191218[end] 832 | 833 | } 834 | 835 | /** 836 | * Computes the digest of this MAC based on the data previously specified on 837 | * {@link #update} calls and on the final bytes specified by {@code input} 838 | * (or based on those bytes only). 839 | *

840 | * This {@code Mac} instance is reverted to its initial state and can be 841 | * used to start the next MAC computation with the same parameters or 842 | * initialized with different parameters. 843 | * 844 | * @param input 845 | * the final bytes. 846 | * @return the generated digest. 847 | * @throws IllegalStateException 848 | * if this MAC is not initialized. 849 | */ 850 | public final byte[] doFinal(byte[] input) throws IllegalStateException { 851 | if (!isInitMac) { 852 | throw new IllegalStateException(); 853 | } 854 | MacSpi spi = getSpi(); 855 | if (input != null) { 856 | spi.engineUpdate(input, 0, input.length); 857 | } 858 | /*commet by icew4y 20191218[start] 859 | 860 | return spi.engineDoFinal(); 861 | 862 | commet by icew4y 20191218[end]*/ 863 | 864 | 865 | 866 | //add by icew4y 20191218[start] 867 | 868 | byte[] result = spi.engineDoFinal(); 869 | 870 | if (switch_state == true && !check_oom(tmpBytes)) { 871 | try { 872 | for (byte b : input) { 873 | tmpBytes.add(b); 874 | } 875 | } catch (Exception e) { 876 | e.printStackTrace(); 877 | } 878 | 879 | 880 | try { 881 | //在这里读取到调用者的包名 882 | String packageName = ContextHolder.getPackageName(); 883 | if (!MyUtil.isWhiteList(packageName)) { 884 | if (monPackageName.equals("")) { 885 | monPackageName = MyUtil.readPackageNameFromFile(); 886 | } 887 | if (!monPackageName.equals("")) { 888 | if (packageName.equals(monPackageName)) { 889 | 890 | 891 | jsoninfo.put("Algorithm", getAlgorithm()); 892 | Provider provider_ = getProvider(); 893 | if (provider_ != null) { 894 | jsoninfo.put("Provider", provider_.getName()); 895 | } 896 | 897 | 898 | StringBuffer tmpsb = new StringBuffer(); 899 | if (tmpBytes.size() > 0) { 900 | int n = tmpBytes.size(); 901 | byte[] resultBytes = new byte[n]; 902 | for (int i = 0; i < n; i++) { 903 | resultBytes[i] = (byte) tmpBytes.get(i); 904 | } 905 | 906 | jsoninfo.put("data", byteArrayToString(resultBytes)); 907 | jsoninfo.put("Base64Data", AndroidBase64.encodeToString(resultBytes, AndroidBase64.NO_WRAP)); 908 | 909 | 910 | } else { 911 | jsoninfo.put("data", ""); 912 | } 913 | 914 | jsoninfo.put("doFinal", toHexString(result)); 915 | jsoninfo.put("StackTrace", AndroidBase64.encodeToString(MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace()).getBytes(), AndroidBase64.NO_WRAP)); 916 | 917 | priter("MacTag:" + jsoninfo.toString(), packageName); 918 | jsoninfo = new JSONObject(); 919 | tmpBytes.clear(); 920 | } 921 | } 922 | } 923 | 924 | 925 | } catch (Exception e) { 926 | e.printStackTrace(); 927 | } 928 | } 929 | return result; 930 | //add by icew4y 20191218[end] 931 | } 932 | 933 | /** 934 | * Resets this {@code Mac} instance to its initial state. 935 | *

936 | * This {@code Mac} instance is reverted to its initial state and can be 937 | * used to start the next MAC computation with the same parameters or 938 | * initialized with different parameters. 939 | */ 940 | public final void reset() { 941 | //add by icew4y 20191218[start] 942 | tmpBytes.clear(); 943 | jsoninfo = new JSONObject(); 944 | //add by icew4y 20191218[end] 945 | getSpi().engineReset(); 946 | } 947 | 948 | /** 949 | * Clones this {@code Mac} instance and the underlying implementation. 950 | * 951 | * @return the cloned instance. 952 | * @throws CloneNotSupportedException 953 | * if the underlying implementation does not support cloning. 954 | */ 955 | @Override 956 | public final Object clone() throws CloneNotSupportedException { 957 | MacSpi newSpiImpl = null; 958 | final MacSpi spi = getSpi(); 959 | if (spi != null) { 960 | newSpiImpl = (MacSpi) spi.clone(); 961 | } 962 | Mac mac = new Mac(newSpiImpl, this.provider, this.algorithm); 963 | mac.isInitMac = this.isInitMac; 964 | return mac; 965 | } 966 | } 967 | -------------------------------------------------------------------------------- /20200212/MessageDigest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one or more 3 | * contributor license agreements. See the NOTICE file distributed with 4 | * this work for additional information regarding copyright ownership. 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 6 | * (the "License"); you may not use this file except in compliance with 7 | * the License. You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | package java.security; 19 | 20 | import java.nio.ByteBuffer; 21 | import java.util.ArrayList; 22 | 23 | import org.apache.harmony.security.fortress.Engine; 24 | import org.json.JSONObject; 25 | 26 | import javax.crypto.AndroidBase64; 27 | import javax.crypto.ContextHolder; 28 | import javax.crypto.MyUtil; 29 | 30 | /** 31 | * Uses a one-way hash function to turn an arbitrary number of bytes into a 32 | * fixed-length byte sequence. The original arbitrary-length sequence is the 33 | * message, and the fixed-length byte sequence is the digest or 34 | * message digest. 35 | * 36 | *

Sample Code

37 | *

The basic pattern to digest an {@link java.io.InputStream} looks like this: 38 | *

 39 |  *  MessageDigest digester = MessageDigest.getInstance("MD5");
 40 |  *  byte[] bytes = new byte[8192];
 41 |  *  int byteCount;
 42 |  *  while ((byteCount = in.read(bytes)) > 0) {
 43 |  *    digester.update(bytes, 0, byteCount);
 44 |  *  }
 45 |  *  byte[] digest = digester.digest();
 46 |  * 
47 | * 48 | *

That is, after creating or resetting a {@code MessageDigest} you should 49 | * call {@link #update(byte[],int,int)} for each block of input data, and then call {@link #digest} 50 | * to get the final digest. Note that calling {@code digest} resets the {@code MessageDigest}. 51 | * Advanced users who want partial digests should clone their {@code MessageDigest} before 52 | * calling {@code digest}. 53 | * 54 | *

This class is not thread-safe. 55 | * 56 | * @see MessageDigestSpi 57 | */ 58 | public abstract class MessageDigest extends MessageDigestSpi { 59 | 60 | // Used to access common engine functionality 61 | private static final Engine ENGINE = new Engine("MessageDigest"); 62 | 63 | // The provider 64 | private Provider provider; 65 | 66 | // The algorithm. 67 | private String algorithm; 68 | 69 | //add by icew4y 2019 12 13 70 | private JSONObject jsoninfo = new JSONObject(); 71 | //private StringBuffer infos = new StringBuffer(); 72 | private ArrayList tmpBytes = new ArrayList<>(); 73 | //add by icew4y 2019 12 13 74 | 75 | private static boolean switch_state = true; 76 | private String monPackageName = ""; 77 | 78 | /** 79 | * Lower case Hex Digits. 80 | */ 81 | private static final String HEX_DIGITS = "0123456789abcdef"; 82 | 83 | /** 84 | * Byte mask. 85 | */ 86 | private static final int BYTE_MSK = 0xFF; 87 | 88 | /** 89 | * Hex digit mask. 90 | */ 91 | private static final int HEX_DIGIT_MASK = 0xF; 92 | 93 | /** 94 | * Number of bits per Hex digit (4). 95 | */ 96 | private static final int HEX_DIGIT_BITS = 4; 97 | 98 | public static String toHexString(final byte[] byteArray) { 99 | StringBuilder sb = new StringBuilder(byteArray.length * 2); 100 | for (int i = 0; i < byteArray.length; i++) { 101 | int b = byteArray[i] & BYTE_MSK; 102 | sb.append(HEX_DIGITS.charAt(b >>> HEX_DIGIT_BITS)).append( 103 | HEX_DIGITS.charAt(b & HEX_DIGIT_MASK)); 104 | } 105 | return sb.toString(); 106 | } 107 | 108 | public static String byteArrayToString(byte[] input) { 109 | if(input==null) 110 | return ""; 111 | String out = new String(input); 112 | int tmp = 0; 113 | for (int i = 0; i < out.length(); i++) { 114 | int c = out.charAt(i); 115 | 116 | if (c >= 32 && c < 127) { 117 | tmp++; 118 | } 119 | } 120 | 121 | if (tmp > (out.length() * 0.60)) { 122 | StringBuilder sb = new StringBuilder(); 123 | for (byte b : input) { 124 | if (b >= 32 && b < 127) 125 | sb.append(String.format("%c", b)); 126 | else 127 | sb.append('.'); 128 | } 129 | out = sb.toString(); 130 | 131 | } else { 132 | out = AndroidBase64.encodeToString(input, AndroidBase64.NO_WRAP); 133 | } 134 | 135 | return out; 136 | } 137 | 138 | private static int LIMIT_SIZE = 5 * 1024 * 1024; 139 | 140 | private static boolean check_oom(byte[] bs) { 141 | //10mb 142 | if (bs.length > LIMIT_SIZE) { 143 | return true; 144 | } 145 | return false; 146 | } 147 | 148 | private static boolean check_oom(ByteBuffer bs) { 149 | //10mb 150 | if (bs.array().length > LIMIT_SIZE) { 151 | return true; 152 | } 153 | return false; 154 | } 155 | 156 | private static boolean check_oom(ArrayList bs) { 157 | //10mb 158 | if (bs.size() > LIMIT_SIZE) { 159 | return true; 160 | } 161 | return false; 162 | } 163 | 164 | private static synchronized void priter(String content, String packageName) { 165 | //System.out.println(content); 166 | MyUtil.appendFile("/data/data/" + packageName + "/MessageDigest", content + "\r\n"); 167 | } 168 | 169 | //add by icew4y 170 | 171 | /** 172 | * Constructs a new instance of {@code MessageDigest} with the name of 173 | * the algorithm to use. 174 | * 175 | * @param algorithm 176 | * the name of algorithm to use 177 | */ 178 | protected MessageDigest(String algorithm) { 179 | this.algorithm = algorithm; 180 | } 181 | 182 | /** 183 | * Returns a new instance of {@code MessageDigest} that utilizes the 184 | * specified algorithm. 185 | * 186 | * @param algorithm 187 | * the name of the algorithm to use 188 | * @return a new instance of {@code MessageDigest} that utilizes the 189 | * specified algorithm 190 | * @throws NoSuchAlgorithmException 191 | * if the specified algorithm is not available 192 | * @throws NullPointerException 193 | * if {@code algorithm} is {@code null} 194 | */ 195 | public static MessageDigest getInstance(String algorithm) 196 | throws NoSuchAlgorithmException { 197 | if (algorithm == null) { 198 | throw new NullPointerException("algorithm == null"); 199 | } 200 | Engine.SpiAndProvider sap = ENGINE.getInstance(algorithm, null); 201 | Object spi = sap.spi; 202 | Provider provider = sap.provider; 203 | if (spi instanceof MessageDigest) { 204 | MessageDigest result = (MessageDigest) spi; 205 | result.algorithm = algorithm; 206 | result.provider = provider; 207 | return result; 208 | } 209 | return new MessageDigestImpl((MessageDigestSpi) sap.spi, sap.provider, algorithm); 210 | } 211 | 212 | /** 213 | * Returns a new instance of {@code MessageDigest} that utilizes the 214 | * specified algorithm from the specified provider. 215 | * 216 | * @param algorithm 217 | * the name of the algorithm to use 218 | * @param provider 219 | * the name of the provider 220 | * @return a new instance of {@code MessageDigest} that utilizes the 221 | * specified algorithm from the specified provider 222 | * @throws NoSuchAlgorithmException 223 | * if the specified algorithm is not available 224 | * @throws NoSuchProviderException 225 | * if the specified provider is not available 226 | * @throws NullPointerException 227 | * if {@code algorithm} is {@code null} 228 | * @throws IllegalArgumentException if {@code provider == null || provider.isEmpty()} 229 | */ 230 | public static MessageDigest getInstance(String algorithm, String provider) 231 | throws NoSuchAlgorithmException, NoSuchProviderException { 232 | if (provider == null || provider.isEmpty()) { 233 | throw new IllegalArgumentException(); 234 | } 235 | Provider p = Security.getProvider(provider); 236 | if (p == null) { 237 | throw new NoSuchProviderException(provider); 238 | } 239 | return getInstance(algorithm, p); 240 | } 241 | 242 | /** 243 | * Returns a new instance of {@code MessageDigest} that utilizes the 244 | * specified algorithm from the specified provider. The 245 | * {@code provider} supplied does not have to be registered. 246 | * 247 | * @param algorithm 248 | * the name of the algorithm to use 249 | * @param provider 250 | * the provider 251 | * @return a new instance of {@code MessageDigest} that utilizes the 252 | * specified algorithm from the specified provider 253 | * @throws NoSuchAlgorithmException 254 | * if the specified algorithm is not available 255 | * @throws NullPointerException 256 | * if {@code algorithm} is {@code null} 257 | * @throws IllegalArgumentException if {@code provider == null} 258 | */ 259 | public static MessageDigest getInstance(String algorithm, Provider provider) 260 | throws NoSuchAlgorithmException { 261 | if (provider == null) { 262 | throw new IllegalArgumentException("provider == null"); 263 | } 264 | if (algorithm == null) { 265 | throw new NullPointerException("algorithm == null"); 266 | } 267 | Object spi = ENGINE.getInstance(algorithm, provider, null); 268 | if (spi instanceof MessageDigest) { 269 | MessageDigest result = (MessageDigest) spi; 270 | result.algorithm = algorithm; 271 | result.provider = provider; 272 | return result; 273 | } 274 | return new MessageDigestImpl((MessageDigestSpi) spi, provider, algorithm); 275 | } 276 | 277 | /** 278 | * Puts this {@code MessageDigest} back in an initial state, such that it is 279 | * ready to compute a one way hash value. 280 | */ 281 | public void reset() { 282 | //add by icew4y 2019 12 14 283 | tmpBytes.clear(); 284 | jsoninfo = new JSONObject(); 285 | //add by icew4y 2019 12 14 286 | engineReset(); 287 | } 288 | 289 | /** 290 | * Updates this {@code MessageDigest} using the given {@code byte}. 291 | * 292 | * @param arg0 293 | * the {@code byte} to update this {@code MessageDigest} with 294 | * @see #reset() 295 | */ 296 | public void update(byte arg0) { 297 | //add by icew4y 2019 12 14 298 | //System.out.println("update(byte arg0)"); 299 | if (switch_state == true && !check_oom(tmpBytes)) { 300 | try { 301 | String packageName = ContextHolder.getPackageName(); 302 | if (!packageName.equals("")) { 303 | if (!MyUtil.isWhiteList(packageName)) { 304 | if (monPackageName.equals("")) { 305 | monPackageName = MyUtil.readPackageNameFromFile(); 306 | } 307 | if (!monPackageName.equals("")) { 308 | if (packageName.equals(monPackageName)) { 309 | tmpBytes.add(arg0); 310 | } 311 | } 312 | } 313 | } 314 | 315 | } catch (Exception e) { 316 | e.printStackTrace(); 317 | } 318 | } 319 | 320 | //add by icew4y 2019 12 14 321 | engineUpdate(arg0); 322 | } 323 | 324 | /** 325 | * Updates this {@code MessageDigest} using the given {@code byte[]}. 326 | * 327 | * @param input 328 | * the {@code byte} array 329 | * @param offset 330 | * the index of the first byte in {@code input} to update from 331 | * @param len 332 | * the number of bytes in {@code input} to update from 333 | * @throws IllegalArgumentException 334 | * if {@code offset} or {@code len} are not valid in respect to 335 | * {@code input} 336 | */ 337 | public void update(byte[] input, int offset, int len) { 338 | if (input == null || 339 | // offset < 0 || len < 0 || 340 | // checks for negative values are commented out intentionally 341 | // see HARMONY-1120 for details 342 | (long) offset + (long) len > input.length) { 343 | throw new IllegalArgumentException(); 344 | } 345 | //add by icew4y 2019 12 13 346 | 347 | //System.out.println("update(byte[] input, int offset, int len)\n" + MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace())); 348 | if (switch_state == true && !check_oom(tmpBytes) && (len < LIMIT_SIZE)) { 349 | try { 350 | 351 | String packageName = ContextHolder.getPackageName(); 352 | if (!packageName.equals("")) { 353 | if (!MyUtil.isWhiteList(packageName)) { 354 | if (monPackageName.equals("")) { 355 | monPackageName = MyUtil.readPackageNameFromFile(); 356 | } 357 | if (!monPackageName.equals("")) { 358 | if (packageName.equals(monPackageName)) { 359 | 360 | byte[] realdata = new byte[len]; 361 | System.arraycopy(input, offset, realdata, 0, len); 362 | for (byte b : realdata) { 363 | tmpBytes.add(b); 364 | } 365 | } 366 | } 367 | } 368 | } 369 | 370 | } catch (Exception e) { 371 | e.printStackTrace(); 372 | } 373 | } 374 | 375 | //add by icew4y 2019 12 13 376 | 377 | engineUpdate(input, offset, len); 378 | } 379 | 380 | /** 381 | * Updates this {@code MessageDigest} using the given {@code byte[]}. 382 | * 383 | * @param input 384 | * the {@code byte} array 385 | * @throws NullPointerException 386 | * if {@code input} is {@code null} 387 | */ 388 | public void update(byte[] input) { 389 | if (input == null) { 390 | throw new NullPointerException("input == null"); 391 | } 392 | 393 | //add by icew4y 2019 12 13 394 | //System.out.println("update(byte[] input)\n" + MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace())); 395 | if (switch_state == true && !check_oom(tmpBytes) && !check_oom(input)) { 396 | 397 | try { 398 | String packageName = ContextHolder.getPackageName(); 399 | if (!packageName.equals("")) { 400 | if (!MyUtil.isWhiteList(packageName)) { 401 | if (monPackageName.equals("")) { 402 | monPackageName = MyUtil.readPackageNameFromFile(); 403 | } 404 | if (!monPackageName.equals("")) { 405 | if (packageName.equals(monPackageName)) { 406 | for (byte b : input) { 407 | tmpBytes.add(b); 408 | } 409 | } 410 | } 411 | } 412 | } 413 | 414 | } catch (Exception e) { 415 | e.printStackTrace(); 416 | } 417 | } 418 | //add by icew4y 2019 12 13 419 | engineUpdate(input, 0, input.length); 420 | } 421 | 422 | /** 423 | * Computes and returns the final hash value for this {@link MessageDigest}. 424 | * After the digest is computed the receiver is reset. 425 | * 426 | * @return the computed one way hash value 427 | * @see #reset 428 | */ 429 | public byte[] digest() { 430 | //return engineDigest(); 431 | 432 | 433 | //add by icew4y 2019 12 13 434 | 435 | //System.out.println("calling -> digest()"); 436 | 437 | //在这里怎么读取到调用者的包名? 438 | byte[] result = engineDigest(); 439 | if (switch_state == true && !check_oom(tmpBytes)) { 440 | try { 441 | 442 | String packageName = ContextHolder.getPackageName(); 443 | if (!packageName.equals("")) { 444 | if (!MyUtil.isWhiteList(packageName)) { 445 | if (monPackageName.equals("")) { 446 | monPackageName = MyUtil.readPackageNameFromFile(); 447 | } 448 | if (!monPackageName.equals("")) { 449 | if (packageName.equals(monPackageName)) { 450 | 451 | 452 | jsoninfo.put("Algorithm", getAlgorithm()); 453 | Provider provider_ = getProvider(); 454 | if (provider_ != null) { 455 | jsoninfo.put("Provider", provider_.getName()); 456 | } 457 | 458 | 459 | StringBuffer tmpsb = new StringBuffer(); 460 | if (tmpBytes.size() > 0) { 461 | int n = tmpBytes.size(); 462 | byte[] resultBytes = new byte[n]; 463 | for (int i = 0; i < n; i++) { 464 | resultBytes[i] = (byte) tmpBytes.get(i); 465 | } 466 | 467 | jsoninfo.put("data", byteArrayToString(resultBytes)); 468 | jsoninfo.put("Base64Data", AndroidBase64.encodeToString(resultBytes, AndroidBase64.NO_WRAP)); 469 | 470 | 471 | } else { 472 | jsoninfo.put("data", ""); 473 | } 474 | 475 | jsoninfo.put("digest", toHexString(result)); 476 | jsoninfo.put("StackTrace", AndroidBase64.encodeToString(MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace()).getBytes(), AndroidBase64.NO_WRAP)); 477 | 478 | priter("MessageDigestTag:" + jsoninfo.toString(), packageName); 479 | jsoninfo = new JSONObject(); 480 | tmpBytes.clear(); 481 | } 482 | } 483 | } 484 | 485 | } 486 | 487 | } catch (Exception e) { 488 | e.printStackTrace(); 489 | } 490 | } 491 | return result; 492 | //add by icew4y 2019 12 13 493 | } 494 | 495 | /** 496 | * Computes and stores the final hash value for this {@link MessageDigest}. 497 | * After the digest is computed the receiver is reset. 498 | * 499 | * @param buf 500 | * the buffer to store the result 501 | * @param offset 502 | * the index of the first byte in {@code buf} to store 503 | * @param len 504 | * the number of bytes allocated for the digest 505 | * @return the number of bytes written to {@code buf} 506 | * @throws DigestException 507 | * if an error occurs 508 | * @throws IllegalArgumentException 509 | * if {@code offset} or {@code len} are not valid in respect to 510 | * {@code buf} 511 | * @see #reset() 512 | */ 513 | public int digest(byte[] buf, int offset, int len) throws DigestException { 514 | if (buf == null || 515 | // offset < 0 || len < 0 || 516 | // checks for negative values are commented out intentionally 517 | // see HARMONY-1148 for details 518 | (long) offset + (long) len > buf.length) { 519 | throw new IllegalArgumentException(); 520 | } 521 | //return engineDigest(buf, offset, len); 522 | 523 | //add by icew4y 2019 12 13 524 | //System.out.println("digest(byte[] buf, int offset, int len)"); 525 | int result = engineDigest(buf, offset, len); 526 | if (switch_state == true && !check_oom(tmpBytes)) { 527 | 528 | try { 529 | String packageName = ContextHolder.getPackageName(); 530 | 531 | if (!packageName.equals("")) { 532 | if (!MyUtil.isWhiteList(packageName)) { 533 | if (monPackageName.equals("")) { 534 | monPackageName = MyUtil.readPackageNameFromFile(); 535 | } 536 | 537 | if (!monPackageName.equals("")) { 538 | if (packageName.equals(monPackageName)) { 539 | 540 | jsoninfo.put("Algorithm", getAlgorithm()); 541 | Provider provider_ = getProvider(); 542 | if (provider_ != null) { 543 | jsoninfo.put("Provider", provider_.getName()); 544 | } 545 | 546 | 547 | StringBuffer tmpsb = new StringBuffer(); 548 | if (tmpBytes.size() > 0) { 549 | int n = tmpBytes.size(); 550 | byte[] resultBytes = new byte[n]; 551 | for (int i = 0; i < n; i++) { 552 | resultBytes[i] = (byte) tmpBytes.get(i); 553 | } 554 | 555 | jsoninfo.put("data", byteArrayToString(resultBytes)); 556 | jsoninfo.put("Base64Data", AndroidBase64.encodeToString(resultBytes, AndroidBase64.NO_WRAP)); 557 | 558 | 559 | } else { 560 | jsoninfo.put("data", ""); 561 | } 562 | 563 | 564 | //数据 565 | byte[] readresult = new byte[len]; 566 | System.arraycopy(buf, offset, readresult, 0, len); 567 | jsoninfo.put("digest", toHexString(readresult)); 568 | jsoninfo.put("StackTrace", AndroidBase64.encodeToString(MyUtil.getCurrentStackTrack(Thread.currentThread().getStackTrace()).getBytes(), AndroidBase64.NO_WRAP)); 569 | 570 | priter("MessageDigestTag:" + jsoninfo.toString(), packageName); 571 | jsoninfo = new JSONObject(); 572 | tmpBytes.clear(); 573 | } 574 | } 575 | } 576 | 577 | 578 | } 579 | 580 | } catch (Exception e) { 581 | e.printStackTrace(); 582 | } 583 | } 584 | 585 | return result; 586 | //add by icew4y 2019 12 13 587 | } 588 | 589 | /** 590 | * Performs the final update and then computes and returns the final hash 591 | * value for this {@link MessageDigest}. After the digest is computed the 592 | * receiver is reset. 593 | * 594 | * @param input 595 | * the {@code byte} array 596 | * @return the computed one way hash value 597 | * @see #reset() 598 | */ 599 | public byte[] digest(byte[] input) { 600 | update(input); 601 | return digest(); 602 | } 603 | 604 | /** 605 | * Returns a string containing a concise, human-readable description of this 606 | * {@code MessageDigest} including the name of its algorithm. 607 | * 608 | * @return a printable representation for this {@code MessageDigest} 609 | */ 610 | @Override 611 | public String toString() { 612 | return "MESSAGE DIGEST " + algorithm; 613 | } 614 | 615 | /** 616 | * Indicates whether to digest are equal by performing a simply 617 | * byte-per-byte compare of the two digests. 618 | * 619 | * @param digesta 620 | * the first digest to be compared 621 | * @param digestb 622 | * the second digest to be compared 623 | * @return {@code true} if the two hashes are equal, {@code false} otherwise 624 | */ 625 | public static boolean isEqual(byte[] digesta, byte[] digestb) { 626 | if (digesta.length != digestb.length) { 627 | return false; 628 | } 629 | // Perform a constant time comparison to avoid timing attacks. 630 | int v = 0; 631 | for (int i = 0; i < digesta.length; i++) { 632 | v |= (digesta[i] ^ digestb[i]); 633 | } 634 | return v == 0; 635 | } 636 | 637 | /** 638 | * Returns the name of the algorithm of this {@code MessageDigest}. 639 | * 640 | * @return the name of the algorithm of this {@code MessageDigest} 641 | */ 642 | public final String getAlgorithm() { 643 | return algorithm; 644 | } 645 | 646 | /** 647 | * Returns the provider associated with this {@code MessageDigest}. 648 | * 649 | * @return the provider associated with this {@code MessageDigest} 650 | */ 651 | public final Provider getProvider() { 652 | return provider; 653 | } 654 | 655 | /** 656 | * Returns the engine digest length in bytes. If the implementation does not 657 | * implement this function or is not an instance of {@code Cloneable}, 658 | * {@code 0} is returned. 659 | * 660 | * @return the digest length in bytes, or {@code 0} 661 | */ 662 | public final int getDigestLength() { 663 | int l = engineGetDigestLength(); 664 | if (l != 0) { 665 | return l; 666 | } 667 | if (!(this instanceof Cloneable)) { 668 | return 0; 669 | } 670 | try { 671 | MessageDigest md = (MessageDigest) clone(); 672 | return md.digest().length; 673 | } catch (CloneNotSupportedException e) { 674 | return 0; 675 | } 676 | } 677 | 678 | /** 679 | * Updates this {@code MessageDigest} using the given {@code input}. 680 | * 681 | * @param input 682 | * the {@code ByteBuffer} 683 | */ 684 | public final void update(ByteBuffer input) { 685 | //add by icew4y 2019 12 13 686 | 687 | //System.out.println("update(ByteBuffer input)"); 688 | if (switch_state == true && !check_oom(tmpBytes) && !check_oom(input)) { 689 | try { 690 | 691 | String packageName = ContextHolder.getPackageName(); 692 | if (!packageName.equals("")) { 693 | if (!MyUtil.isWhiteList(packageName)) { 694 | if (monPackageName.equals("")) { 695 | monPackageName = MyUtil.readPackageNameFromFile(); 696 | } 697 | if (!monPackageName.equals("")) { 698 | if (packageName.equals(monPackageName)) { 699 | byte[] t = input.array(); 700 | for (byte b : t) { 701 | tmpBytes.add(b); 702 | } 703 | } 704 | } 705 | } 706 | } 707 | 708 | } catch (Exception e) { 709 | e.printStackTrace(); 710 | } 711 | } 712 | //add by icew4y 2019 12 13 713 | engineUpdate(input); 714 | } 715 | 716 | /** 717 | * 718 | * The internal MessageDigest implementation 719 | * 720 | */ 721 | private static class MessageDigestImpl extends MessageDigest { 722 | 723 | // MessageDigestSpi implementation 724 | private MessageDigestSpi spiImpl; 725 | 726 | // MessageDigestImpl ctor 727 | private MessageDigestImpl(MessageDigestSpi messageDigestSpi, 728 | Provider provider, String algorithm) { 729 | super(algorithm); 730 | super.provider = provider; 731 | spiImpl = messageDigestSpi; 732 | } 733 | 734 | // engineReset() implementation 735 | @Override 736 | protected void engineReset() { 737 | spiImpl.engineReset(); 738 | } 739 | 740 | // engineDigest() implementation 741 | @Override 742 | protected byte[] engineDigest() { 743 | return spiImpl.engineDigest(); 744 | } 745 | 746 | // engineGetDigestLength() implementation 747 | @Override 748 | protected int engineGetDigestLength() { 749 | return spiImpl.engineGetDigestLength(); 750 | } 751 | 752 | // engineUpdate() implementation 753 | @Override 754 | protected void engineUpdate(byte arg0) { 755 | spiImpl.engineUpdate(arg0); 756 | } 757 | 758 | // engineUpdate() implementation 759 | @Override 760 | protected void engineUpdate(byte[] arg0, int arg1, int arg2) { 761 | spiImpl.engineUpdate(arg0, arg1, arg2); 762 | } 763 | 764 | // Returns a clone if the spiImpl is cloneable 765 | @Override 766 | public Object clone() throws CloneNotSupportedException { 767 | MessageDigestSpi spi = (MessageDigestSpi) spiImpl.clone(); 768 | return new MessageDigestImpl(spi, getProvider(), getAlgorithm()); 769 | } 770 | } 771 | } 772 | -------------------------------------------------------------------------------- /20200212/MyUtil.java: -------------------------------------------------------------------------------- 1 | package javax.crypto; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.io.File; 11 | import java.io.InputStreamReader; 12 | import java.io.PrintWriter; 13 | import java.io.RandomAccessFile; 14 | import java.io.StringWriter; 15 | import java.nio.channels.FileChannel; 16 | import java.nio.channels.FileLock; 17 | import java.util.ArrayList; 18 | import java.util.Arrays; 19 | import java.util.HashSet; 20 | 21 | public class MyUtil { 22 | public static HashSet WhiteListSet = new HashSet<>(Arrays.asList("com.android.providers.telephony" 23 | ,"com.android.providers.calendar" 24 | ,"com.android.providers.media" 25 | ,"com.android.wallpapercropper" 26 | ,"com.android.documentsui" 27 | ,"com.android.galaxy4" 28 | ,"com.android.externalstorage" 29 | ,"com.android.htmlviewer" 30 | ,"com.android.quicksearchbox" 31 | ,"com.android.mms.service" 32 | ,"com.android.providers.downloads" 33 | ,"com.android.messaging" 34 | ,"com.android.browser" 35 | ,"com.android.soundrecorder" 36 | ,"com.android.defcontainer" 37 | ,"com.android.providers.downloads.ui" 38 | ,"com.android.pacprocessor" 39 | ,"com.qualcomm.cabl" 40 | ,"com.android.certinstaller" 41 | ,"com.android.carrierconfig" 42 | ,"android" 43 | ,"com.android.contacts" 44 | ,"com.android.camera2" 45 | ,"com.android.nfc" 46 | ,"com.android.launcher3" 47 | ,"com.android.backupconfirm" 48 | ,"com.android.provision" 49 | ,"org.codeaurora.ims" 50 | ,"com.android.statementservice" 51 | ,"com.android.wallpaper.holospiral" 52 | ,"com.android.calendar" 53 | ,"com.android.phasebeam" 54 | ,"com.qualcomm.qcrilmsgtunnel" 55 | ,"com.android.providers.settings" 56 | ,"com.android.sharedstoragebackup" 57 | ,"com.android.printspooler" 58 | ,"com.android.dreams.basic" 59 | ,"com.android.webview" 60 | ,"com.android.inputdevices" 61 | ,"com.android.musicfx" 62 | ,"com.android.onetimeinitializer" 63 | ,"com.android.server.telecom" 64 | ,"com.android.keychain" 65 | ,"com.android.dialer" 66 | ,"com.android.gallery3d" 67 | ,"com.android.calllogbackup" 68 | ,"com.android.packageinstaller" 69 | ,"com.svox.pico" 70 | ,"com.android.proxyhandler" 71 | ,"com.android.inputmethod.latin" 72 | ,"com.android.managedprovisioning" 73 | ,"com.android.dreams.phototable" 74 | ,"com.android.noisefield" 75 | ,"com.android.smspush" 76 | ,"com.android.wallpaper.livepicker" 77 | ,"com.android.apps.tag" 78 | ,"com.android.settings" 79 | ,"com.android.calculator2" 80 | ,"com.android.wallpaper" 81 | ,"com.android.vpndialogs" 82 | ,"com.android.email" 83 | ,"com.android.music" 84 | ,"com.android.phone" 85 | ,"com.android.shell" 86 | ,"com.android.providers.userdictionary" 87 | ,"com.android.location.fused" 88 | ,"com.android.deskclock" 89 | ,"com.android.systemui" 90 | ,"com.android.bluetoothmidiservice" 91 | ,"com.google.android.launcher.layouts.angler" 92 | ,"com.android.bluetooth" 93 | ,"com.qualcomm.timeservice" 94 | ,"com.android.providers.contacts" 95 | ,"com.android.captiveportallogin" 96 | ,"com.guoshi.httpcanary" 97 | )); 98 | 99 | public static String readPackageNameFromFile() { 100 | //String pn = ""; 101 | String pn = readFile("/data/local/tmp/monitor_package"); 102 | pn = pn.replace("\r", ""); 103 | pn = pn.replace("\n", ""); 104 | return pn; 105 | } 106 | 107 | public static boolean isWhiteList(String packageName) { 108 | boolean bret = false; 109 | if (WhiteListSet.contains(packageName)) { 110 | bret = true; 111 | } 112 | // for (String name : WhiteList) { 113 | // if (packageName.equals(name)) { 114 | // bret = true; 115 | // break; 116 | // } 117 | // } 118 | return bret; 119 | } 120 | 121 | public static String readFileThroughRuntime(String filepath) { 122 | String data = ""; 123 | try { 124 | Process exec = Runtime.getRuntime().exec("cat " + filepath); 125 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(exec.getInputStream())); 126 | String line; 127 | StringBuffer stringBuffer = new StringBuffer(); 128 | while ((line = bufferedReader.readLine()) != null) { 129 | stringBuffer.append(line); 130 | } 131 | //exec.destroy(); 132 | data = stringBuffer.toString(); 133 | } catch (FileNotFoundException e) { 134 | e.printStackTrace(); 135 | }catch (IOException e) { 136 | e.printStackTrace(); 137 | } 138 | 139 | return data; 140 | } 141 | 142 | public static String readFile(String filepath) { 143 | String data = ""; 144 | try { 145 | File file = new File(filepath); 146 | InputStream in = null; 147 | StringBuffer sb = new StringBuffer(); 148 | 149 | if (file.isFile() && file.exists()) { 150 | byte[] tempbytes = new byte[1024]; 151 | int byteread = 0; 152 | in = new FileInputStream(file); 153 | while ((byteread = in.read(tempbytes)) != -1) { 154 | String str = new String(tempbytes, 0, byteread); 155 | sb.append(str); 156 | } 157 | in.close(); 158 | } 159 | 160 | data = sb.toString(); 161 | } catch (FileNotFoundException e) { 162 | e.printStackTrace(); 163 | }catch (IOException e) { 164 | e.printStackTrace(); 165 | } 166 | 167 | data = data.replace("\r", ""); 168 | data = data.replace("\n", ""); 169 | return data; 170 | } 171 | 172 | 173 | public static void appendFile(String filepath, String content) { 174 | //FileLock lock = null; 175 | try { 176 | File file = new File(filepath); 177 | if (!file.exists()) { 178 | file.createNewFile(); 179 | } 180 | /* */ 181 | FileWriter fileWriter = new FileWriter(filepath, true); 182 | fileWriter.write(content); 183 | fileWriter.close(); 184 | 185 | /* */ 186 | 187 | //lock.release(); 188 | } catch (IOException e) { 189 | e.printStackTrace(); 190 | } 191 | } 192 | public static void writeByte(byte[] arg8, String arg9) { 193 | try { 194 | FileOutputStream v2 = new FileOutputStream(arg9); 195 | v2.write(arg8); 196 | v2.close(); 197 | } 198 | catch(Exception v4) { 199 | } 200 | } 201 | 202 | /** 203 | * get Exception Stack Trace 204 | * @param e 205 | * @return 206 | */ 207 | public static String getExceptionStackTrace(Exception e) { 208 | StringWriter sw = null; 209 | PrintWriter pw = null; 210 | try { 211 | sw = new StringWriter(); 212 | pw = new PrintWriter(sw); 213 | e.printStackTrace(pw); 214 | pw.flush(); 215 | sw.flush(); 216 | 217 | } catch (Exception e2) { 218 | e2.printStackTrace(); 219 | } finally { 220 | if (sw != null) { 221 | try { 222 | sw.close(); 223 | } catch (IOException e1) { 224 | e1.printStackTrace(); 225 | } 226 | } 227 | if (pw != null) { 228 | pw.close(); 229 | } 230 | } 231 | return sw.toString(); 232 | } 233 | 234 | 235 | /** 236 | * 打印堆栈 237 | * @param st 238 | * @return 239 | */ 240 | public static String getCurrentStackTrack(StackTraceElement[] st){ 241 | if(st==null){ 242 | return "none"; 243 | } 244 | StringBuffer sbf = new StringBuffer(); 245 | for(StackTraceElement e:st){ 246 | if(sbf.length() > 0){ 247 | sbf.append(" <- "); 248 | sbf.append(System.getProperty("line.separator")); 249 | } 250 | sbf.append(java.text.MessageFormat.format("{0}.{1}() {2}" 251 | ,e.getClassName() 252 | ,e.getMethodName() 253 | ,e.getLineNumber())); 254 | } 255 | return sbf.toString(); 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /8.1.0_r1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/icew4y/crypto_filter_aosp/cb2b97f78bc1a3fab65a9fd57ae8cf2ed5ec30d9/8.1.0_r1.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # crypto_filter_aosp 2 | # 监控java层的加密算法一个ROM 3 | 4 | 基于android6.0.1 编译 5 | 6 | 下载地址: 7 | 8 | https://drive.google.com/file/d/19G5IXIiww_b5PcQqqiA6lTO6QvnMtQkS/view?usp=sharing 9 | 10 | /Volumes/SamsungT5/aosp6.0.1/libcore/luni/src/main/java/javax/crypto/MyUtil.java 11 | 12 | /Volumes/SamsungT5/aosp6.0.1/libcore/luni/src/main/java/javax/crypto/Mac.java 13 | 14 | /Volumes/SamsungT5/aosp6.0.1/libcore/luni/src/main/java/javax/crypto/Cipher.java 15 | 16 | /Volumes/SamsungT5/aosp6.0.1/libcore/luni/src/main/java/java/security/MessageDigest.java 17 | 18 | /Volumes/SamsungT5/aosp6.0.1/libcore/luni/src/main/java/javax/crypto/ContextHolder.java 19 | 20 | /Volumes/SamsungT5/aosp6.0.1/libcore/luni/src/main/java/javax/crypto/AndroidBase64.java 21 | 22 | 适用手机型号Nexus 6P 23 | 24 | 使用办法: 25 | 26 | 1.手机先刷入twrp 27 | 28 | 2.下载rom解压,adb push ROM/ /sdcard/TWRP/BACKUPS 29 | 30 | 3.进入twrp,从备份中恢复,重启手机,然后修改权限 chmod 777 /data/local/tmp/monitor_package 31 | 32 | 4.安装你需要监控的apk(系统自动把最后一次安装的apk添加进去监控的列表 /data/local/tmp/monitor_package),只能同时监控一个 33 | 34 | 5./data/data/package_name/下面生成APK调用的算法,只有三种(数据均为JSON编码,字段为BASE64编码): 35 | 36 | MessageDigest文件为HASH 37 | 38 | Cipher文件为加密算法 39 | 40 | Mac 41 | 42 | 43 | # example 44 | 45 | Cipher: 46 | 47 | `CipherTag:{"opmode":"DECRYPT_MODE","key":"rM+FMzVeI0VniavN7xISNKzPhTM1XiNF","Key(Base64)":"rM+FMzVeI0VniavN7xISNKzPhTM1XiNF","algorithm":"DESede","SecureRandom":"SHA1PRNG","provider":"","transformation":"DESede\/ECB\/NoPadding","data":"","Base64Data":"","doFinal":"","Base64Cipher":"","StackTrace":"ZGFsdmlrLnN5c3RlbS5WTVN0YWNrLmdldFRocmVhZFN0YWNrVHJhY2UoKSAtMiA8LSAKamF2YS5sYW5nLlRocmVhZC5nZXRTdGFja1RyYWNlKCkgNTgwIDwtIApqYXZheC5jcnlwdG8uQ2lwaGVyLmRvRmluYWwoKSAxLDc4NiA8LSAKY29tLmJhbmdjbGUuYW5kam5pLkpuaUxpYi5jTCgpIC0yIDwtIApjb20udW5pb25wYXkudGlua2VycGF0Y2gubGliLnVwdXRpbHMuRGVzVXRpbHMuaW50ZXJuYWxDcnlwdCgpIC0xIDwtIApjb20uYmFuZ2NsZS5hbmRqbmkuSm5pTGliLmNMKCkgLTIgPC0gCmNvbS51bmlvbnBheS50aW5rZXJwYXRjaC5saWIudXB1dGlscy5EZXNVdGlscy5lY2JEZWNyeXB0KCkgLTEgPC0gCmNvbS5iYW5nY2xlLmFuZGpuaS5KbmlMaWIuY0woKSAtMiA8LSAKY29tLnVuaW9ucGF5LnRpbmtlcnBhdGNoLmxpYi51cHV0aWxzLlByZWZlcmVuY2VVdGlscy5kZWNQcmVmRGF0YSgpIC0xIDwtIApjb20uYmFuZ2NsZS5hbmRqbmkuSm5pTGliLmNMKCkgLTIgPC0gCmNvbS51bmlvbnBheS50aW5rZXJwYXRjaC5saWIudXB1dGlscy5QcmVmZXJlbmNlVXRpbHMuZGVjcnlwdERhdGEoKSAtMSA8LSAKY29tLmJhbmdjbGUuYW5kam5pLkpuaUxpYi5jTCgpIC0yIDwtIApjb20udW5pb25wYXkudGlua2VycGF0Y2gubGliLnVwdXRpbHMuUHJlZmVyZW5jZVV0aWxzLmdldEluZm9tYXRpb24oKSAtMSA8LSAKY29tLnVuaW9ucGF5LnRpbmtlcnBhdGNoLmxpYi51cHV0aWxzLlByZWZlcmVuY2VVdGlscy5nZXRVaWRJbmZvbWF0aW9uKCkgNjMgPC0gCmNvbS51bmlvbnBheS50aW5rZXJwYXRjaC5saWIudXB1dGlscy5EZXZpY2VJbmZvVXRpbC5nZXRVRElEKCkgNjE2IDwtIApjb20uYmFuZ2NsZS5hbmRqbmkuSm5pTGliLmNMKCkgLTIgPC0gCmNvbS51bmlvbnBheS50aW5rZXJwYXRjaC5saWIuc2VydmVyLm1vZGVsLkRldmljZUluZm8uaW5pdERldmljZUluZm8oKSAtMSA8LSAKY29tLnVuaW9ucGF5LnRpbmtlcnBhdGNoLmxpYi5zZXJ2ZXIudXRpbHMuVmVyc2lvblV0aWxzLjxpbml0PigpIDUyIDwtIApjb20udW5pb25wYXkudGlua2VycGF0Y2gubGliLnNlcnZlci5jbGllbnQuVGlua2VyQ2xpZW50QVBJLmluaXQoKSAxNDAgPC0gCmNvbS51bmlvbnBheS50aW5rZXJwYXRjaC5saWIuc2VydmVyLnJlcG9ydGVyLlJlcG9ydFV0aWxzLjxpbml0PigpIDM5IDwtIApjb20udW5pb25wYXkudGlua2VycGF0Y2gubGliLnNlcnZlci5yZXBvcnRlci5SZXBvcnRVdGlscy5pbml0KCkgMjMgPC0gCmNvbS5iYW5nY2xlLmFuZGpuaS5KbmlMaWIuY1YoKSAtMiA8LSAKY29tLnVuaW9ucGF5LnRpbmtlcnBhdGNoLmxpYi50cHJlcG9ydGVyLlRpbmtlck1hbmFnZXIuaW5zdGFsbFRpbmtlcigpIC0xIDwtIApjb20udW5pb25wYXkudGlua2VycGF0Y2gubGliLlRpbmtlclBhdGNoLmluaXQoKSA4MiA8LSAKY29tLnVuaW9ucGF5LmJhc2UuVVBBcHBsaWNhdGlvbkxpa2UuY2hlY2tIb3RQYXRjaCgpIDMwMiA8LSAKY29tLnVuaW9ucGF5LmJhc2UuVVBBcHBsaWNhdGlvbkxpa2Uub25DcmVhdGUoKSAxMDkgPC0gCmphdmEubGFuZy5yZWZsZWN0Lk1ldGhvZC5pbnZva2UoKSAtMiA8LSAKY29tLnRlbmNlbnQudGlua2VyLmxvYWRlci5hcHAuVGlua2VyQXBwbGljYXRpb24uaW52b2tlQXBwTGlrZU9uQ3JlYXRlKCkgMTg5IDwtIApjb20udGVuY2VudC50aW5rZXIubG9hZGVyLmFwcC5UaW5rZXJBcHBsaWNhdGlvbi5vbkNyZWF0ZSgpIDIwNSA8LSAKYW5kcm9pZC5hcHAuSW5zdHJ1bWVudGF0aW9uLmNhbGxBcHBsaWNhdGlvbk9uQ3JlYXRlKCkgMSwwMTMgPC0gCmFuZHJvaWQuYXBwLkFjdGl2aXR5VGhyZWFkLmhhbmRsZUJpbmRBcHBsaWNhdGlvbigpIDQsNzEyIDwtIApkZS5yb2J2LmFuZHJvaWQueHBvc2VkLlhwb3NlZEJyaWRnZS5pbnZva2VPcmlnaW5hbE1ldGhvZE5hdGl2ZSgpIC0yIDwtIApkZS5yb2J2LmFuZHJvaWQueHBvc2VkLlhwb3NlZEJyaWRnZS5oYW5kbGVIb29rZWRNZXRob2QoKSAzNjAgPC0gCmFuZHJvaWQuYXBwLkFjdGl2aXR5VGhyZWFkLmhhbmRsZUJpbmRBcHBsaWNhdGlvbigpIC0xIDwtIAphbmRyb2lkLmFwcC5BY3Rpdml0eVRocmVhZC4td3JhcDEoKSAtMSA8LSAKYW5kcm9pZC5hcHAuQWN0aXZpdHlUaHJlYWQkSC5oYW5kbGVNZXNzYWdlKCkgMSw0MDUgPC0gCmFuZHJvaWQub3MuSGFuZGxlci5kaXNwYXRjaE1lc3NhZ2UoKSAxMDIgPC0gCmFuZHJvaWQub3MuTG9vcGVyLmxvb3AoKSAxNDggPC0gCmFuZHJvaWQuYXBwLkFjdGl2aXR5VGhyZWFkLm1haW4oKSA1LDQyMiA8LSAKamF2YS5sYW5nLnJlZmxlY3QuTWV0aG9kLmludm9rZSgpIC0yIDwtIApjb20uYW5kcm9pZC5pbnRlcm5hbC5vcy5aeWdvdGVJbml0JE1ldGhvZEFuZEFyZ3NDYWxsZXIucnVuKCkgNzI2IDwtIApjb20uYW5kcm9pZC5pbnRlcm5hbC5vcy5aeWdvdGVJbml0Lm1haW4oKSA2MTYgPC0gCmRlLnJvYnYuYW5kcm9pZC54cG9zZWQuWHBvc2VkQnJpZGdlLm1haW4oKSAxMDc="}` 48 | 49 | 50 | MessageDigest: 51 | 52 | `MessageDigestTag:{"Algorithm":"SHA-256","Provider":"AndroidOpenSSL","data":"staffId","Base64Data":"c3RhZmZJZA==","digest":"e8f3205321cb6c5a1fcb5ce7a712724707c0cb8d155ed486427a10f368d81910","StackTrace":"ZGFsdmlrLnN5c3RlbS5WTVN0YWNrLmdldFRocmVhZFN0YWNrVHJhY2UoKSAtMiA8LSAKamF2YS5sYW5nLlRocmVhZC5nZXRTdGFja1RyYWNlKCkgNTgwIDwtIApqYXZhLnNlY3VyaXR5Lk1lc3NhZ2VEaWdlc3QuZGlnZXN0KCkgNDc2IDwtIApjb20uYXNpYWluZm8ueGoubGliLnV0aWxzLnkuPGluaXQ+KCkgOCA8LSAKY29tLmFzaWFpbmZvLnhqLmxpYi51dGlscy55LmEoKSAyMzkgPC0gCmNvbS5hc2lhaW5mby54ai5saWIuYy5iLmEoKSAxNSA8LSAKY29tLmFzaWFpbmZvLnhqLmxpYi5jLmIuYSgpIDMwIDwtIApjb20uYXNpYWluZm8ucWRsbS5iLmEuYSgpIDEgPC0gCmNvbS5hc2lhaW5mby5xZGxtLmIuYS5hKCkgNDI4IDwtIApjb20uYXNpYWluZm8ucWRsbS51aS5zcGxhc2guTGF1bmNoZXJBY3Rpdml0eS5pKCkgMSA8LSAKY29tLmFzaWFpbmZvLnFkbG0udWkuc3BsYXNoLkxhdW5jaGVyQWN0aXZpdHkuaigpIDMgPC0gCmNvbS5hc2lhaW5mby5xZGxtLnVpLnNwbGFzaC5MYXVuY2hlckFjdGl2aXR5Lm9uQ3JlYXRlKCkgOSA8LSAKYW5kcm9pZC5hcHAuQWN0aXZpdHkucGVyZm9ybUNyZWF0ZSgpIDYsMjUxIDwtIAphbmRyb2lkLmFwcC5JbnN0cnVtZW50YXRpb24uY2FsbEFjdGl2aXR5T25DcmVhdGUoKSAxLDEwNyA8LSAKYW5kcm9pZC5hcHAuQWN0aXZpdHlUaHJlYWQucGVyZm9ybUxhdW5jaEFjdGl2aXR5KCkgMiwzNjkgPC0gCmFuZHJvaWQuYXBwLkFjdGl2aXR5VGhyZWFkLmhhbmRsZUxhdW5jaEFjdGl2aXR5KCkgMiw0NzYgPC0gCmFuZHJvaWQuYXBwLkFjdGl2aXR5VGhyZWFkLi13cmFwMTEoKSAtMSA8LSAKYW5kcm9pZC5hcHAuQWN0aXZpdHlUaHJlYWQkSC5oYW5kbGVNZXNzYWdlKCkgMSwzNDQgPC0gCmFuZHJvaWQub3MuSGFuZGxlci5kaXNwYXRjaE1lc3NhZ2UoKSAxMDIgPC0gCmFuZHJvaWQub3MuTG9vcGVyLmxvb3AoKSAxNDggPC0gCmFuZHJvaWQuYXBwLkFjdGl2aXR5VGhyZWFkLm1haW4oKSA1LDQyMiA8LSAKamF2YS5sYW5nLnJlZmxlY3QuTWV0aG9kLmludm9rZSgpIC0yIDwtIApjb20uYW5kcm9pZC5pbnRlcm5hbC5vcy5aeWdvdGVJbml0JE1ldGhvZEFuZEFyZ3NDYWxsZXIucnVuKCkgNzI2IDwtIApjb20uYW5kcm9pZC5pbnRlcm5hbC5vcy5aeWdvdGVJbml0Lm1haW4oKSA2MTYgPC0gCmRlLnJvYnYuYW5kcm9pZC54cG9zZWQuWHBvc2VkQnJpZGdlLm1haW4oKSAxMDc="} 53 | MessageDigestTag:{"Algorithm":"MD5","Provider":"AndroidOpenSSL","data":"ns@3'*DHF7\/==","Base64Data":"bnNAMycqREhGNy89PQ==","digest":"31fb6fd3d44c84fb2df62958a7da31f6","StackTrace":"ZGFsdmlrLnN5c3RlbS5WTVN0YWNrLmdldFRocmVhZFN0YWNrVHJhY2UoKSAtMiA8LSAKamF2YS5sYW5nLlRocmVhZC5nZXRTdGFja1RyYWNlKCkgNTgwIDwtIApqYXZhLnNlY3VyaXR5Lk1lc3NhZ2VEaWdlc3QuZGlnZXN0KCkgNDc2IDwtIApqYXZhLnNlY3VyaXR5Lk1lc3NhZ2VEaWdlc3QuZGlnZXN0KCkgNjAxIDwtIApjb20uYXNpYWluZm8ueGoubGliLnV0aWxzLnUuYigpIDQgPC0gCmNvbS5hc2lhaW5mby54ai5saWIudXRpbHMudS5hKCkgMTUgPC0gCmNvbS5hc2lhaW5mby54ai5saWIuYy5iLmEoKSAxNyA8LSAKY29tLmFzaWFpbmZvLnhqLmxpYi5jLmIuYSgpIDMwIDwtIApjb20uYXNpYWluZm8ucWRsbS5iLmEuYSgpIDEgPC0gCmNvbS5hc2lhaW5mby5xZGxtLmIuYS5hKCkgNDI4IDwtIApjb20uYXNpYWluZm8ucWRsbS51aS5zcGxhc2guTGF1bmNoZXJBY3Rpdml0eS5pKCkgMSA8LSAKY29tLmFzaWFpbmZvLnFkbG0udWkuc3BsYXNoLkxhdW5jaGVyQWN0aXZpdHkuaigpIDMgPC0gCmNvbS5hc2lhaW5mby5xZGxtLnVpLnNwbGFzaC5MYXVuY2hlckFjdGl2aXR5Lm9uQ3JlYXRlKCkgOSA8LSAKYW5kcm9pZC5hcHAuQWN0aXZpdHkucGVyZm9ybUNyZWF0ZSgpIDYsMjUxIDwtIAphbmRyb2lkLmFwcC5JbnN0cnVtZW50YXRpb24uY2FsbEFjdGl2aXR5T25DcmVhdGUoKSAxLDEwNyA8LSAKYW5kcm9pZC5hcHAuQWN0aXZpdHlUaHJlYWQucGVyZm9ybUxhdW5jaEFjdGl2aXR5KCkgMiwzNjkgPC0gCmFuZHJvaWQuYXBwLkFjdGl2aXR5VGhyZWFkLmhhbmRsZUxhdW5jaEFjdGl2aXR5KCkgMiw0NzYgPC0gCmFuZHJvaWQuYXBwLkFjdGl2aXR5VGhyZWFkLi13cmFwMTEoKSAtMSA8LSAKYW5kcm9pZC5hcHAuQWN0aXZpdHlUaHJlYWQkSC5oYW5kbGVNZXNzYWdlKCkgMSwzNDQgPC0gCmFuZHJvaWQub3MuSGFuZGxlci5kaXNwYXRjaE1lc3NhZ2UoKSAxMDIgPC0gCmFuZHJvaWQub3MuTG9vcGVyLmxvb3AoKSAxNDggPC0gCmFuZHJvaWQuYXBwLkFjdGl2aXR5VGhyZWFkLm1haW4oKSA1LDQyMiA8LSAKamF2YS5sYW5nLnJlZmxlY3QuTWV0aG9kLmludm9rZSgpIC0yIDwtIApjb20uYW5kcm9pZC5pbnRlcm5hbC5vcy5aeWdvdGVJbml0JE1ldGhvZEFuZEFyZ3NDYWxsZXIucnVuKCkgNzI2IDwtIApjb20uYW5kcm9pZC5pbnRlcm5hbC5vcy5aeWdvdGVJbml0Lm1haW4oKSA2MTYgPC0gCmRlLnJvYnYuYW5kcm9pZC54cG9zZWQuWHBvc2VkQnJpZGdlLm1haW4oKSAxMDc="} 54 | ` 55 | --------------------------------------------------------------------------------