1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=utf-8">
<TITLE>ESAPI 2.0 Symmetric Encryption User Guide</TITLE>
<META NAME="GENERATOR" CONTENT="OpenOffice.org 3.0 (Linux)">
<META NAME="CREATED" CONTENT="20100214;0">
<META NAME="CHANGEDBY" CONTENT="Kevin W. Wall">
<META NAME="CHANGED" CONTENT="20100304;00400700">
</HEAD>
<BODY LANG="en-US" DIR="LTR">
<TABLE BORDER="0" BORDERCOLOR="#000000" CELLPADDING=4 CELLSPACING=0 STYLE="page-break-before: auto; page-break-after: auto; page-break-inside: auto">
<TR>
<TD>
<OBJECT TYPE="audio/x-mpeg" data="http://www.catonmat.net/download/crypt-o.mp3"
WIDTH="500" HEIGHT="64" AUTOPLAY="false">
<PARAM NAME="src" VALUE="http://www.catonmat.net/download/crypt-o.mp3" />
<PARAM NAME="controller" VALUE="true" />
<PARAM NAME="autoplay" VALUE="false" />
<PARAM NAME="autostart" VALUE="0" />
</OBJECT>
</TD>
<TD>
<FONT COLOR="#00a444" SIZE="+2">
<I>Crypto song. Take a listen and enjoy! Harry Belafonte never sounded this good. ;-)</I>
</FONT>
</TD>
</TABLE>
<H1 ALIGN=CENTER>ESAPI 2.0 Symmetric Encryption User Guide</H1>
<H2>ESAPI.properties Properties Relevant to Symmetric Encryption</H2>
<P>Those properties that are new since ESAPI 2.0-rc2 are shown in
<FONT COLOR="#ff0000">red</FONT>. Values shown in <FONT COLOR="#0000ff">blue</FONT>
are ones that you would replace.</P>
<TABLE BORDER=1 BORDERCOLOR="#000000" CELLPADDING=4 CELLSPACING=0 STYLE="page-break-before: auto; page-break-after: auto; page-break-inside: auto">
<COL WIDTH=249>
<COL WIDTH=202>
<COL WIDTH=226>
<TR VALIGN=TOP>
<TH WIDTH=249>
<P>Property Name</P>
</TH>
<TH WIDTH=202>
<P>Default Value</P>
</TH>
<TH WIDTH=226>
<P>Comment</P>
</TH>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT SIZE=2>ESAPI.Encryptor</FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT SIZE=2>org.owasp.esapi.reference.crypto.JavaEncryptor</FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>The class implementing the Encryptor interface and
returned by ESAPI.encryptor().</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT SIZE=2>Encryptor.MasterKey</FONT></PRE>
</TD>
<TD WIDTH=202>
<P><FONT COLOR="#0000ff"><FONT SIZE=2><initially unset></FONT></FONT></P>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>The base64-encoded SecretKey. The key must be
appropriate to the specified key size and cipher algorithm.</FONT></P>
<P><FONT SIZE=2>Set as per the instructions in the ESAPI
Installation Guide.</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT SIZE=2>Encryptor.MasterSalt</FONT></PRE>
</TD>
<TD WIDTH=202>
<P><FONT COLOR="#0000ff"><FONT SIZE=2><initially unset></FONT></FONT></P>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>A base64-encoded random “salt”. This should be
at least 20-bytes. It is used to generate a random (but
consistent) public/private key pair used in asymmetric encryption
and digital signatures.</FONT></P>
<P><FONT SIZE=2>Set as per the instructions in the ESAPI
Installation Guide.</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><STRIKE><FONT SIZE=2>Encryptor.EncryptionAlgorithm</FONT></STRIKE></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT SIZE=2>AES</FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>A deprecated property, superseded by
Encryptor.CipherTransformation.</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>Encryptor.CipherTransformation</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>AES/CBC/PKCS5Padding</FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>Specifies the cipher transformation to use for
symmetric encryption. The format is
cipherAlgorithm/cipherMode/paddingScheme.</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>Encryptor.EncryptionKeyLength</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>128</FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>Key size, in bits. Required for cipher algorithms
that support multiple key sizes.</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>Encryptor.ChooseIVMethod</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>random</FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>Legal values are “random” or “fixed”.
Random is recommended. Set to “fixed” only if required for
compatibility with legacy or third party software. If set to
“fixed”, then the property Encryptor.fixedIV must also be
set to hex-encoded specific IV that you need to use.
</FONT></P><P><FONT SIZE=2>
<B>CAUTION:</B> While it is not required that the IV be kept
secret, encryption relying on fixed IVs can lead to a known
plaintext attack called a "Key Collision Attack". While this
attack is probably not practical (for those with modest
resources) for ciphers with 128-bit key size, this attack
makes it possible to capture the ciphertexts from only
2<sup>(N/2)</sup> known plaintexts to discover the
encryption key. Loughran and Dowling explain a Java
implementation of Eli Biham's key collision attack on DES in
their easy to understand paper,
<a href="http://homepage.eircom.net/~johnloughran/projects/computer/camDesAttackv4.pdf">
A Java Implemented Key Collision Attack on the
Data Encryption Standard (DES)</a>. Since attacks only get
better and the cost of storage is dropping rapidly, you are
urged to avoid using "fixed" IVs except when required for
backward compatibility. In particular, should never use
fixed IVs just to avoid the storage cost of storing a random
IV.
</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>Encryptor.fixedIV</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#0000ff"><FONT SIZE=2>0x000102030405060708090a0b0c0d0e0f</FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>A hex-encoded value to use as a fixed IV. Only
used if the property Encryptor.fixedIV is set to “fixed”. Intended
<I>only</I> for compatibility with legacy code. See the above
related above caution for <code>Encryptor.ChooseIVMethod</code>.
</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>Encryptor.CipherText.useMAC</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>true</FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>Whether or not <code>CipherText</code>
should use a message authentication code (MAC) with
it. This prevents an adversary from altering the IV
as well as allowing a more fool-proof way of
determining the decryption failed because of an incorrect key
being supplied. This refers to the "separate" MAC
calculated and stored in <code>CipherText</code>, not
part of any MAC that is calculated as a result
of a "combined mode" cipher mode.</FONT></P>
<P><FONT SIZE=2>Note: If the cipher mode used is one specified in
the comma-separated list of cipher modes given in the property
<b>Encryptor.cipher_modes.combined_modes</b>, then a separate MAC
is <i>not</i> calculated for <code>CipherText</code> regardless of
the setting of this property. (Doing so would be
superfluous.)</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>Encryptor.PreferredJCEProvider</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2><i><empty string></i></FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>Specifies the <i>preferred</i> JCE provider, that
is the JCE provider that is first looked at for JCE algorithms.
The <code>Encryptor</code> reference implementation,
<code>JavaEncryptor</code>, attempts to
load this JCE provider at position the first position when the
<code>JavaEncryptor</code> class is first loaded.
<br><br>
The value may either be a provider name (e.g., “BC” for
Bouncy Castle) or the fully qualified class name implementing
<code>java.security.Provider</code> for
the desired JCE provider. If left set to the empty string (the
default) or unset, the effect is to not change the preferred JCE
provider so that your application ends up using whatever your Java
VM is already using, which is generally determined by the settings
in your <code>$JAVA_HOME/jre/lib/security/java.security</code>
file.</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>Encryptor.cipher_modes.additional_allowed</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>CBC</FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>Additional cipher modes allowed for ESAPI 2.0
symmetric encryption. These cipher modes are in <I>addition</I> to
those specified by the property
<b>Encryptor.cipher_modes.combined_modes</b>.</FONT></P>
<P><FONT SIZE=2>Note: We will add support for streaming modes like
CFB & OFB once we add support for 'specified' to the property
<b>Encryptor.ChooseIVMethod</b> (probably in ESAPI 2.1).</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>Encryptor.cipher_modes.combined_modes</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>GCM,CCM,IAPM,EAX,OCB,CWC</FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>Comma-separated list of cipher modes that provide
<B><I>both</I></B> confidentiality <B><I>and</I></B>
message authenticity. (NIST refers to such cipher
modes as "combined modes" so that's what we
shall call them.) If any of these cipher modes are used then no
MAC is calculated and stored in the <code>CipherText</code>
upon encryption. Likewise, if one of these cipher
modes is used with decryption, no attempt will be
made to validate the MAC contained in the <code>CipherText</code>
object regardless of whether it contains one or not.
Since the expectation is that these cipher modes support support
message authenticity already, injecting a MAC in the
<code>CipherText</code> object would be at best redundant.</FONT>
</P>
<P><FONT SIZE=2>Note that as of JDK 1.5, the SunJCE provider does
not support <I>any</I> of these cipher modes. Of these listed,
only GCM and CCM are currently NIST approved.</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>Encryptor.PlainText.overwrite</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>TRUE</FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>Whether or not the plaintext bytes for the
PlainText object may be overwritten with “*” characters and
then marked eligible for garbage collection. If not set, this is
still treated as 'true'. If this is set to 'true', you will not be
able to use any PlainText object after you have used it with one
of the Encryptor encrypt() methods.</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>Encryptor.KDF.PDF</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#ff0000"><FONT SIZE=2>HmacSHA256</FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>
This is the Pseudo Random Function (PRF) that ESAPI's Key
Derivation Function (KDF) normally uses. NSA wanted us to
support something stronger than HmacSHA1 (even though that
is considered fine for now--unless perhaps you are guarding
nuclear launch codes--and if so, your Java license probably
prohibits that ;-).
<BR /><BR />
(Note this is *only* the PRF used for ESAPI's KDF and *not*
what is used for ESAPI's MAC. Currently, HMacSHA1 is always
used for the MAC.)
<BR /><BR />
Currently supported choices for JDK 1.5 and 1.6 are:
HMacSHA1 (160 bits), HMacSHA256 (256 bits), HMacSHA384
(384 bits), and HMacSHA512 (512 bits).
<BR /><BR />
Note that HMacMD5 is *not* supported for the PRF
used by the KDF even though these JDKs support it.
ESAPI 2.0 release candidates prior to 2.0_rc11
ALWAYS used HMacSHA1. It is somewhat faster than
the SHA2 HMAC variations, but not significantly so.
<BR /><BR />
The only legitimate reason to tweak this would be to change it to
one of the new HMACs based on the future SHA-3 winner once it is
announced by NIST and supported in ESAPI and most JDKs. Until then,
don't meddle.
</FONT></P>
</TD>
</TR>
<TR VALIGN=TOP>
<TD WIDTH=249>
<PRE><FONT COLOR="#000000"><FONT SIZE=2>Encryptor.CharacterEncoding</FONT></FONT></PRE>
</TD>
<TD WIDTH=202>
<PRE><FONT COLOR="#000000"><FONT SIZE=2>UTF-8</FONT></FONT></PRE>
</TD>
<TD WIDTH=226>
<P><FONT SIZE=2>The default encoding used for certain aspects such
as signing and sealing.</FONT></P>
</TD>
</TR>
</TABLE>
<H2>How the Old (Deprecated) Methods Were Used</H2>
<P>To encrypt / decrypt using the String-based, deprecated methods
carried over from ESAPI 1.4, code similar to the following would be
used.
</P>
<PRE> String myplaintext = "My plaintext";
try {
String ciphertext = ESAPI.encryptor().encrypt(myplaintext);
String decrypted = ESAPI.encryptor().decrypt(ciphertext);
assert decrypted.equals(myplaintext);
} catch(EncryptionException ex) {
// Log error then return error designation however appropriate
}</PRE><P>
This code will still work, however if you are using the standard
(default) reference for <CODE>ESAPI.Encryptor</CODE>, which is
<CODE>org.owasp.esapi.reference.crypto.JavaEncryptor</CODE>, the
cipher transformation used with be that specified by the property
<b>Encryptor.CipherTransformation</b> with a key size (when the
algorithm supports a variable key size) of that specified by
<b>Encryptor.EncryptionKeyLength</b> and the IV type specified
by <b>Encryptor.ChooseIVMethod</b>. What is not provided by
these methods (and why they are deprecated) is that they provide no
mechanism to ensure message authenticity unless they are used with a
so-called “combined” cipher mode such as CCM or GCM. <SPAN STYLE="font-style: normal">(Note
that as of JDK 1.6, the default JCE provider, “SunJCE”, does not
support any combined cipher modes.)</SPAN></P>
<H2>Requirements for using ESAPI Symmetric Encryption</H2>
<P>
The parties participating in using ESAPI's symmetric encryption
capabilities must agree on the following:
<ol>
<li>
All parties must share the same encryption key(s). If multiple keys are
used, each party must know which key to use for encryption / decryption.
Parties must ensure that exchanging, storing, and all management
of these encryption keys is done securely. How this is done is
presently outside the scope of ESAPI encryptions, but developers may
find the advice in
<a href="http://www.owasp.org/index.php/Cryptographic_Storage_Cheat_Sheet">
OWASP's Cryptographic Storage Cheat Sheet</a> helpful in this regard.
</li>
<li>
If parties are only exchanging raw ciphertext (plus IV, when appropriate),
then they must also agree on the cipher transformation to use.
</li>
<li>
If the involved parties participating in encryption are <i>not</i> using a
"combined" cipher mode that provides both confidentiality and authenticity
(for example, something like GCM or CCM), then they <i>must</i> whether or
not there will be an additional MAC sent allow with the raw ciphertext and
other cipher spec information in order to provide evidence of authenticity /
data integrity. (See the property <b>Encryptor.CipherText.useMAC</b>
for further details.) Failure to agree on this may allow an adversary to
carry out certain chosen ciphertext attacks against their encrypted data
resulting in (possibly complete) leakage of the corresponding plaintext.
</li>
</ol>
<H2>Encrypting / Decrypting with the New Methods -- The Simple Usage</H2>
<P>Using the new encryption / decryption methods is somewhat more
complicated, but this is in part because they are more flexible and
that flexibility means that more information needs to be communicated
as to the details of the encryption.
</P>
<P>A code snippet using the new methods that use the master
encryption key would look something like this:
</P>
<PRE> String myplaintext = "My plaintext";
try {
CipherText ciphertext =
ESAPI.encryptor().encrypt( new PlainText(myplaintext) );
PlainText recoveredPlaintext = ESAPI.encryptor().decrypt(ciphertext) );
assert myplaintext.equals( recoveredPlaintext.toString() );
} catch(EncryptionException ex) {
// Log error then return error designation however appropriate.
}</PRE><P>
Yes, this is a bit more complicated, but it will 1) work across
different hardware platforms and operating systems whereas the older
methods may not, and 2) it provides for <I>authenticity</I> <I><B>and</B></I>
<I>confidentiality</I> of the ciphertext regardless of which cipher
mode is chosen.</P>
<P>Also, these new methods allow a general byte array to be
encrypted, not just a Java String. If one needed to encrypt a byte
array with the old deprecated method, one would first have to use
</P>
<PRE> byte[] plaintextByteArray = { /* byte array to be encrypted */ };
String plaintext = new String(plaintextByteArray, "UTF-8");</PRE><P>
all the while catching the required <CODE>UnsupportedEncodingException</CODE>.
For example, to handle this in ESAPI 1.4, one would have to write
something like:</P>
<PRE>
try {
byte[] plaintextByteArray = { /* byte array to be encrypted */ };
String myplaintext = new String(plaintextByteArray, "UTF-8");
String ciphertext = ESAPI.encryptor().encrypt(myplaintext);
String decrypted = ESAPI.encryptor().decrypt(ciphertext);
byte[] recoveredBytes = decrypted.getBytes(“UFT-8”);
assert java.util.Arrays.equals( plaintextByteArray, recoveredBytes );
} catch( UnsupportedEncodingException ex) {
// Should not happen but need to catch and deal with it anyhow.
// Log error then return error designation however appropriate.
} catch(EncryptionException ex) {
// Log error then return error designation however appropriate.
}
</PRE><P>
However, dealing with this in ESAPI 2.0 is not any more cumbersome
than dealing with Strings:</P>
<PRE>
try {
byte[] plaintextByteArray = { /* byte array to be encrypted */ };
CipherText ciphertext =
ESAPI.encryptor().encrypt( new PlainText(plaintextByteArray) );
PlainText recoveredPlaintext = ESAPI.encryptor().decrypt(ciphertext) );
assert java.util.Arrays.equals( plaintextByteArray,
recoveredPlaintext.asBytes() );
} catch(EncryptionException ex) {
// Log error then return error designation however appropriate.
}
</PRE><P>
Ideally when you are encrypting sensitive data you do not want the
plaintext sensitive data to be left lying around after it is
encrypted. Instead, you should overwrite them after their value as
been used. However, when you are using immutable Strings, this is not
possible using native Java methods. But if you are able to pass in
byte arrays that are passed directly to <CODE>PlainText</CODE>
objects (as shown above), the <I>default</I> is to overwrite this
after they are encrypted.
<!-- Need to verify this. It was like this, but think I may have changed
it to return a copy rather than a reference based on FindBugs report. -->
<SPAN STYLE="background: #ffff00">(Note: Verify!) If the default for
</SPAN><CODE><SPAN STYLE="background: #ffff00">Encryptor.PlainText.overwrite</SPAN></CODE><SPAN STYLE="background: #ffff00">
of </SPAN><CODE><B><SPAN STYLE="background: #ffff00">true</SPAN></B></CODE><SPAN STYLE="background: #ffff00">
had been used, then the array </SPAN><CODE><SPAN STYLE="background: #ffff00">plaintextByteArray</SPAN></CODE><SPAN STYLE="background: #ffff00">
would have been overwritten with ASCII “*” characters.</SPAN></P>
<H2>Encrypting / Decrypting with the New Methods – Storing Encrypted Data</H2>
<P><SPAN STYLE="background: transparent">If you use one of the new
Encryptor encrypt() / decrypt() methods, how do you persist the
<code>CipherText</code> object returned by the encrypt() methods and how do
you restore it to pass to the decrypt() method?</SPAN></P>
<P><SPAN STYLE="background: transparent">The following example code
snippet will illustrate this. In the following example we will simply
write out the serialized <code>CipherText</code> object to a local file, but
obviously you could hex- or base64-encode the serialized byte array
and store it in a database or sent it in a SOAP XML message to a web
service, etc.</SPAN></P>
<PRE> public class PersistedEncryptedData
{
public static int persistEncryptedData(PlainText plaintext,
String filename)
throws EncryptionException, IOException
{
File serializedFile = new File(filename);
serializedFile.delete(); // Delete any old serialized file.
CipherText ct = ESAPI.encryptor().encrypt(plaintext);
byte[] serializedCiphertext = ct.asPortableSerializedByteArray();
FileOutputStream fos = new FileOutputStream(serializedFile);
fos.write(serializedCiphertext);
fos.close();
return serializedCiphertext.length;
}
public static PlainText restorePlaintext(String encryptedDataFilename)
throws EncryptionException, IOException
{
File serializedFile = new File(encryptedDataFilename);
FileInputStream fis = new FileInputStream(serializedFile);
int avail = fis.available();
byte[] bytes = new byte[avail];
fis.read(bytes, 0, avail);
CipherText restoredCipherText =
CipherText.fromPortableSerializedBytes(bytes);
fis.close();
PlainText plaintext = ESAPI.encryptor().decrypt(restoredCipherText);
return plaintext;
}
}
</PRE>
<H2>Advanced Usage</H2>
<H3>Encrypting / Decrypting with the New Methods</H3>
<P>ESAPI 1.4 and earlier only allowed you to use the master key
(<FONT FACE="DejaVu Sans Mono, sans-serif">MasterPassword</FONT> in
ESAPI 1.4; <CODE>Encryptor.MasterKey</CODE> in ESAPI 2.0) to encrypt
and decrypt with. But encryption with a single key seldom is
sufficient. For instance, lets say that your application has a need
to encrypt both bank account numbers and credit card numbers. The
encrypted bank account numbers are to be sent to one recipient and
the encrypted credit card numbers are to be sent to a different
recipient. Obviously in such cases, you do not want to share the same
key for both recipients.
</P>
<P>In ESAPI 1.4 there was not much you can do, but in ESAPI 2.0 and
later, there are new encryption / decryption methods that allow you
to specify a specific <CODE>SecretKey</CODE>. There is also a static
helper method in <CODE>CryptoHelper</CODE> to allow you to generate a
<CODE>SecretKey</CODE> of a specific type. (Distribution of this key
is out of scope for this particular example, but for the moment, we
will assume that secret keys are first generated, and then
distributed to the recipients out-of-band. On you could distribute
them dynamically via asymmetric encryption assuming that you've
previously exchanged public keys with the recipients.)</P>
<P>The following illustrates how these new methods might be used.
</P>
<P>First, we would generate some appropriate secret keys and
distribute them securely (e.g., perhaps over SSL/TLS) or exchange
them earlier out-of-band to the intended recipients. (E.g., one could
put them on two separate thumb drives and use a trusted courier to
distribute them to the recipients or one could use PGP-mail or S/MIME
to securely email them, etc.)
</P>
<PRE> // Generate two random, 128-bit AES keys to be distributed out-of-band.
import javax.crypto.SecretKey;
import org.owasp.esapi.crypto.CryptoHelper;
import org.owasp.esapi.codecs.Hex;
public class MySecretKeys {
public void main(String[] args) {
try {
SecretKey bankAcctKey = CryptoHelper.generateSecretKey("AES", 128);
SecretKey credCardKey = CryptoHelper.generateSecretKey("AES", 128);
System.out.println("Bank account key: " +
Hex.encode( bankAcctKey.getEncoding(), true ) );
System.out.println("Credit card key: " +
Hex.encode( credCardKey.getEncoding(), true ) );
} catch(Exception ex) {
ex.printStackTrace(System.err);
System.exit(1);
}
System.exit(0);
}
}</PRE><P>
Second, these keys would be printed out and stored somewhere secure
by our application, perhaps using something like ESAPI's
<CODE>EncryptedProperties</CODE> class, where they could later be
retrieved and used.
</P>
<P>In the following code, we assume that the <CODE>SecretKey</CODE>
values have already been initialized elsewhere.
</P>
<PRE> SecretKey bankAcctKey = ...; // These might be read from EncryptedProperties
SecretKey credCardKey = ...; // or from a restricted database, etc.
...
String bankAccountNumber = ...; // Assume obtained elsewhere
String creditCardNumber = ...; // Ditto
...
try {
// Encrypt each with their appropriate secret key
CipherText encryptedBankAcct =
ESAPI.encryptor().encrypt( bankAcctKey, new PlainText(bankAccountNumber) );
CipherText encryptedCreditCard =
ESAPI.encryptor().encrypt( credCardKey, new PlainText(creditCardNumber) );
...
// Decrypt using appropriate secret key
PlainText recoveredBankAcct = ESAPI.encryptor().decrypt( bankAcctKey, encryptedBankAcct ) );
assert bankAccountNumber.equals( recoveredBankAcct );
... etc. ...
} catch(EncryptionException ex) {
// Log error then return error designation however appropriate.
}</PRE>
<H3>Using ESAPI with Multiple Cipher Transformations</H3>
For the most part, the architecture of ESAPI assumes that you will
stick to using the defaults in the <b>ESAPI.properties</b> configuration
file or implment your own classes--possibly by extending the ESAPI
reference classes--and use these classes instead of the reference
classes.
<p>
For most things, this works well. Most applications likely can
standardize on a single cipher transformation such as AES/CBC/PKCS5Padding
with a 128-bit AES key and use that 100% of the time. However, on
occassion, an application may need to use two separate cipher
transformations (or even two different cipher algorithms) to
handle legacy applications or deal with multiple partners.
</p><p>
This section discusses how to do this without implementing your own
classes or extending the ESAPI reference class, <code>JavaEncryptor</code>.
Note that it is recognized that this approach is somewhat of a kludge.
A simpler approach is planned for ESAPI 2.1, but the approach shown
here is workable even though it's not pretty.
</p><p>
If you find yourself in need of encrypting with a different cipher
transformation, the first thing that you should count on is not
using the same encryption key for each. While in some cases this
likely would work (e.g., you are only using a different cipher mode
or you have 256-bit AES key for "Encryptor.MasterKey" but also have
a need to do encryption with a 128-bit AES key), it is not guaranteed
to do so. Instead, you should count on generating a separate encryption
key and using the encrypt / decrypt methods taking an additional
<code>SecretKey</code> parameter as show in the previous section.
</p>
<p>
Rather than repeating all the details of how to do this in this
user guide, we encourage you to investigate how this was done in
the Junit testing for the <code>JavaEncryptor</code> class. Please
look at the source code for the private method
<code>runNewEncryptDecryptTestCase(String, int, byte[])</code> in
the <code>EncryptorTest</code> JUnit test in the source code
"src/test/java/org/owasp/esapi/reference/crypto/EncryptorTest.java".
This code calls:
<pre>
ESAPI.securityConfiguration().setCipherTransformation(cipherXform);
</pre>
which sets ESAPI to use the specified cipher transformation,
<code>cipherXform</code>. As a convenience (for later restoral),
it returns the previous cipher transformation.
<p>
There are also a few non-obvious key size adjustments that are also
going on with DES and DESede (aka, triple DES) keys that are made there
as well. This has to do with the fact that for DES keys (which
includes DESede), the "true" key size differs from the "effective"
key size. (E.g., in DES, the "true" key size--from the DES algorithms's
perspective is 64-bits, however the <i>effective</i> key size for DES
is only 56-bits because of the 8-bits of parity "imposed" by the NSA in
the early 1970s.) This inconsistency manifests itself in the JCE by
the fact that <code>KeyGenerator.init()</code> wants the <i>effective</i>
key size to be specified (so 56-bits for DES, 112- or 168-bits for
DESede), but <code>SecretKey.getEncoding().length</code> stores the
"true" key size (e.g., 64-bits or 192-bits for DES and DESede respectively).
Other cipher algorithms do not have this discrepancy between true and
effective key sizes. Since a <code>SecretKey</code> is returned by the
<code>KeyGenerator</code>, this is only all too confusing. The
reference <code>JavaEncryptor</code> and its JUnit test,
<code>EncryptorTest</code> attempt to deal with this discrepency.
See the adjustments made to key size in
<code>EncryptorTest.runNewEncryptDecryptTestCase()</code>
for further details.
</p>
<H2>Using ESAPI Symmetric Encryption with FIPS 140-2 Cryptographic Modules</H2>
If you wish to use ESAPI with a FIPS 140-2 validated, JCE-compliant
cryptographic module such as the
<a
href="http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/1401val2005.htm#497"
target="_blank">
IBM Java JCE FIPS 140-2 Cryptographic Module</a>
(hereafter referred to as IBMJCEFIPS) or the
<a
href="http://csrc.nist.gov/groups/STM/cmvp/documents/140-1/1401val2008.htm#1048"
target="_blank">
RSA Security BSafe Crypto-J</a>
(hereafter referred to as Crypto-J), or other similar products, you
<i>must</i> follow these instructions. Failure to do so will mean that
you will fail to meet FISMA compliance. (<b>Note</b>: The mention of these
two specific vendor products does not constitute an endorsement from
either OWASP or this author.)
<br />
<ol>
<li>Follow the vendor's regular instructions to configure your application
to use the vendor product in a FIPS 140-2 compliant manner. Generally this
will include some special configuration and/or initialization requirements
that must be followed to restrict the vendor software to use FIPS 140-2
approved algorithms.
<br /><br />
If the vendor's instructions do not already include a recommendation to edit
the <code>$JAVA_HOME/jre/lib/security/java.security</code> file, the OWASP
team recommends that you do so to prevent you from accidentally using any
other cryptographic module (such as SunJCE). To do this, you will need
to change the property "security.provider.1" (which represents the default)
provider so that it refers to the fully-qualified classname of
your vendor's JCE <code>Provider</code> class. (By default, this is set to
"sun.security.provider.Sun".) In fact, you may wish to go as far as to
either comment out or remove the other providers to reduce the possibility
that they will accidentally be used by your application.
</li>
<li>Edit the <b>ESAPI.properties</b> that your application is going to
be using and set the property "Encryptor.PreferredJCEProvider" to
the fully qualified classname of your vendor's FIPS 140-2 compliant
JCE provider class. (If you are using a Java <code>SecurityManager</code>
you may also need to grant
<code>org.owasp.esapi.reference.crypto.JavaEncryptor</code> permissions
to change the JCE provider.)
</li>
<li>Edit the <b>ESAPI.properties</b> that your application is going to
be using and set the property <b>Encryptor.CipherText.useMAC</b> to
<b><code>false</code></b>. This is critical as having this property
set to <b><code>true</code></b> causes ESAPI to use <i>derived</i> keys
for the actual encryption and MAC calculation, which is against FIPS 140-2
compliance. (<b>Note</b>: This
does not mean that OWASP believes that this key derivation is weak--its
design has been suggested some cryptographers--but it would be creating and
using a related key for encryption in a manner not reviewed by NIST
and thus it is not acceptable to FIPS 140-2 approval.)
</li>
<li>Edit the <b>ESAPI.properties</b> that your application is going to
be using and set the property "Encryptor.CipherTransformation" to
a cipher transformation that is FIPS 140-2 certified for you vendor's
software. OWASP recommends using a NIST "combined" cipher mode, that is
one that provides for both message confidentiality <i>and</i> message
authenticity if such a cipher mode is available from your vendor
and FIPS 140-2 certified. (Cipher modes "GCM" and "CCM" are the only
FIPS 140-2 approved as of this writing.)
If such a "combined" cipher mode is not available, then use a cipher
transformation like "AES/CBC/PKCS5Padding" with a random IV.
This is almost always available as one of the FIPS 140-2 certified cipher
transformations, however it will not provide you with message authenticity
because to remain FIPS 140-2 compliant you will have had to disable the
MAC calculation (via setting <b>Encryptor.CipherText.useMAC</b> to
<b><code>false</code></b>) causing ESAPI to skip calculating an
explicit MAC for you and hence providing no assurance of data integrity
to the party attempting to decrypt your data. Without authenticity
however, your encryption may still be vulnerable to the "padded oracle"
chose ciphertext attack. Consult with your local cryptographic expert in
such cases as this depends greatly on the circumstances of how you are
using encryption.
</li>
<li>
If your vendor softare requires you to explicitly to initialize their
software for FIPS-mode (e.g., to cause the required FIPS 140-2 "power-on
self tests" to run) by calling some software method, then this must be
done <i>by your application code <b>before</b></i> calling any of the ESAPI
crypto-related code. Specifically, it must be called <i>before</i>
your application calls <code>ESAPI.encryptor()</code>.
</li>
</ol>
<br />
We believe that following these steps will still allow for your application
to be FIPS 140-2 / FISMA compliant, however, as always, you should check
with your FIPS auditor before using ESAPI in this manner. Should your
auditors ask, feel free to point them to the ESAPI source code, which
we believe will convince them that ESAPI is not a cryptographic module.
(Rather, it only provides a wrapper to call other cryptographic modules
through the standard JCE APIs.)
<H2>Acknowledgments</H2>
The OWASP ESAPI development team would like to acknowledge the contributions
of cryptographers David A. Wagner and Ian Grigg. David provided the
outline of how to securely compute derived keys for confidentiality
and authenticity from a single master key and Ian convinced us
to take a packetizing approach to laying out the portable, serialized
<code>CipherText</code> object.
<p>
In addition, Kevin Kenan has agreed to review all the crypto code
from ESAPI 2.0-rc5 or 2.0-rc6 candidate release. Others are invited
to participate as well, especially those with a background in cryptography.
(See <a href="http://www.owasp.org/index.php/Request_to_review_ESAPI_2.0_crypto">
"Request to review ESAPI 2.0 crypto"</a> for details.)
</p><p>
I would also like to thank Jessica Fitzgerald-McKay and Andy Sampson of
the Systems and Network Analysis Center of the NSA for their excellent feedback in
response to the review request made in Google Issue #81. Working with bureaucracy
is not something that I do particularly well, but Jessica and Andy made it as
painless as it possibly could be. Their feedback, which at this point,
unfortunately we are unable to quote, was generally favorable, but in the
places where they had recommendations, these were very precise and
helpful.
</p><p>
Lastly, I would like to thank Jeffrey Walton of Software Integrity, LLC.
Jeff provided an extremely thorough analysis of ESAPI 2.0's (as of 2.0_rc10)
Key Derivation Function (KDF). Jeff's analysis convinced me to bring ESAPI's
KDF more in line with NIST's recommendations for KDFs as described in
NIST Special Publication 800-108 (and specifically section 5.1). You can
read about Jeff's review at
<a href="http://owasp-esapi-java.googlecode.com/svn/trunk/documentation/Analysis-of-ESAPI-2.0-KDF.pdf">
Analysis of ESAPI 2.0's Key Derivation Function
</a>
</p>
</BODY>
</HTML>
|