1 /* 2 * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 25 // common infrastructure for SunPKCS11 tests 26 27 import java.io.BufferedReader; 28 import java.io.ByteArrayOutputStream; 29 import java.io.File; 30 import java.io.FileInputStream; 31 import java.io.IOException; 32 import java.io.InputStreamReader; 33 import java.io.StringReader; 34 import java.security.AlgorithmParameters; 35 import java.security.InvalidAlgorithmParameterException; 36 import java.security.KeyPairGenerator; 37 import java.security.NoSuchProviderException; 38 import java.security.Provider; 39 import java.security.ProviderException; 40 import java.security.Security; 41 import java.security.spec.ECGenParameterSpec; 42 import java.security.spec.ECParameterSpec; 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.HashMap; 46 import java.util.Iterator; 47 import java.util.List; 48 import java.util.Map; 49 import java.util.Properties; 50 import java.util.ServiceLoader; 51 import java.util.Set; 52 53 public abstract class PKCS11Test { 54 55 private boolean enableSM = false; 56 57 static final Properties props = System.getProperties(); 58 59 static final String PKCS11 = "PKCS11"; 60 61 // directory of the test source 62 static final String BASE = System.getProperty("test.src", "."); 63 64 static final char SEP = File.separatorChar; 65 66 private static final String DEFAULT_POLICY = 67 BASE + SEP + ".." + SEP + "policy"; 68 69 // directory corresponding to BASE in the /closed hierarchy 70 static final String CLOSED_BASE; 71 72 static { 73 // hack 74 String absBase = new File(BASE).getAbsolutePath(); 75 int k = absBase.indexOf(SEP + "test" + SEP + "sun" + SEP); 76 if (k < 0) k = 0; 77 String p1 = absBase.substring(0, k + 6); 78 String p2 = absBase.substring(k + 5); 79 CLOSED_BASE = p1 + "closed" + p2; 80 81 // set it as a system property to make it available in policy file 82 System.setProperty("closed.base", CLOSED_BASE); 83 } 84 85 // NSS version info 86 public static enum ECCState { None, Basic, Extended }; 87 static double nss_version = -1; 88 static ECCState nss_ecc_status = ECCState.Extended; 89 90 // The NSS library we need to search for in getNSSLibDir() 91 // Default is "libsoftokn3.so", listed as "softokn3" 92 // The other is "libnss3.so", listed as "nss3". 93 static String nss_library = "softokn3"; 94 95 // NSS versions of each library. It is simplier to keep nss_version 96 // for quick checking for generic testing than many if-else statements. 97 static double softoken3_version = -1; 98 static double nss3_version = -1; 99 static Provider pkcs11; 100 101 // Goes through ServiceLoader instead of Provider.getInstance() since it 102 // works on all platforms 103 static { 104 ServiceLoader sl = ServiceLoader.load(java.security.Provider.class); 105 Iterator<Provider> iter = sl.iterator(); 106 Provider p = null; 107 boolean found = false; 108 while (iter.hasNext()) { 109 try { 110 p = iter.next(); 111 if (p.getName().equals("SunPKCS11")) { 112 found = true; 113 break; 114 } 115 } catch (Exception e) { 116 // ignore and move on to the next one 117 } 118 } 119 // Nothing found through ServiceLoader; fall back to reflection 120 if (!found) { 121 try { 122 Class clazz = Class.forName("sun.security.pkcs11.SunPKCS11"); 123 p = (Provider) clazz.newInstance(); 124 } catch (Exception ex) { 125 ex.printStackTrace(); 126 } 127 } 128 pkcs11 = p; 129 } 130 131 /* 132 * Use Solaris SPARC 11.2 or later to avoid an intermittent failure 133 * when running SunPKCS11-Solaris (8044554) 134 */ 135 static boolean isBadSolarisSparc(Provider p) { 136 if ("SunPKCS11-Solaris".equals(p.getName()) && badSolarisSparc) { 137 System.out.println("SunPKCS11-Solaris provider requires " + 138 "Solaris SPARC 11.2 or later, skipping"); 139 return true; 140 } 141 return false; 142 } 143 144 // Return a SunPKCS11 provider configured with the specified config file 145 static Provider getSunPKCS11(String config) throws Exception { 146 if (pkcs11 == null) { 147 throw new NoSuchProviderException("No PKCS11 provider available"); 148 } 149 return pkcs11.configure(config); 150 } 151 152 public abstract void main(Provider p) throws Exception; 153 154 private void premain(Provider p) throws Exception { 155 // set a security manager and policy before a test case runs, 156 // and disable them after the test case finished 157 try { 158 if (enableSM) { 159 System.setSecurityManager(new SecurityManager()); 160 } 161 long start = System.currentTimeMillis(); 162 System.out.printf( 163 "Running test with provider %s (security manager %s) ...%n", 164 p.getName(), enableSM ? "enabled" : "disabled"); 165 main(p); 166 long stop = System.currentTimeMillis(); 167 System.out.println("Completed test with provider " + p.getName() + 168 " (" + (stop - start) + " ms)."); 169 } finally { 170 if (enableSM) { 171 System.setSecurityManager(null); 172 } 173 } 174 } 175 176 public static void main(PKCS11Test test) throws Exception { 177 main(test, null); 178 } 179 180 public static void main(PKCS11Test test, String[] args) throws Exception { 181 if (args != null) { 182 if (args.length > 0) { 183 if ("sm".equals(args[0])) { 184 test.enableSM = true; 185 } else { 186 throw new RuntimeException("Unknown Command, use 'sm' as " 187 + "first arguemtn to enable security manager"); 188 } 189 } 190 if (test.enableSM) { 191 System.setProperty("java.security.policy", 192 (args.length > 1) ? BASE + SEP + args[1] 193 : DEFAULT_POLICY); 194 } 195 } 196 197 Provider[] oldProviders = Security.getProviders(); 198 try { 199 System.out.println("Beginning test run " + test.getClass().getName() + "..."); 200 testDefault(test); 201 testNSS(test); 202 testDeimos(test); 203 } finally { 204 // NOTE: Do not place a 'return' in any finally block 205 // as it will suppress exceptions and hide test failures. 206 Provider[] newProviders = Security.getProviders(); 207 boolean found = true; 208 // Do not restore providers if nothing changed. This is especailly 209 // useful for ./Provider/Login.sh, where a SecurityManager exists. 210 if (oldProviders.length == newProviders.length) { 211 found = false; 212 for (int i = 0; i<oldProviders.length; i++) { 213 if (oldProviders[i] != newProviders[i]) { 214 found = true; 215 break; 216 } 217 } 218 } 219 if (found) { 220 for (Provider p: newProviders) { 221 Security.removeProvider(p.getName()); 222 } 223 for (Provider p: oldProviders) { 224 Security.addProvider(p); 225 } 226 } 227 } 228 } 229 230 public static void testDeimos(PKCS11Test test) throws Exception { 231 if (new File("/opt/SUNWconn/lib/libpkcs11.so").isFile() == false || 232 "true".equals(System.getProperty("NO_DEIMOS"))) { 233 return; 234 } 235 String base = getBase(); 236 String p11config = base + SEP + "nss" + SEP + "p11-deimos.txt"; 237 Provider p = getSunPKCS11(p11config); 238 test.premain(p); 239 } 240 241 public static void testDefault(PKCS11Test test) throws Exception { 242 // run test for default configured PKCS11 providers (if any) 243 244 if ("true".equals(System.getProperty("NO_DEFAULT"))) { 245 return; 246 } 247 248 Provider[] providers = Security.getProviders(); 249 for (int i = 0; i < providers.length; i++) { 250 Provider p = providers[i]; 251 if (p.getName().startsWith("SunPKCS11-")) { 252 test.premain(p); 253 } 254 } 255 } 256 257 private static String PKCS11_BASE; 258 static { 259 try { 260 PKCS11_BASE = getBase(); 261 } catch (Exception e) { 262 // ignore 263 } 264 } 265 266 private final static String PKCS11_REL_PATH = "sun/security/pkcs11"; 267 268 public static String getBase() throws Exception { 269 if (PKCS11_BASE != null) { 270 return PKCS11_BASE; 271 } 272 File cwd = new File(System.getProperty("test.src", ".")).getCanonicalFile(); 273 while (true) { 274 File file = new File(cwd, "TEST.ROOT"); 275 if (file.isFile()) { 276 break; 277 } 278 cwd = cwd.getParentFile(); 279 if (cwd == null) { 280 throw new Exception("Test root directory not found"); 281 } 282 } 283 PKCS11_BASE = new File(cwd, PKCS11_REL_PATH.replace('/', SEP)).getAbsolutePath(); 284 return PKCS11_BASE; 285 } 286 287 public static String getNSSLibDir() throws Exception { 288 return getNSSLibDir(nss_library); 289 } 290 291 static String getNSSLibDir(String library) throws Exception { 292 String osName = props.getProperty("os.name"); 293 if (osName.startsWith("Win")) { 294 osName = "Windows"; 295 } else if (osName.equals("Mac OS X")) { 296 osName = "MacOSX"; 297 } 298 String osid = osName + "-" 299 + props.getProperty("os.arch") + "-" + props.getProperty("sun.arch.data.model"); 300 String[] nssLibDirs = osMap.get(osid); 301 if (nssLibDirs == null) { 302 System.out.println("Unsupported OS, skipping: " + osid); 303 return null; 304 } 305 if (nssLibDirs.length == 0) { 306 System.out.println("NSS not supported on this platform, skipping test"); 307 return null; 308 } 309 String nssLibDir = null; 310 for (String dir : nssLibDirs) { 311 if (new File(dir).exists() && 312 new File(dir + System.mapLibraryName(library)).exists()) { 313 nssLibDir = dir; 314 System.setProperty("pkcs11test.nss.libdir", nssLibDir); 315 break; 316 } 317 } 318 return nssLibDir; 319 } 320 321 static boolean isBadNSSVersion(Provider p) { 322 if (isNSS(p) && badNSSVersion) { 323 System.out.println("NSS 3.11 has a DER issue that recent " + 324 "version do not."); 325 return true; 326 } 327 return false; 328 } 329 330 protected static void safeReload(String lib) throws Exception { 331 try { 332 System.load(lib); 333 } catch (UnsatisfiedLinkError e) { 334 if (e.getMessage().contains("already loaded")) { 335 return; 336 } 337 } 338 } 339 340 static boolean loadNSPR(String libdir) throws Exception { 341 // load NSS softoken dependencies in advance to avoid resolver issues 342 safeReload(libdir + System.mapLibraryName("nspr4")); 343 safeReload(libdir + System.mapLibraryName("plc4")); 344 safeReload(libdir + System.mapLibraryName("plds4")); 345 safeReload(libdir + System.mapLibraryName("sqlite3")); 346 safeReload(libdir + System.mapLibraryName("nssutil3")); 347 return true; 348 } 349 350 // Check the provider being used is NSS 351 public static boolean isNSS(Provider p) { 352 return p.getName().toUpperCase().equals("SUNPKCS11-NSS"); 353 } 354 355 static double getNSSVersion() { 356 if (nss_version == -1) 357 getNSSInfo(); 358 return nss_version; 359 } 360 361 static ECCState getNSSECC() { 362 if (nss_version == -1) 363 getNSSInfo(); 364 return nss_ecc_status; 365 } 366 367 public static double getLibsoftokn3Version() { 368 if (softoken3_version == -1) 369 return getNSSInfo("softokn3"); 370 return softoken3_version; 371 } 372 373 public static double getLibnss3Version() { 374 if (nss3_version == -1) 375 return getNSSInfo("nss3"); 376 return nss3_version; 377 } 378 379 /* Read the library to find out the verison */ 380 static void getNSSInfo() { 381 getNSSInfo(nss_library); 382 } 383 384 static double getNSSInfo(String library) { 385 // look for two types of headers in NSS libraries 386 String nssHeader1 = "$Header: NSS"; 387 String nssHeader2 = "Version: NSS"; 388 boolean found = false; 389 String s = null; 390 int i = 0; 391 String libfile = ""; 392 393 if (library.compareTo("softokn3") == 0 && softoken3_version > -1) 394 return softoken3_version; 395 if (library.compareTo("nss3") == 0 && nss3_version > -1) 396 return nss3_version; 397 398 try { 399 libfile = getNSSLibDir() + System.mapLibraryName(library); 400 try (FileInputStream is = new FileInputStream(libfile)) { 401 byte[] data = new byte[1000]; 402 int read = 0; 403 404 while (is.available() > 0) { 405 if (read == 0) { 406 read = is.read(data, 0, 1000); 407 } else { 408 // Prepend last 100 bytes in case the header was split 409 // between the reads. 410 System.arraycopy(data, 900, data, 0, 100); 411 read = 100 + is.read(data, 100, 900); 412 } 413 414 s = new String(data, 0, read); 415 i = s.indexOf(nssHeader1); 416 if (i > 0 || (i = s.indexOf(nssHeader2)) > 0) { 417 found = true; 418 // If the nssHeader is before 920 we can break, otherwise 419 // we may not have the whole header so do another read. If 420 // no bytes are in the stream, that is ok, found is true. 421 if (i < 920) { 422 break; 423 } 424 } 425 } 426 } 427 } catch (Exception e) { 428 e.printStackTrace(); 429 } 430 431 if (!found) { 432 System.out.println("lib" + library + 433 " version not found, set to 0.0: " + libfile); 434 nss_version = 0.0; 435 return nss_version; 436 } 437 438 // the index after whitespace after nssHeader 439 int afterheader = s.indexOf("NSS", i) + 4; 440 String version = s.substring(afterheader, s.indexOf(' ', afterheader)); 441 442 // If a "dot dot" release, strip the extra dots for double parsing 443 String[] dot = version.split("\\."); 444 if (dot.length > 2) { 445 version = dot[0]+"."+dot[1]; 446 for (int j = 2; dot.length > j; j++) { 447 version += dot[j]; 448 } 449 } 450 451 // Convert to double for easier version value checking 452 try { 453 nss_version = Double.parseDouble(version); 454 } catch (NumberFormatException e) { 455 System.out.println("Failed to parse lib" + library + 456 " version. Set to 0.0"); 457 e.printStackTrace(); 458 } 459 460 System.out.print("lib" + library + " version = "+version+". "); 461 462 // Check for ECC 463 if (s.indexOf("Basic") > 0) { 464 nss_ecc_status = ECCState.Basic; 465 System.out.println("ECC Basic."); 466 } else if (s.indexOf("Extended") > 0) { 467 nss_ecc_status = ECCState.Extended; 468 System.out.println("ECC Extended."); 469 } else { 470 System.out.println("ECC None."); 471 } 472 473 if (library.compareTo("softokn3") == 0) { 474 softoken3_version = nss_version; 475 } else if (library.compareTo("nss3") == 0) { 476 nss3_version = nss_version; 477 } 478 479 return nss_version; 480 } 481 482 // Used to set the nss_library file to search for libsoftokn3.so 483 public static void useNSS() { 484 nss_library = "nss3"; 485 } 486 487 public static void testNSS(PKCS11Test test) throws Exception { 488 String libdir = getNSSLibDir(); 489 if (libdir == null) { 490 return; 491 } 492 String base = getBase(); 493 494 if (loadNSPR(libdir) == false) { 495 return; 496 } 497 498 String libfile = libdir + System.mapLibraryName(nss_library); 499 500 String customDBdir = System.getProperty("CUSTOM_DB_DIR"); 501 String dbdir = (customDBdir != null) ? 502 customDBdir : 503 base + SEP + "nss" + SEP + "db"; 504 // NSS always wants forward slashes for the config path 505 dbdir = dbdir.replace('\\', '/'); 506 507 String customConfig = System.getProperty("CUSTOM_P11_CONFIG"); 508 String customConfigName = System.getProperty("CUSTOM_P11_CONFIG_NAME", "p11-nss.txt"); 509 String p11config = (customConfig != null) ? 510 customConfig : 511 base + SEP + "nss" + SEP + customConfigName; 512 513 System.setProperty("pkcs11test.nss.lib", libfile); 514 System.setProperty("pkcs11test.nss.db", dbdir); 515 Provider p = getSunPKCS11(p11config); 516 test.premain(p); 517 } 518 519 // Generate a vector of supported elliptic curves of a given provider 520 static List<ECParameterSpec> getKnownCurves(Provider p) throws Exception { 521 int index; 522 int begin; 523 int end; 524 String curve; 525 526 List<ECParameterSpec> results = new ArrayList<>(); 527 // Get Curves to test from SunEC. 528 String kcProp = Security.getProvider("SunEC"). 529 getProperty("AlgorithmParameters.EC SupportedCurves"); 530 531 if (kcProp == null) { 532 throw new RuntimeException( 533 "\"AlgorithmParameters.EC SupportedCurves property\" not found"); 534 } 535 536 System.out.println("Finding supported curves using list from SunEC\n"); 537 index = 0; 538 for (;;) { 539 // Each set of curve names is enclosed with brackets. 540 begin = kcProp.indexOf('[', index); 541 end = kcProp.indexOf(']', index); 542 if (begin == -1 || end == -1) { 543 break; 544 } 545 546 /* 547 * Each name is separated by a comma. 548 * Just get the first name in the set. 549 */ 550 index = end + 1; 551 begin++; 552 end = kcProp.indexOf(',', begin); 553 if (end == -1) { 554 // Only one name in the set. 555 end = index -1; 556 } 557 558 curve = kcProp.substring(begin, end); 559 ECParameterSpec e = getECParameterSpec(p, curve); 560 System.out.print("\t "+ curve + ": "); 561 try { 562 KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", p); 563 kpg.initialize(e); 564 kpg.generateKeyPair(); 565 results.add(e); 566 System.out.println("Supported"); 567 } catch (ProviderException ex) { 568 System.out.println("Unsupported: PKCS11: " + 569 ex.getCause().getMessage()); 570 } catch (InvalidAlgorithmParameterException ex) { 571 System.out.println("Unsupported: Key Length: " + 572 ex.getMessage()); 573 } 574 } 575 576 if (results.size() == 0) { 577 throw new RuntimeException("No supported EC curves found"); 578 } 579 580 return results; 581 } 582 583 private static ECParameterSpec getECParameterSpec(Provider p, String name) 584 throws Exception { 585 586 AlgorithmParameters parameters = 587 AlgorithmParameters.getInstance("EC", p); 588 589 parameters.init(new ECGenParameterSpec(name)); 590 591 return parameters.getParameterSpec(ECParameterSpec.class); 592 } 593 594 // Check support for a curve with a provided Vector of EC support 595 boolean checkSupport(List<ECParameterSpec> supportedEC, 596 ECParameterSpec curve) { 597 for (ECParameterSpec ec: supportedEC) { 598 if (ec.equals(curve)) { 599 return true; 600 } 601 } 602 return false; 603 } 604 605 private static final Map<String,String[]> osMap; 606 607 // Location of the NSS libraries on each supported platform 608 static { 609 osMap = new HashMap<>(); 610 osMap.put("SunOS-sparc-32", new String[]{"/usr/lib/mps/"}); 611 osMap.put("SunOS-sparcv9-64", new String[]{"/usr/lib/mps/64/"}); 612 osMap.put("SunOS-x86-32", new String[]{"/usr/lib/mps/"}); 613 osMap.put("SunOS-amd64-64", new String[]{"/usr/lib/mps/64/"}); 614 osMap.put("Linux-i386-32", new String[]{ 615 "/usr/lib/i386-linux-gnu/", "/usr/lib32/", "/usr/lib/"}); 616 osMap.put("Linux-amd64-64", new String[]{ 617 "/usr/lib/x86_64-linux-gnu/", "/usr/lib/x86_64-linux-gnu/nss/", 618 "/usr/lib64/"}); 619 osMap.put("Linux-ppc64-64", new String[]{"/usr/lib64/"}); 620 osMap.put("Linux-ppc64le-64", new String[]{"/usr/lib64/"}); 621 osMap.put("Windows-x86-32", new String[]{ 622 PKCS11_BASE + "/nss/lib/windows-i586/".replace('/', SEP)}); 623 osMap.put("Windows-amd64-64", new String[]{ 624 PKCS11_BASE + "/nss/lib/windows-amd64/".replace('/', SEP)}); 625 osMap.put("MacOSX-x86_64-64", new String[]{ 626 PKCS11_BASE + "/nss/lib/macosx-x86_64/"}); 627 } 628 629 private final static char[] hexDigits = "0123456789abcdef".toCharArray(); 630 631 static final boolean badNSSVersion = 632 getNSSVersion() >= 3.11 && getNSSVersion() < 3.12; 633 634 static final boolean badSolarisSparc = 635 System.getProperty("os.name").equals("SunOS") && 636 System.getProperty("os.arch").equals("sparcv9") && 637 System.getProperty("os.version").compareTo("5.11") <= 0 && 638 getDistro().compareTo("11.2") < 0; 639 640 public static String toString(byte[] b) { 641 if (b == null) { 642 return "(null)"; 643 } 644 StringBuilder sb = new StringBuilder(b.length * 3); 645 for (int i = 0; i < b.length; i++) { 646 int k = b[i] & 0xff; 647 if (i != 0) { 648 sb.append(':'); 649 } 650 sb.append(hexDigits[k >>> 4]); 651 sb.append(hexDigits[k & 0xf]); 652 } 653 return sb.toString(); 654 } 655 656 public static byte[] parse(String s) { 657 if (s.equals("(null)")) { 658 return null; 659 } 660 try { 661 int n = s.length(); 662 ByteArrayOutputStream out = new ByteArrayOutputStream(n / 3); 663 StringReader r = new StringReader(s); 664 while (true) { 665 int b1 = nextNibble(r); 666 if (b1 < 0) { 667 break; 668 } 669 int b2 = nextNibble(r); 670 if (b2 < 0) { 671 throw new RuntimeException("Invalid string " + s); 672 } 673 int b = (b1 << 4) | b2; 674 out.write(b); 675 } 676 return out.toByteArray(); 677 } catch (IOException e) { 678 throw new RuntimeException(e); 679 } 680 } 681 682 private static int nextNibble(StringReader r) throws IOException { 683 while (true) { 684 int ch = r.read(); 685 if (ch == -1) { 686 return -1; 687 } else if ((ch >= '0') && (ch <= '9')) { 688 return ch - '0'; 689 } else if ((ch >= 'a') && (ch <= 'f')) { 690 return ch - 'a' + 10; 691 } else if ((ch >= 'A') && (ch <= 'F')) { 692 return ch - 'A' + 10; 693 } 694 } 695 } 696 697 <T> T[] concat(T[] a, T[] b) { 698 if ((b == null) || (b.length == 0)) { 699 return a; 700 } 701 T[] r = Arrays.copyOf(a, a.length + b.length); 702 System.arraycopy(b, 0, r, a.length, b.length); 703 return r; 704 } 705 706 /** 707 * Returns supported algorithms of specified type. 708 */ 709 static List<String> getSupportedAlgorithms(String type, String alg, 710 Provider p) { 711 // prepare a list of supported algorithms 712 List<String> algorithms = new ArrayList<>(); 713 Set<Provider.Service> services = p.getServices(); 714 for (Provider.Service service : services) { 715 if (service.getType().equals(type) 716 && service.getAlgorithm().startsWith(alg)) { 717 algorithms.add(service.getAlgorithm()); 718 } 719 } 720 return algorithms; 721 } 722 723 /** 724 * Get the identifier for the operating system distribution 725 */ 726 static String getDistro() { 727 try (BufferedReader in = 728 new BufferedReader(new InputStreamReader( 729 Runtime.getRuntime().exec("uname -v").getInputStream()))) { 730 731 return in.readLine(); 732 } catch (Exception e) { 733 return ""; 734 } 735 } 736 737 static byte[] generateData(int length) { 738 byte data[] = new byte[length]; 739 for (int i=0; i<data.length; i++) { 740 data[i] = (byte) (i % 256); 741 } 742 return data; 743 } 744 }