[not-yet-commons-ssl] 01/08: Imported Upstream version 0.3.9
Tony Mancill
tmancill at moszumanska.debian.org
Thu Aug 28 21:03:12 UTC 2014
This is an automated email from the git hooks/post-receive script.
tmancill pushed a commit to branch master
in repository not-yet-commons-ssl.
commit 0a17f4672500f5e093b583ae45b1c9906d88da10
Author: tony mancill <tmancill at debian.org>
Date: Thu Aug 28 08:12:16 2014 -0700
Imported Upstream version 0.3.9
---
LICENSE.txt | 176 ++++
NOTICE.txt | 10 +
README.txt | 9 +
build.xml | 106 ++
docs/.htaccess | 3 +
docs/404.html | 51 +
docs/404.html~ | 51 +
docs/TrustExample.java | 114 +++
docs/TrustExample.java.html | 131 +++
docs/about.html | 73 ++
docs/download.html | 229 +++++
docs/download.html~ | 229 +++++
docs/index.html | 110 +++
docs/pbe.html | 204 ++++
docs/ping.html | 92 ++
docs/pkcs8.html | 156 +++
docs/rmi.html | 102 ++
docs/source.html | 38 +
docs/ssl.html | 106 ++
docs/tree.html | 156 +++
docs/utilities.html | 91 ++
samples/PASSWORD.txt | 3 +
samples/README.txt | 3 +
samples/createPBESamples.sh | 106 ++
samples/dsa.html | 114 +++
samples/dsa/openssl_dsa_aes128_cbc.pem | 23 +
samples/dsa/openssl_dsa_aes128_cfb.pem | 23 +
samples/dsa/openssl_dsa_aes128_ecb.pem | 23 +
samples/dsa/openssl_dsa_aes128_ofb.pem | 23 +
samples/dsa/openssl_dsa_aes192_cbc.pem | 23 +
samples/dsa/openssl_dsa_aes192_cfb.pem | 23 +
samples/dsa/openssl_dsa_aes192_ecb.pem | 23 +
samples/dsa/openssl_dsa_aes192_ofb.pem | 23 +
samples/dsa/openssl_dsa_aes256_cbc.pem | 23 +
samples/dsa/openssl_dsa_aes256_cfb.pem | 23 +
samples/dsa/openssl_dsa_aes256_ecb.pem | 23 +
samples/dsa/openssl_dsa_aes256_ofb.pem | 23 +
samples/dsa/openssl_dsa_blowfish_cbc.pem | 23 +
samples/dsa/openssl_dsa_blowfish_cfb.pem | 23 +
samples/dsa/openssl_dsa_blowfish_ecb.pem | 23 +
samples/dsa/openssl_dsa_blowfish_ofb.pem | 23 +
samples/dsa/openssl_dsa_des1_cbc.pem | 23 +
samples/dsa/openssl_dsa_des1_cfb.pem | 23 +
samples/dsa/openssl_dsa_des1_ecb.pem | 23 +
samples/dsa/openssl_dsa_des1_ofb.pem | 23 +
samples/dsa/openssl_dsa_des2_cbc.pem | 23 +
samples/dsa/openssl_dsa_des2_cfb.pem | 23 +
samples/dsa/openssl_dsa_des2_ecb.pem | 23 +
samples/dsa/openssl_dsa_des2_ofb.pem | 23 +
samples/dsa/openssl_dsa_des3_cbc.pem | 23 +
samples/dsa/openssl_dsa_des3_cfb.pem | 23 +
samples/dsa/openssl_dsa_des3_ecb.pem | 23 +
samples/dsa/openssl_dsa_des3_ofb.pem | 23 +
samples/dsa/openssl_dsa_rc2_128_cbc.pem | 23 +
samples/dsa/openssl_dsa_rc2_128_cfb.pem | 23 +
samples/dsa/openssl_dsa_rc2_128_ecb.pem | 23 +
samples/dsa/openssl_dsa_rc2_128_ofb.pem | 23 +
samples/dsa/openssl_dsa_rc2_40_cbc.pem | 23 +
samples/dsa/openssl_dsa_rc2_64_cbc.pem | 23 +
samples/dsa/openssl_dsa_unencrypted.der | Bin 0 -> 834 bytes
samples/dsa/openssl_dsa_unencrypted.pem | 20 +
samples/dsa/pkcs8_dsa_unencrypted.der | Bin 0 -> 593 bytes
samples/dsa/pkcs8_dsa_unencrypted.pem | 15 +
samples/dsa/pkcs8v1_dsa_md2_des1_cbc.der | Bin 0 -> 637 bytes
samples/dsa/pkcs8v1_dsa_md2_des1_cbc.pem | 16 +
samples/dsa/pkcs8v1_dsa_md2_rc2_64_cbc.der | Bin 0 -> 637 bytes
samples/dsa/pkcs8v1_dsa_md2_rc2_64_cbc.pem | 16 +
samples/dsa/pkcs8v1_dsa_md5_des1_cbc.der | Bin 0 -> 637 bytes
samples/dsa/pkcs8v1_dsa_md5_des1_cbc.pem | 16 +
samples/dsa/pkcs8v1_dsa_md5_rc2_64_cbc.der | Bin 0 -> 637 bytes
samples/dsa/pkcs8v1_dsa_md5_rc2_64_cbc.pem | 16 +
samples/dsa/pkcs8v1_dsa_sha1_des1_cbc.der | Bin 0 -> 637 bytes
samples/dsa/pkcs8v1_dsa_sha1_des1_cbc.pem | 16 +
samples/dsa/pkcs8v1_dsa_sha1_des2_cbc.der | Bin 0 -> 638 bytes
samples/dsa/pkcs8v1_dsa_sha1_des2_cbc.pem | 16 +
samples/dsa/pkcs8v1_dsa_sha1_des3_cbc.der | Bin 0 -> 638 bytes
samples/dsa/pkcs8v1_dsa_sha1_des3_cbc.pem | 16 +
samples/dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.der | Bin 0 -> 638 bytes
samples/dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.pem | 16 +
samples/dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.der | Bin 0 -> 638 bytes
samples/dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.pem | 16 +
samples/dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.der | Bin 0 -> 637 bytes
samples/dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.pem | 16 +
samples/dsa/pkcs8v1_dsa_sha1_rc4_128.der | Bin 0 -> 631 bytes
samples/dsa/pkcs8v1_dsa_sha1_rc4_128.pem | 16 +
samples/dsa/pkcs8v1_dsa_sha1_rc4_40.der | Bin 0 -> 631 bytes
samples/dsa/pkcs8v1_dsa_sha1_rc4_40.pem | 16 +
samples/dsa/pkcs8v2_dsa_aes128_cbc.der | Bin 0 -> 691 bytes
samples/dsa/pkcs8v2_dsa_aes128_cbc.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes128_cfb.der | Bin 0 -> 676 bytes
samples/dsa/pkcs8v2_dsa_aes128_cfb.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes128_ecb.der | Bin 0 -> 691 bytes
samples/dsa/pkcs8v2_dsa_aes128_ecb.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes128_ofb.der | Bin 0 -> 676 bytes
samples/dsa/pkcs8v2_dsa_aes128_ofb.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes192_cbc.der | Bin 0 -> 691 bytes
samples/dsa/pkcs8v2_dsa_aes192_cbc.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes192_cfb.der | Bin 0 -> 676 bytes
samples/dsa/pkcs8v2_dsa_aes192_cfb.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes192_ecb.der | Bin 0 -> 691 bytes
samples/dsa/pkcs8v2_dsa_aes192_ecb.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes192_ofb.der | Bin 0 -> 676 bytes
samples/dsa/pkcs8v2_dsa_aes192_ofb.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes256_cbc.der | Bin 0 -> 691 bytes
samples/dsa/pkcs8v2_dsa_aes256_cbc.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes256_cfb.der | Bin 0 -> 676 bytes
samples/dsa/pkcs8v2_dsa_aes256_cfb.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes256_ecb.der | Bin 0 -> 691 bytes
samples/dsa/pkcs8v2_dsa_aes256_ecb.pem | 17 +
samples/dsa/pkcs8v2_dsa_aes256_ofb.der | Bin 0 -> 676 bytes
samples/dsa/pkcs8v2_dsa_aes256_ofb.pem | 17 +
samples/dsa/pkcs8v2_dsa_blowfish_cbc.der | Bin 0 -> 675 bytes
samples/dsa/pkcs8v2_dsa_blowfish_cbc.pem | 17 +
samples/dsa/pkcs8v2_dsa_des1_cbc.der | Bin 0 -> 671 bytes
samples/dsa/pkcs8v2_dsa_des1_cbc.pem | 16 +
samples/dsa/pkcs8v2_dsa_des1_cfb.der | Bin 0 -> 664 bytes
samples/dsa/pkcs8v2_dsa_des1_cfb.pem | 16 +
samples/dsa/pkcs8v2_dsa_des1_ecb.der | Bin 0 -> 671 bytes
samples/dsa/pkcs8v2_dsa_des1_ecb.pem | 16 +
samples/dsa/pkcs8v2_dsa_des1_ofb.der | Bin 0 -> 664 bytes
samples/dsa/pkcs8v2_dsa_des1_ofb.pem | 16 +
samples/dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.der | Bin 0 -> 671 bytes
samples/dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.pem | 16 +
samples/dsa/pkcs8v2_dsa_des3_cbc.der | Bin 0 -> 674 bytes
samples/dsa/pkcs8v2_dsa_des3_cbc.pem | 17 +
samples/dsa/pkcs8v2_dsa_rc2_128_cbc.der | Bin 0 -> 682 bytes
samples/dsa/pkcs8v2_dsa_rc2_128_cbc.pem | 17 +
samples/dsa/pkcs8v2_dsa_rc2_40_cbc.der | Bin 0 -> 683 bytes
samples/dsa/pkcs8v2_dsa_rc2_40_cbc.pem | 17 +
samples/dsa/pkcs8v2_dsa_rc2_64_cbc.der | Bin 0 -> 682 bytes
samples/dsa/pkcs8v2_dsa_rc2_64_cbc.pem | 17 +
samples/dsa_result.html | 38 +
samples/pbe.tests | 45 +
samples/pbe/README.txt | 36 +
samples/pbe/java/aes-128-cbc.base64 | 1 +
samples/pbe/java/aes-128-cbc.raw | 1 +
samples/pbe/java/aes-128-cfb.base64 | 1 +
samples/pbe/java/aes-128-cfb.raw | 1 +
samples/pbe/java/aes-128-cfb8.base64 | 1 +
samples/pbe/java/aes-128-cfb8.raw | 1 +
samples/pbe/java/aes-128-ecb.base64 | 1 +
samples/pbe/java/aes-128-ecb.raw | 1 +
samples/pbe/java/aes-128-ofb.base64 | 1 +
samples/pbe/java/aes-128-ofb.raw | 1 +
samples/pbe/java/aes-128.base64 | 1 +
samples/pbe/java/aes-128.raw | 1 +
samples/pbe/java/aes-192-cbc.base64 | 1 +
samples/pbe/java/aes-192-cbc.raw | 1 +
samples/pbe/java/aes-192-cfb.base64 | 1 +
samples/pbe/java/aes-192-cfb.raw | 1 +
samples/pbe/java/aes-192-cfb8.base64 | 1 +
samples/pbe/java/aes-192-cfb8.raw | 1 +
samples/pbe/java/aes-192-ecb.base64 | 1 +
samples/pbe/java/aes-192-ecb.raw | 2 +
samples/pbe/java/aes-192-ofb.base64 | 1 +
samples/pbe/java/aes-192-ofb.raw | 1 +
samples/pbe/java/aes-192.base64 | 1 +
samples/pbe/java/aes-192.raw | 1 +
samples/pbe/java/aes-256-cbc.base64 | 1 +
samples/pbe/java/aes-256-cbc.raw | 1 +
samples/pbe/java/aes-256-cfb.base64 | 1 +
samples/pbe/java/aes-256-cfb.raw | 1 +
samples/pbe/java/aes-256-cfb8.base64 | 1 +
samples/pbe/java/aes-256-cfb8.raw | 1 +
samples/pbe/java/aes-256-ecb.base64 | 1 +
samples/pbe/java/aes-256-ecb.raw | 1 +
samples/pbe/java/aes-256-ofb.base64 | 1 +
samples/pbe/java/aes-256-ofb.raw | 1 +
samples/pbe/java/aes-256.base64 | 1 +
samples/pbe/java/aes-256.raw | 1 +
samples/pbe/java/aes128-cbc.base64 | 1 +
samples/pbe/java/aes128-cbc.raw | 1 +
samples/pbe/java/aes128-cfb.base64 | 1 +
samples/pbe/java/aes128-cfb.raw | 1 +
samples/pbe/java/aes128-cfb8.base64 | 1 +
samples/pbe/java/aes128-cfb8.raw | 1 +
samples/pbe/java/aes128-ecb.base64 | 1 +
samples/pbe/java/aes128-ecb.raw | 1 +
samples/pbe/java/aes128-ofb.base64 | 1 +
samples/pbe/java/aes128-ofb.raw | 1 +
samples/pbe/java/aes128.base64 | 1 +
samples/pbe/java/aes128.raw | 1 +
samples/pbe/java/aes192-cbc.base64 | 1 +
samples/pbe/java/aes192-cbc.raw | Bin 0 -> 32 bytes
samples/pbe/java/aes192-cfb.base64 | 1 +
samples/pbe/java/aes192-cfb.raw | 2 +
samples/pbe/java/aes192-cfb8.base64 | 1 +
samples/pbe/java/aes192-cfb8.raw | 1 +
samples/pbe/java/aes192-ecb.base64 | 1 +
samples/pbe/java/aes192-ecb.raw | 1 +
samples/pbe/java/aes192-ofb.base64 | 1 +
samples/pbe/java/aes192-ofb.raw | 1 +
samples/pbe/java/aes192.base64 | 1 +
samples/pbe/java/aes192.raw | 1 +
samples/pbe/java/aes256-cbc.base64 | 1 +
samples/pbe/java/aes256-cbc.raw | 1 +
samples/pbe/java/aes256-cfb.base64 | 1 +
samples/pbe/java/aes256-cfb.raw | 2 +
samples/pbe/java/aes256-cfb8.base64 | 1 +
samples/pbe/java/aes256-cfb8.raw | 1 +
samples/pbe/java/aes256-ecb.base64 | 1 +
samples/pbe/java/aes256-ecb.raw | 1 +
samples/pbe/java/aes256-ofb.base64 | 1 +
samples/pbe/java/aes256-ofb.raw | 1 +
samples/pbe/java/aes256.base64 | 1 +
samples/pbe/java/aes256.raw | 1 +
samples/pbe/java/bf-cbc.base64 | 1 +
samples/pbe/java/bf-cbc.raw | 1 +
samples/pbe/java/bf-cfb.base64 | 1 +
samples/pbe/java/bf-cfb.raw | 1 +
samples/pbe/java/bf-cfb8.base64 | 1 +
samples/pbe/java/bf-cfb8.raw | 1 +
samples/pbe/java/bf-ecb.base64 | 1 +
samples/pbe/java/bf-ecb.raw | 1 +
samples/pbe/java/bf-ofb.base64 | 1 +
samples/pbe/java/bf-ofb.raw | 1 +
samples/pbe/java/bf.base64 | 1 +
samples/pbe/java/bf.raw | 1 +
samples/pbe/java/blowfish-cbc.base64 | 1 +
samples/pbe/java/blowfish-cbc.raw | 1 +
samples/pbe/java/blowfish-cfb.base64 | 1 +
samples/pbe/java/blowfish-cfb.raw | 1 +
samples/pbe/java/blowfish-cfb8.base64 | 1 +
samples/pbe/java/blowfish-cfb8.raw | 1 +
samples/pbe/java/blowfish-ecb.base64 | 1 +
samples/pbe/java/blowfish-ecb.raw | 1 +
samples/pbe/java/blowfish-ofb.base64 | 1 +
samples/pbe/java/blowfish-ofb.raw | 2 +
samples/pbe/java/blowfish.base64 | 1 +
samples/pbe/java/blowfish.raw | 1 +
samples/pbe/java/camellia-128-cbc.base64 | 1 +
samples/pbe/java/camellia-128-cbc.raw | 1 +
samples/pbe/java/camellia-128-cfb.base64 | 1 +
samples/pbe/java/camellia-128-cfb.raw | Bin 0 -> 28 bytes
samples/pbe/java/camellia-128-cfb8.base64 | 1 +
samples/pbe/java/camellia-128-cfb8.raw | 1 +
samples/pbe/java/camellia-128-ecb.base64 | 1 +
samples/pbe/java/camellia-128-ecb.raw | 1 +
samples/pbe/java/camellia-128-ofb.base64 | 1 +
samples/pbe/java/camellia-128-ofb.raw | 1 +
samples/pbe/java/camellia-128.base64 | 1 +
samples/pbe/java/camellia-128.raw | 1 +
samples/pbe/java/camellia-192-cbc.base64 | 1 +
samples/pbe/java/camellia-192-cbc.raw | 1 +
samples/pbe/java/camellia-192-cfb.base64 | 1 +
samples/pbe/java/camellia-192-cfb.raw | 2 +
samples/pbe/java/camellia-192-cfb8.base64 | 1 +
samples/pbe/java/camellia-192-cfb8.raw | 1 +
samples/pbe/java/camellia-192-ecb.base64 | 1 +
samples/pbe/java/camellia-192-ecb.raw | 1 +
samples/pbe/java/camellia-192-ofb.base64 | 1 +
samples/pbe/java/camellia-192-ofb.raw | 1 +
samples/pbe/java/camellia-192.base64 | 1 +
samples/pbe/java/camellia-192.raw | 1 +
samples/pbe/java/camellia-256-cbc.base64 | 1 +
samples/pbe/java/camellia-256-cbc.raw | 1 +
samples/pbe/java/camellia-256-cfb.base64 | 1 +
samples/pbe/java/camellia-256-cfb.raw | 1 +
samples/pbe/java/camellia-256-cfb8.base64 | 1 +
samples/pbe/java/camellia-256-cfb8.raw | 1 +
samples/pbe/java/camellia-256-ecb.base64 | 1 +
samples/pbe/java/camellia-256-ecb.raw | 1 +
samples/pbe/java/camellia-256-ofb.base64 | 1 +
samples/pbe/java/camellia-256-ofb.raw | 1 +
samples/pbe/java/camellia-256.base64 | 1 +
samples/pbe/java/camellia-256.raw | 1 +
samples/pbe/java/camellia128-cbc.base64 | 1 +
samples/pbe/java/camellia128-cbc.raw | 1 +
samples/pbe/java/camellia128-cfb.base64 | 1 +
samples/pbe/java/camellia128-cfb.raw | 1 +
samples/pbe/java/camellia128-cfb8.base64 | 1 +
samples/pbe/java/camellia128-cfb8.raw | 1 +
samples/pbe/java/camellia128-ecb.base64 | 1 +
samples/pbe/java/camellia128-ecb.raw | 1 +
samples/pbe/java/camellia128-ofb.base64 | 1 +
samples/pbe/java/camellia128-ofb.raw | 1 +
samples/pbe/java/camellia128.base64 | 1 +
samples/pbe/java/camellia128.raw | 1 +
samples/pbe/java/camellia192-cbc.base64 | 1 +
samples/pbe/java/camellia192-cbc.raw | 1 +
samples/pbe/java/camellia192-cfb.base64 | 1 +
samples/pbe/java/camellia192-cfb.raw | 1 +
samples/pbe/java/camellia192-cfb8.base64 | 1 +
samples/pbe/java/camellia192-cfb8.raw | 1 +
samples/pbe/java/camellia192-ecb.base64 | 1 +
samples/pbe/java/camellia192-ecb.raw | 1 +
samples/pbe/java/camellia192-ofb.base64 | 1 +
samples/pbe/java/camellia192-ofb.raw | 1 +
samples/pbe/java/camellia192.base64 | 1 +
samples/pbe/java/camellia192.raw | 1 +
samples/pbe/java/camellia256-cbc.base64 | 1 +
samples/pbe/java/camellia256-cbc.raw | 1 +
samples/pbe/java/camellia256-cfb.base64 | 1 +
samples/pbe/java/camellia256-cfb.raw | 1 +
samples/pbe/java/camellia256-cfb8.base64 | 1 +
samples/pbe/java/camellia256-cfb8.raw | 1 +
samples/pbe/java/camellia256-ecb.base64 | 1 +
samples/pbe/java/camellia256-ecb.raw | 1 +
samples/pbe/java/camellia256-ofb.base64 | 1 +
samples/pbe/java/camellia256-ofb.raw | 1 +
samples/pbe/java/camellia256.base64 | 1 +
samples/pbe/java/camellia256.raw | 1 +
samples/pbe/java/cast5-cbc.base64 | 1 +
samples/pbe/java/cast5-cbc.raw | 1 +
samples/pbe/java/cast5-cfb.base64 | 1 +
samples/pbe/java/cast5-cfb.raw | 1 +
samples/pbe/java/cast5-cfb8.base64 | 1 +
samples/pbe/java/cast5-cfb8.raw | 1 +
samples/pbe/java/cast5-ecb.base64 | 1 +
samples/pbe/java/cast5-ecb.raw | 1 +
samples/pbe/java/cast5-ofb.base64 | 1 +
samples/pbe/java/cast5-ofb.raw | 1 +
samples/pbe/java/cast5.base64 | 1 +
samples/pbe/java/cast5.raw | 2 +
samples/pbe/java/cast6-cbc.base64 | 1 +
samples/pbe/java/cast6-cbc.raw | 1 +
samples/pbe/java/cast6-cfb.base64 | 1 +
samples/pbe/java/cast6-cfb.raw | 1 +
samples/pbe/java/cast6-cfb8.base64 | 1 +
samples/pbe/java/cast6-cfb8.raw | 1 +
samples/pbe/java/cast6-ecb.base64 | 1 +
samples/pbe/java/cast6-ecb.raw | 1 +
samples/pbe/java/cast6-ofb.base64 | 1 +
samples/pbe/java/cast6-ofb.raw | 1 +
samples/pbe/java/cast6.base64 | 1 +
samples/pbe/java/cast6.raw | 1 +
samples/pbe/java/des-cbc.base64 | 1 +
samples/pbe/java/des-cbc.raw | 1 +
samples/pbe/java/des-cfb.base64 | 1 +
samples/pbe/java/des-cfb.raw | 1 +
samples/pbe/java/des-cfb8.base64 | 1 +
samples/pbe/java/des-cfb8.raw | 1 +
samples/pbe/java/des-ecb.base64 | 1 +
samples/pbe/java/des-ecb.raw | 1 +
samples/pbe/java/des-ede-cbc.base64 | 1 +
samples/pbe/java/des-ede-cbc.raw | 1 +
samples/pbe/java/des-ede-cfb.base64 | 1 +
samples/pbe/java/des-ede-cfb.raw | Bin 0 -> 28 bytes
samples/pbe/java/des-ede-cfb8.base64 | 1 +
samples/pbe/java/des-ede-cfb8.raw | 1 +
samples/pbe/java/des-ede-ecb.base64 | 1 +
samples/pbe/java/des-ede-ecb.raw | 1 +
samples/pbe/java/des-ede-ofb.base64 | 1 +
samples/pbe/java/des-ede-ofb.raw | 1 +
samples/pbe/java/des-ede.base64 | 1 +
samples/pbe/java/des-ede.raw | Bin 0 -> 32 bytes
samples/pbe/java/des-ede3-cbc.base64 | 1 +
samples/pbe/java/des-ede3-cbc.raw | 1 +
samples/pbe/java/des-ede3-cfb.base64 | 1 +
samples/pbe/java/des-ede3-cfb.raw | 1 +
samples/pbe/java/des-ede3-cfb8.base64 | 1 +
samples/pbe/java/des-ede3-cfb8.raw | 1 +
samples/pbe/java/des-ede3-ecb.base64 | 1 +
samples/pbe/java/des-ede3-ecb.raw | 1 +
samples/pbe/java/des-ede3-ofb.base64 | 1 +
samples/pbe/java/des-ede3-ofb.raw | 1 +
samples/pbe/java/des-ede3.base64 | 1 +
samples/pbe/java/des-ede3.raw | Bin 0 -> 32 bytes
samples/pbe/java/des-ofb.base64 | 1 +
samples/pbe/java/des-ofb.raw | 1 +
samples/pbe/java/des.base64 | 1 +
samples/pbe/java/des.raw | 1 +
samples/pbe/java/des2-cbc.base64 | 1 +
samples/pbe/java/des2-cbc.raw | 1 +
samples/pbe/java/des2-cfb.base64 | 1 +
samples/pbe/java/des2-cfb.raw | 1 +
samples/pbe/java/des2-cfb8.base64 | 1 +
samples/pbe/java/des2-cfb8.raw | 1 +
samples/pbe/java/des2-ecb.base64 | 1 +
samples/pbe/java/des2-ecb.raw | Bin 0 -> 32 bytes
samples/pbe/java/des2-ofb.base64 | 1 +
samples/pbe/java/des2-ofb.raw | 1 +
samples/pbe/java/des2.base64 | 1 +
samples/pbe/java/des2.raw | 1 +
samples/pbe/java/des3-cbc.base64 | 1 +
samples/pbe/java/des3-cbc.raw | 1 +
samples/pbe/java/des3-cfb.base64 | 1 +
samples/pbe/java/des3-cfb.raw | 1 +
samples/pbe/java/des3-cfb8.base64 | 1 +
samples/pbe/java/des3-cfb8.raw | 1 +
samples/pbe/java/des3-ecb.base64 | 1 +
samples/pbe/java/des3-ecb.raw | 1 +
samples/pbe/java/des3-ofb.base64 | 1 +
samples/pbe/java/des3-ofb.raw | 1 +
samples/pbe/java/des3.base64 | 1 +
samples/pbe/java/des3.raw | 1 +
samples/pbe/java/gost-cbc.base64 | 1 +
samples/pbe/java/gost-cbc.raw | 1 +
samples/pbe/java/gost-cfb.base64 | 1 +
samples/pbe/java/gost-cfb.raw | 1 +
samples/pbe/java/gost-cfb8.base64 | 1 +
samples/pbe/java/gost-cfb8.raw | 1 +
samples/pbe/java/gost-ecb.base64 | 1 +
samples/pbe/java/gost-ecb.raw | 1 +
samples/pbe/java/gost-ofb.base64 | 1 +
samples/pbe/java/gost-ofb.raw | 1 +
samples/pbe/java/gost.base64 | 1 +
samples/pbe/java/gost.raw | 2 +
samples/pbe/java/gost28147-cbc.base64 | 1 +
samples/pbe/java/gost28147-cbc.raw | 1 +
samples/pbe/java/gost28147-cfb.base64 | 1 +
samples/pbe/java/gost28147-cfb.raw | 1 +
samples/pbe/java/gost28147-cfb8.base64 | 1 +
samples/pbe/java/gost28147-cfb8.raw | 1 +
samples/pbe/java/gost28147-ecb.base64 | 1 +
samples/pbe/java/gost28147-ecb.raw | 1 +
samples/pbe/java/gost28147-ofb.base64 | 1 +
samples/pbe/java/gost28147-ofb.raw | 1 +
samples/pbe/java/gost28147.base64 | 1 +
samples/pbe/java/gost28147.raw | Bin 0 -> 32 bytes
samples/pbe/java/idea-cbc.base64 | 1 +
samples/pbe/java/idea-cbc.raw | 1 +
samples/pbe/java/idea-cfb.base64 | 1 +
samples/pbe/java/idea-cfb.raw | 2 +
samples/pbe/java/idea-cfb8.base64 | 1 +
samples/pbe/java/idea-cfb8.raw | 1 +
samples/pbe/java/idea-ecb.base64 | 1 +
samples/pbe/java/idea-ecb.raw | 2 +
samples/pbe/java/idea-ofb.base64 | 1 +
samples/pbe/java/idea-ofb.raw | 1 +
samples/pbe/java/idea.base64 | 1 +
samples/pbe/java/idea.raw | 1 +
samples/pbe/java/rc2-40-cbc.base64 | 1 +
samples/pbe/java/rc2-40-cbc.raw | 1 +
samples/pbe/java/rc2-40-cfb.base64 | 1 +
samples/pbe/java/rc2-40-cfb.raw | 1 +
samples/pbe/java/rc2-40-cfb8.base64 | 1 +
samples/pbe/java/rc2-40-cfb8.raw | 1 +
samples/pbe/java/rc2-40-ecb.base64 | 1 +
samples/pbe/java/rc2-40-ecb.raw | 1 +
samples/pbe/java/rc2-40-ofb.base64 | 1 +
samples/pbe/java/rc2-40-ofb.raw | 1 +
samples/pbe/java/rc2-40.base64 | 1 +
samples/pbe/java/rc2-40.raw | 1 +
samples/pbe/java/rc2-64-cbc.base64 | 1 +
samples/pbe/java/rc2-64-cbc.raw | 1 +
samples/pbe/java/rc2-64-cfb.base64 | 1 +
samples/pbe/java/rc2-64-cfb.raw | 1 +
samples/pbe/java/rc2-64-cfb8.base64 | 1 +
samples/pbe/java/rc2-64-cfb8.raw | Bin 0 -> 28 bytes
samples/pbe/java/rc2-64-ecb.base64 | 1 +
samples/pbe/java/rc2-64-ecb.raw | 1 +
samples/pbe/java/rc2-64-ofb.base64 | 1 +
samples/pbe/java/rc2-64-ofb.raw | 1 +
samples/pbe/java/rc2-64.base64 | 1 +
samples/pbe/java/rc2-64.raw | 1 +
samples/pbe/java/rc2-cbc.base64 | 1 +
samples/pbe/java/rc2-cbc.raw | Bin 0 -> 32 bytes
samples/pbe/java/rc2-cfb.base64 | 1 +
samples/pbe/java/rc2-cfb.raw | 1 +
samples/pbe/java/rc2-cfb8.base64 | 1 +
samples/pbe/java/rc2-cfb8.raw | 1 +
samples/pbe/java/rc2-ecb.base64 | 1 +
samples/pbe/java/rc2-ecb.raw | 1 +
samples/pbe/java/rc2-ofb.base64 | 1 +
samples/pbe/java/rc2-ofb.raw | 1 +
samples/pbe/java/rc2.base64 | 1 +
samples/pbe/java/rc2.raw | 1 +
samples/pbe/java/rc4-40-cbc.base64 | 1 +
samples/pbe/java/rc4-40-cbc.raw | 1 +
samples/pbe/java/rc4-40-cfb.base64 | 1 +
samples/pbe/java/rc4-40-cfb.raw | 1 +
samples/pbe/java/rc4-40-cfb1.base64 | 1 +
samples/pbe/java/rc4-40-cfb1.raw | 1 +
samples/pbe/java/rc4-40-cfb8.base64 | 1 +
samples/pbe/java/rc4-40-cfb8.raw | 1 +
samples/pbe/java/rc4-40-ecb.base64 | 1 +
samples/pbe/java/rc4-40-ecb.raw | 1 +
samples/pbe/java/rc4-40-ofb.base64 | 1 +
samples/pbe/java/rc4-40-ofb.raw | 1 +
samples/pbe/java/rc4-40.base64 | 1 +
samples/pbe/java/rc4-40.raw | 1 +
samples/pbe/java/rc4-cbc.base64 | 1 +
samples/pbe/java/rc4-cbc.raw | 1 +
samples/pbe/java/rc4-cfb.base64 | 1 +
samples/pbe/java/rc4-cfb.raw | 1 +
samples/pbe/java/rc4-cfb1.base64 | 1 +
samples/pbe/java/rc4-cfb1.raw | 1 +
samples/pbe/java/rc4-cfb8.base64 | 1 +
samples/pbe/java/rc4-cfb8.raw | 1 +
samples/pbe/java/rc4-ecb.base64 | 1 +
samples/pbe/java/rc4-ecb.raw | 1 +
samples/pbe/java/rc4-ofb.base64 | 1 +
samples/pbe/java/rc4-ofb.raw | 1 +
samples/pbe/java/rc4.base64 | 1 +
samples/pbe/java/rc4.raw | Bin 0 -> 28 bytes
samples/pbe/java/rc5-cbc.base64 | 1 +
samples/pbe/java/rc5-cbc.raw | Bin 0 -> 32 bytes
samples/pbe/java/rc5-cfb.base64 | 1 +
samples/pbe/java/rc5-cfb.raw | 1 +
samples/pbe/java/rc5-cfb8.base64 | 1 +
samples/pbe/java/rc5-cfb8.raw | 1 +
samples/pbe/java/rc5-ecb.base64 | 1 +
samples/pbe/java/rc5-ecb.raw | 1 +
samples/pbe/java/rc5-ofb.base64 | 1 +
samples/pbe/java/rc5-ofb.raw | 1 +
samples/pbe/java/rc5.base64 | 1 +
samples/pbe/java/rc5.raw | 2 +
samples/pbe/java/rc6-cbc.base64 | 1 +
samples/pbe/java/rc6-cbc.raw | 1 +
samples/pbe/java/rc6-cfb.base64 | 1 +
samples/pbe/java/rc6-cfb.raw | 1 +
samples/pbe/java/rc6-cfb8.base64 | 1 +
samples/pbe/java/rc6-cfb8.raw | 1 +
samples/pbe/java/rc6-ecb.base64 | 1 +
samples/pbe/java/rc6-ecb.raw | 1 +
samples/pbe/java/rc6-ofb.base64 | 1 +
samples/pbe/java/rc6-ofb.raw | 1 +
samples/pbe/java/rc6.base64 | 1 +
samples/pbe/java/rc6.raw | 1 +
samples/pbe/java/rijndael-cbc.base64 | 1 +
samples/pbe/java/rijndael-cbc.raw | 1 +
samples/pbe/java/rijndael-cfb.base64 | 1 +
samples/pbe/java/rijndael-cfb.raw | 1 +
samples/pbe/java/rijndael-cfb8.base64 | 1 +
samples/pbe/java/rijndael-cfb8.raw | 1 +
samples/pbe/java/rijndael-ecb.base64 | 1 +
samples/pbe/java/rijndael-ecb.raw | 1 +
samples/pbe/java/rijndael-ofb.base64 | 1 +
samples/pbe/java/rijndael-ofb.raw | Bin 0 -> 28 bytes
samples/pbe/java/rijndael.base64 | 1 +
samples/pbe/java/rijndael.raw | 1 +
samples/pbe/java/seed-cbc.base64 | 1 +
samples/pbe/java/seed-cbc.raw | 1 +
samples/pbe/java/seed-cfb.base64 | 1 +
samples/pbe/java/seed-cfb.raw | 1 +
samples/pbe/java/seed-cfb8.base64 | 1 +
samples/pbe/java/seed-cfb8.raw | 1 +
samples/pbe/java/seed-ecb.base64 | 1 +
samples/pbe/java/seed-ecb.raw | 1 +
samples/pbe/java/seed-ofb.base64 | 1 +
samples/pbe/java/seed-ofb.raw | Bin 0 -> 28 bytes
samples/pbe/java/seed.base64 | 1 +
samples/pbe/java/seed.raw | 1 +
samples/pbe/java/serpent-cbc.base64 | 1 +
samples/pbe/java/serpent-cbc.raw | 1 +
samples/pbe/java/serpent-cfb.base64 | 1 +
samples/pbe/java/serpent-cfb.raw | Bin 0 -> 28 bytes
samples/pbe/java/serpent-cfb8.base64 | 1 +
samples/pbe/java/serpent-cfb8.raw | 1 +
samples/pbe/java/serpent-ecb.base64 | 1 +
samples/pbe/java/serpent-ecb.raw | 1 +
samples/pbe/java/serpent-ofb.base64 | 1 +
samples/pbe/java/serpent-ofb.raw | 1 +
samples/pbe/java/serpent.base64 | 1 +
samples/pbe/java/serpent.raw | 2 +
samples/pbe/java/skipjack-cbc.base64 | 1 +
samples/pbe/java/skipjack-cbc.raw | 1 +
samples/pbe/java/skipjack-cfb.base64 | 1 +
samples/pbe/java/skipjack-cfb.raw | 1 +
samples/pbe/java/skipjack-cfb8.base64 | 1 +
samples/pbe/java/skipjack-cfb8.raw | 1 +
samples/pbe/java/skipjack-ecb.base64 | 1 +
samples/pbe/java/skipjack-ecb.raw | 1 +
samples/pbe/java/skipjack-ofb.base64 | 1 +
samples/pbe/java/skipjack-ofb.raw | 1 +
samples/pbe/java/skipjack.base64 | 1 +
samples/pbe/java/skipjack.raw | 1 +
samples/pbe/java/tea-cbc.base64 | 1 +
samples/pbe/java/tea-cbc.raw | 1 +
samples/pbe/java/tea-cfb.base64 | 1 +
samples/pbe/java/tea-cfb.raw | Bin 0 -> 28 bytes
samples/pbe/java/tea-cfb8.base64 | 1 +
samples/pbe/java/tea-cfb8.raw | Bin 0 -> 28 bytes
samples/pbe/java/tea-ecb.base64 | 1 +
samples/pbe/java/tea-ecb.raw | 1 +
samples/pbe/java/tea-ofb.base64 | 1 +
samples/pbe/java/tea-ofb.raw | 1 +
samples/pbe/java/tea.base64 | 1 +
samples/pbe/java/tea.raw | 1 +
samples/pbe/java/twofish-cbc.base64 | 1 +
samples/pbe/java/twofish-cbc.raw | 2 +
samples/pbe/java/twofish-cfb.base64 | 1 +
samples/pbe/java/twofish-cfb.raw | 1 +
samples/pbe/java/twofish-cfb8.base64 | 1 +
samples/pbe/java/twofish-cfb8.raw | Bin 0 -> 28 bytes
samples/pbe/java/twofish-ecb.base64 | 1 +
samples/pbe/java/twofish-ecb.raw | 1 +
samples/pbe/java/twofish-ofb.base64 | 1 +
samples/pbe/java/twofish-ofb.raw | 1 +
samples/pbe/java/twofish.base64 | 1 +
samples/pbe/java/twofish.raw | 1 +
samples/pbe/java/xtea-cbc.base64 | 1 +
samples/pbe/java/xtea-cbc.raw | 1 +
samples/pbe/java/xtea-cfb.base64 | 1 +
samples/pbe/java/xtea-cfb.raw | 1 +
samples/pbe/java/xtea-cfb8.base64 | 1 +
samples/pbe/java/xtea-cfb8.raw | Bin 0 -> 28 bytes
samples/pbe/java/xtea-ecb.base64 | 1 +
samples/pbe/java/xtea-ecb.raw | 1 +
samples/pbe/java/xtea-ofb.base64 | 1 +
samples/pbe/java/xtea-ofb.raw | 1 +
samples/pbe/java/xtea.base64 | 1 +
samples/pbe/java/xtea.raw | 1 +
samples/pbe/openssl/README.txt | 5 +
samples/pbe/openssl/aes-128-cbc.base64 | 1 +
samples/pbe/openssl/aes-128-cbc.raw | Bin 0 -> 32 bytes
samples/pbe/openssl/aes-128-cfb.base64 | 1 +
samples/pbe/openssl/aes-128-cfb.raw | 1 +
samples/pbe/openssl/aes-128-cfb1.base64 | 1 +
samples/pbe/openssl/aes-128-cfb1.raw | Bin 0 -> 28 bytes
samples/pbe/openssl/aes-128-cfb8.base64 | 1 +
samples/pbe/openssl/aes-128-cfb8.raw | 2 +
samples/pbe/openssl/aes-128-ecb.base64 | 1 +
samples/pbe/openssl/aes-128-ecb.raw | 1 +
samples/pbe/openssl/aes-128-ofb.base64 | 1 +
samples/pbe/openssl/aes-128-ofb.raw | 1 +
samples/pbe/openssl/aes-192-cbc.base64 | 1 +
samples/pbe/openssl/aes-192-cbc.raw | 1 +
samples/pbe/openssl/aes-192-cfb.base64 | 1 +
samples/pbe/openssl/aes-192-cfb.raw | 1 +
samples/pbe/openssl/aes-192-cfb1.base64 | 1 +
samples/pbe/openssl/aes-192-cfb1.raw | Bin 0 -> 28 bytes
samples/pbe/openssl/aes-192-cfb8.base64 | 1 +
samples/pbe/openssl/aes-192-cfb8.raw | 1 +
samples/pbe/openssl/aes-192-ecb.base64 | 1 +
samples/pbe/openssl/aes-192-ecb.raw | 1 +
samples/pbe/openssl/aes-192-ofb.base64 | 1 +
samples/pbe/openssl/aes-192-ofb.raw | 1 +
samples/pbe/openssl/aes-256-cbc.base64 | 1 +
samples/pbe/openssl/aes-256-cbc.raw | 1 +
samples/pbe/openssl/aes-256-cfb.base64 | 1 +
samples/pbe/openssl/aes-256-cfb.raw | 1 +
samples/pbe/openssl/aes-256-cfb1.base64 | 1 +
samples/pbe/openssl/aes-256-cfb1.raw | Bin 0 -> 28 bytes
samples/pbe/openssl/aes-256-cfb8.base64 | 1 +
samples/pbe/openssl/aes-256-cfb8.raw | 1 +
samples/pbe/openssl/aes-256-ecb.base64 | 1 +
samples/pbe/openssl/aes-256-ecb.raw | Bin 0 -> 32 bytes
samples/pbe/openssl/aes-256-ofb.base64 | 1 +
samples/pbe/openssl/aes-256-ofb.raw | 1 +
samples/pbe/openssl/aes128.base64 | 1 +
samples/pbe/openssl/aes128.raw | Bin 0 -> 32 bytes
samples/pbe/openssl/aes192.base64 | 1 +
samples/pbe/openssl/aes192.raw | 3 +
samples/pbe/openssl/aes256.base64 | 1 +
samples/pbe/openssl/aes256.raw | Bin 0 -> 32 bytes
samples/pbe/openssl/bf-cbc.base64 | 1 +
samples/pbe/openssl/bf-cbc.raw | 1 +
samples/pbe/openssl/bf-cfb.base64 | 1 +
samples/pbe/openssl/bf-cfb.raw | Bin 0 -> 28 bytes
samples/pbe/openssl/bf-ecb.base64 | 1 +
samples/pbe/openssl/bf-ecb.raw | 1 +
samples/pbe/openssl/bf-ofb.base64 | 1 +
samples/pbe/openssl/bf-ofb.raw | 1 +
samples/pbe/openssl/bf.base64 | 1 +
samples/pbe/openssl/bf.raw | 1 +
samples/pbe/openssl/blowfish.base64 | 1 +
samples/pbe/openssl/blowfish.raw | 1 +
samples/pbe/openssl/camellia-128-cbc.base64 | 1 +
samples/pbe/openssl/camellia-128-cbc.raw | 1 +
samples/pbe/openssl/camellia-128-cfb.base64 | 1 +
samples/pbe/openssl/camellia-128-cfb.raw | 1 +
samples/pbe/openssl/camellia-128-cfb1.base64 | 1 +
samples/pbe/openssl/camellia-128-cfb1.raw | Bin 0 -> 28 bytes
samples/pbe/openssl/camellia-128-cfb8.base64 | 1 +
samples/pbe/openssl/camellia-128-cfb8.raw | 1 +
samples/pbe/openssl/camellia-128-ecb.base64 | 1 +
samples/pbe/openssl/camellia-128-ecb.raw | 1 +
samples/pbe/openssl/camellia-128-ofb.base64 | 1 +
samples/pbe/openssl/camellia-128-ofb.raw | 1 +
samples/pbe/openssl/camellia-192-cbc.base64 | 1 +
samples/pbe/openssl/camellia-192-cbc.raw | 1 +
samples/pbe/openssl/camellia-192-cfb.base64 | 1 +
samples/pbe/openssl/camellia-192-cfb.raw | 1 +
samples/pbe/openssl/camellia-192-cfb1.base64 | 1 +
samples/pbe/openssl/camellia-192-cfb1.raw | Bin 0 -> 28 bytes
samples/pbe/openssl/camellia-192-cfb8.base64 | 1 +
samples/pbe/openssl/camellia-192-cfb8.raw | 1 +
samples/pbe/openssl/camellia-192-ecb.base64 | 1 +
samples/pbe/openssl/camellia-192-ecb.raw | 1 +
samples/pbe/openssl/camellia-192-ofb.base64 | 1 +
samples/pbe/openssl/camellia-192-ofb.raw | Bin 0 -> 28 bytes
samples/pbe/openssl/camellia-256-cbc.base64 | 1 +
samples/pbe/openssl/camellia-256-cbc.raw | 1 +
samples/pbe/openssl/camellia-256-cfb.base64 | 1 +
samples/pbe/openssl/camellia-256-cfb.raw | 2 +
samples/pbe/openssl/camellia-256-cfb1.base64 | 1 +
samples/pbe/openssl/camellia-256-cfb1.raw | Bin 0 -> 28 bytes
samples/pbe/openssl/camellia-256-cfb8.base64 | 1 +
samples/pbe/openssl/camellia-256-cfb8.raw | 1 +
samples/pbe/openssl/camellia-256-ecb.base64 | 1 +
samples/pbe/openssl/camellia-256-ecb.raw | 1 +
samples/pbe/openssl/camellia-256-ofb.base64 | 1 +
samples/pbe/openssl/camellia-256-ofb.raw | 1 +
samples/pbe/openssl/camellia128.base64 | 1 +
samples/pbe/openssl/camellia128.raw | 1 +
samples/pbe/openssl/camellia192.base64 | 1 +
samples/pbe/openssl/camellia192.raw | 1 +
samples/pbe/openssl/camellia256.base64 | 1 +
samples/pbe/openssl/camellia256.raw | Bin 0 -> 32 bytes
samples/pbe/openssl/cast-cbc.base64 | 1 +
samples/pbe/openssl/cast-cbc.raw | Bin 0 -> 32 bytes
samples/pbe/openssl/cast.base64 | 1 +
samples/pbe/openssl/cast.raw | 1 +
samples/pbe/openssl/cast5-cbc.base64 | 1 +
samples/pbe/openssl/cast5-cbc.raw | 2 +
samples/pbe/openssl/cast5-cfb.base64 | 1 +
samples/pbe/openssl/cast5-cfb.raw | 1 +
samples/pbe/openssl/cast5-ecb.base64 | 1 +
samples/pbe/openssl/cast5-ecb.raw | 1 +
samples/pbe/openssl/cast5-ofb.base64 | 1 +
samples/pbe/openssl/cast5-ofb.raw | 2 +
samples/pbe/openssl/des-cbc.base64 | 1 +
samples/pbe/openssl/des-cbc.raw | 1 +
samples/pbe/openssl/des-cfb.base64 | 1 +
samples/pbe/openssl/des-cfb.raw | 1 +
samples/pbe/openssl/des-cfb1.base64 | 1 +
samples/pbe/openssl/des-cfb1.raw | Bin 0 -> 28 bytes
samples/pbe/openssl/des-cfb8.base64 | 1 +
samples/pbe/openssl/des-cfb8.raw | 1 +
samples/pbe/openssl/des-ecb.base64 | 1 +
samples/pbe/openssl/des-ecb.raw | Bin 0 -> 32 bytes
samples/pbe/openssl/des-ede-cbc.base64 | 1 +
samples/pbe/openssl/des-ede-cbc.raw | 1 +
samples/pbe/openssl/des-ede-cfb.base64 | 1 +
samples/pbe/openssl/des-ede-cfb.raw | 1 +
samples/pbe/openssl/des-ede-ofb.base64 | 1 +
samples/pbe/openssl/des-ede-ofb.raw | 1 +
samples/pbe/openssl/des-ede.base64 | 1 +
samples/pbe/openssl/des-ede.raw | 1 +
samples/pbe/openssl/des-ede3-cbc.base64 | 1 +
samples/pbe/openssl/des-ede3-cbc.raw | 2 +
samples/pbe/openssl/des-ede3-cfb.base64 | 1 +
samples/pbe/openssl/des-ede3-cfb.raw | 1 +
samples/pbe/openssl/des-ede3-ofb.base64 | 1 +
samples/pbe/openssl/des-ede3-ofb.raw | 1 +
samples/pbe/openssl/des-ede3.base64 | 1 +
samples/pbe/openssl/des-ede3.raw | 1 +
samples/pbe/openssl/des-ofb.base64 | 1 +
samples/pbe/openssl/des-ofb.raw | 1 +
samples/pbe/openssl/des.base64 | 1 +
samples/pbe/openssl/des.raw | 1 +
samples/pbe/openssl/des3.base64 | 1 +
samples/pbe/openssl/des3.raw | 1 +
samples/pbe/openssl/idea-cbc.base64 | 1 +
samples/pbe/openssl/idea-cbc.raw | 1 +
samples/pbe/openssl/idea-cfb.base64 | 1 +
samples/pbe/openssl/idea-cfb.raw | 1 +
samples/pbe/openssl/idea-ecb.base64 | 1 +
samples/pbe/openssl/idea-ecb.raw | 1 +
samples/pbe/openssl/idea-ofb.base64 | 1 +
samples/pbe/openssl/idea-ofb.raw | 1 +
samples/pbe/openssl/idea.base64 | 1 +
samples/pbe/openssl/idea.raw | 1 +
samples/pbe/openssl/rc2-40-cbc.base64 | 1 +
samples/pbe/openssl/rc2-40-cbc.raw | 1 +
samples/pbe/openssl/rc2-64-cbc.base64 | 1 +
samples/pbe/openssl/rc2-64-cbc.raw | 1 +
samples/pbe/openssl/rc2-cbc.base64 | 1 +
samples/pbe/openssl/rc2-cbc.raw | 1 +
samples/pbe/openssl/rc2-cfb.base64 | 1 +
samples/pbe/openssl/rc2-cfb.raw | 1 +
samples/pbe/openssl/rc2-ecb.base64 | 1 +
samples/pbe/openssl/rc2-ecb.raw | 1 +
samples/pbe/openssl/rc2-ofb.base64 | 1 +
samples/pbe/openssl/rc2-ofb.raw | 1 +
samples/pbe/openssl/rc2.base64 | 1 +
samples/pbe/openssl/rc2.raw | 1 +
samples/pbe/openssl/rc4-40.base64 | 1 +
samples/pbe/openssl/rc4-40.raw | 1 +
samples/pbe/openssl/rc4.base64 | 1 +
samples/pbe/openssl/rc4.raw | 1 +
samples/pbe/openssl/rc5-cbc.base64 | 1 +
samples/pbe/openssl/rc5-cbc.raw | 1 +
samples/pbe/openssl/rc5-cfb.base64 | 1 +
samples/pbe/openssl/rc5-cfb.raw | 1 +
samples/pbe/openssl/rc5-ecb.base64 | 1 +
samples/pbe/openssl/rc5-ecb.raw | 1 +
samples/pbe/openssl/rc5-ofb.base64 | 1 +
samples/pbe/openssl/rc5-ofb.raw | 1 +
samples/pbe/openssl/rc5.base64 | 1 +
samples/pbe/openssl/rc5.raw | 1 +
samples/pkcs12/pkcs12_client_cert.p12 | Bin 0 -> 4070 bytes
samples/pkcs12/pkcs12_client_cert.pem | 94 ++
samples/rsa.html | 114 +++
samples/rsa/openssl_rsa_aes128_cbc.pem | 30 +
samples/rsa/openssl_rsa_aes128_cfb.pem | 30 +
samples/rsa/openssl_rsa_aes128_ecb.pem | 30 +
samples/rsa/openssl_rsa_aes128_ofb.pem | 30 +
samples/rsa/openssl_rsa_aes192_cbc.pem | 30 +
samples/rsa/openssl_rsa_aes192_cfb.pem | 30 +
samples/rsa/openssl_rsa_aes192_ecb.pem | 30 +
samples/rsa/openssl_rsa_aes192_ofb.pem | 30 +
samples/rsa/openssl_rsa_aes256_cbc.pem | 30 +
samples/rsa/openssl_rsa_aes256_cfb.pem | 30 +
samples/rsa/openssl_rsa_aes256_ecb.pem | 30 +
samples/rsa/openssl_rsa_aes256_ofb.pem | 30 +
samples/rsa/openssl_rsa_blowfish_cbc.pem | 30 +
samples/rsa/openssl_rsa_blowfish_cfb.pem | 30 +
samples/rsa/openssl_rsa_blowfish_ecb.pem | 30 +
samples/rsa/openssl_rsa_blowfish_ofb.pem | 30 +
samples/rsa/openssl_rsa_des1_cbc.pem | 30 +
samples/rsa/openssl_rsa_des1_cfb.pem | 30 +
samples/rsa/openssl_rsa_des1_ecb.pem | 30 +
samples/rsa/openssl_rsa_des1_ofb.pem | 30 +
samples/rsa/openssl_rsa_des2_cbc.pem | 30 +
samples/rsa/openssl_rsa_des2_cfb.pem | 30 +
samples/rsa/openssl_rsa_des2_ecb.pem | 30 +
samples/rsa/openssl_rsa_des2_ofb.pem | 30 +
samples/rsa/openssl_rsa_des3_cbc.pem | 30 +
samples/rsa/openssl_rsa_des3_cfb.pem | 30 +
samples/rsa/openssl_rsa_des3_ecb.pem | 30 +
samples/rsa/openssl_rsa_des3_ofb.pem | 30 +
samples/rsa/openssl_rsa_rc2_128_cbc.pem | 30 +
samples/rsa/openssl_rsa_rc2_128_cfb.pem | 30 +
samples/rsa/openssl_rsa_rc2_128_ecb.pem | 30 +
samples/rsa/openssl_rsa_rc2_128_ofb.pem | 30 +
samples/rsa/openssl_rsa_rc2_40.pem | 30 +
samples/rsa/openssl_rsa_rc2_64.pem | 30 +
samples/rsa/openssl_rsa_unencrypted.der | Bin 0 -> 1192 bytes
samples/rsa/openssl_rsa_unencrypted.pem | 27 +
samples/rsa/pkcs8_rsa_unencrypted.der | Bin 0 -> 1218 bytes
samples/rsa/pkcs8_rsa_unencrypted.pem | 28 +
samples/rsa/pkcs8v1_rsa_md2_des1.der | Bin 0 -> 1261 bytes
samples/rsa/pkcs8v1_rsa_md2_des1.pem | 29 +
samples/rsa/pkcs8v1_rsa_md2_rc2_64.der | Bin 0 -> 1261 bytes
samples/rsa/pkcs8v1_rsa_md2_rc2_64.pem | 29 +
samples/rsa/pkcs8v1_rsa_md5_des1.der | Bin 0 -> 1261 bytes
samples/rsa/pkcs8v1_rsa_md5_des1.pem | 29 +
samples/rsa/pkcs8v1_rsa_md5_rc2_64.der | Bin 0 -> 1261 bytes
samples/rsa/pkcs8v1_rsa_md5_rc2_64.pem | 29 +
samples/rsa/pkcs8v1_rsa_sha1_des1.der | Bin 0 -> 1261 bytes
samples/rsa/pkcs8v1_rsa_sha1_des1.pem | 29 +
samples/rsa/pkcs8v1_rsa_sha1_des2.der | Bin 0 -> 1262 bytes
samples/rsa/pkcs8v1_rsa_sha1_des2.pem | 29 +
samples/rsa/pkcs8v1_rsa_sha1_des3.der | Bin 0 -> 1262 bytes
samples/rsa/pkcs8v1_rsa_sha1_des3.pem | 29 +
samples/rsa/pkcs8v1_rsa_sha1_rc2_128.der | Bin 0 -> 1262 bytes
samples/rsa/pkcs8v1_rsa_sha1_rc2_128.pem | 29 +
samples/rsa/pkcs8v1_rsa_sha1_rc2_40.der | Bin 0 -> 1262 bytes
samples/rsa/pkcs8v1_rsa_sha1_rc2_40.pem | 29 +
samples/rsa/pkcs8v1_rsa_sha1_rc2_64.der | Bin 0 -> 1261 bytes
samples/rsa/pkcs8v1_rsa_sha1_rc2_64.pem | 29 +
samples/rsa/pkcs8v1_rsa_sha1_rc4_128.der | Bin 0 -> 1256 bytes
samples/rsa/pkcs8v1_rsa_sha1_rc4_128.pem | 29 +
samples/rsa/pkcs8v1_rsa_sha1_rc4_40.der | Bin 0 -> 1256 bytes
samples/rsa/pkcs8v1_rsa_sha1_rc4_40.pem | 29 +
samples/rsa/pkcs8v2_rsa_aes128_cbc.der | Bin 0 -> 1315 bytes
samples/rsa/pkcs8v2_rsa_aes128_cbc.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes128_cfb.der | Bin 0 -> 1301 bytes
samples/rsa/pkcs8v2_rsa_aes128_cfb.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes128_ecb.der | Bin 0 -> 1315 bytes
samples/rsa/pkcs8v2_rsa_aes128_ecb.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes128_ofb.der | Bin 0 -> 1301 bytes
samples/rsa/pkcs8v2_rsa_aes128_ofb.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes192_cbc.der | Bin 0 -> 1315 bytes
samples/rsa/pkcs8v2_rsa_aes192_cbc.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes192_cfb.der | Bin 0 -> 1301 bytes
samples/rsa/pkcs8v2_rsa_aes192_cfb.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes192_ecb.der | Bin 0 -> 1315 bytes
samples/rsa/pkcs8v2_rsa_aes192_ecb.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes192_ofb.der | Bin 0 -> 1301 bytes
samples/rsa/pkcs8v2_rsa_aes192_ofb.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes256_cbc.der | Bin 0 -> 1315 bytes
samples/rsa/pkcs8v2_rsa_aes256_cbc.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes256_cfb.der | Bin 0 -> 1301 bytes
samples/rsa/pkcs8v2_rsa_aes256_cfb.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes256_ecb.der | Bin 0 -> 1315 bytes
samples/rsa/pkcs8v2_rsa_aes256_ecb.pem | 30 +
samples/rsa/pkcs8v2_rsa_aes256_ofb.der | Bin 0 -> 1301 bytes
samples/rsa/pkcs8v2_rsa_aes256_ofb.pem | 30 +
samples/rsa/pkcs8v2_rsa_blowfish_cbc.der | Bin 0 -> 1299 bytes
samples/rsa/pkcs8v2_rsa_blowfish_cbc.pem | 30 +
samples/rsa/pkcs8v2_rsa_des1_cbc.der | Bin 0 -> 1295 bytes
samples/rsa/pkcs8v2_rsa_des1_cbc.pem | 29 +
samples/rsa/pkcs8v2_rsa_des1_cfb.der | Bin 0 -> 1289 bytes
samples/rsa/pkcs8v2_rsa_des1_cfb.pem | 29 +
samples/rsa/pkcs8v2_rsa_des1_ecb.der | Bin 0 -> 1295 bytes
samples/rsa/pkcs8v2_rsa_des1_ecb.pem | 29 +
samples/rsa/pkcs8v2_rsa_des1_ofb.der | Bin 0 -> 1289 bytes
samples/rsa/pkcs8v2_rsa_des1_ofb.pem | 29 +
samples/rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.der | Bin 0 -> 1295 bytes
samples/rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.pem | 29 +
samples/rsa/pkcs8v2_rsa_des3.der | Bin 0 -> 1298 bytes
samples/rsa/pkcs8v2_rsa_des3.pem | 30 +
samples/rsa/pkcs8v2_rsa_rc2_128.der | Bin 0 -> 1306 bytes
samples/rsa/pkcs8v2_rsa_rc2_128.pem | 30 +
samples/rsa/pkcs8v2_rsa_rc2_40.der | Bin 0 -> 1307 bytes
samples/rsa/pkcs8v2_rsa_rc2_40.pem | 30 +
samples/rsa/pkcs8v2_rsa_rc2_64.der | Bin 0 -> 1306 bytes
samples/rsa/pkcs8v2_rsa_rc2_64.pem | 30 +
samples/rsa_result.html | 38 +
samples/x509/certificate.der | Bin 0 -> 1092 bytes
samples/x509/certificate.pem | 85 ++
samples/x509/certificate_chain.pem | 79 ++
samples/x509/certificate_root_ca.der | Bin 0 -> 1156 bytes
samples/x509/certificate_root_ca.pem | 87 ++
samples/x509/oscp.pem | 22 +
samples/x509/two-crls.pem | 46 +
samples/x509/x509_foo.pem | 85 ++
samples/x509/x509_foo_bar.pem | 88 ++
samples/x509/x509_foo_bar_hanako.pem | 88 ++
samples/x509/x509_hanako.pem | 85 ++
samples/x509/x509_no_cns_foo.pem | 87 ++
samples/x509/x509_three_cns_foo_bar_hanako.pem | 86 ++
samples/x509/x509_wild_co_jp.pem | 85 ++
samples/x509/x509_wild_foo.pem | 85 ++
samples/x509/x509_wild_foo_bar_hanako.pem | 88 ++
.../contrib/ssl/AuthSSLProtocolSocketFactory.java | 196 ++++
.../contrib/ssl/EasySSLProtocolSocketFactory.java | 102 ++
.../ssl/StrictSSLProtocolSocketFactory.java | 131 +++
.../contrib/ssl/TrustSSLProtocolSocketFactory.java | 199 ++++
src/java/org/apache/commons/ssl/ASN1Structure.java | 112 +++
src/java/org/apache/commons/ssl/ASN1Util.java | 211 ++++
src/java/org/apache/commons/ssl/Base64.java | 535 ++++++++++
.../org/apache/commons/ssl/Base64InputStream.java | 120 +++
src/java/org/apache/commons/ssl/CRLUtil.java | 75 ++
src/java/org/apache/commons/ssl/Certificates.java | 591 +++++++++++
.../org/apache/commons/ssl/ComboInputStream.java | 96 ++
src/java/org/apache/commons/ssl/DerivedKey.java | 49 +
src/java/org/apache/commons/ssl/HostPort.java | 55 ++
.../org/apache/commons/ssl/HostnameVerifier.java | 481 +++++++++
.../org/apache/commons/ssl/HttpSecureProtocol.java | 93 ++
src/java/org/apache/commons/ssl/Java13.java | 290 ++++++
.../commons/ssl/Java13KeyManagerWrapper.java | 82 ++
.../commons/ssl/Java13TrustManagerWrapper.java | 99 ++
src/java/org/apache/commons/ssl/Java14.java | 258 +++++
.../commons/ssl/Java14KeyManagerWrapper.java | 82 ++
.../commons/ssl/Java14TrustManagerWrapper.java | 128 +++
src/java/org/apache/commons/ssl/JavaImpl.java | 245 +++++
src/java/org/apache/commons/ssl/KeyMaterial.java | 201 ++++
.../org/apache/commons/ssl/KeyStoreBuilder.java | 625 ++++++++++++
src/java/org/apache/commons/ssl/LDAPSocket.java | 83 ++
src/java/org/apache/commons/ssl/LogHelper.java | 87 ++
src/java/org/apache/commons/ssl/LogWrapper.java | 295 ++++++
src/java/org/apache/commons/ssl/OpenSSL.java | 720 ++++++++++++++
src/java/org/apache/commons/ssl/OpenSSLTest.java | 92 ++
src/java/org/apache/commons/ssl/PBETestCreate.java | 79 ++
src/java/org/apache/commons/ssl/PEMItem.java | 106 ++
src/java/org/apache/commons/ssl/PEMUtil.java | 238 +++++
src/java/org/apache/commons/ssl/PKCS8Key.java | 1034 ++++++++++++++++++++
src/java/org/apache/commons/ssl/Ping.java | 464 +++++++++
.../commons/ssl/ProbablyBadPasswordException.java | 51 +
.../commons/ssl/ProbablyNotPKCS8Exception.java | 50 +
.../apache/commons/ssl/RMISocketFactoryImpl.java | 578 +++++++++++
src/java/org/apache/commons/ssl/SSL.java | 739 ++++++++++++++
src/java/org/apache/commons/ssl/SSLClient.java | 233 +++++
src/java/org/apache/commons/ssl/SSLEchoServer.java | 142 +++
.../org/apache/commons/ssl/SSLProxyServer.java | 193 ++++
src/java/org/apache/commons/ssl/SSLServer.java | 295 ++++++
.../apache/commons/ssl/SSLServerSocketWrapper.java | 182 ++++
.../org/apache/commons/ssl/SSLSocketWrapper.java | 251 +++++
.../org/apache/commons/ssl/SSLWrapperFactory.java | 109 +++
.../org/apache/commons/ssl/TomcatServerXML.java | 231 +++++
src/java/org/apache/commons/ssl/TrustChain.java | 206 ++++
src/java/org/apache/commons/ssl/TrustMaterial.java | 272 +++++
src/java/org/apache/commons/ssl/Util.java | 403 ++++++++
src/java/org/apache/commons/ssl/Version.java | 197 ++++
.../commons/ssl/X509CertificateChainBuilder.java | 181 ++++
.../org/apache/commons/ssl/asn1/ASN1Choice.java | 13 +
.../org/apache/commons/ssl/asn1/ASN1Encodable.java | 74 ++
.../commons/ssl/asn1/ASN1EncodableVector.java | 10 +
.../org/apache/commons/ssl/asn1/ASN1Generator.java | 13 +
.../apache/commons/ssl/asn1/ASN1InputStream.java | 420 ++++++++
src/java/org/apache/commons/ssl/asn1/ASN1Null.java | 30 +
.../org/apache/commons/ssl/asn1/ASN1Object.java | 34 +
.../apache/commons/ssl/asn1/ASN1ObjectParser.java | 55 ++
.../apache/commons/ssl/asn1/ASN1OctetString.java | 137 +++
.../commons/ssl/asn1/ASN1OctetStringParser.java | 8 +
.../apache/commons/ssl/asn1/ASN1OutputStream.java | 26 +
.../org/apache/commons/ssl/asn1/ASN1Sequence.java | 183 ++++
.../commons/ssl/asn1/ASN1SequenceParser.java | 9 +
src/java/org/apache/commons/ssl/asn1/ASN1Set.java | 281 ++++++
.../org/apache/commons/ssl/asn1/ASN1SetParser.java | 9 +
.../apache/commons/ssl/asn1/ASN1StreamParser.java | 193 ++++
.../apache/commons/ssl/asn1/ASN1TaggedObject.java | 177 ++++
.../commons/ssl/asn1/ASN1TaggedObjectParser.java | 11 +
.../ssl/asn1/BERConstructedOctetString.java | 137 +++
.../commons/ssl/asn1/BERConstructedSequence.java | 29 +
.../org/apache/commons/ssl/asn1/BERGenerator.java | 82 ++
.../apache/commons/ssl/asn1/BERInputStream.java | 179 ++++
src/java/org/apache/commons/ssl/asn1/BERNull.java | 22 +
.../commons/ssl/asn1/BEROctetStringGenerator.java | 86 ++
.../commons/ssl/asn1/BEROctetStringParser.java | 36 +
.../apache/commons/ssl/asn1/BEROutputStream.java | 26 +
.../org/apache/commons/ssl/asn1/BERSequence.java | 44 +
.../commons/ssl/asn1/BERSequenceGenerator.java | 36 +
.../apache/commons/ssl/asn1/BERSequenceParser.java | 21 +
src/java/org/apache/commons/ssl/asn1/BERSet.java | 51 +
.../org/apache/commons/ssl/asn1/BERSetParser.java | 21 +
.../apache/commons/ssl/asn1/BERTaggedObject.java | 94 ++
.../commons/ssl/asn1/BERTaggedObjectParser.java | 118 +++
.../commons/ssl/asn1/ConstructedOctetStream.java | 92 ++
.../commons/ssl/asn1/DERApplicationSpecific.java | 143 +++
.../org/apache/commons/ssl/asn1/DERBMPString.java | 104 ++
.../org/apache/commons/ssl/asn1/DERBitString.java | 245 +++++
.../org/apache/commons/ssl/asn1/DERBoolean.java | 96 ++
.../commons/ssl/asn1/DERConstructedSequence.java | 46 +
.../apache/commons/ssl/asn1/DERConstructedSet.java | 63 ++
.../org/apache/commons/ssl/asn1/DEREncodable.java | 5 +
.../commons/ssl/asn1/DEREncodableVector.java | 31 +
.../org/apache/commons/ssl/asn1/DEREnumerated.java | 96 ++
.../apache/commons/ssl/asn1/DERGeneralString.java | 75 ++
.../commons/ssl/asn1/DERGeneralizedTime.java | 242 +++++
.../org/apache/commons/ssl/asn1/DERGenerator.java | 108 ++
.../org/apache/commons/ssl/asn1/DERIA5String.java | 142 +++
.../apache/commons/ssl/asn1/DERInputStream.java | 237 +++++
.../org/apache/commons/ssl/asn1/DERInteger.java | 114 +++
src/java/org/apache/commons/ssl/asn1/DERNull.java | 20 +
.../apache/commons/ssl/asn1/DERNumericString.java | 148 +++
.../org/apache/commons/ssl/asn1/DERObject.java | 18 +
.../commons/ssl/asn1/DERObjectIdentifier.java | 245 +++++
.../apache/commons/ssl/asn1/DEROctetString.java | 23 +
.../apache/commons/ssl/asn1/DEROutputStream.java | 73 ++
.../commons/ssl/asn1/DERPrintableString.java | 172 ++++
.../org/apache/commons/ssl/asn1/DERSequence.java | 62 ++
.../commons/ssl/asn1/DERSequenceGenerator.java | 39 +
src/java/org/apache/commons/ssl/asn1/DERSet.java | 76 ++
.../org/apache/commons/ssl/asn1/DERString.java | 6 +
.../org/apache/commons/ssl/asn1/DERT61String.java | 103 ++
.../apache/commons/ssl/asn1/DERTaggedObject.java | 74 ++
src/java/org/apache/commons/ssl/asn1/DERTags.java | 35 +
.../org/apache/commons/ssl/asn1/DERUTCTime.java | 214 ++++
.../org/apache/commons/ssl/asn1/DERUTF8String.java | 83 ++
.../commons/ssl/asn1/DERUniversalString.java | 100 ++
.../org/apache/commons/ssl/asn1/DERUnknownTag.java | 71 ++
.../apache/commons/ssl/asn1/DERVisibleString.java | 103 ++
.../ssl/asn1/DefiniteLengthInputStream.java | 83 ++
.../ssl/asn1/IndefiniteLengthInputStream.java | 98 ++
.../commons/ssl/asn1/LimitedInputStream.java | 23 +
.../org/apache/commons/ssl/asn1/OIDTokenizer.java | 42 +
src/java/org/apache/commons/ssl/asn1/Strings.java | 195 ++++
src/java/org/apache/commons/ssl/rmi/DateRMI.java | 69 ++
.../org/apache/commons/ssl/rmi/IntegerRMI.java | 69 ++
.../org/apache/commons/ssl/rmi/RemoteDate.java | 46 +
.../org/apache/commons/ssl/rmi/RemoteInteger.java | 45 +
src/java/org/apache/commons/ssl/rmi/Test.java | 200 ++++
src/java/org/apache/commons/ssl/util/Hex.java | 83 ++
.../apache/commons/ssl/util/PublicKeyDeriver.java | 82 ++
version.txt | 3 +
1031 files changed, 27782 insertions(+)
diff --git a/LICENSE.txt b/LICENSE.txt
new file mode 100644
index 0000000..2bb9ad2
--- /dev/null
+++ b/LICENSE.txt
@@ -0,0 +1,176 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
\ No newline at end of file
diff --git a/NOTICE.txt b/NOTICE.txt
new file mode 100644
index 0000000..2807f75
--- /dev/null
+++ b/NOTICE.txt
@@ -0,0 +1,10 @@
+This product includes software developed by
+The Apache Software Foundation (http://www.apache.org/).
+
+The PKCS12 key derivation function was developed by BouncyCastle
+(bouncycastle.org). (Look for the "pkcs12()" method inside PKCS8.java).
+
+Some of this software was originally developed by
+Credit Union Central of British Columbia (http://www.cucbc.com/).
+The CUCBC code was licensed to the Apache Software Foundation on
+August 23rd, 2006.
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..2497e38
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,9 @@
+Jakarta Commons SSL
+===========================
+Welcome to the SSL component of the Jakarta Commons
+project.
+
+This is not a real Jakarta Project yet. I'm just
+trying to copy their directory structure while I work
+on this proposal.
+
diff --git a/build.xml b/build.xml
new file mode 100644
index 0000000..a5854e2
--- /dev/null
+++ b/build.xml
@@ -0,0 +1,106 @@
+<!--
+ $ ant -p
+ Buildfile: build.xml
+
+ Main targets:
+
+ clean Deletes class files and other generated files.
+ jar Jars compiled java class files.
+ javac Compiles java source code.
+ javadocs Generates javadocs.
+
+ Default target: jar
+-->
+<project name="commons-ssl" default="jar" basedir=".">
+
+ <property name="httpclient-jar" value="commons-httpclient-3.0.jar"/>
+ <property name="log4j-jar" value="log4j-1.2.13.jar"/>
+ <property name="src" location="./src/java"/>
+ <property name="build" location="./build"/>
+ <property name="lib" location="./lib"/>
+ <property name="classes" value="${build}/classes"/>
+ <property name="jar-file" value="${ant.project.name}.jar"/>
+ <property name="javadocs" value="${build}/javadocs"/>
+ <property name="rmic.includes" value="**/*RMI.class"/>
+
+ <path id="compile-classpath">
+ <pathelement location="${classes}"/>
+ <pathelement location="${lib}/${httpclient-jar}"/>
+ <pathelement location="${lib}/${log4j-jar}"/>
+ </path>
+
+ <target name="init">
+ <tstamp>
+ <format property="date" pattern="zzz:yyyy-MM-dd/HH:mm:ss" locale="en"/>
+ </tstamp>
+ <mkdir dir="${build}"/>
+ </target>
+
+ <target name="javac" depends="init" description="Compiles java source code.">
+ <mkdir dir="${classes}"/>
+ <javac
+ includeAntRuntime="false"
+ destdir="${classes}"
+ debug="true"
+ optimize="false"
+ srcdir="${src}"
+ excludes="${javac.exclude}"
+ >
+ <classpath refid="compile-classpath"/>
+ </javac>
+ <copy todir="${classes}">
+ <fileset dir="${src}" excludes="**/*.java"/>
+ </copy>
+ </target>
+
+ <target name="rmic" depends="javac" description="Rmics java class files named "*RMI.class".">
+ <rmic
+ base="${classes}"
+ includes="${rmic.includes}"
+ classpathref="compile-classpath"
+ />
+ </target>
+
+ <target name="jar" depends="rmic" description="Jars compiled java class files.">
+ <jar
+ basedir="${classes}"
+ destfile="${build}/${jar-file}"
+ index="true"
+ duplicate="fail"
+ >
+ <manifest>
+ <attribute name="Built-By" value="cucbc.com"/>
+ <attribute name="Created-By" value="cucbc.com"/>
+ <attribute name="Main-Class" value="org.apache.commons.ssl.Ping"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <!-- Alias for "javadocs". -->
+ <target name="javadoc" depends="javadocs"/>
+
+ <target name="javadocs" depends="init" description="Generates javadocs.">
+ <mkdir dir="${javadocs}"/>
+ <javadoc
+ sourcepath="${src}"
+ destdir="${javadocs}"
+ packagenames="*"
+ classpathref="compile-classpath"
+ access="private"
+ source="yes"
+ linksource="yes"
+ >
+ <link href="http://java.sun.com/j2se/1.5.0/docs/api/"/>
+ <link href="http://java.sun.com/j2ee/1.4/docs/api/"/>
+ <link href="http://jakarta.apache.org/commons/httpclient/apidocs/"/>
+ </javadoc>
+ </target>
+
+ <target name="clean" description="Deletes class files and other generated files.">
+ <delete dir="${build}"/>
+ </target>
+
+ <target name="all" depends="clean,jar"/>
+
+
+</project>
diff --git a/docs/.htaccess b/docs/.htaccess
new file mode 100644
index 0000000..6f20845
--- /dev/null
+++ b/docs/.htaccess
@@ -0,0 +1,3 @@
+AddType text/html .html
+AddHandler server-parsed .html
+ErrorDocument 404 /commons-ssl/404.html
diff --git a/docs/404.html b/docs/404.html
new file mode 100644
index 0000000..92d9bad
--- /dev/null
+++ b/docs/404.html
@@ -0,0 +1,51 @@
+<html>
+<head>
+<title>Not-Yet-Commons-SSL - 404 Page Not Found</title>
+<style type="text/css">
+dl, h1, h2, h3, h4 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+td.v { text-align: center; }
+dt { padding: 8px 0 8px 5px; }
+dd { padding-left: 15px; }
+li { padding-bottom: 6px; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="/commons-ssl/index.html">main</a> |
+<a href="/commons-ssl/ssl.html">ssl</a> |
+<a href="/commons-ssl/pkcs8.html">pkcs8</a> |
+<a href="/commons-ssl/pbe.html">pbe</a> |
+<a href="/commons-ssl/rmi.html">rmi</a> |
+<a href="/commons-ssl/utilities.html">utilities</a> |
+<a href="/commons-ssl/source.html">source</a> |
+<a href="/commons-ssl/javadocs/">javadocs</a> |
+<a href="/commons-ssl/download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>404 - Page Not Found</h2>
+<p>The path you requested is not available.</p>
+<table cellpadding="6" cellspacing="0" border="0" style="margin-top: 9px;">
+<tr><th colspan="3">Current Version (November 14th, 2007):</th></tr>
+<tr><td>Full source:</td><td><a href="/commons-ssl/not-yet-commons-ssl-0.3.9.zip">not-yet-commons-ssl-0.3.9.zip</a></td><td>2.3MB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 8063831d05fc6204a7c0c23a0f86b086</td></tr>
+<tr><td>Binary only:</td><td><a href="/commons-ssl/not-yet-commons-ssl-0.3.9.jar">not-yet-commons-ssl-0.3.9.jar</a></td><td>189KB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 34996468b477e3a6c81d7feec213288b</td></tr>
+<tr><th colspan="3">Previous Version (July 4th, 2007):</th></tr>
+<tr><td>Full source:</td><td><a href="/not-yet-commons-ssl-0.3.8/not-yet-commons-ssl-0.3.8.zip">not-yet-commons-ssl-0.3.8.zip</a></td><td>2.3MB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 6c709837f9fef310a69f8659f1697c81</td></tr>
+<tr><td>Binary only:</td><td><a href="/not-yet-commons-ssl-0.3.8/not-yet-commons-ssl-0.3.8.jar">not-yet-commons-ssl-0.3.8.jar</a></td><td>189KB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 34996468b477e3a6c81d7feec213288b</td></tr>
+</table>
+<br/><b>Warning:</b>
+ <span style="color: red; font-weight: bold;">not-yet-commons-ssl-0.3.9 should be considered to be of "Alpha" quality!
+This code probably contains bugs. This code may have security issues.</span>
+<p>Future versions will definitely break the current API in a non-reverse compatible way. After commons-ssl-0.5.0, though, we
+plan on always being reverse compatible with ourselves.
+<hr/>
+
+</body>
+</html>
diff --git a/docs/404.html~ b/docs/404.html~
new file mode 100644
index 0000000..e6e28ab
--- /dev/null
+++ b/docs/404.html~
@@ -0,0 +1,51 @@
+<html>
+<head>
+<title>Not-Yet-Commons-SSL - 404 Page Not Found</title>
+<style type="text/css">
+dl, h1, h2, h3, h4 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+td.v { text-align: center; }
+dt { padding: 8px 0 8px 5px; }
+dd { padding-left: 15px; }
+li { padding-bottom: 6px; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="/commons-ssl/index.html">main</a> |
+<a href="/commons-ssl/ssl.html">ssl</a> |
+<a href="/commons-ssl/pkcs8.html">pkcs8</a> |
+<a href="/commons-ssl/pbe.html">pbe</a> |
+<a href="/commons-ssl/rmi.html">rmi</a> |
+<a href="/commons-ssl/utilities.html">utilities</a> |
+<a href="/commons-ssl/source.html">source</a> |
+<a href="/commons-ssl/javadocs/">javadocs</a> |
+<a href="/commons-ssl/download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>404 - Page Not Found</h2>
+<p>The path you requested is not available.</p>
+<table cellpadding="6" cellspacing="0" border="0" style="margin-top: 9px;">
+<tr><th colspan="3">Current Version (November 14th, 2007):</th></tr>
+<tr><td>Full source:</td><td><a href="/commons-ssl/not-yet-commons-ssl-0.3.9.zip">not-yet-commons-ssl-0.3.9.zip</a></td><td>2.3MB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 6c709837f9fef310a69f8659f1697c81</td></tr>
+<tr><td>Binary only:</td><td><a href="/commons-ssl/not-yet-commons-ssl-0.3.9.jar">not-yet-commons-ssl-0.3.9.jar</a></td><td>189KB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 34996468b477e3a6c81d7feec213288b</td></tr>
+<tr><th colspan="3">Previous Version (July 4th, 2007):</th></tr>
+<tr><td>Full source:</td><td><a href="/not-yet-commons-ssl-0.3.8/not-yet-commons-ssl-0.3.8.zip">not-yet-commons-ssl-0.3.8.zip</a></td><td>2.3MB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 6c709837f9fef310a69f8659f1697c81</td></tr>
+<tr><td>Binary only:</td><td><a href="/not-yet-commons-ssl-0.3.8/not-yet-commons-ssl-0.3.8.jar">not-yet-commons-ssl-0.3.8.jar</a></td><td>189KB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 34996468b477e3a6c81d7feec213288b</td></tr>
+</table>
+<br/><b>Warning:</b>
+ <span style="color: red; font-weight: bold;">not-yet-commons-ssl-0.3.9 should be considered to be of "Alpha" quality!
+This code probably contains bugs. This code may have security issues.</span>
+<p>Future versions will definitely break the current API in a non-reverse compatible way. After commons-ssl-0.5.0, though, we
+plan on always being reverse compatible with ourselves.
+<hr/>
+
+</body>
+</html>
diff --git a/docs/TrustExample.java b/docs/TrustExample.java
new file mode 100644
index 0000000..c4561de
--- /dev/null
+++ b/docs/TrustExample.java
@@ -0,0 +1,114 @@
+
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.protocol.Protocol;
+import org.apache.commons.ssl.HttpSecureProtocol;
+import org.apache.commons.ssl.TrustMaterial;
+
+import javax.net.ssl.SSLHandshakeException;
+import java.net.URL;
+
+/**
+ *
+ * Example of trusting certs to answer a question Sudip Shrestha posed on the
+ * httpclient-user at jakarta.apache.org mailing list, Fri 5/5/2006.
+ *
+ * @author Julius Davies
+ * @since May 5, 2006
+ */
+public class TrustExample {
+
+/*
+Microsoft IE trusts usertrust.com CA certs by default, but Java doesn't, so we need
+to tell Java to.
+
+Cert is good until 2019 !
+
+openssl x509 -in cert.pem -noout -text
+=======================================
+
+Serial Number:
+ 44:be:0c:8b:50:00:24:b4:11:d3:36:2a:fe:65:0a:fd
+Signature Algorithm: sha1WithRSAEncryption
+Issuer: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Hardware
+Validity
+ Not Before: Jul 9 18:10:42 1999 GMT
+ Not After : Jul 9 18:19:22 2019 GMT
+Subject: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Hardware
+
+X509v3 extensions:
+ X509v3 Key Usage:
+ Digital Signature, Non Repudiation, Certificate Sign, CRL Sign
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ A1:72:5F:26:1B:28:98:43:95:5D:07:37:D5:85:96:9D:4B:D2:C3:45
+ X509v3 CRL Distribution Points:
+ URI:http://crl.usertrust.com/UTN-USERFirst-Hardware.crl
+
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication, IPSec End System, IPSec Tunnel, IPSec User
+
+*/
+ private static byte[] pemCert = (
+ "-----BEGIN CERTIFICATE-----\n" +
+ "MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB\n" +
+ "lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug\n" +
+ "Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho\n" +
+ "dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt\n" +
+ "SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG\n" +
+ "A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe\n" +
+ "MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v\n" +
+ "d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh\n" +
+ "cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn\n" +
+ "0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ\n" +
+ "M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a\n" +
+ "MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd\n" +
+ "oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI\n" +
+ "DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy\n" +
+ "oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD\n" +
+ "VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0\n" +
+ "dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy\n" +
+ "bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF\n" +
+ "BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM\n" +
+ "//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli\n" +
+ "CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE\n" +
+ "CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t\n" +
+ "3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS\n" +
+ "KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==\n" +
+ "-----END CERTIFICATE-----\n" ).getBytes();
+
+ public static void main( String[] args ) throws Exception
+ {
+ HttpSecureProtocol f = new HttpSecureProtocol();
+
+ // might as well trust the usual suspects:
+ f.addTrustMaterial(TrustMaterial.CACERTS);
+
+ // here's where we start trusting usertrust.com's CA:
+ f.addTrustMaterial(new TrustMaterial( pemCert ));
+
+ Protocol trustHttps = new Protocol("https", f, 443);
+ Protocol.registerProtocol("https", trustHttps);
+
+ HttpClient client = new HttpClient();
+ GetMethod httpget = new GetMethod("https://www.usertrust.com/");
+ client.executeMethod(httpget);
+ String s = httpget.getStatusLine().toString();
+ System.out.println( "HTTPClient: " + s );
+
+ // Notice that Java still can't access it. Only HTTPClient knows
+ // to trust the cert!
+ URL u = new URL( "https://www.usertrust.com/" );
+ try
+ {
+ // This will throw an SSLHandshakeException
+ u.openStream();
+ }
+ catch ( SSLHandshakeException she )
+ {
+ System.out.println( "Java: " + she );
+ }
+ }
+
+}
diff --git a/docs/TrustExample.java.html b/docs/TrustExample.java.html
new file mode 100644
index 0000000..ec2752d
--- /dev/null
+++ b/docs/TrustExample.java.html
@@ -0,0 +1,131 @@
+<HTML>
+<HEAD>
+<TITLE>/home/julius/dev/commons-ssl/src/java/TrustExample.java</TITLE>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=windows-1252">
+<META NAME="KEYWORDS" CONTENT="IntelliJ_IDEA_Html">
+</HEAD>
+<BODY BGCOLOR="#ffffff">
+<TABLE CELLSPACING=0 CELLPADDING=5 COLS=1 WIDTH="100%" BGCOLOR="#C0C0C0" >
+<TR><TD><CENTER>
+<FONT FACE="Arial, Helvetica" COLOR="#000000">
+/home/julius/dev/commons-ssl/src/java/TrustExample.java</FONT>
+</center></TD></TR></TABLE>
+<PRE>
+
+<FONT COLOR=0 STYLE="font-style:normal">1 </FONT><FONT style="font-family:monospaced;" COLOR="#000000">
+<FONT COLOR=0 STYLE="font-style:normal">2 </FONT></FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>import</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> org.apache.commons.httpclient.HttpClient;
+<FONT COLOR=0 STYLE="font-style:normal">3 </FONT></FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>import</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> org.apache.commons.httpclient.methods.GetMethod;
+<FONT COLOR=0 STYLE="font-style:normal">4 </FONT></FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>import</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> org.apache.commons.httpclient.protocol.Protocol;
+<FONT COLOR=0 STYLE="font-style:normal">5 </FONT></FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>import</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> org.apache.commons.ssl.HttpSecureProtocol;
+<FONT COLOR=0 STYLE="font-style:normal">6 </FONT></FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>import</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> org.apache.commons.ssl.TrustMaterial;
+<FONT COLOR=0 STYLE="font-style:normal">7 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">8 </FONT></FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>import</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> javax.net.ssl.SSLHandshakeException;
+<FONT COLOR=0 STYLE="font-style:normal">9 </FONT></FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>import</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> java.net.URL;
+<FONT COLOR=0 STYLE="font-style:normal">10 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">11 </FONT></FONT><FONT style="font-family:monospaced;" COLOR="#008000"><I>/**
+<FONT COLOR=0 STYLE="font-style:normal">12 </FONT> *
+<FONT COLOR=0 STYLE="font-style:normal">13 </FONT> * Example of trusting certs to answer a question Sudip Shrestha posed on the
+<FONT COLOR=0 STYLE="font-style:normal">14 </FONT> * httpclient-user at jakarta.apache.org mailing list, Fri 5/5/2006.
+<FONT COLOR=0 STYLE="font-style:normal">15 </FONT> *
+<FONT COLOR=0 STYLE="font-style:normal">16 </FONT> * </I></FONT><FONT style="font-family:monospaced;" COLOR="#008000"><B>@author</B></FONT><FONT style="font-family:monospaced;" COLOR="#008000"><I> Julius Davies
+<FONT COLOR=0 STYLE="font-style:normal">17 </FONT> * </I></FONT><FONT style="font-family:monospaced;" COLOR="#008000"><B>@since</B></FONT><FONT style="font-family:monospaced;" COLOR="#008000"><I> May 5, 2006
+<FONT COLOR=0 STYLE="font-style:normal">18 </FONT> */</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000">
+<FONT COLOR=0 STYLE="font-style:normal">19 </FONT></FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>public</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>class</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> TrustExample {
+<FONT COLOR=0 STYLE="font-style:normal">20 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">21 </FONT></FONT><FONT style="font-family:monospaced;" COLOR="#008000"><I>/*
+<FONT COLOR=0 STYLE="font-style:normal">22 </FONT>Microsoft IE trusts usertrust.com CA certs by default, but Java doesn't, so we need
+<FONT COLOR=0 STYLE="font-style:normal">23 </FONT>to tell Java to.
+<FONT COLOR=0 STYLE="font-style:normal">24 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">25 </FONT>Cert is good until 2019 !
+<FONT COLOR=0 STYLE="font-style:normal">26 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">27 </FONT>openssl x509 -in cert.pem -noout -text
+<FONT COLOR=0 STYLE="font-style:normal">28 </FONT>=======================================
+<FONT COLOR=0 STYLE="font-style:normal">29 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">30 </FONT>Serial Number:
+<FONT COLOR=0 STYLE="font-style:normal">31 </FONT> 44:be:0c:8b:50:00:24:b4:11:d3:36:2a:fe:65:0a:fd
+<FONT COLOR=0 STYLE="font-style:normal">32 </FONT>Signature Algorithm: sha1WithRSAEncryption
+<FONT COLOR=0 STYLE="font-style:normal">33 </FONT>Issuer: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Hardware
+<FONT COLOR=0 STYLE="font-style:normal">34 </FONT>Validity
+<FONT COLOR=0 STYLE="font-style:normal">35 </FONT> Not Before: Jul 9 18:10:42 1999 GMT
+<FONT COLOR=0 STYLE="font-style:normal">36 </FONT> Not After : Jul 9 18:19:22 2019 GMT
+<FONT COLOR=0 STYLE="font-style:normal">37 </FONT>Subject: C=US, ST=UT, L=Salt Lake City, O=The USERTRUST Network, OU=http://www.usertrust.com, CN=UTN-USERFirst-Hardware
+<FONT COLOR=0 STYLE="font-style:normal">38 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">39 </FONT>X509v3 extensions:
+<FONT COLOR=0 STYLE="font-style:normal">40 </FONT> X509v3 Key Usage:
+<FONT COLOR=0 STYLE="font-style:normal">41 </FONT> Digital Signature, Non Repudiation, Certificate Sign, CRL Sign
+<FONT COLOR=0 STYLE="font-style:normal">42 </FONT> X509v3 Basic Constraints: critical
+<FONT COLOR=0 STYLE="font-style:normal">43 </FONT> CA:TRUE
+<FONT COLOR=0 STYLE="font-style:normal">44 </FONT> X509v3 Subject Key Identifier:
+<FONT COLOR=0 STYLE="font-style:normal">45 </FONT> A1:72:5F:26:1B:28:98:43:95:5D:07:37:D5:85:96:9D:4B:D2:C3:45
+<FONT COLOR=0 STYLE="font-style:normal">46 </FONT> X509v3 CRL Distribution Points:
+<FONT COLOR=0 STYLE="font-style:normal">47 </FONT> URI:http://crl.usertrust.com/UTN-USERFirst-Hardware.crl
+<FONT COLOR=0 STYLE="font-style:normal">48 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">49 </FONT> X509v3 Extended Key Usage:
+<FONT COLOR=0 STYLE="font-style:normal">50 </FONT> TLS Web Server Authentication, IPSec End System, IPSec Tunnel, IPSec User
+<FONT COLOR=0 STYLE="font-style:normal">51 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">52 </FONT>*/</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000">
+<FONT COLOR=0 STYLE="font-style:normal">53 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>private</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>static</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>byte</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">[] pemCert = (
+<FONT COLOR=0 STYLE="font-style:normal">54 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"-----BEGIN CERTIFICATE-----</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">55 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">56 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">57 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">58 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">59 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">60 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">61 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">62 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">63 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">64 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">65 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">66 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">67 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">68 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">69 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">70 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">71 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">72 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">73 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">74 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">75 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">76 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">77 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">78 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> +
+<FONT COLOR=0 STYLE="font-style:normal">79 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"-----END CERTIFICATE-----</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>\n</B></FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> ).getBytes();
+<FONT COLOR=0 STYLE="font-style:normal">80 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">81 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>public</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>static</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>void</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> main( String[] args ) </FONT>< [...]
+<FONT COLOR=0 STYLE="font-style:normal">82 </FONT> {
+<FONT COLOR=0 STYLE="font-style:normal">83 </FONT> HttpSecureProtocol f = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> HttpSecureProtocol();
+<FONT COLOR=0 STYLE="font-style:normal">84 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">85 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#008000"><I>// might as well trust the usual suspects:</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000">
+<FONT COLOR=0 STYLE="font-style:normal">86 </FONT> f.addTrustMaterial(TrustMaterial.CACERTS);
+<FONT COLOR=0 STYLE="font-style:normal">87 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">88 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#008000"><I>// here's where we start trusting usertrust.com's CA:</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000">
+<FONT COLOR=0 STYLE="font-style:normal">89 </FONT> f.addTrustMaterial(</FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> TrustMaterial( pemCert ));
+<FONT COLOR=0 STYLE="font-style:normal">90 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">91 </FONT> Protocol trustHttps = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> Protocol(</FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"https"</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, f, </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">443</FONT><FONT style="font-family:monospaced;" COLOR="#000000">);
+<FONT COLOR=0 STYLE="font-style:normal">92 </FONT> Protocol.registerProtocol(</FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"https"</FONT><FONT style="font-family:monospaced;" COLOR="#000000">, trustHttps);
+<FONT COLOR=0 STYLE="font-style:normal">93 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">94 </FONT> HttpClient client = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> HttpClient();
+<FONT COLOR=0 STYLE="font-style:normal">95 </FONT> GetMethod httpget = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> GetMethod(</FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"https://www.usertrust.com/"</FONT><FONT style="font-family:monospaced;" COLOR="#000000">);
+<FONT COLOR=0 STYLE="font-style:normal">96 </FONT> client.executeMethod(httpget);
+<FONT COLOR=0 STYLE="font-style:normal">97 </FONT> String s = httpget.getStatusLine().toString();
+<FONT COLOR=0 STYLE="font-style:normal">98 </FONT> System.out.println( </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"HTTPClient: "</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> + s );
+<FONT COLOR=0 STYLE="font-style:normal">99 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">100 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#008000"><I>// Notice that Java still can't access it. Only HTTPClient knows</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000">
+<FONT COLOR=0 STYLE="font-style:normal">101 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#008000"><I>// to trust the cert!</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000">
+<FONT COLOR=0 STYLE="font-style:normal">102 </FONT> URL u = </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>new</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> URL( </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"https://www.usertrust.com/"</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> );
+<FONT COLOR=0 STYLE="font-style:normal">103 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>try</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000">
+<FONT COLOR=0 STYLE="font-style:normal">104 </FONT> {
+<FONT COLOR=0 STYLE="font-style:normal">105 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#008000"><I>// This will throw an SSLHandshakeException</I></FONT><FONT style="font-family:monospaced;" COLOR="#000000">
+<FONT COLOR=0 STYLE="font-style:normal">106 </FONT> u.openStream();
+<FONT COLOR=0 STYLE="font-style:normal">107 </FONT> }
+<FONT COLOR=0 STYLE="font-style:normal">108 </FONT> </FONT><FONT style="font-family:monospaced;" COLOR="#000080"><B>catch</B></FONT><FONT style="font-family:monospaced;" COLOR="#000000"> ( SSLHandshakeException she )
+<FONT COLOR=0 STYLE="font-style:normal">109 </FONT> {
+<FONT COLOR=0 STYLE="font-style:normal">110 </FONT> System.out.println( </FONT><FONT style="font-family:monospaced;" COLOR="#0000ff">"Java: "</FONT><FONT style="font-family:monospaced;" COLOR="#000000"> + she );
+<FONT COLOR=0 STYLE="font-style:normal">111 </FONT> }
+<FONT COLOR=0 STYLE="font-style:normal">112 </FONT> }
+<FONT COLOR=0 STYLE="font-style:normal">113 </FONT>
+<FONT COLOR=0 STYLE="font-style:normal">114 </FONT>}
+<FONT COLOR=0 STYLE="font-style:normal">115 </FONT></FONT></PRE>
+</BODY>
+</HTML>
\ No newline at end of file
diff --git a/docs/about.html b/docs/about.html
new file mode 100644
index 0000000..3b61f22
--- /dev/null
+++ b/docs/about.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta name="Author" content="Julius Davies">
+<title>About Not-Yet-Commons-SSL</title>
+<style type="text/css">
+dl, h1, h2, h3, h4 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl, a.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+.nav a.hl { color: white; }
+dt { padding: 8px 0 8px 5px; }
+li { padding-bottom: 6px; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="index.html" class="hl">main</a> |
+<a href="ssl.html">ssl</a> |
+<a href="pkcs8.html">pkcs8</a> |
+<a href="pbe.html">pbe</a> |
+<a href="rmi.html">rmi</a> |
+<a href="utilities.html">utilities</a> |
+<a href="source.html">source</a> |
+<a href="javadocs/">javadocs</a> |
+<a href="download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>About Not-Yet-Commons-SSL</h2>
+
+<h4 style="margin-top: 1em;">5 Design Goals:</h4>
+<ol>
+<li style="margin-top: 6px;"><b>Make SSL and Java Easier.</b> Ever wanted to work with self-signed
+certificates in your Java application in a secure fashion? Ever wanted to use more than one client
+certificte in a single running JVM? You can edit your <code>$JAVA_HOME/jre/lib/security/cacerts</code>
+file, and you can invoke Java with <code>-Djavax.net.ssl.keyStore=/path/to/keystore</code>. Both of
+these approaches are great at first, but they don't scale well. Do you really want to pollute every
+SSL socket in your JVM (HTTP, LDAP, JDBC, RMI, etc...) with those system-wide changes? Commons-SSL let's you
+control the SSL options you need in an natural way for each SSLSocketFactory, and those options
+won't bleed into the rest of your system.</li>
+<li style="margin-top: 6px;"><b>Improve Security.</b>
+<a href="http://en.wikipedia.org/wiki/Certificate_revocation_list">CRL</a> checking turned on by default.
+We hope to add support for
+<a href="http://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol">OCSP</a> soon!
+It's obnoxious to have to download CRL files around 500KB each from Thawte and Verisign every 24 hours.
+OCSP improves on that.</li>
+<li style="margin-top: 6px;"><b>Improve Flexibility.</b> Checking hostnames, expirations, CRL's, and many
+other options can be enabled/disabled for each SSLSocketFactory created.</li>
+<li style="margin-top: 6px;"><b>Support more file formats, and support these formats more robustly.</b>
+<ul>
+<li>commons-ssl supports over <a href="samples/rsa_result.html">50 formats</a> of PKCS8 and OpenSSL Encrypted Private Keys in PEM or DER</li>
+<li>X.509 Certificates can be PEM or DER encoded. Can also come in PKCS7 chains. (To be fair, Java always supported this.)</li>
+<li>PKCS12 files can be in <a href="samples/pkcs12/pkcs12_client_cert.pem">PEM</a> (as created by <code>openssl pkcs12</code>).</li>
+<li>Parsing of Base64-PEM is more tolerant of extra whitespace or comments, especially outside the Base64 sections:
+<pre style="padding-left: 100px;">any comments or whitespace up here are ignored
+
+-----BEGIN TYPE-----
+[...base64....]
+-----END TYPE-----
+
+any comments or whitespace down here are also ignored</pre></li></ul></li>
+<li><b>Automatically detect type of KeyMaterial or TrustMaterial.</b> Consumer does not need to know
+whether keystore is PKCS12 or JKS. They just need to know the password to decrypt the private key.</li>
+</ol>
+
+</body>
+</html>
\ No newline at end of file
diff --git a/docs/download.html b/docs/download.html
new file mode 100644
index 0000000..9eb706b
--- /dev/null
+++ b/docs/download.html
@@ -0,0 +1,229 @@
+<html>
+<head>
+<title>Not-Yet-Commons-SSL - Downloads, Features, Future Directions</title>
+<style type="text/css">
+dl, h1, h2, h3, h4 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+td.v { text-align: center; }
+dt { padding: 8px 0 8px 5px; }
+dd { padding-left: 15px; }
+li { padding-bottom: 6px; }
+tr.released td, tr.released th { background-color: yellow; font-weight: bold; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="index.html">main</a> |
+<a href="ssl.html">ssl</a> |
+<a href="pkcs8.html">pkcs8</a> |
+<a href="pbe.html">pbe</a> |
+<a href="rmi.html">rmi</a> |
+<a href="utilities.html">utilities</a> |
+<a href="source.html">source</a> |
+<a href="javadocs/">javadocs</a> |
+<span class="hl" href="download.html">download</span>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>Download Not-Yet-Commons-SSL!</em></h2>
+<p>Not-Yet-Commons-SSL currently has NO affiliation with the <a href="http://apache.org/">Apache Software Foundation</a> (apache.org), but we're hoping
+to start <a href="http://incubator.apache.org/incubation/Incubation_Policy.html">Incubation</a> one day.
+<table cellpadding="6" cellspacing="0" border="0" style="margin-top: 9px;">
+<tr><th colspan="3">Current Version (November 14th, 2007):</th></tr>
+<tr><td>Full source:</td><td><a href="/commons-ssl/not-yet-commons-ssl-0.3.9.zip">not-yet-commons-ssl-0.3.9.zip</a></td><td>2.3MB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 8063831d05fc6204a7c0c23a0f86b086</td></tr>
+<tr><td>Binary only:</td><td><a href="/commons-ssl/not-yet-commons-ssl-0.3.9.jar">not-yet-commons-ssl-0.3.9.jar</a></td><td>189KB</td><td><span style="color: red;">Alpha</span></td><td>MD5: </td></tr>
+<tr><th colspan="3">Previous Version (July 4th, 2007):</th></tr>
+<tr><td>Full source:</td><td><a href="/not-yet-commons-ssl-0.3.8/not-yet-commons-ssl-0.3.8.zip">not-yet-commons-ssl-0.3.8.zip</a></td><td>2.3MB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 6c709837f9fef310a69f8659f1697c81</td></tr>
+<tr><td>Binary only:</td><td><a href="/not-yet-commons-ssl-0.3.8/not-yet-commons-ssl-0.3.8.jar">not-yet-commons-ssl-0.3.8.jar</a></td><td>189KB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 34996468b477e3a6c81d7feec213288b</td></tr>
+</table>
+<br/><b>Warning:</b>
+ <span style="color: red; font-weight: bold;">not-yet-commons-ssl-0.3.9 should be considered to be of "Alpha" quality!
+This code probably contains bugs. This code may have security issues.</span>
+<p>Future versions will definitely break the current API in a non-reverse compatible way. After commons-ssl-0.5.0, though, we
+plan on always being reverse compatible with ourselves.
+<hr/>
+<h3>Features as of not-yet-commons-ssl-0.3.9:</h3>
+<dl>
+<dt>1. <a href="pbe.html">PBE</a> is now Compatible with <code>openssl enc -K [key] -iv [IV]</code>.</dt>
+<dd>People were asking for this. See the PBE page for more details.</dd>
+<dt>2. DES2 with PBE was broken.</dt>
+<dd>Fixed.</dd>
+<dt>3. directory.apache.org didn't write the ASN.1 code. BouncyCastle did.</dt>
+<dd>Now using latest ASN.1 parsing code from BC, and attributing it properly.</dd>
+<dt>4. The "ping" utility has a few more options.</dt>
+<dd>For those who need more than just a "HEAD /" request. You can also set the HTTP host header,
+independant of the target host/ip.</dd>
+</dl>
+<br/>
+<h3>Features as of not-yet-commons-ssl-0.3.8:</h3>
+<dl>
+<dt>1. useDefaultJavaCiphers() actually works now.</dt>
+<dd>When you want to allow 40 bit, 56 bit, and MD5 based SSL ciphers, use this. It was 99% functional in 0.3.7, but there was a
+rare situation where setting ciphers was causing SSL handshake errors.</dd>
+<dt>2. <a href="pbe.html">PBE</a> (password-based-encryption) improved.</dt>
+<dd>PBE now has its own <a href="pbe.html">HTML page</a>. Support for all of OpenSSL's PBE ciphers implemented and tested, including
+IDEA and RC5. (DES-X might work, but couldn't find a JCE provider that supported it). Threw in support for some
+additional BouncyCastle ciphers even though OpenSSL doesn't support them (cast6, gost28147, rc6, seed, serpent,
+skipjack, tea, twofish, xtea). Around <a href="samples/pbe/">650 test files</a> created to make sure PBE is working properly.
+</dd>
+<dt>3. PBE API changed on <a href="javadocs/org/apache/commons/ssl/OpenSSL.html#encrypt(java.lang.String,%20char[],%20java.io.InputStream)">OpenSSL.encrypt()</a> and <a href="javadocs/org/apache/commons/ssl/OpenSSL.html#decrypt(java.lang.String,%20char[],%20java.io.InputStream)">OpenSSL.decrypt()</a>.</dt>
+<dd>The password is now char[] instead of byte[] (sorry!). Encrypt/decrypt on byte[] introduced. Encrypt/decrypt on InputStream
+is still available, and is properly streamed so that even extremely large files can be encrypted/decrypted.</dd>
+</dl>
+<br/>
+<h3>Features as of not-yet-commons-ssl-0.3.7:</h3>
+<dl>
+<dt>1. useStrongCiphers() used by default.</dt>
+<dd>40 bit and 56 bit ciphers are now disabled by default. To turn them back on call useDefaultJavaCiphers().</dd>
+<dt>2. addAllowedName() adds some flexibility to the CN verification.</dt>
+<dd>
+Here's a code example using "cucbc.com" to connect, but anticipating "www.cucbc.com" in the server's certificate:
+<pre>
+SSLClient client = new SSLClient();
+client.addAllowedName( "www.cucbc.com" );
+Socket s = client.createSocket( "cucbc.com", 443 );
+</pre>
+This technique is also useful if you don't want to use DNS, and want to
+connect using the IP address.
+</dd>
+<dt>3. SSLServer can re-use a Tomcat-8443 private key if running from inside Tomcat.</dt>
+<dd>
+<pre>
+SSLClient server = new SSLServer();
+server.useTomcatSSLMaterial();
+</pre>
+</dd>
+<dt>4. RMI-SSL support improved.</dt>
+<dd>Attempts to re-use the Tomcat-8443 private key for all RMI SSL Server sockets.
+Anonymous server-sockets (port 0) will always be set to port 31099. Analyzes the
+server certificate CN field and tries to set "java.rmi.server.hostname" to something
+compatible with that. Probably the only free implementation around that does a good
+job on the hostname verification!
+</dd>
+<dt>5. KeyMaterial constructor blows up earlier.</dt>
+<dd>If a JKS or PKCS12 file is provided that isn't going to work (e.g. no private keys),
+the KeyMaterial constructor throws an exception right away.</dd>
+<dt>6. getSSLContext() now available to help inter-op with Java 5 SSL-NIO libraries.</dt>
+<dd>Oleg has been working hard on SSL-NIO for the Apache httpcomponents library. Go
+check it out!</dd>
+<dt>7. Fixed bug where SSLClient couldn't be used with javax.net.ssl.HttpsURLConnection
+on Java 1.4.x</dt>
+<dd>I was wrapping the SSLSocket, but Java 1.4.x guards against that inside HttpsURLConnection
+and throws this exciting exception:
+<pre>
+java.lang.RuntimeException: Export restriction: this JSSE implementation is non-pluggable.
+ at com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl.checkCreate(DashoA6275)
+ at sun.net.www.protocol.https.HttpsClient.afterConnect(DashoA6275)
+ at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(DashoA6275)
+ at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:560)
+ at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(DashoA6275)
+</pre>
+Silly Java - I'm still using <em>your</em> JSSE implementation, I'm just wrapping it!
+</dd>
+</dl>
+<br/>
+<h3>Features as of not-yet-commons-ssl-0.3.4:</h3>
+<dl>
+<dt>1. <code>"javax.net.ssl.keyStore"</code> and <code>"javax.net.ssl.trustStore"</code></dt>
+<dd>SSLClient and SSLServer now set their default TrustMaterial and KeyMaterial from these
+ system properties if they are present.</dd>
+<dt>2. <code>ssl.setCheckCRL( true/false )</code> <em>Note: <a href="http://en.wikipedia.org/wiki/Certificate_revocation_list">CRL</a> is an abbreviation for "Certificate Revocation List"</em></dt>
+<dd>Set to <code>true</code> by default. If you're using SSLClient, then the remote
+server's certificate chain is checked. If you're using SSLServer, CRL checking is ignored <em>unless</em>
+client certificates are presented. Commons-SSL tries to perform the CRL check against each certificate in
+the chain, but we're not sure if we always know the entire chain.
+<p><em>Implementation note:</em>
+To reduce memory consumption all CRL's are saved to disk using
+<code>File.createTempFile()</code> and <code>File.deleteOnExit()</code>.
+CRL's are re-downloaded every 24 hours. To reduce disk IO
+the "pass/fail" result of a CRL check for a given X.509 Certificate is cached using the 20 byte SHA1 hash of the
+certificate as the key. The cached "pass" result is discarded every 24 hours. The cached "fail" result is retained
+until the JVM restarts.
+</p>
+</dd>
+<dt>3. <code>ssl.setCheckExpiry( true/false )</code></dt>
+<dd>Certificate expiry checking can be turned off. Turned on by default. For Java 1.4 and newer we're
+intercepting the CertificateException thrown by the TrustManager. But we still implemented our own
+expiry checking because Java 1.3 doesn't check expiry. We check every certificate in
+the chain, but we're not sure if we always know the entire chain.</dd>
+<dt>4. <code>ssl.setCheckHostname( true/false )</code></dt>
+<dd>Certificate hostname checking improved. Turned on by default for SSLClient, but turned off by
+default for SSLServer. If turned on for SSLServer, only applied to client certificates by checking
+against a reverse DNS lookup of the client's IP address. Turning on for SSLServer will probably be
+quite rare. We imagine that applications (such as Tomcat) will pass the client chain back up into
+the business layer where people can code in any kind of validation logic they like. But we put
+it in anyway to keep things consistent.
+<p>Support added for certificates with wildcards in the CN field
+(e.g. <a href="https://www.credential.com/">*.credential.com</a>).
+Java already had this, to be fair. We broke it
+by accident!
+<pre style="font-style: 90%; padding: 0 30px;">
+s: CN=*.credential.com, OU=Domain Control Validated - RapidSSL(R), OU=See www.rapidssl.com/cps (c)05,
+ OU=businessprofile.geotrust.com/get.jsp?GT27402892, O=*.credential.com, C=CA
+i: CN=Equifax Secure Global eBusiness CA-1, O=Equifax Secure Inc., C=US
+</pre>
+</p>
+</dd>
+<dt>5. PKCS8 support.</dt>
+<dd>Support for OpenSSL "Traditional" and PKCS8 encrypted private keys added.
+Private keys can be RSA or DSA. See our <a href="pkcs8.html">pkcs8 page</a> for more details.</dt>
+<dt>6. New Utility: "<code>KeyStoreBuilder</code>"</dt>
+<dd>Command line utility converts an OpenSSL pair (private key + certificate) into a Java Keystore ("JKS")
+file. To see the command-line options, visit our <a href="utilities.html">utilities page</a>, or just run:
+<pre style="font-style: 90%; padding: 0 30px;">
+java -cp commons-ssl-0.3.4.jar org.apache.commons.ssl.KeyStoreBuilder
+</pre></dd>
+</dl>
+
+<hr/>
+<h3><a name="roadmap">Road Map For Future Versions</a></h3>
+<p>0.3.10 - 0.3.11 are just some feature ideas. They might not be feasible. <b style="background-color: yellow;">0.3.9 is the current version.</b></p>
+<table cellspacing="0" cellpadding="4" border="1">
+<tr><th>Version</th><th>Release Date?</th><th>Description</th></tr>
+<tr><td class="v">0.3.4</td><td class="v">Nov 2006</td><td>90% feature complete. Probably contains some bugs.</td></tr>
+<tr><td class="v">0.3.5</td><td class="v">Dec 2006</td><td>PKCS8Key constructor is public now. Whoops. Hostname verification
+knows about more than just CN's now - also checks subjectAlts in the server's certificate.</td></tr>
+<tr><td class="v">0.3.6</td><td class="v">Jan 2007</td><td>Fixed Java 1.4 bug with HttpsURLConnection.</td></tr>
+<tr><td class="v">0.3.7</td><td class="v">Feb 2007</td><td>40 bit and 56 bit ciphers disabled by default. RMI-SSL improved. getSSLContext() added. Various other improvements.</td></tr>
+<tr class="v"><td class="v">0.3.8</td><td class="v">Nov 2007</td><td>PBE (password-based-encryption) formally introduced and improved. 40 bit and 56 bit ciphers still disabled by default, but working better when re-enabled.</td></tr>
+<tr class="released"><td class="v">0.3.9</td><td class="v">May 2008</td><td>Some PBE fixes. Using latest ASN.1 code from BouncyCastle.</td></tr>
+<tr class="unreleased"><td class="v">0.3.10</td><td class="v">May 2008</td><td>
+<p>
+Socket monitoring. Make it easier for long-running server applications to warn
+about impending certificate expiries.
+</p>
+<p>
+<a href="http://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol">OCSP</a> - Online Certificate Status Protocol
+</p>
+<p>
+NotQuiteSoEasySSLProtocolSocketFactory will trust any server The First Time, and store that server's cert on disk for future accesses.
+</p>
+</td></tr>
+<tr><td class="v">0.3.11</td><td class="v">Jun 2008</td><td><code>TrustMaterial.setAutoReload( true / false )</code>, and <code>KeyMaterial.setAutoReload( true / false )</code>,
+but only if no password, or "changeit" was provided. (Question: should this "reload" tear down all open sockets?).
+</td></tr>
+<tr><td class="v">0.4.0</td><td class="v">Jul 2008</td><td>Non-public code (protected, private, etc) moved into a separate "impl" package where possible.</td></tr>
+<tr><td class="v">0.5.0</td><td class="v">Aug 2008</td><td>API froven. All future versions must be reverse-compatible with 0.5.0 (except for any parts of 0.5.0 later found to be insecure).</td></tr>
+<tr><td class="v">0.7.0</td><td class="v">Nov 2008</td><td>JavaDocs written for all public methods and classes.</td></tr>
+<tr><td class="v">0.7.5</td><td class="v">Mar 2009</td><td>JUnit tests written for all classes.</td></tr>
+<tr><td class="v">0.9.0</td><td class="v">May 2009</td><td>First BETA release. JUnit tests passing on all targetted platforms:
+<ol>
+<li>Intel/AMD: (Sun, IBM, BEA) x (Linux, Mac, Windows) x (1.3, 1.4, 5, 6, 7)</li>
+<li>All of the above with and without BouncyCastle.</li>
+<li>PowerPC: Mac OS X 10.4, 10.5</li>
+<li>Linux: Latest GCJ, Kaffe, and Blackdown releases. BouncyCastle added if necessary to get tests to pass.</li>
+<li>Anyone got an IBM mainframe we can test on?</li>
+</td></tr>
+<tr><td class="v">0.9.1 - 0.9.9</td><td class="v">Aug 2009</td><td>Bug fixes.</td></tr>
+<tr><td class="v">1.0.0</td><td class="v">Jan 2010</td><td>Development mostly stops.</td></tr>
+</table>
+<p>The problem we're solving with Commons-SSL
+is quite small, so I don't see any reason to ever go beyond 1.0.0, except for fixing bugs.</p>
+</body>
+</html>
diff --git a/docs/download.html~ b/docs/download.html~
new file mode 100644
index 0000000..9eb706b
--- /dev/null
+++ b/docs/download.html~
@@ -0,0 +1,229 @@
+<html>
+<head>
+<title>Not-Yet-Commons-SSL - Downloads, Features, Future Directions</title>
+<style type="text/css">
+dl, h1, h2, h3, h4 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+td.v { text-align: center; }
+dt { padding: 8px 0 8px 5px; }
+dd { padding-left: 15px; }
+li { padding-bottom: 6px; }
+tr.released td, tr.released th { background-color: yellow; font-weight: bold; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="index.html">main</a> |
+<a href="ssl.html">ssl</a> |
+<a href="pkcs8.html">pkcs8</a> |
+<a href="pbe.html">pbe</a> |
+<a href="rmi.html">rmi</a> |
+<a href="utilities.html">utilities</a> |
+<a href="source.html">source</a> |
+<a href="javadocs/">javadocs</a> |
+<span class="hl" href="download.html">download</span>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>Download Not-Yet-Commons-SSL!</em></h2>
+<p>Not-Yet-Commons-SSL currently has NO affiliation with the <a href="http://apache.org/">Apache Software Foundation</a> (apache.org), but we're hoping
+to start <a href="http://incubator.apache.org/incubation/Incubation_Policy.html">Incubation</a> one day.
+<table cellpadding="6" cellspacing="0" border="0" style="margin-top: 9px;">
+<tr><th colspan="3">Current Version (November 14th, 2007):</th></tr>
+<tr><td>Full source:</td><td><a href="/commons-ssl/not-yet-commons-ssl-0.3.9.zip">not-yet-commons-ssl-0.3.9.zip</a></td><td>2.3MB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 8063831d05fc6204a7c0c23a0f86b086</td></tr>
+<tr><td>Binary only:</td><td><a href="/commons-ssl/not-yet-commons-ssl-0.3.9.jar">not-yet-commons-ssl-0.3.9.jar</a></td><td>189KB</td><td><span style="color: red;">Alpha</span></td><td>MD5: </td></tr>
+<tr><th colspan="3">Previous Version (July 4th, 2007):</th></tr>
+<tr><td>Full source:</td><td><a href="/not-yet-commons-ssl-0.3.8/not-yet-commons-ssl-0.3.8.zip">not-yet-commons-ssl-0.3.8.zip</a></td><td>2.3MB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 6c709837f9fef310a69f8659f1697c81</td></tr>
+<tr><td>Binary only:</td><td><a href="/not-yet-commons-ssl-0.3.8/not-yet-commons-ssl-0.3.8.jar">not-yet-commons-ssl-0.3.8.jar</a></td><td>189KB</td><td><span style="color: red;">Alpha</span></td><td>MD5: 34996468b477e3a6c81d7feec213288b</td></tr>
+</table>
+<br/><b>Warning:</b>
+ <span style="color: red; font-weight: bold;">not-yet-commons-ssl-0.3.9 should be considered to be of "Alpha" quality!
+This code probably contains bugs. This code may have security issues.</span>
+<p>Future versions will definitely break the current API in a non-reverse compatible way. After commons-ssl-0.5.0, though, we
+plan on always being reverse compatible with ourselves.
+<hr/>
+<h3>Features as of not-yet-commons-ssl-0.3.9:</h3>
+<dl>
+<dt>1. <a href="pbe.html">PBE</a> is now Compatible with <code>openssl enc -K [key] -iv [IV]</code>.</dt>
+<dd>People were asking for this. See the PBE page for more details.</dd>
+<dt>2. DES2 with PBE was broken.</dt>
+<dd>Fixed.</dd>
+<dt>3. directory.apache.org didn't write the ASN.1 code. BouncyCastle did.</dt>
+<dd>Now using latest ASN.1 parsing code from BC, and attributing it properly.</dd>
+<dt>4. The "ping" utility has a few more options.</dt>
+<dd>For those who need more than just a "HEAD /" request. You can also set the HTTP host header,
+independant of the target host/ip.</dd>
+</dl>
+<br/>
+<h3>Features as of not-yet-commons-ssl-0.3.8:</h3>
+<dl>
+<dt>1. useDefaultJavaCiphers() actually works now.</dt>
+<dd>When you want to allow 40 bit, 56 bit, and MD5 based SSL ciphers, use this. It was 99% functional in 0.3.7, but there was a
+rare situation where setting ciphers was causing SSL handshake errors.</dd>
+<dt>2. <a href="pbe.html">PBE</a> (password-based-encryption) improved.</dt>
+<dd>PBE now has its own <a href="pbe.html">HTML page</a>. Support for all of OpenSSL's PBE ciphers implemented and tested, including
+IDEA and RC5. (DES-X might work, but couldn't find a JCE provider that supported it). Threw in support for some
+additional BouncyCastle ciphers even though OpenSSL doesn't support them (cast6, gost28147, rc6, seed, serpent,
+skipjack, tea, twofish, xtea). Around <a href="samples/pbe/">650 test files</a> created to make sure PBE is working properly.
+</dd>
+<dt>3. PBE API changed on <a href="javadocs/org/apache/commons/ssl/OpenSSL.html#encrypt(java.lang.String,%20char[],%20java.io.InputStream)">OpenSSL.encrypt()</a> and <a href="javadocs/org/apache/commons/ssl/OpenSSL.html#decrypt(java.lang.String,%20char[],%20java.io.InputStream)">OpenSSL.decrypt()</a>.</dt>
+<dd>The password is now char[] instead of byte[] (sorry!). Encrypt/decrypt on byte[] introduced. Encrypt/decrypt on InputStream
+is still available, and is properly streamed so that even extremely large files can be encrypted/decrypted.</dd>
+</dl>
+<br/>
+<h3>Features as of not-yet-commons-ssl-0.3.7:</h3>
+<dl>
+<dt>1. useStrongCiphers() used by default.</dt>
+<dd>40 bit and 56 bit ciphers are now disabled by default. To turn them back on call useDefaultJavaCiphers().</dd>
+<dt>2. addAllowedName() adds some flexibility to the CN verification.</dt>
+<dd>
+Here's a code example using "cucbc.com" to connect, but anticipating "www.cucbc.com" in the server's certificate:
+<pre>
+SSLClient client = new SSLClient();
+client.addAllowedName( "www.cucbc.com" );
+Socket s = client.createSocket( "cucbc.com", 443 );
+</pre>
+This technique is also useful if you don't want to use DNS, and want to
+connect using the IP address.
+</dd>
+<dt>3. SSLServer can re-use a Tomcat-8443 private key if running from inside Tomcat.</dt>
+<dd>
+<pre>
+SSLClient server = new SSLServer();
+server.useTomcatSSLMaterial();
+</pre>
+</dd>
+<dt>4. RMI-SSL support improved.</dt>
+<dd>Attempts to re-use the Tomcat-8443 private key for all RMI SSL Server sockets.
+Anonymous server-sockets (port 0) will always be set to port 31099. Analyzes the
+server certificate CN field and tries to set "java.rmi.server.hostname" to something
+compatible with that. Probably the only free implementation around that does a good
+job on the hostname verification!
+</dd>
+<dt>5. KeyMaterial constructor blows up earlier.</dt>
+<dd>If a JKS or PKCS12 file is provided that isn't going to work (e.g. no private keys),
+the KeyMaterial constructor throws an exception right away.</dd>
+<dt>6. getSSLContext() now available to help inter-op with Java 5 SSL-NIO libraries.</dt>
+<dd>Oleg has been working hard on SSL-NIO for the Apache httpcomponents library. Go
+check it out!</dd>
+<dt>7. Fixed bug where SSLClient couldn't be used with javax.net.ssl.HttpsURLConnection
+on Java 1.4.x</dt>
+<dd>I was wrapping the SSLSocket, but Java 1.4.x guards against that inside HttpsURLConnection
+and throws this exciting exception:
+<pre>
+java.lang.RuntimeException: Export restriction: this JSSE implementation is non-pluggable.
+ at com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl.checkCreate(DashoA6275)
+ at sun.net.www.protocol.https.HttpsClient.afterConnect(DashoA6275)
+ at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(DashoA6275)
+ at sun.net.www.protocol.http.HttpURLConnection.getOutputStream(HttpURLConnection.java:560)
+ at sun.net.www.protocol.https.HttpsURLConnectionImpl.getOutputStream(DashoA6275)
+</pre>
+Silly Java - I'm still using <em>your</em> JSSE implementation, I'm just wrapping it!
+</dd>
+</dl>
+<br/>
+<h3>Features as of not-yet-commons-ssl-0.3.4:</h3>
+<dl>
+<dt>1. <code>"javax.net.ssl.keyStore"</code> and <code>"javax.net.ssl.trustStore"</code></dt>
+<dd>SSLClient and SSLServer now set their default TrustMaterial and KeyMaterial from these
+ system properties if they are present.</dd>
+<dt>2. <code>ssl.setCheckCRL( true/false )</code> <em>Note: <a href="http://en.wikipedia.org/wiki/Certificate_revocation_list">CRL</a> is an abbreviation for "Certificate Revocation List"</em></dt>
+<dd>Set to <code>true</code> by default. If you're using SSLClient, then the remote
+server's certificate chain is checked. If you're using SSLServer, CRL checking is ignored <em>unless</em>
+client certificates are presented. Commons-SSL tries to perform the CRL check against each certificate in
+the chain, but we're not sure if we always know the entire chain.
+<p><em>Implementation note:</em>
+To reduce memory consumption all CRL's are saved to disk using
+<code>File.createTempFile()</code> and <code>File.deleteOnExit()</code>.
+CRL's are re-downloaded every 24 hours. To reduce disk IO
+the "pass/fail" result of a CRL check for a given X.509 Certificate is cached using the 20 byte SHA1 hash of the
+certificate as the key. The cached "pass" result is discarded every 24 hours. The cached "fail" result is retained
+until the JVM restarts.
+</p>
+</dd>
+<dt>3. <code>ssl.setCheckExpiry( true/false )</code></dt>
+<dd>Certificate expiry checking can be turned off. Turned on by default. For Java 1.4 and newer we're
+intercepting the CertificateException thrown by the TrustManager. But we still implemented our own
+expiry checking because Java 1.3 doesn't check expiry. We check every certificate in
+the chain, but we're not sure if we always know the entire chain.</dd>
+<dt>4. <code>ssl.setCheckHostname( true/false )</code></dt>
+<dd>Certificate hostname checking improved. Turned on by default for SSLClient, but turned off by
+default for SSLServer. If turned on for SSLServer, only applied to client certificates by checking
+against a reverse DNS lookup of the client's IP address. Turning on for SSLServer will probably be
+quite rare. We imagine that applications (such as Tomcat) will pass the client chain back up into
+the business layer where people can code in any kind of validation logic they like. But we put
+it in anyway to keep things consistent.
+<p>Support added for certificates with wildcards in the CN field
+(e.g. <a href="https://www.credential.com/">*.credential.com</a>).
+Java already had this, to be fair. We broke it
+by accident!
+<pre style="font-style: 90%; padding: 0 30px;">
+s: CN=*.credential.com, OU=Domain Control Validated - RapidSSL(R), OU=See www.rapidssl.com/cps (c)05,
+ OU=businessprofile.geotrust.com/get.jsp?GT27402892, O=*.credential.com, C=CA
+i: CN=Equifax Secure Global eBusiness CA-1, O=Equifax Secure Inc., C=US
+</pre>
+</p>
+</dd>
+<dt>5. PKCS8 support.</dt>
+<dd>Support for OpenSSL "Traditional" and PKCS8 encrypted private keys added.
+Private keys can be RSA or DSA. See our <a href="pkcs8.html">pkcs8 page</a> for more details.</dt>
+<dt>6. New Utility: "<code>KeyStoreBuilder</code>"</dt>
+<dd>Command line utility converts an OpenSSL pair (private key + certificate) into a Java Keystore ("JKS")
+file. To see the command-line options, visit our <a href="utilities.html">utilities page</a>, or just run:
+<pre style="font-style: 90%; padding: 0 30px;">
+java -cp commons-ssl-0.3.4.jar org.apache.commons.ssl.KeyStoreBuilder
+</pre></dd>
+</dl>
+
+<hr/>
+<h3><a name="roadmap">Road Map For Future Versions</a></h3>
+<p>0.3.10 - 0.3.11 are just some feature ideas. They might not be feasible. <b style="background-color: yellow;">0.3.9 is the current version.</b></p>
+<table cellspacing="0" cellpadding="4" border="1">
+<tr><th>Version</th><th>Release Date?</th><th>Description</th></tr>
+<tr><td class="v">0.3.4</td><td class="v">Nov 2006</td><td>90% feature complete. Probably contains some bugs.</td></tr>
+<tr><td class="v">0.3.5</td><td class="v">Dec 2006</td><td>PKCS8Key constructor is public now. Whoops. Hostname verification
+knows about more than just CN's now - also checks subjectAlts in the server's certificate.</td></tr>
+<tr><td class="v">0.3.6</td><td class="v">Jan 2007</td><td>Fixed Java 1.4 bug with HttpsURLConnection.</td></tr>
+<tr><td class="v">0.3.7</td><td class="v">Feb 2007</td><td>40 bit and 56 bit ciphers disabled by default. RMI-SSL improved. getSSLContext() added. Various other improvements.</td></tr>
+<tr class="v"><td class="v">0.3.8</td><td class="v">Nov 2007</td><td>PBE (password-based-encryption) formally introduced and improved. 40 bit and 56 bit ciphers still disabled by default, but working better when re-enabled.</td></tr>
+<tr class="released"><td class="v">0.3.9</td><td class="v">May 2008</td><td>Some PBE fixes. Using latest ASN.1 code from BouncyCastle.</td></tr>
+<tr class="unreleased"><td class="v">0.3.10</td><td class="v">May 2008</td><td>
+<p>
+Socket monitoring. Make it easier for long-running server applications to warn
+about impending certificate expiries.
+</p>
+<p>
+<a href="http://en.wikipedia.org/wiki/Online_Certificate_Status_Protocol">OCSP</a> - Online Certificate Status Protocol
+</p>
+<p>
+NotQuiteSoEasySSLProtocolSocketFactory will trust any server The First Time, and store that server's cert on disk for future accesses.
+</p>
+</td></tr>
+<tr><td class="v">0.3.11</td><td class="v">Jun 2008</td><td><code>TrustMaterial.setAutoReload( true / false )</code>, and <code>KeyMaterial.setAutoReload( true / false )</code>,
+but only if no password, or "changeit" was provided. (Question: should this "reload" tear down all open sockets?).
+</td></tr>
+<tr><td class="v">0.4.0</td><td class="v">Jul 2008</td><td>Non-public code (protected, private, etc) moved into a separate "impl" package where possible.</td></tr>
+<tr><td class="v">0.5.0</td><td class="v">Aug 2008</td><td>API froven. All future versions must be reverse-compatible with 0.5.0 (except for any parts of 0.5.0 later found to be insecure).</td></tr>
+<tr><td class="v">0.7.0</td><td class="v">Nov 2008</td><td>JavaDocs written for all public methods and classes.</td></tr>
+<tr><td class="v">0.7.5</td><td class="v">Mar 2009</td><td>JUnit tests written for all classes.</td></tr>
+<tr><td class="v">0.9.0</td><td class="v">May 2009</td><td>First BETA release. JUnit tests passing on all targetted platforms:
+<ol>
+<li>Intel/AMD: (Sun, IBM, BEA) x (Linux, Mac, Windows) x (1.3, 1.4, 5, 6, 7)</li>
+<li>All of the above with and without BouncyCastle.</li>
+<li>PowerPC: Mac OS X 10.4, 10.5</li>
+<li>Linux: Latest GCJ, Kaffe, and Blackdown releases. BouncyCastle added if necessary to get tests to pass.</li>
+<li>Anyone got an IBM mainframe we can test on?</li>
+</td></tr>
+<tr><td class="v">0.9.1 - 0.9.9</td><td class="v">Aug 2009</td><td>Bug fixes.</td></tr>
+<tr><td class="v">1.0.0</td><td class="v">Jan 2010</td><td>Development mostly stops.</td></tr>
+</table>
+<p>The problem we're solving with Commons-SSL
+is quite small, so I don't see any reason to ever go beyond 1.0.0, except for fixing bugs.</p>
+</body>
+</html>
diff --git a/docs/index.html b/docs/index.html
new file mode 100644
index 0000000..eafed68
--- /dev/null
+++ b/docs/index.html
@@ -0,0 +1,110 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta name="Author" content="Julius Davies">
+<title>Java and SSL/TLS Made Easier - Not-Yet-Commons-SSL</title>
+<meta name="description" content="Java library for controlling aspects of SSL. Also helps interop between Java and OpenSSL."/>
+<meta name="keywords" content="Java, SSL, TLS, OpenSSL, HTTPS, Certificates, X.509, X509, Secure Socket Layer, Transport Layer Security, Client Auth, Client Certificate, Client Cert, Client Certificates, Server Cert, Server Certificate, Server Certificates"/>
+<style type="text/css">
+dl, h1, h2, h3, h4 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+dt { padding: 8px 0 8px 5px; }
+li { padding-bottom: 6px; }
+th { text-align: right; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<span class="hl">main</span> |
+<a href="ssl.html">ssl</a> |
+<a href="pkcs8.html">pkcs8</a> |
+<a href="pbe.html">pbe</a> |
+<a href="rmi.html">rmi</a> |
+<a href="utilities.html">utilities</a> |
+<a href="source.html">source</a> |
+<a href="javadocs/">javadocs</a> |
+<a href="download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>Not-Yet-Commons-SSL</h2>
+<p><a href="download.html">not-yet-commons-ssl-0.3.9</a> released! (November 14th, 2007)</p>
+<p>Requires Java 1.3.x or higher.
+<br/>Some features require Java 1.4.x or higher. (<a href="rmi.html">RMI-SSL</a>, for example).</p>
+<p>Please see our <a href="ssl.html">ssl page</a> for code examples on how to use this library.</a></p>
+
+<h3>Resources:</h3>
+<table border="0" cellpadding="5" cellspacing="5">
+<tr>
+ <th>Design Goals:</th>
+ <td><a href="about.html">about.html</a></td>
+</tr>
+<tr>
+ <th>Code Examples:</th>
+ <td><a href="ssl.html">SSL/TLS</a> | <a href="pkcs8.html">PKCS #8</a> | <a href="pbe.html">PBE</a></td>
+</tr>
+<tr>
+ <th>Join Mailing List:</th>
+ <td><a href="http://lists.juliusdavies.ca/listinfo.cgi/not-yet-commons-ssl-juliusdavies.ca/">http://lists.juliusdavies.ca/listinfo.cgi/not-yet-commons-ssl-juliusdavies.ca/</a></td>
+</tr>
+<tr>
+ <th>Mailing List Archives:</th>
+ <td><a href="http://lists.juliusdavies.ca/pipermail/not-yet-commons-ssl-juliusdavies.ca/">http://lists.juliusdavies.ca/pipermail/not-yet-commons-ssl-juliusdavies.ca/</a></td>
+</tr>
+<tr>
+ <th>Downloads:</th>
+ <td><a href="download.html">http://juliusdavies.ca/commons-ssl/download.html</a></td>
+</tr>
+<tr>
+ <th>Checkout From Subversion:</th>
+ <td><code>svn co <a style="text-decoration: none;" href="http://juliusdavies.ca/svn/not-yet-commons-ssl/trunk">http://juliusdavies.ca/svn/not-yet-commons-ssl/trunk</a> not-yet-commons-ssl</code></td>
+</tr>
+<tr>
+ <th>Browse Subversion (via viewvc):</th>
+ <td><a href="http://juliusdavies.ca/svn/viewvc.cgi">http://juliusdavies.ca/svn/not-yet-commons-ssl/viewvc.cgi</a></td>
+</tr>
+<tr>
+ <th>License (Apache 2.0):</th>
+ <td><a href="../LICENSE.txt">LICENSE.txt</a></td>
+</tr>
+</table>
+<hr/>
+<h4>About</h4>
+<p>We're calling this library "Not-Yet-Commons-SSL" since we have the intention of one day
+becoming an official Apache project. Not-Yet-Commons-SSL was originally developed by
+<a href="https://www.cucbc.com">Credit Union Central of British Columbia</a>.
+The webpages, releases, and code here on <a href="http://juliusdavies.ca/">juliusdavies.ca</a> have no relationship to
+the Apache Software Foundation, but all code is licensed under <a href="LICENSE.txt">ASL 2.0</a>.
+</p>
+<p>The <a href="http://juliusdavies.ca/svn/viewvc.cgi/trunk/src/java/org/apache/commons/ssl/asn1/">ASN.1 parsing code</a>
+comes directly from BouncyCastle (<a href="http://bouncycastle.org/">bouncycastle.org</a>). Our only modification to this
+code was an accidental "reformat" to bring it inline with our code style. Also, in two places, we switched the BC code
+to use <em>our</em> Hex.java
+for encoding/decoding instead of their own.
+The PKCS12 key derivation function (for some PKCS8 version 1.5 encrypted keys) also comes from BouncyCastle.
+Presumably they got it from RSA's PKCS12 specification
+(<a href="ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf">ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1.pdf</a>).
+BouncyCastle maintains copyright over all the code used, but allows us to reuse and redistribute
+(the BouncyCastle license is compatible with ASL 2.0). We are very thankful for their excellent code.
+</p>
+
+<p>Not-Yet-Commons-SSL would never have happened without Oleg Kalnichevski's excellent
+"<a href="http://svn.apache.org/viewvc/jakarta/httpcomponents/oac.hc3x/trunk/src/contrib/org/apache/commons/httpclient/contrib/ssl/">contrib</a>"
+example in the <a href="http://jakarta.apache.org/httpcomponents/">HttpComponents</a> SVN repository.
+His
+<a href="http://svn.apache.org/viewvc/jakarta/httpcomponents/oac.hc3x/trunk/src/contrib/org/apache/commons/httpclient/contrib/ssl/AuthSSLProtocolSocketFactory.java?view=markup">AuthSSLProtocolSocketFactory.java</a>
+and
+<a href="http://svn.apache.org/viewvc/jakarta/httpcomponents/oac.hc3x/trunk/src/contrib/org/apache/commons/httpclient/contrib/ssl/AuthSSLX509TrustManager.java?view=markup">AuthSSLX509TrustManager.java</a>
+examples
+were the seeds for all of this. Evil Comrade Oleg's Javadocs on those classes were also extremely helpful. We
+only one day hope that we can write Javadocs like that (hopefully by <a href="download.html#roadmap">0.7.0</a>!).
+</p>
+</body>
+</html>
diff --git a/docs/pbe.html b/docs/pbe.html
new file mode 100644
index 0000000..eab326a
--- /dev/null
+++ b/docs/pbe.html
@@ -0,0 +1,204 @@
+<html>
+<head>
+<title>OpenSSL's "enc" in Java (PBE / Password Based Encryption)</title>
+<style type="text/css">
+h1, h2, h3 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+li.top { margin-top: 10px; }
+li { margin-top: 6px; width: 750px; }
+ul.openssl { float: left; width: 100px; margin-top: 8px; }
+ul.pkcs8 { float: left; width: 200px; margin-top: 8px; }
+i { color: purple; }
+i.special { color: red; }
+dt { font-weight: bold; }
+dd { margin-top: 1em; margin-bottom: 1em; }
+sup a { text-decoration: none; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="index.html">main</a> |
+<a href="ssl.html">ssl</a> |
+<a href="pkcs8.html">pkcs8</a> |
+<span class="hl" href="pbe.html">pbe</span> |
+<a href="rmi.html">rmi</a> |
+<a href="utilities.html">utilities</a> |
+<a href="source.html">source</a> |
+<a href="javadocs/">javadocs</a> |
+<a href="download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>OpenSSL's "enc" in Java (PBE / Password Based Encryption)</h2>
+<p>Not-Yet-Commons-SSL has an implementation of PBE ("password based encryption") that is 100%
+compatible with OpenSSL's command-line "enc" utility. PBE is a form of symmetric encryption where
+the same key or password is used to encrypt and decrypt the file.
+</p>
+<p>
+We are also compatible with <code>openssl enc -K [key] -iv [IV]</code>, where the key and IV are provided explicitly,
+instead of being derived from a password. Look for encrypt()/decrypt() methods that take
+<a href="http://juliusdavies.ca/commons-ssl/javadocs/org/apache/commons/ssl/OpenSSL.html#encrypt(java.lang.String,%20byte[],%20byte[],%20byte[])">byte[] key, byte[] iv</a>
+instead of char[] password.
+
+</p>
+<p>Please visit the <a href="#Quick-FAQ">Quick-FAQ</a> if you are having problems.</p>
+
+
+<pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>PBE code example (DES-3):</b></u><sup><a href="#fn">*</a></sup>
+
+char[] password = {'c','h','a','n','g','e','i','t'};
+byte[] data = "Hello World!".getBytes();
+
+<em style="color: green;">// Encrypt!</em>
+byte[] encrypted = OpenSSL.encrypt("des3", password, data);
+System.out.println("ENCRYPTED: [" + new String(encrypted) + "]");
+
+<em style="color: green;">// Decrypt results of previous!</em>
+data = OpenSSL.decrypt("des3", password, encrypted);
+System.out.println("DECRYPTED: [" + new String(data) + "]");
+
+
+OUTPUT:
+=======================
+ENCRYPTED: [U2FsdGVkX19qplb9qVDVVEYxH8wjJDGpMS+F4/2pS2c=]
+DECRYPTED: [Hello World!]
+
+<sup><a name="fn">*</a></sup> <span style="font-size: 85%;">- This code example is <a href="#nqr">not quite right</a>.</span>
+</pre>
+<br clear="all"/>
+<p>Some notes:
+<ul>
+ <li>The OpenSSL.encrypt() and OpenSSL.decrypt() methods have InputStream and byte[] versions. For large
+ files you're going to have to use the InputStream versions.</li>
+ <li>OpenSSL.encrypt() produces base64 output by default. Use
+<a href="http://juliusdavies.ca/commons-ssl/javadocs/org/apache/commons/ssl/OpenSSL.html#encrypt(java.lang.String,%20char[],%20byte[],%20boolean)">OpenSSL.encrypt(alg, pwd, data, false)</a>
+ to turn that off.</li>
+ <li>OpenSSL.decrypt() auto-detects whether input is base64 or raw binary, so you don't need to worry about it
+ when decrypting. The base64 "true/false" parameter is only applicable when encrypting.</li>
+ <li>We also have methods that are compatible with "<code>openssl enc -K [key] -iv [IV]</code>" where key and iv
+ are explicitly provided, rather than being derived from a password. The [key] and [IV] should be specified
+ in either raw binary, or hexidecimal (4 bits per character). This isn't really PBE anymore, but it's a
+ common use case.</li>
+</ul>
+</p>
+
+<p>Here's a list of supported OpenSSL ciphers. The <i>purple ones</i> require the <a href="http://www.bouncycastle.org/latest_releases.html">BouncyCastle JCE</a>.
+The <i class="special">red ones (desx, desx-cbc)</i> probably require RSA's <a href="http://www.rsa.com/node.aspx?id=1204">BSAFE JCE</a>,
+and have not been tested.
+</p>
+<pre>
+aes-128-cbc aes-128-cfb <!-- aes-128-cfb1 -->
+aes-128-cfb8 aes-128-ecb aes-128-ofb
+aes-192-cbc aes-192-cfb <!-- aes-192-cfb1 -->
+aes-192-cfb8 aes-192-ecb aes-192-ofb
+aes-256-cbc aes-256-cfb <!-- aes-256-cfb1 -->
+aes-256-cfb8 aes-256-ecb aes-256-ofb
+aes128 aes192 aes256
+bf bf-cbc bf-cfb
+bf-ecb bf-ofb blowfish
+<i>camellia-128-cbc</i> <i>camellia-128-cfb</i> <!-- <i>camellia-128-cfb1</i> -->
+<i>camellia-128-cfb8</i> <i>camellia-128-ecb</i> <i>camellia-128-ofb</i>
+<i>camellia-192-cbc</i> <i>camellia-192-cfb</i> <!-- <i>camellia-192-cfb1</i> -->
+<i>camellia-192-cfb8</i> <i>camellia-192-ecb</i> <i>camellia-192-ofb</i>
+<i>camellia-256-cbc</i> <i>camellia-256-cfb</i> <!-- <i>camellia-256-cfb1</i> -->
+<i>camellia-256-cfb8</i> <i>camellia-256-ecb</i> <i>camellia-256-ofb</i>
+<i>camellia128</i> <i>camellia192</i> <i>camellia256</i>
+<i>cast</i> <i>cast-cbc</i> <i>cast5-cbc</i>
+<i>cast5-cfb</i> <i>cast5-ecb</i> <i>cast5-ofb</i>
+des des-cbc des-cfb
+<!-- des-cfb1 --> des-cfb8 des-ecb
+des-ede des-ede-cbc des-ede-cfb
+des-ede-ofb des-ede3 des-ede3-cbc
+des-ede3-cfb des-ede3-ofb des-ofb
+des3 <i class="special">desx</i> <i class="special">desx-cbc</i>
+<i>idea</i> <i>idea-cbc</i> <i>idea-cfb</i>
+<i>idea-ecb</i> <i>idea-ofb</i> rc2
+rc2-40-cbc rc2-64-cbc rc2-cbc
+rc2-cfb rc2-ecb rc2-ofb
+rc4 rc4-40 <i>rc5</i>
+<i>rc5-cbc</i> <i>rc5-cfb</i> <i>rc5-ecb</i>
+<i>rc5-ofb</i>
+</pre>
+
+<p>Here are some additional ciphers supported by BouncyCastle, but not by OpenSSL:</p>
+<pre>
+<i>cast6</i>
+<i>gost</i> (aka: <i>gost28147</i>)
+<i>rc6</i>
+<i>seed</i>
+<i>serpent</i>
+<i>skipjack</i>
+<i>tea</i>
+<i>twofish</i>
+<i>xtea</i>
+</pre>
+
+<hr/>
+<h3><a name="Quick-FAQ">Quick FAQ about PBE and Java</a></h3>
+<hr/>
+<dl>
+<dt>Why do I keep getting "java.security.InvalidKeyException: Illegal key size"?</dt>
+<dd>
+Don't forget to install your JVM's Unlimited Strength
+Jurisdiction Policy Files if you want AES-192 and AES-256 to work. (Same is true
+for Camillia-192, Camellia-256, and GOST28147).
+
+Visit <a href="http://java.sun.com/javase/downloads/">http://java.sun.com/javase/downloads/</a>
+and scroll to the bottom:
+<blockquote>
+Other Downloads
+<br/>Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 6
+</blockquote>
+You can use DES-3 (168 bit keys) without
+installing the extra policy files.
+</dd>
+<dt>Why do the encrypted files always start with "Salted__" ("U2FsdGVkX1" in base64)?
+Isn't giving away information like this insecure?</dt>
+<dd>
+The encrypted files must always start with "Salted__" to interoperate with OpenSSL.
+OpenSSL expects this. The 8 bytes that spell "Salted__" are always immediately followed
+by another random 8 bytes of salt. The encrypted stream starts at the 17th byte.
+This way, even if you use the same password to encrypt 2 different files, the actual
+secret keys used to encrypt these 2 files are very different.
+<br/>
+<br/>
+It is possible to omit the salt, but this is highly discouraged:
+
+<pre style="padding: 10px; float: left;">
+boolean useBase64 = true;
+boolean useSalt = false; <em style="color: green;">// Omitting the salt is bad for security!</em>
+byte[] result = <a href="http://juliusdavies.ca/commons-ssl/javadocs/org/apache/commons/ssl/OpenSSL.html#encrypt(java.lang.String,%20char[],%20byte[],%20boolean,%20boolean)">OpenSSL.encrypt(alg, pwd, data, useBase64, useSalt);</a>
+</pre>
+<br clear="all"/>
+</dd>
+<dt><a name="nqr">Why</a> is code example above "not quite right"?</dt>
+<dd>It relies on the platform's default character set. Here is the proper version (forcing UTF-8):
+
+<pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>PBE example (DES-3):</b></u>
+
+char[] password = {'c','h','a','n','g','e','i','t'};
+byte[] data = "Hello World!".getBytes("UTF-8");
+
+<em style="color: green;">// Encrypt!</em>
+byte[] encrypted = OpenSSL.encrypt("des3", password, data);
+System.out.println("ENCRYPTED: [" + new String(encrypted, "UTF-8") + "]");
+
+<em style="color: green;">// Decrypt results of previous!</em>
+data = OpenSSL.decrypt("des3", password, encrypted);
+System.out.println("DECRYPTED: [" + new String(data, "UTF-8") + "]");
+
+OUTPUT:
+======================
+ENCRYPTED: [U2FsdGVkX19qplb9qVDVVEYxH8wjJDGpMS+F4/2pS2c=]
+DECRYPTED: [Hello World!]
+</pre>
+</dd>
+</dl>
+</body>
+</html>
diff --git a/docs/ping.html b/docs/ping.html
new file mode 100644
index 0000000..9be48fd
--- /dev/null
+++ b/docs/ping.html
@@ -0,0 +1,92 @@
+<html>
+<head>
+<title>Commons-SSL - Utilities</title>
+<style type="text/css">
+h1, h2, h3 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+li.top { margin-top: 10px; }
+ul.openssl { float: left; width: 100px; margin-top: 8px; }
+ul.pkcs8 { float: left; width: 200px; margin-top: 8px; }
+</style>
+</head>
+<body>
+<h1>commons-ssl</h1>
+<div class="nav">
+<a href="index.html">main</a> |
+<a href="ssl.html">ssl</a> |
+<a href="pkcs8.html">pkcs8</a> |
+<a href="pbe.html">pbe</a> |
+<a href="rmi.html">rmi</a> |
+<span class="hl" href="utilities.html">utilities</span> |
+<a href="source.html">source</a> |
+<a href="javadocs/">javadocs</a> |
+<a href="download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>Ping</h2>
+
+<p>"org.apache.commons.ssl.Ping" contains a main method to help you diagnose SSL issues.
+It's modeled on OpenSSL's very handy "s_client" utility. We've been very careful to
+make sure "org.apache.commons.ssl.Ping" can execute without any additional jar files
+on the classpath (except if using Java 1.3 - then you'll need jsse.jar).</p>
+
+<pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>"Ping" Utility Attempts "HEAD / HTTP/1.1" Request</b></u>
+This utility is very handy because it can get you the server's public
+certificate even if your client certificate is bad (so even though the SSL
+handshake fails). And unlike "openssl s_client", this utility can bind
+against any IP address available.
+
+$Name: commons-ssl-0_3_8 $ compiled=[EST:2007-02-22/10:12:26.000]
+Usage: java -jar not-yet-commons-ssl-0.3.7.jar [options]
+Options: (*=required)
+* -t --target [hostname[:port]] default port=443
+ -b --bind [hostname[:port]] default port=0 "ANY"
+ -r --proxy [hostname[:port]] default port=80
+ -tm --trust-cert [path to trust material] *.{pem, der, crt, jks}
+ -km --client-cert [path to client's private key] *.{jks, pkcs12, pkcs8}
+ -cc --cert-chain [path to client's cert chain if using pkcs8/OpenSSL key]
+ -p --password [client cert password]
+
+Example:
+
+java -jar commons-ssl.jar -t cucbc.com:443 -c ./client.pfx -p `cat ./pass.txt`</pre><br clear="all"/>
+
+<p style="margin-top: 8px;"><b>TODO:</b><br/>Apparently Java 6.0 includes support for grabbing passwords from
+standard-in without echoing the typed characters. Would be nice to use that feature when it's
+available, instead of requiring the password to be specified as a command-line argument.</p>
+
+<hr/>
+<h2>KeyStoreBuilder</em></h2>
+<p><code>java -cp commons-ssl-0.3.7.jar org.apache.commons.ssl.KeyStoreBuilder</code></p>
+
+<pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>KeyStoreBuilder converts PKCS12 and PKCS8 to Java "Keystore", and vice versa.</b></u>
+
+KeyStoreBuilder: creates '[alias].jks' (Java Key Store)
+ -topk8 mode: creates '[alias].pem' (x509 chain + unencrypted pkcs8)
+[alias] will be set to the first CN value of the X509 certificate.
+-------------------------------------------------------------------
+Usage1: [password] [file:pkcs12]
+Usage2: [password] [file:private-key] [file:certificate-chain]
+Usage3: -topk8 [password] [file:jks]
+-------------------------------------------------------------------
+[private-key] can be openssl format, or pkcs8.
+[password] decrypts [private-key], and also encrypts outputted JKS file.
+All files can be PEM or DER.
+</pre><br clear="all"/>
+
+<br/><b>Warning:</b>
+ <span style="color: red; font-weight: bold;">-topk8 outputs the private key UNENCRYPTED!
+Cut and paste the private key into a separate file, and then use "openssl rsa" or "openssl dsa"
+to encrypt it with a password.</span>
+<br/>
+<br/>
+
+
+</body>
+</html>
diff --git a/docs/pkcs8.html b/docs/pkcs8.html
new file mode 100644
index 0000000..40b799f
--- /dev/null
+++ b/docs/pkcs8.html
@@ -0,0 +1,156 @@
+<html>
+<head>
+<title>Decrypting PKCS #8 and OpenSSL Private Keys with Java</title>
+<style type="text/css">
+h1, h2, h3 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+li.top { margin-top: 10px; }
+ul.openssl { float: left; width: 100px; margin-top: 8px; }
+ul.pkcs8 { float: left; width: 200px; margin-top: 8px; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="index.html">main</a> |
+<a href="ssl.html">ssl</a> |
+<span class="hl" href="pkcs8.html">pkcs8</span> |
+<a href="pbe.html">pbe</a> |
+<a href="rmi.html">rmi</a> |
+<a href="utilities.html">utilities</a> |
+<a href="source.html">source</a> |
+<a href="javadocs/">javadocs</a> |
+<a href="download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>PKCS #8 / OpenSSL Encrypted Keys</em></h2>
+<br/>
+<h3>Java 1.3 Compatible! (with <a href="http://java.sun.com/products/jce/index-122.html">jce1_2_2.jar</a>) (or <a href="http://bouncycastle.org/latest_releases.html">bcprov-jdk13.jar</a>)</h3>
+<p>Commons-SSL includes support for extracting private keys from PKCS #8 files.
+We also support the OpenSSL formats ("traditional SSLeay"). The private keys can be in PEM (base64)
+or DER (raw ASN.1 - a binary format).
+</p>
+<p>The code works with Java 1.3 (+JCE), 1.4, 5.0, 6.0, but not all of the ciphers and hashes are available
+until Java 5.0 (unless you use BouncyCastle). Fortunately the most common formats [OpenSSL MD5 with 3DES], [PKCS #8 V1.5 MD5 with DES], [PKCS #8 V2.0 HmacSHA1 with 3DES]
+work with all versions of Java, including Java 1.3.</p>
+<pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>pkcs8 example:</b></u>
+
+FileInputStream in = new FileInputStream( "/path/to/pkcs8_private_key.der" );
+
+<em style="color: green;">// If the provided InputStream is encrypted, we need a password to decrypt</em>
+<em style="color: green;">// it. If the InputStream is not encrypted, then the password is ignored</em>
+<em style="color: green;">// (can be null). The InputStream can be DER (raw ASN.1) or PEM (base64).</em>
+PKCS8Key pkcs8 = new PKCS8Key( in, "changeit".toCharArray() );
+
+<em style="color: green;">// If an unencrypted PKCS8 key was provided, then this actually returns</em>
+<em style="color: green;">// exactly what was originally passed in (with no changes). If an OpenSSL</em>
+<em style="color: green;">// key was provided, it gets reformatted as PKCS #8 first, and so these</em>
+<em style="color: green;">// bytes will still be PKCS #8, not OpenSSL.</em>
+byte[] decrypted = pkcs8.getDecryptedBytes();
+PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec( decrypted );
+
+<em style="color: green;">// A Java PrivateKey object is born.</em>
+PrivateKey pk = null;
+if ( pkcs8.isDSA() )
+{
+ pk = KeyFactory.getInstance( "DSA" ).generatePrivate( spec );
+}
+else if ( pkcs8.isRSA() )
+{
+ pk = KeyFactory.getInstance( "RSA" ).generatePrivate( spec );
+}
+
+<em style="color: green;">// For lazier types (like me):</em>
+pk = pkcs8.getPrivateKey();
+</pre>
+<br clear="all"/>
+<p>Both RSA and DSA keys are supported. Here is a list of supported formats:</p>
+<ul>
+<li class="top"><b>OpenSSL "Traditional SSLeay Compatible Format"</b><ul>
+<li>Unencrypted PEM or DER</li>
+<li>Encrypted PEM:<br/>
+<ul class="openssl"><li>des</li><li>des2</li><li>des3</li><li>blowfish</li></ul>
+<ul class="openssl"><li>aes128</li><li>aes192</li><li>aes256</li></ul>
+<ul class="openssl"><li>rc2-40</li><li>rc2-64</li><li>rc2-128</li></ul>
+<br clear="all"/>
+<dl style="margin-top: 1em; width: 600px;"><dt>Note:</dt><dd>OpenSSL "traditional SSLeay" format does not allow encrypted keys to be encoded in DER. Only
+unencrypted keys can be encoded in DER.</dd></dl></li>
+</ul>
+</li>
+<li class="top"><b>PKCS #8 (Unencrypted)</b>
+<ul><li>PEM or DER</li></ul></li>
+<li class="top"><b>PKCS #8 with PKCS #5 Version 1.5 Encryption</b>
+<ul><li>PEM or DER:
+<ul class="pkcs8">
+<li>MD2 with DES</li>
+<li>MD2 with RC2-64</li>
+</ul>
+<ul class="pkcs8">
+<li>MD5 with DES</li>
+<li>MD5 with RC2-64</li>
+</ul>
+<ul class="pkcs8">
+<li>SHA1 with DES</li>
+<li>SHA1 with RC2-64</li>
+</ul>
+<br clear="all"/>
+</li></ul></li>
+<li class="top"><b>PKCS #8 with PKCS #5 Version 1.5 Encryption and PKCS #12 Key Derivation</b>
+<ul><li>PEM or DER:
+<ul class="pkcs8">
+<li>SHA1 with 3DES</li>
+<li>SHA1 with 2DES</li>
+</ul>
+<ul class="pkcs8">
+<li>SHA1 with RC2-128</li>
+<li>SHA1 with RC2-40</li>
+</ul>
+<ul class="pkcs8">
+<li>SHA1 with RC4-128</li>
+<li>SHA1 with RC4-40</li>
+</ul>
+<br clear="all"/>
+</li></ul></li>
+<li class="top"><b>PKCS #8 with PKCS #5 Version 2.0 Encryption and HmacSHA1</b>
+<ul><li>PEM or DER:
+<ul class="pkcs8">
+<li>DES</li>
+<li>3DES</li>
+<li>Blowfish</li>
+</ul>
+<ul class="pkcs8">
+<li>AES-128</li>
+<li>AES-192</li>
+<li>AES-256</li>
+</ul>
+<ul class="pkcs8">
+<li>RC2-40</li>
+<li>RC2-64</li>
+<li>RC2-128</li>
+</ul>
+<br clear="all"/>
+</li></ul></li></ul>
+<hr/>
+<p>
+Here are links to the raw samples and test results:
+<ol>
+<li><a href="samples/rsa_result.html">2048 Bit RSA</a></li>
+<li><a href="samples/dsa_result.html">2048 Bit DSA</a></li>
+</ol>
+</p>
+<p>The samples were all generated using OpenSSL's
+<code>rsa</code>, <code>genrsa</code>, <code>dsa</code>, <code>gendsa</code>, <code>dsaparam</code>
+and <code>pkcs8</code> commands. We're curious to know if
+PKCS #8 keys created by other programs will also work, but OpenSSL is all we have to play
+with at the moment.</p>
+<p>The password to decrypt the samples is always "changeit", and they all have the same RSA or DSA
+key.</p>
+
+</body>
+</html>
diff --git a/docs/rmi.html b/docs/rmi.html
new file mode 100644
index 0000000..6d7b2b6
--- /dev/null
+++ b/docs/rmi.html
@@ -0,0 +1,102 @@
+<html>
+<head>
+<title>Not-Yet-Commons-SSL - RMI over SSL Java Example</title>
+<style type="text/css">
+h1, h2, h3 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+li.top { margin-top: 10px; }
+ul.openssl { float: left; width: 100px; margin-top: 8px; }
+ul.pkcs8 { float: left; width: 200px; margin-top: 8px; }
+ol.points li { margin-top: 8px; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="index.html">main</a> |
+<a href="ssl.html">ssl</a> |
+<a href="pkcs8.html">pkcs8</a> |
+<a href="pbe.html">pbe</a> |
+<span class="hl" href="rmi.html">rmi</span> |
+<a href="utilities.html">utilities</a> |
+<a href="source.html">source</a> |
+<a href="javadocs/">javadocs</a> |
+<a href="download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>RMI over SSL <em style="color: red; font-weight: normal;">(experimental)</em></h2>
+<br/><b>3 points to consider:</b>
+<ol class="points">
+<li>To run the RMI-SSL server, you must invoke <code>LocateRegistry.createRegistry( 1099 )</code>
+from within your own application. You must do this AFTER calling <code>RMISocketFactory.setSocketFactory( impl )</code>.
+RMISocketFactoryImpl will open the registry on 1099, and will open anonymous RMI servers (where port 0 is
+specified) on port 31099.
+RMI-SSL, as shown here, doesn't work with <code>$JAVA_HOME/bin/rmiregistry</code>.
+<br/>See the example code below for help with <code>RMISocketFactory.setSocketFactory( impl )</code>.
+</li>
+<li>To run the RMI-SSL client, you need to find an RMI-SSL server to connect to. See #1, above. ;-)</li>
+<li>If you don't manage to find an RMI-SSL server, then the RMI-SSL client will automatically downgrade itself
+to plain-socket. There is an important security consideration to consider regarding this: RMISocketFactoryImpl
+at this time only guarantees the security of the registry and the server sockets it opens. Client sockets
+it creates might be plain-socket.</li>
+</ol>
+
+<pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>RMI over SSL Example</b></u>
+
+import org.apache.commons.ssl.RMISocketFactoryImpl;
+
+<em style="color: green;">// RMISocketFactoryImpl tries to detect plain sockets, so you should be able to use</em>
+<em style="color: green;">// this even in situations where not all of the RMI servers you are talking to are</em>
+<em style="color: green;">// using SSL.</em>
+RMISocketFactoryImpl impl = new RMISocketFactoryImpl();
+
+<em style="color: green;">// Let's change some settings on our default SSL client.</em>
+SSLClient defaultClient = (SSLClient) impl.getDefaultClient();
+client.setCheckHostname( false );
+client.setCheckCRL( true );
+client.setCheckExpiry( false );
+
+<em style="color: green;">// By default we trust Java's "cacerts", as well as whatever cert is on localhost:1099,</em>
+<em style="color: green;">// so this is redundant: (Trusting localhost:1099 is some commons-ssl magic).</em>
+client.addTrustMaterial( TrustMaterial.DEFAULT );
+
+<em style="color: green;">// But if we had used setTrustMaterial() instead of addTrustMaterial(), we would (probably)</em>
+<em style="color: green;">// no longer trust localhost:1099! Using set instead of add causes all previous "adds" to</em>
+<em style="color: green;">// to be thrown out.</em>
+
+<em style="color: green;">// Meanwhile, RMI calls to rmi://special.com:1099/ need to trust a self-signed certificate,</em>
+<em style="color: green;">// but we don't want to pollute our default trust with this shoddy cert. So only calls</em>
+<em style="color: green;">// specifically to "special.com" (any port) will use this.</em>
+SSLClient specialClient = new SSLClient();
+TrustMaterial tm = new TrustMaterial( "special.pem" );
+specialClient.addTrustMaterial( tm );
+<em style="color: green;">// Here's where the special cert gets associated with "special.com":</em>
+impl.setClient( "special.com", specialClient );
+
+
+<em style="color: green;">// We're might also want to be an RMI server ourselves!</em>
+<em style="color: green;">// By default commons-ssl looks for "~/.keystore" and tries password "changeit",</em>
+<em style="color: green;">// but we can change things if we want:</em>
+SSLServer server = (SSLServer) impl.getDefaultServer();
+tm = new TrustMaterial( "trust_only_these_client_certs.pem" );
+KeyMaterial km = new KeyMaterial( "/path/to/myKey.p12", "password".toCharArray() );
+server.setTrustMaterial( tm );
+server.setKeyMaterial( km );
+<em style="color: green;">// This particular RMI server will only accept connections with client certs!</em>
+server.setNeedClientAuth( true );
+
+<em style="color: green;">// Finally, we tell Java to use our new RMI socket factory!</em>
+RMISocketFactory.setSocketFactory( impl );</pre>
+<br clear="all">
+<pre>
+<!-- make the page scroll a little more -->
+
+</pre>
+</body>
+</html>
diff --git a/docs/source.html b/docs/source.html
new file mode 100644
index 0000000..6c2fc85
--- /dev/null
+++ b/docs/source.html
@@ -0,0 +1,38 @@
+<html>
+<head>
+<title>Not-Yet-Commons-SSL - Source Tree</title>
+<style type="text/css">
+h1, h2, h3 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+li.top { margin-top: 10px; }
+ul.openssl { float: left; width: 100px; margin-top: 8px; }
+ul.pkcs8 { float: left; width: 200px; margin-top: 8px; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="index.html">main</a> |
+<a href="ssl.html">ssl</a> |
+<a href="pkcs8.html">pkcs8</a> |
+<a href="pbe.html">pbe</a> |
+<a href="rmi.html">rmi</a> |
+<a href="utilities.html">utilities</a> |
+<span class="hl" href="source.html">source</span> |
+<a href="javadocs/">javadocs</a> |
+<a href="download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>not-yet-commons-ssl Source Code</em></h2>
+<br clear="all">
+
+<!--#include virtual="tree.html" -->
+
+</body>
+</html>
diff --git a/docs/ssl.html b/docs/ssl.html
new file mode 100644
index 0000000..86bfa4d
--- /dev/null
+++ b/docs/ssl.html
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<meta name="Author" content="Julius Davies">
+<title>Java Examples for Creating SSL/TLS Sockets</title>
+<style type="text/css">
+h1, h2, h3 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="index.html">main</a> |
+<span class="hl" href="ssl.html">ssl</span> |
+<a href="pkcs8.html">pkcs8</a> |
+<a href="pbe.html">pbe</a> |
+<a href="rmi.html">rmi</a> |
+<a href="utilities.html">utilities</a> |
+<a href="source.html">source</a> |
+<a href="javadocs/">javadocs</a> |
+<a href="download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>Code Examples For Creating SSL Sockets</h2>
+<div style="font-family: arial; margin-top: 18px;">
+<b class="n">Note:</b>
+<br/>SSLClient <b class="n">extends</b> SSLSocketFactory
+<br/>SSLServer <b class="n">extends</b> SSLServerSocketFactory
+</div>
+<pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>Client Example:</b></u>
+
+SSLClient client = new SSLClient();
+
+<em style="color: green;">// Let's trust usual "cacerts" that come with Java. Plus, let's also trust a self-signed cert</em>
+<em style="color: green;">// we know of. We have some additional certs to trust inside a java keystore file.</em>
+client.addTrustMaterial( TrustMaterial.DEFAULT );
+client.addTrustMaterial( new TrustMaterial( "/path/to/self-signed.pem" ) );
+client.addTrustMaterial( new KeyMaterial( "/path/to/keystore.jks", "changeit".toCharArray() ) );
+
+<em style="color: green;">// To be different, let's allow for expired certificates (not recommended).</em>
+client.setCheckHostname( true ); <em style="color: green;">// default setting is "true" for SSLClient</em>
+client.setCheckExpiry( false ); <em style="color: green;">// default setting is "true" for SSLClient</em>
+client.setCheckCRL( true ); <em style="color: green;">// default setting is "true" for SSLClient</em>
+
+<em style="color: green;">// Let's load a client certificate (max: 1 per SSLClient instance).</em>
+client.setKeyMaterial( new KeyMaterial( "/path/to/client.pfx", "secret".toCharArray() ) );
+SSLSocket s = (SSLSocket) client.createSocket( "www.cucbc.com", 443 );</pre>
+
+<br clear="all"><pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>Server Example (OpenSSL/Apache Style)</b></u>
+<em style="color: green;">// Compatible with the private key / certificate chain created from following the Apache2</em>
+<em style="color: green;">// TLS FAQ: "How do I create a self-signed SSL Certificate for testing purposes?"</em>
+<em style="color: green;">// <a href="http://httpd.apache.org/docs/2.2/ssl/ssl_faq.html#selfcert">http://httpd.apache.org/docs/2.2/ssl/ssl_faq.html#selfcert</a></em>
+
+SSLServer server = new SSLServer();
+
+<em style="color: green;">// Server needs some key material. We'll use an OpenSSL/PKCS8 style key (possibly encrypted).</em>
+String certificateChain = "/path/to/this/server.crt";
+String privateKey = "/path/to/this/server.key";
+char[] password = "changeit".toCharArray();
+KeyMaterial km = new KeyMaterial( certificateChain, privateKey, password );
+
+server.setKeyMaterial( km );
+
+<em style="color: green;">// These settings have to do with how we'll treat client certificates that are presented</em>
+<em style="color: green;">// to us. If the client doesn't present any client certificate, then these are ignored.</em>
+server.setCheckHostname( false ); <em style="color: green;">// default setting is "false" for SSLServer</em>
+server.setCheckExpiry( true ); <em style="color: green;">// default setting is "true" for SSLServer</em>
+server.setCheckCRL( true ); <em style="color: green;">// default setting is "true" for SSLServer</em>
+
+<em style="color: green;">// This server trusts all client certificates presented (usually people won't present</em>
+<em style="color: green;">// client certs, but if they do, we'll give them a socket at the very least).</em>
+server.addTrustMaterial( TrustMaterial.TRUST_ALL );
+SSLServerSocket ss = (SSLServerSocket) server.createServerSocket( 7443 );
+SSLSocket socket = (SSLSocket) ss.accept();</pre>
+
+<br clear="all"><pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>Server Example (Traditional Java "KeyStore" Style)</b></u>
+
+SSLServer server = new SSLServer();
+
+<em style="color: green;">// Server needs some key material. We'll use a Java Keystore (.jks) or Netscape</em>
+<em style="color: green;">// PKCS12 (.pfx or .p12) file. Commons-ssl automatically detects the type.</em>
+String pathToKeyMaterial = "/path/to/.keystore";
+char[] password = "changeit".toCharArray();
+KeyMaterial km = new KeyMaterial( pathToKeyMaterial, password );
+
+server.setKeyMaterial( km );
+
+<em style="color: green;">// This server trusts all client certificates presented (usually people won't present</em>
+<em style="color: green;">// client certs, but if they do, we'll give them a socket at the very least).</em>
+server.addTrustMaterial( TrustMaterial.TRUST_ALL );
+SSLServerSocket ss = (SSLServerSocket) server.createServerSocket( 7443 );
+SSLSocket socket = (SSLSocket) ss.accept();</pre>
+
+
+<br clear="all">
+
+</body>
+</html>
diff --git a/docs/tree.html b/docs/tree.html
new file mode 100644
index 0000000..1e543b4
--- /dev/null
+++ b/docs/tree.html
@@ -0,0 +1,156 @@
+<pre>
+ <a href=".">.</a>
+ |-- [2.5K] <a href="./404.html">404.html</a>
+ |-- [9.9K] <a href="./LICENSE.txt">LICENSE.txt</a>
+ |-- [ 441] <a href="./NOTICE.txt">NOTICE.txt</a>
+ |-- [ 235] <a href="./README.txt">README.txt</a>
+ |-- [4.8K] <a href="./TrustExample.java">TrustExample.java</a>
+ |-- [ 23K] <a href="./TrustExample.java.html">TrustExample.java.html</a>
+ |-- [3.0K] <a href="./build.xml">build.xml</a>
+ |-- [ 13K] <a href="./download.html">download.html</a>
+ |-- [6.2K] <a href="./index.html">index.html</a>
+ |-- [4.0K] <a href="./javadocs/">javadocs</a>
+ |-- [4.0K] <a href="./lib/">lib</a>
+ | |-- [ 46K] <a href="./lib/commons-codec-1.3.jar">commons-codec-1.3.jar</a>
+ | |-- [273K] <a href="./lib/commons-httpclient-3.0.jar">commons-httpclient-3.0.jar</a>
+ | |-- [ 37K] <a href="./lib/commons-logging-1.0.4.jar">commons-logging-1.0.4.jar</a>
+ | `-- [350K] <a href="./lib/log4j-1.2.13.jar">log4j-1.2.13.jar</a>
+ |-- [189K] <a href="./not-yet-commons-ssl-0.3.8.jar">not-yet-commons-ssl-0.3.8.jar</a>
+ |-- [2.3M] <a href="./not-yet-commons-ssl-0.3.8.zip">not-yet-commons-ssl-0.3.8.zip</a>
+ |-- [1.3K] <a href="./oscp.pem">oscp.pem</a>
+ |-- [7.4K] <a href="./pbe.html">pbe.html</a>
+ |-- [3.9K] <a href="./ping.html">ping.html</a>
+ |-- [5.7K] <a href="./pkcs8.html">pkcs8.html</a>
+ |-- [4.9K] <a href="./rmi.html">rmi.html</a>
+ |-- [4.0K] <a href="./samples/">samples</a>
+ | |-- [ 66] <a href="./samples/PASSWORD.txt">PASSWORD.txt</a>
+ | |-- [ 66] <a href="./samples/README.txt">README.txt</a>
+ | |-- [1.5K] <a href="./samples/createPBESamples.sh">createPBESamples.sh</a>
+ | |-- [4.0K] <a href="./samples/dsa/">dsa</a>
+ | |-- [ 14K] <a href="./samples/dsa.html">dsa.html</a>
+ | |-- [1.3K] <a href="./samples/dsa_result.html">dsa_result.html</a>
+ | |-- [4.0K] <a href="./samples/pbe/">pbe</a>
+ | | |-- [1.3K] <a href="./samples/pbe/README.txt">README.txt</a>
+ | | |-- [ 20K] <a href="./samples/pbe/java/">java</a>
+ | | `-- [ 12K] <a href="./samples/pbe/openssl/">openssl</a>
+ | |-- [ 395] <a href="./samples/pbe.tests">pbe.tests</a>
+ | |-- [4.0K] <a href="./samples/pkcs12/">pkcs12</a>
+ | |-- [4.0K] <a href="./samples/rsa/">rsa</a>
+ | |-- [ 14K] <a href="./samples/rsa.html">rsa.html</a>
+ | |-- [1.3K] <a href="./samples/rsa_result.html">rsa_result.html</a>
+ | `-- [4.0K] <a href="./samples/x509/">x509</a>
+ |-- [ 993] <a href="./server.crt">server.crt</a>
+ |-- [1.1K] <a href="./source.html">source.html</a>
+ |-- [4.0K] <a href="./src/">src</a>
+ | `-- [4.0K] <a href="./src/java/">java</a>
+ | `-- [4.0K] <a href="./src/java/org/">org</a>
+ | `-- [4.0K] <a href="./src/java/org/apache/">apache</a>
+ | `-- [4.0K] <a href="./src/java/org/apache/commons/">commons</a>
+ | |-- [4.0K] <a href="./src/java/org/apache/commons/httpclient/">httpclient</a>
+ | | `-- [4.0K] <a href="./src/java/org/apache/commons/httpclient/contrib/">contrib</a>
+ | | `-- [4.0K] <a href="./src/java/org/apache/commons/httpclient/contrib/ssl/">ssl</a>
+ | | |-- [7.2K] <a href="./src/java/org/apache/commons/httpclient/contrib/ssl/AuthSSLProtocolSocketFactory.java">AuthSSLProtocolSocketFactory.java</a>
+ | | |-- [3.5K] <a href="./src/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java">EasySSLProtocolSocketFactory.java</a>
+ | | |-- [5.8K] <a href="./src/java/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java">StrictSSLProtocolSocketFactory.java</a>
+ | | `-- [8.8K] <a href="./src/java/org/apache/commons/httpclient/contrib/ssl/TrustSSLProtocolSocketFactory.java">TrustSSLProtocolSocketFactory.java</a>
+ | `-- [4.0K] <a href="./src/java/org/apache/commons/ssl/">ssl</a>
+ | |-- [3.1K] <a href="./src/java/org/apache/commons/ssl/ASN1Structure.java">ASN1Structure.java</a>
+ | |-- [7.1K] <a href="./src/java/org/apache/commons/ssl/ASN1Util.java">ASN1Util.java</a>
+ | |-- [ 17K] <a href="./src/java/org/apache/commons/ssl/Base64.java">Base64.java</a>
+ | |-- [3.5K] <a href="./src/java/org/apache/commons/ssl/Base64InputStream.java">Base64InputStream.java</a>
+ | |-- [2.7K] <a href="./src/java/org/apache/commons/ssl/CRLUtil.java">CRLUtil.java</a>
+ | |-- [ 18K] <a href="./src/java/org/apache/commons/ssl/Certificates.java">Certificates.java</a>
+ | |-- [2.5K] <a href="./src/java/org/apache/commons/ssl/ComboInputStream.java">ComboInputStream.java</a>
+ | |-- [1.6K] <a href="./src/java/org/apache/commons/ssl/DerivedKey.java">DerivedKey.java</a>
+ | |-- [1.9K] <a href="./src/java/org/apache/commons/ssl/HostPort.java">HostPort.java</a>
+ | |-- [ 19K] <a href="./src/java/org/apache/commons/ssl/HostnameVerifier.java">HostnameVerifier.java</a>
+ | |-- [3.5K] <a href="./src/java/org/apache/commons/ssl/HttpSecureProtocol.java">HttpSecureProtocol.java</a>
+ | |-- [9.9K] <a href="./src/java/org/apache/commons/ssl/Java13.java">Java13.java</a>
+ | |-- [2.8K] <a href="./src/java/org/apache/commons/ssl/Java13KeyManagerWrapper.java">Java13KeyManagerWrapper.java</a>
+ | |-- [3.1K] <a href="./src/java/org/apache/commons/ssl/Java13TrustManagerWrapper.java">Java13TrustManagerWrapper.java</a>
+ | |-- [8.3K] <a href="./src/java/org/apache/commons/ssl/Java14.java">Java14.java</a>
+ | |-- [2.8K] <a href="./src/java/org/apache/commons/ssl/Java14KeyManagerWrapper.java">Java14KeyManagerWrapper.java</a>
+ | |-- [3.9K] <a href="./src/java/org/apache/commons/ssl/Java14TrustManagerWrapper.java">Java14TrustManagerWrapper.java</a>
+ | |-- [8.4K] <a href="./src/java/org/apache/commons/ssl/JavaImpl.java">JavaImpl.java</a>
+ | |-- [6.6K] <a href="./src/java/org/apache/commons/ssl/KeyMaterial.java">KeyMaterial.java</a>
+ | |-- [ 21K] <a href="./src/java/org/apache/commons/ssl/KeyStoreBuilder.java">KeyStoreBuilder.java</a>
+ | |-- [2.5K] <a href="./src/java/org/apache/commons/ssl/LDAPSocket.java">LDAPSocket.java</a>
+ | |-- [3.0K] <a href="./src/java/org/apache/commons/ssl/LogHelper.java">LogHelper.java</a>
+ | |-- [8.2K] <a href="./src/java/org/apache/commons/ssl/LogWrapper.java">LogWrapper.java</a>
+ | |-- [ 23K] <a href="./src/java/org/apache/commons/ssl/OpenSSL.java">OpenSSL.java</a>
+ | |-- [2.0K] <a href="./src/java/org/apache/commons/ssl/OpenSSLTest.java">OpenSSLTest.java</a>
+ | |-- [2.2K] <a href="./src/java/org/apache/commons/ssl/PBETestCreate.java">PBETestCreate.java</a>
+ | |-- [3.2K] <a href="./src/java/org/apache/commons/ssl/PEMItem.java">PEMItem.java</a>
+ | |-- [8.4K] <a href="./src/java/org/apache/commons/ssl/PEMUtil.java">PEMUtil.java</a>
+ | |-- [ 34K] <a href="./src/java/org/apache/commons/ssl/PKCS8Key.java">PKCS8Key.java</a>
+ | |-- [ 14K] <a href="./src/java/org/apache/commons/ssl/Ping.java">Ping.java</a>
+ | |-- [1.9K] <a href="./src/java/org/apache/commons/ssl/ProbablyBadPasswordException.java">ProbablyBadPasswordException.java</a>
+ | |-- [1.9K] <a href="./src/java/org/apache/commons/ssl/ProbablyNotPKCS8Exception.java">ProbablyNotPKCS8Exception.java</a>
+ | |-- [ 20K] <a href="./src/java/org/apache/commons/ssl/RMISocketFactoryImpl.java">RMISocketFactoryImpl.java</a>
+ | |-- [ 24K] <a href="./src/java/org/apache/commons/ssl/SSL.java">SSL.java</a>
+ | |-- [7.6K] <a href="./src/java/org/apache/commons/ssl/SSLClient.java">SSLClient.java</a>
+ | |-- [4.1K] <a href="./src/java/org/apache/commons/ssl/SSLEchoServer.java">SSLEchoServer.java</a>
+ | |-- [5.1K] <a href="./src/java/org/apache/commons/ssl/SSLProxyServer.java">SSLProxyServer.java</a>
+ | |-- [9.8K] <a href="./src/java/org/apache/commons/ssl/SSLServer.java">SSLServer.java</a>
+ | |-- [5.2K] <a href="./src/java/org/apache/commons/ssl/SSLServerSocketWrapper.java">SSLServerSocketWrapper.java</a>
+ | |-- [6.9K] <a href="./src/java/org/apache/commons/ssl/SSLSocketWrapper.java">SSLSocketWrapper.java</a>
+ | |-- [3.8K] <a href="./src/java/org/apache/commons/ssl/SSLWrapperFactory.java">SSLWrapperFactory.java</a>
+ | |-- [7.5K] <a href="./src/java/org/apache/commons/ssl/TomcatServerXML.java">TomcatServerXML.java</a>
+ | |-- [6.7K] <a href="./src/java/org/apache/commons/ssl/TrustChain.java">TrustChain.java</a>
+ | |-- [8.2K] <a href="./src/java/org/apache/commons/ssl/TrustMaterial.java">TrustMaterial.java</a>
+ | |-- [ 11K] <a href="./src/java/org/apache/commons/ssl/Util.java">Util.java</a>
+ | |-- [4.5K] <a href="./src/java/org/apache/commons/ssl/Version.java">Version.java</a>
+ | |-- [7.1K] <a href="./src/java/org/apache/commons/ssl/X509CertificateChainBuilder.java">X509CertificateChainBuilder.java</a>
+ | |-- [4.0K] <a href="./src/java/org/apache/commons/ssl/asn1/">asn1</a>
+ | | |-- [ 10K] <a href="./src/java/org/apache/commons/ssl/asn1/ASN1InputStream.java">ASN1InputStream.java</a>
+ | | |-- [2.4K] <a href="./src/java/org/apache/commons/ssl/asn1/ASN1OutputStream.java">ASN1OutputStream.java</a>
+ | | |-- [4.1K] <a href="./src/java/org/apache/commons/ssl/asn1/BERConstructedOctetString.java">BERConstructedOctetString.java</a>
+ | | |-- [1.5K] <a href="./src/java/org/apache/commons/ssl/asn1/BERNull.java">BERNull.java</a>
+ | | |-- [1.7K] <a href="./src/java/org/apache/commons/ssl/asn1/BERSequence.java">BERSequence.java</a>
+ | | |-- [1.7K] <a href="./src/java/org/apache/commons/ssl/asn1/BERSet.java">BERSet.java</a>
+ | | |-- [2.9K] <a href="./src/java/org/apache/commons/ssl/asn1/BERTaggedObject.java">BERTaggedObject.java</a>
+ | | |-- [2.3K] <a href="./src/java/org/apache/commons/ssl/asn1/DERApplicationSpecific.java">DERApplicationSpecific.java</a>
+ | | |-- [1.7K] <a href="./src/java/org/apache/commons/ssl/asn1/DERBMPString.java">DERBMPString.java</a>
+ | | |-- [1.8K] <a href="./src/java/org/apache/commons/ssl/asn1/DERBitString.java">DERBitString.java</a>
+ | | |-- [2.0K] <a href="./src/java/org/apache/commons/ssl/asn1/DERBoolean.java">DERBoolean.java</a>
+ | | |-- [1.4K] <a href="./src/java/org/apache/commons/ssl/asn1/DEREncodable.java">DEREncodable.java</a>
+ | | |-- [2.2K] <a href="./src/java/org/apache/commons/ssl/asn1/DEREnumerated.java">DEREnumerated.java</a>
+ | | |-- [1.6K] <a href="./src/java/org/apache/commons/ssl/asn1/DERGeneralString.java">DERGeneralString.java</a>
+ | | |-- [2.4K] <a href="./src/java/org/apache/commons/ssl/asn1/DERGeneralizedTime.java">DERGeneralizedTime.java</a>
+ | | |-- [1.6K] <a href="./src/java/org/apache/commons/ssl/asn1/DERIA5String.java">DERIA5String.java</a>
+ | | |-- [2.1K] <a href="./src/java/org/apache/commons/ssl/asn1/DERInteger.java">DERInteger.java</a>
+ | | |-- [1.5K] <a href="./src/java/org/apache/commons/ssl/asn1/DERNull.java">DERNull.java</a>
+ | | |-- [1.7K] <a href="./src/java/org/apache/commons/ssl/asn1/DERNumericString.java">DERNumericString.java</a>
+ | | |-- [3.5K] <a href="./src/java/org/apache/commons/ssl/asn1/DERObject.java">DERObject.java</a>
+ | | |-- [4.4K] <a href="./src/java/org/apache/commons/ssl/asn1/DERObjectIdentifier.java">DERObjectIdentifier.java</a>
+ | | |-- [1.5K] <a href="./src/java/org/apache/commons/ssl/asn1/DEROctetString.java">DEROctetString.java</a>
+ | | |-- [1.7K] <a href="./src/java/org/apache/commons/ssl/asn1/DERPrintableString.java">DERPrintableString.java</a>
+ | | |-- [2.4K] <a href="./src/java/org/apache/commons/ssl/asn1/DERSequence.java">DERSequence.java</a>
+ | | |-- [2.2K] <a href="./src/java/org/apache/commons/ssl/asn1/DERSet.java">DERSet.java</a>
+ | | |-- [2.3K] <a href="./src/java/org/apache/commons/ssl/asn1/DERString.java">DERString.java</a>
+ | | |-- [3.6K] <a href="./src/java/org/apache/commons/ssl/asn1/DERTaggedObject.java">DERTaggedObject.java</a>
+ | | |-- [1.6K] <a href="./src/java/org/apache/commons/ssl/asn1/DERTeletexString.java">DERTeletexString.java</a>
+ | | |-- [2.4K] <a href="./src/java/org/apache/commons/ssl/asn1/DERUTCTime.java">DERUTCTime.java</a>
+ | | |-- [1.6K] <a href="./src/java/org/apache/commons/ssl/asn1/DERUTF8String.java">DERUTF8String.java</a>
+ | | |-- [2.2K] <a href="./src/java/org/apache/commons/ssl/asn1/DERUniversalString.java">DERUniversalString.java</a>
+ | | |-- [1.5K] <a href="./src/java/org/apache/commons/ssl/asn1/DERUnknownTag.java">DERUnknownTag.java</a>
+ | | |-- [1.7K] <a href="./src/java/org/apache/commons/ssl/asn1/DERVisibleString.java">DERVisibleString.java</a>
+ | | `-- [1.8K] <a href="./src/java/org/apache/commons/ssl/asn1/OIDTokenizer.java">OIDTokenizer.java</a>
+ | `-- [4.0K] <a href="./src/java/org/apache/commons/ssl/rmi/">rmi</a>
+ | |-- [2.1K] <a href="./src/java/org/apache/commons/ssl/rmi/DateRMI.java">DateRMI.java</a>
+ | |-- [2.1K] <a href="./src/java/org/apache/commons/ssl/rmi/IntegerRMI.java">IntegerRMI.java</a>
+ | |-- [1.6K] <a href="./src/java/org/apache/commons/ssl/rmi/RemoteDate.java">RemoteDate.java</a>
+ | |-- [1.6K] <a href="./src/java/org/apache/commons/ssl/rmi/RemoteInteger.java">RemoteInteger.java</a>
+ | `-- [6.1K] <a href="./src/java/org/apache/commons/ssl/rmi/Test.java">Test.java</a>
+ |-- [5.4K] <a href="./ssl.html">ssl.html</a>
+ |-- [ 0] <a href="./tree.html">tree.html</a>
+ |-- [2.8K] <a href="./two-crls.pem">two-crls.pem</a>
+ |-- [3.8K] <a href="./utilities.html">utilities.html</a>
+ `-- [ 27] <a href="./version.txt">version.txt</a>
+
+20 directories, 126 files
+
+ tree v1.5.1 (c) 1996 - 2007 by Steve Baker and Thomas Moore
+ HTML output hacked and copyleft (c) 1998 by Francesc Rocher
+ Charsets / OS/2 support (c) 2001 by Kyosuke Tokoro
+</pre>
diff --git a/docs/utilities.html b/docs/utilities.html
new file mode 100644
index 0000000..d4e3134
--- /dev/null
+++ b/docs/utilities.html
@@ -0,0 +1,91 @@
+<html>
+<head>
+<title>Not-Yet-Commons-SSL - Utilities</title>
+<style type="text/css">
+h1, h2, h3 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+li.top { margin-top: 10px; }
+ul.openssl { float: left; width: 100px; margin-top: 8px; }
+ul.pkcs8 { float: left; width: 200px; margin-top: 8px; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="index.html">main</a> |
+<a href="ssl.html">ssl</a> |
+<a href="pkcs8.html">pkcs8</a> |
+<a href="pbe.html">pbe</a> |
+<a href="rmi.html">rmi</a> |
+<span class="hl" href="utilities.html">utilities</span> |
+<a href="source.html">source</a> |
+<a href="javadocs/">javadocs</a> |
+<a href="download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>Ping</h2>
+
+<p>"org.apache.commons.ssl.Ping" contains a main method to help you diagnose SSL issues.
+It's modeled on OpenSSL's very handy "s_client" utility. We've been very careful to
+make sure "org.apache.commons.ssl.Ping" can execute without any additional jar files
+on the classpath (except if using Java 1.3 - then you'll need jsse.jar).</p>
+
+<pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>"Ping" Utility Attempts "HEAD / HTTP/1.1" Request</b></u>
+This utility is very handy because it can get you the server's public
+certificate even if your client certificate is bad (so even though the SSL
+handshake fails). And unlike "openssl s_client", this utility can bind
+against any IP address available.
+
+Usage: java -jar not-yet-commons-ssl-0.3.9.jar [options]
+Version 0.3.9 compiled=[PST:2007-11-14/14:42:18.000]
+Options: (*=required)
+* -t --target [hostname[:port]] default port=443
+ -b --bind [hostname[:port]] default port=0 "ANY"
+ -r --proxy [hostname[:port]] default port=80
+ -tm --trust-cert [path to trust material] {pem, der, crt, jks}
+ -km --client-cert [path to client's private key] {jks, pkcs12, pkcs8}
+ -cc --cert-chain [path to client's cert chain for pkcs8/OpenSSL key]
+ -p --password [client cert password]
+ -h --host-header [http-host-header] in case -t is an IP address
+ -u --path [path for GET/HEAD request] default=/
+ -m --method [http method to use] default=HEAD
+
+Example:
+
+java -jar not-yet-commons-ssl.jar -t host.com:443 -c ./client.pfx -p `cat ./pass.txt`</pre><br clear="all"/>
+
+<p style="margin-top: 8px;"><b>TODO:</b><br/>Apparently Java 6.0 includes support for grabbing passwords from
+standard-in without echoing the typed characters. Would be nice to use that feature when it's
+available, instead of requiring the password to be specified as a command-line argument.</p>
+
+<hr/>
+<h2>KeyStoreBuilder</h2>
+<p>org.apache.commons.ssl.KeyStoreBuilder is able to convert OpenSSL style public/private keys into
+Java KeyStore files. It can also convert Java Keystore files into the PEM format that Apache likes.</p>
+
+<p><code>java -cp not-yet-commons-ssl-0.3.9.jar org.apache.commons.ssl.KeyStoreBuilder</code></p>
+
+<pre style="border: 1px solid red; padding: 10px; float: left;"><u><b>KeyStoreBuilder converts PKCS12 and PKCS8 to Java "Keystore"</b></u>
+
+KeyStoreBuilder: creates '[alias].jks' (Java Key Store)
+ -topk8 mode: creates '[alias].pem' (x509 chain + unencrypted pkcs8)
+[alias] will be set to the first CN value of the X509 certificate.
+-------------------------------------------------------------------
+Usage1: [password] [file:pkcs12]
+Usage2: [password] [file:private-key] [file:certificate-chain]
+Usage3: -topk8 [password] [file:jks]
+-------------------------------------------------------------------
+[private-key] can be openssl format, or pkcs8.
+[password] decrypts [private-key], and also encrypts outputted JKS file.
+All files can be PEM or DER.
+</pre><br clear="all"/>
+
+
+</body>
+</html>
diff --git a/samples/PASSWORD.txt b/samples/PASSWORD.txt
new file mode 100644
index 0000000..ceda279
--- /dev/null
+++ b/samples/PASSWORD.txt
@@ -0,0 +1,3 @@
+Password for decrypting any of these files is
+always "changeit".
+
diff --git a/samples/README.txt b/samples/README.txt
new file mode 100644
index 0000000..ceda279
--- /dev/null
+++ b/samples/README.txt
@@ -0,0 +1,3 @@
+Password for decrypting any of these files is
+always "changeit".
+
diff --git a/samples/createPBESamples.sh b/samples/createPBESamples.sh
new file mode 100755
index 0000000..af39169
--- /dev/null
+++ b/samples/createPBESamples.sh
@@ -0,0 +1,106 @@
+#/bin/bash
+export TARGET_DIR=/home/julius/dev/commons-ssl/samples/pbe/openssl
+export OPENSSL_APP='/home/julius/dev/commons-ssl/t/openssl-0.9.8e/apps/openssl'
+
+export CIPHERS='
+aes-128-cbc
+aes-128-cfb
+aes-128-cfb1
+aes-128-cfb8
+aes-128-ecb
+aes-128-ofb
+aes-192-cbc
+aes-192-cfb
+aes-192-cfb1
+aes-192-cfb8
+aes-192-ecb
+aes-192-ofb
+aes-256-cbc
+aes-256-cfb
+aes-256-cfb1
+aes-256-cfb8
+aes-256-ecb
+aes-256-ofb
+aes128
+aes192
+aes256
+bf
+bf-cbc
+bf-cfb
+bf-ecb
+bf-ofb
+blowfish
+camellia-128-cbc
+camellia-128-cfb
+camellia-128-cfb1
+camellia-128-cfb8
+camellia-128-ecb
+camellia-128-ofb
+camellia-192-cbc
+camellia-192-cfb
+camellia-192-cfb1
+camellia-192-cfb8
+camellia-192-ecb
+camellia-192-ofb
+camellia-256-cbc
+camellia-256-cfb
+camellia-256-cfb1
+camellia-256-cfb8
+camellia-256-ecb
+camellia-256-ofb
+camellia128
+camellia192
+camellia256
+cast
+cast-cbc
+cast5-cbc
+cast5-cfb
+cast5-ecb
+cast5-ofb
+des
+des-cbc
+des-cfb
+des-cfb1
+des-cfb8
+des-ecb
+des-ofb
+des-ede
+des-ede-cbc
+des-ede-cfb
+des-ede-ofb
+des-ede3
+des-ede3-cbc
+des-ede3-cfb
+des-ede3-ofb
+des3
+idea
+idea-cbc
+idea-cfb
+idea-ecb
+idea-ofb
+rc2
+rc2-40-cbc
+rc2-64-cbc
+rc2-cbc
+rc2-cfb
+rc2-ecb
+rc2-ofb
+rc4
+rc4-40
+rc5
+rc5-cbc
+rc5-cfb
+rc5-ecb
+rc5-ofb'
+
+for CIPHER in $CIPHERS
+do
+ export OPENSSL_YES_B64_CMD="$OPENSSL_APP enc -$CIPHER -pass pass:changeit -a"
+ export OPENSSL_NO_B64_CMD="$OPENSSL_APP enc -$CIPHER -pass pass:changeit"
+ echo -n "Hello World!" | $OPENSSL_YES_B64_CMD > $TARGET_DIR/$CIPHER.base64
+ echo -n "Hello World!" | $OPENSSL_NO_B64_CMD > $TARGET_DIR/$CIPHER.raw
+done
+
+# Not supported by any JSSE implementation I have access to:
+# desx
+# desx-cbc
diff --git a/samples/dsa.html b/samples/dsa.html
new file mode 100644
index 0000000..6851348
--- /dev/null
+++ b/samples/dsa.html
@@ -0,0 +1,114 @@
+<pre>
+java -showversion -cp <a href="../download.html">build/not-yet-commons-ssl-0.3.7.jar</a> org.apache.commons.ssl.PKCS8Key <a href="dsa/">samples/dsa/*.*</a>
+
+java version "1.6.0"
+Java(TM) SE Runtime Environment (build 1.6.0-b105)
+Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)
+
+ SUCCESS DSA AES/CBC/PKCS5Padding 128 <a href="dsa/openssl_dsa_aes128_cbc.pem">samples/dsa/openssl_dsa_aes128_cbc.pem</a>
+ SUCCESS DSA AES/CFB/NoPadding 128 <a href="dsa/openssl_dsa_aes128_cfb.pem">samples/dsa/openssl_dsa_aes128_cfb.pem</a>
+ SUCCESS DSA AES/ECB/PKCS5Padding 128 <a href="dsa/openssl_dsa_aes128_ecb.pem">samples/dsa/openssl_dsa_aes128_ecb.pem</a>
+ SUCCESS DSA AES/OFB/NoPadding 128 <a href="dsa/openssl_dsa_aes128_ofb.pem">samples/dsa/openssl_dsa_aes128_ofb.pem</a>
+ SUCCESS DSA AES/CBC/PKCS5Padding 192 <a href="dsa/openssl_dsa_aes192_cbc.pem">samples/dsa/openssl_dsa_aes192_cbc.pem</a>
+ SUCCESS DSA AES/CFB/NoPadding 192 <a href="dsa/openssl_dsa_aes192_cfb.pem">samples/dsa/openssl_dsa_aes192_cfb.pem</a>
+ SUCCESS DSA AES/ECB/PKCS5Padding 192 <a href="dsa/openssl_dsa_aes192_ecb.pem">samples/dsa/openssl_dsa_aes192_ecb.pem</a>
+ SUCCESS DSA AES/OFB/NoPadding 192 <a href="dsa/openssl_dsa_aes192_ofb.pem">samples/dsa/openssl_dsa_aes192_ofb.pem</a>
+ SUCCESS DSA AES/CBC/PKCS5Padding 256 <a href="dsa/openssl_dsa_aes256_cbc.pem">samples/dsa/openssl_dsa_aes256_cbc.pem</a>
+ SUCCESS DSA AES/CFB/NoPadding 256 <a href="dsa/openssl_dsa_aes256_cfb.pem">samples/dsa/openssl_dsa_aes256_cfb.pem</a>
+ SUCCESS DSA AES/ECB/PKCS5Padding 256 <a href="dsa/openssl_dsa_aes256_ecb.pem">samples/dsa/openssl_dsa_aes256_ecb.pem</a>
+ SUCCESS DSA AES/OFB/NoPadding 256 <a href="dsa/openssl_dsa_aes256_ofb.pem">samples/dsa/openssl_dsa_aes256_ofb.pem</a>
+ SUCCESS DSA Blowfish/CBC/PKCS5Padding 128 <a href="dsa/openssl_dsa_blowfish_cbc.pem">samples/dsa/openssl_dsa_blowfish_cbc.pem</a>
+ SUCCESS DSA Blowfish/CFB/NoPadding 128 <a href="dsa/openssl_dsa_blowfish_cfb.pem">samples/dsa/openssl_dsa_blowfish_cfb.pem</a>
+ SUCCESS DSA Blowfish/ECB/PKCS5Padding 128 <a href="dsa/openssl_dsa_blowfish_ecb.pem">samples/dsa/openssl_dsa_blowfish_ecb.pem</a>
+ SUCCESS DSA Blowfish/OFB/NoPadding 128 <a href="dsa/openssl_dsa_blowfish_ofb.pem">samples/dsa/openssl_dsa_blowfish_ofb.pem</a>
+ SUCCESS DSA DES/CBC/PKCS5Padding 64 <a href="dsa/openssl_dsa_des1_cbc.pem">samples/dsa/openssl_dsa_des1_cbc.pem</a>
+ SUCCESS DSA DES/CFB/NoPadding 64 <a href="dsa/openssl_dsa_des1_cfb.pem">samples/dsa/openssl_dsa_des1_cfb.pem</a>
+ SUCCESS DSA DES/ECB/PKCS5Padding 64 <a href="dsa/openssl_dsa_des1_ecb.pem">samples/dsa/openssl_dsa_des1_ecb.pem</a>
+ SUCCESS DSA DES/OFB/NoPadding 64 <a href="dsa/openssl_dsa_des1_ofb.pem">samples/dsa/openssl_dsa_des1_ofb.pem</a>
+ SUCCESS DSA DESede/CBC/PKCS5Padding 192 <a href="dsa/openssl_dsa_des2_cbc.pem">samples/dsa/openssl_dsa_des2_cbc.pem</a>
+ SUCCESS DSA DESede/CFB/NoPadding 192 <a href="dsa/openssl_dsa_des2_cfb.pem">samples/dsa/openssl_dsa_des2_cfb.pem</a>
+ SUCCESS DSA DESede/ECB/PKCS5Padding 192 <a href="dsa/openssl_dsa_des2_ecb.pem">samples/dsa/openssl_dsa_des2_ecb.pem</a>
+ SUCCESS DSA DESede/OFB/NoPadding 192 <a href="dsa/openssl_dsa_des2_ofb.pem">samples/dsa/openssl_dsa_des2_ofb.pem</a>
+ SUCCESS DSA DESede/CBC/PKCS5Padding 192 <a href="dsa/openssl_dsa_des3_cbc.pem">samples/dsa/openssl_dsa_des3_cbc.pem</a>
+ SUCCESS DSA DESede/CFB/NoPadding 192 <a href="dsa/openssl_dsa_des3_cfb.pem">samples/dsa/openssl_dsa_des3_cfb.pem</a>
+ SUCCESS DSA DESede/ECB/PKCS5Padding 192 <a href="dsa/openssl_dsa_des3_ecb.pem">samples/dsa/openssl_dsa_des3_ecb.pem</a>
+ SUCCESS DSA DESede/OFB/NoPadding 192 <a href="dsa/openssl_dsa_des3_ofb.pem">samples/dsa/openssl_dsa_des3_ofb.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 128 <a href="dsa/openssl_dsa_rc2_128_cbc.pem">samples/dsa/openssl_dsa_rc2_128_cbc.pem</a>
+ SUCCESS DSA RC2/CFB/NoPadding 128 <a href="dsa/openssl_dsa_rc2_128_cfb.pem">samples/dsa/openssl_dsa_rc2_128_cfb.pem</a>
+ SUCCESS DSA RC2/ECB/PKCS5Padding 128 <a href="dsa/openssl_dsa_rc2_128_ecb.pem">samples/dsa/openssl_dsa_rc2_128_ecb.pem</a>
+ SUCCESS DSA RC2/OFB/NoPadding 128 <a href="dsa/openssl_dsa_rc2_128_ofb.pem">samples/dsa/openssl_dsa_rc2_128_ofb.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 40 <a href="dsa/openssl_dsa_rc2_40_cbc.pem">samples/dsa/openssl_dsa_rc2_40_cbc.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 64 <a href="dsa/openssl_dsa_rc2_64_cbc.pem">samples/dsa/openssl_dsa_rc2_64_cbc.pem</a>
+ SUCCESS DSA UNENCRYPTED 0 <a href="dsa/openssl_dsa_unencrypted.der">samples/dsa/openssl_dsa_unencrypted.der</a>
+ SUCCESS DSA UNENCRYPTED 0 <a href="dsa/openssl_dsa_unencrypted.pem">samples/dsa/openssl_dsa_unencrypted.pem</a>
+ SUCCESS DSA UNENCRYPTED 0 <a href="dsa/pkcs8_dsa_unencrypted.der">samples/dsa/pkcs8_dsa_unencrypted.der</a>
+ SUCCESS DSA UNENCRYPTED 0 <a href="dsa/pkcs8_dsa_unencrypted.pem">samples/dsa/pkcs8_dsa_unencrypted.pem</a>
+ SUCCESS DSA DES/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_md2_des1_cbc.der">samples/dsa/pkcs8v1_dsa_md2_des1_cbc.der</a>
+ SUCCESS DSA DES/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_md2_des1_cbc.pem">samples/dsa/pkcs8v1_dsa_md2_des1_cbc.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_md2_rc2_64_cbc.der">samples/dsa/pkcs8v1_dsa_md2_rc2_64_cbc.der</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_md2_rc2_64_cbc.pem">samples/dsa/pkcs8v1_dsa_md2_rc2_64_cbc.pem</a>
+ SUCCESS DSA DES/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_md5_des1_cbc.der">samples/dsa/pkcs8v1_dsa_md5_des1_cbc.der</a>
+ SUCCESS DSA DES/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_md5_des1_cbc.pem">samples/dsa/pkcs8v1_dsa_md5_des1_cbc.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_md5_rc2_64_cbc.der">samples/dsa/pkcs8v1_dsa_md5_rc2_64_cbc.der</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_md5_rc2_64_cbc.pem">samples/dsa/pkcs8v1_dsa_md5_rc2_64_cbc.pem</a>
+ SUCCESS DSA DES/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_sha1_des1_cbc.der">samples/dsa/pkcs8v1_dsa_sha1_des1_cbc.der</a>
+ SUCCESS DSA DES/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_sha1_des1_cbc.pem">samples/dsa/pkcs8v1_dsa_sha1_des1_cbc.pem</a>
+ SUCCESS DSA DESede/CBC/PKCS5Padding 192 <a href="dsa/pkcs8v1_dsa_sha1_des2_cbc.der">samples/dsa/pkcs8v1_dsa_sha1_des2_cbc.der</a>
+ SUCCESS DSA DESede/CBC/PKCS5Padding 192 <a href="dsa/pkcs8v1_dsa_sha1_des2_cbc.pem">samples/dsa/pkcs8v1_dsa_sha1_des2_cbc.pem</a>
+ SUCCESS DSA DESede/CBC/PKCS5Padding 192 <a href="dsa/pkcs8v1_dsa_sha1_des3_cbc.der">samples/dsa/pkcs8v1_dsa_sha1_des3_cbc.der</a>
+ SUCCESS DSA DESede/CBC/PKCS5Padding 192 <a href="dsa/pkcs8v1_dsa_sha1_des3_cbc.pem">samples/dsa/pkcs8v1_dsa_sha1_des3_cbc.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 128 <a href="dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.der">samples/dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.der</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 128 <a href="dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.pem">samples/dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 40 <a href="dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.der">samples/dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.der</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 40 <a href="dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.pem">samples/dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.der">samples/dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.der</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.pem">samples/dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.pem</a>
+ SUCCESS DSA RC4 128 <a href="dsa/pkcs8v1_dsa_sha1_rc4_128.der">samples/dsa/pkcs8v1_dsa_sha1_rc4_128.der</a>
+ SUCCESS DSA RC4 128 <a href="dsa/pkcs8v1_dsa_sha1_rc4_128.pem">samples/dsa/pkcs8v1_dsa_sha1_rc4_128.pem</a>
+ SUCCESS DSA RC4 40 <a href="dsa/pkcs8v1_dsa_sha1_rc4_40.der">samples/dsa/pkcs8v1_dsa_sha1_rc4_40.der</a>
+ SUCCESS DSA RC4 40 <a href="dsa/pkcs8v1_dsa_sha1_rc4_40.pem">samples/dsa/pkcs8v1_dsa_sha1_rc4_40.pem</a>
+ SUCCESS DSA AES/CBC/PKCS5Padding 128 <a href="dsa/pkcs8v2_dsa_aes128_cbc.der">samples/dsa/pkcs8v2_dsa_aes128_cbc.der</a>
+ SUCCESS DSA AES/CBC/PKCS5Padding 128 <a href="dsa/pkcs8v2_dsa_aes128_cbc.pem">samples/dsa/pkcs8v2_dsa_aes128_cbc.pem</a>
+ SUCCESS DSA AES/CFB/NoPadding 128 <a href="dsa/pkcs8v2_dsa_aes128_cfb.der">samples/dsa/pkcs8v2_dsa_aes128_cfb.der</a>
+ SUCCESS DSA AES/CFB/NoPadding 128 <a href="dsa/pkcs8v2_dsa_aes128_cfb.pem">samples/dsa/pkcs8v2_dsa_aes128_cfb.pem</a>
+ SUCCESS DSA AES/ECB/PKCS5Padding 128 <a href="dsa/pkcs8v2_dsa_aes128_ecb.der">samples/dsa/pkcs8v2_dsa_aes128_ecb.der</a>
+ SUCCESS DSA AES/ECB/PKCS5Padding 128 <a href="dsa/pkcs8v2_dsa_aes128_ecb.pem">samples/dsa/pkcs8v2_dsa_aes128_ecb.pem</a>
+ SUCCESS DSA AES/OFB/NoPadding 128 <a href="dsa/pkcs8v2_dsa_aes128_ofb.der">samples/dsa/pkcs8v2_dsa_aes128_ofb.der</a>
+ SUCCESS DSA AES/OFB/NoPadding 128 <a href="dsa/pkcs8v2_dsa_aes128_ofb.pem">samples/dsa/pkcs8v2_dsa_aes128_ofb.pem</a>
+ SUCCESS DSA AES/CBC/PKCS5Padding 192 <a href="dsa/pkcs8v2_dsa_aes192_cbc.der">samples/dsa/pkcs8v2_dsa_aes192_cbc.der</a>
+ SUCCESS DSA AES/CBC/PKCS5Padding 192 <a href="dsa/pkcs8v2_dsa_aes192_cbc.pem">samples/dsa/pkcs8v2_dsa_aes192_cbc.pem</a>
+ SUCCESS DSA AES/CFB/NoPadding 192 <a href="dsa/pkcs8v2_dsa_aes192_cfb.der">samples/dsa/pkcs8v2_dsa_aes192_cfb.der</a>
+ SUCCESS DSA AES/CFB/NoPadding 192 <a href="dsa/pkcs8v2_dsa_aes192_cfb.pem">samples/dsa/pkcs8v2_dsa_aes192_cfb.pem</a>
+ SUCCESS DSA AES/ECB/PKCS5Padding 192 <a href="dsa/pkcs8v2_dsa_aes192_ecb.der">samples/dsa/pkcs8v2_dsa_aes192_ecb.der</a>
+ SUCCESS DSA AES/ECB/PKCS5Padding 192 <a href="dsa/pkcs8v2_dsa_aes192_ecb.pem">samples/dsa/pkcs8v2_dsa_aes192_ecb.pem</a>
+ SUCCESS DSA AES/OFB/NoPadding 192 <a href="dsa/pkcs8v2_dsa_aes192_ofb.der">samples/dsa/pkcs8v2_dsa_aes192_ofb.der</a>
+ SUCCESS DSA AES/OFB/NoPadding 192 <a href="dsa/pkcs8v2_dsa_aes192_ofb.pem">samples/dsa/pkcs8v2_dsa_aes192_ofb.pem</a>
+ SUCCESS DSA AES/CBC/PKCS5Padding 256 <a href="dsa/pkcs8v2_dsa_aes256_cbc.der">samples/dsa/pkcs8v2_dsa_aes256_cbc.der</a>
+ SUCCESS DSA AES/CBC/PKCS5Padding 256 <a href="dsa/pkcs8v2_dsa_aes256_cbc.pem">samples/dsa/pkcs8v2_dsa_aes256_cbc.pem</a>
+ SUCCESS DSA AES/CFB/NoPadding 256 <a href="dsa/pkcs8v2_dsa_aes256_cfb.der">samples/dsa/pkcs8v2_dsa_aes256_cfb.der</a>
+ SUCCESS DSA AES/CFB/NoPadding 256 <a href="dsa/pkcs8v2_dsa_aes256_cfb.pem">samples/dsa/pkcs8v2_dsa_aes256_cfb.pem</a>
+ SUCCESS DSA AES/ECB/PKCS5Padding 256 <a href="dsa/pkcs8v2_dsa_aes256_ecb.der">samples/dsa/pkcs8v2_dsa_aes256_ecb.der</a>
+ SUCCESS DSA AES/ECB/PKCS5Padding 256 <a href="dsa/pkcs8v2_dsa_aes256_ecb.pem">samples/dsa/pkcs8v2_dsa_aes256_ecb.pem</a>
+ SUCCESS DSA AES/OFB/NoPadding 256 <a href="dsa/pkcs8v2_dsa_aes256_ofb.der">samples/dsa/pkcs8v2_dsa_aes256_ofb.der</a>
+ SUCCESS DSA AES/OFB/NoPadding 256 <a href="dsa/pkcs8v2_dsa_aes256_ofb.pem">samples/dsa/pkcs8v2_dsa_aes256_ofb.pem</a>
+ SUCCESS DSA Blowfish/CBC/PKCS5Padding 128 <a href="dsa/pkcs8v2_dsa_blowfish_cbc.der">samples/dsa/pkcs8v2_dsa_blowfish_cbc.der</a>
+ SUCCESS DSA Blowfish/CBC/PKCS5Padding 128 <a href="dsa/pkcs8v2_dsa_blowfish_cbc.pem">samples/dsa/pkcs8v2_dsa_blowfish_cbc.pem</a>
+ SUCCESS DSA DES/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v2_dsa_des1_cbc.der">samples/dsa/pkcs8v2_dsa_des1_cbc.der</a>
+ SUCCESS DSA DES/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v2_dsa_des1_cbc.pem">samples/dsa/pkcs8v2_dsa_des1_cbc.pem</a>
+ SUCCESS DSA DES/CFB/NoPadding 64 <a href="dsa/pkcs8v2_dsa_des1_cfb.der">samples/dsa/pkcs8v2_dsa_des1_cfb.der</a>
+ SUCCESS DSA DES/CFB/NoPadding 64 <a href="dsa/pkcs8v2_dsa_des1_cfb.pem">samples/dsa/pkcs8v2_dsa_des1_cfb.pem</a>
+ SUCCESS DSA DES/ECB/PKCS5Padding 64 <a href="dsa/pkcs8v2_dsa_des1_ecb.der">samples/dsa/pkcs8v2_dsa_des1_ecb.der</a>
+ SUCCESS DSA DES/ECB/PKCS5Padding 64 <a href="dsa/pkcs8v2_dsa_des1_ecb.pem">samples/dsa/pkcs8v2_dsa_des1_ecb.pem</a>
+ SUCCESS DSA DES/OFB/NoPadding 64 <a href="dsa/pkcs8v2_dsa_des1_ofb.der">samples/dsa/pkcs8v2_dsa_des1_ofb.der</a>
+ SUCCESS DSA DES/OFB/NoPadding 64 <a href="dsa/pkcs8v2_dsa_des1_ofb.pem">samples/dsa/pkcs8v2_dsa_des1_ofb.pem</a>
+ SUCCESS DSA DESede/ECB/PKCS5Padding 192 <a href="dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.der">samples/dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.der</a>
+ SUCCESS DSA DESede/ECB/PKCS5Padding 192 <a href="dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.pem">samples/dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.pem</a>
+ SUCCESS DSA DESede/CBC/PKCS5Padding 192 <a href="dsa/pkcs8v2_dsa_des3_cbc.der">samples/dsa/pkcs8v2_dsa_des3_cbc.der</a>
+ SUCCESS DSA DESede/CBC/PKCS5Padding 192 <a href="dsa/pkcs8v2_dsa_des3_cbc.pem">samples/dsa/pkcs8v2_dsa_des3_cbc.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 128 <a href="dsa/pkcs8v2_dsa_rc2_128_cbc.der">samples/dsa/pkcs8v2_dsa_rc2_128_cbc.der</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 128 <a href="dsa/pkcs8v2_dsa_rc2_128_cbc.pem">samples/dsa/pkcs8v2_dsa_rc2_128_cbc.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 40 <a href="dsa/pkcs8v2_dsa_rc2_40_cbc.der">samples/dsa/pkcs8v2_dsa_rc2_40_cbc.der</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 40 <a href="dsa/pkcs8v2_dsa_rc2_40_cbc.pem">samples/dsa/pkcs8v2_dsa_rc2_40_cbc.pem</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v2_dsa_rc2_64_cbc.der">samples/dsa/pkcs8v2_dsa_rc2_64_cbc.der</a>
+ SUCCESS DSA RC2/CBC/PKCS5Padding 64 <a href="dsa/pkcs8v2_dsa_rc2_64_cbc.pem">samples/dsa/pkcs8v2_dsa_rc2_64_cbc.pem</a>
+</pre>
diff --git a/samples/dsa/openssl_dsa_aes128_cbc.pem b/samples/dsa/openssl_dsa_aes128_cbc.pem
new file mode 100644
index 0000000..7af858e
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes128_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,3D7028A746BE6B09694E16A222C543CB
+
+RkTEJRJjGfaMfNc876Tx1hD92cblJRj7TvUafRKnH0J3Zv7l67MSG/6rY5HD91HP
+s9i9Se+H8Sjn/HaUl3QTZv04egloNlL3MPSkI5fusR6maZGPVLRJBLfVKYQZVDja
+9YRe+ZhXMS8jTe/IhYMcTlQLBnnwmmgZC09Y9Wm39idu7lytOl3JBMgz0aUNA+P6
+lN2MtaQyIBXHbaqfNDGFn/r7+MH4CGw6MtrPzGqRJgGMHhV6T5o/x0nEU+loQVOK
+mPkSZTxBbn7xUb4JvFPnLTbsI4Cnre3QmfmDwkCAklQXqAIT9Ex1Slq8qaCc6TEf
+mWJQCYPUkpQOqyinR8o1VbYm3DFFvE5F+CktJrppqkQvAct0dQNjMTBFxUjCkZum
+qGfAslGPBREmmnsExm5GThYqA5LN+qo2prBtvt6Eso0i2jNiXA8bi5OfDzDr24R5
+/RKUdFPf7keaAjg9jSArwp6EfM3y3sj2riibwZlty2ckPJw3SwxIe6QSMwKRbKlh
+GJoi05/cO0NxQYhMmlwVN9v5+YpvWmT3CsFvCA+Zb5rXPx2AZpFv8YoHdQb0qyEs
+b5YuVoavL58+BWIPQpeYy/jttR5pEPpgM+C/6/1o4Cae4lwppP2OYFl1fsqyqbKh
+iadErB6QRaJCnfnhG6511CxY+vZtQE5EM36blOl/op+6G+36ApuqDtfA0C074daV
+uHfcqA/g5dODEJP+ps6yoWtM5lbd5bZZVidWhrU6Skbt0faF9w5ECF0qkYDGqF85
+qqFcaoimq+NP7EtUEFSneOee72zYALXyzjoEU9InktzDi0Oufojzc1gjhh7LbObw
+UBANPHTsbaL6FPTEs4a3JYSyat9m/R5GAaT0EBynHxvdQRGNhtEWFPkpGYUrAz9W
+0A9mNX1as8Jsxkh9wqjgOR6Xpbqh0aFHNnkodwV72H5ROga5EN8/bbuCBxInNzy8
+o9z19AnajR7vCW/p42QwsGfSolQgE3KBdqWsle81LcCPVQPQshXzcjgBHZbH9/mY
+M4bX4iEsC9yeNgoMcHtIagOKipsqd4nuPskutf07Mh71OXFuxsVyGcOBVhhdZCb0
+3ZYzVi+nzORPRZ93nPXipy3+NmoARk7mhXDgX9p1bPI=
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes128_cfb.pem b/samples/dsa/openssl_dsa_aes128_cfb.pem
new file mode 100644
index 0000000..de088f9
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes128_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CFB,C0CCB782DF620FA388D9A356F8B7C346
+
+DftIvr+HZuCHBanw4n8P5ZajHAw1ldQkSgLxtxY0ZYhhVDLEqEqh6z+4ySjZz5SR
+KY7kYFo6yJnURurg3DAGvJ55s6jgyrRHQZkhiO1fBxhyarOfcBjJauJKDT4uhFtC
+LWZ7dqft3PlcHi09mFKjK+BYjULe1QkdrKQlV5FBpCj7ENuHqtfx//bV+IWWVnbu
+QRx4ec2nNCiS2qiI9Qg7fgMdXWrpJlr8Zvfmn0Mta3Dn9SWR9hK5J4d3xiBtaF0F
++BNuszy9poxnsRaORZYAsBh2vdLaQyn1gGdehlsWG4J2Zb5RHApYczJcp2AoPX4K
+j9wAzlfLRSZ4Lt5edShd1zf/iDxegBKQFFHTfPA6uu+fe38qckdxVyBdGaCCBvUz
+Quu2DjjXdCWWo8To5C28LVoVyAy+qJaX86vn7yw03/6n0y2dkydiB3u6wnucsom2
+HfLX+pdyarFoNvtCeSW3Y/1Eqd54dDhz3GrSTh6c7G+wiRziKpTduEmoZ+l+CIrl
+tWxmh59YTSeX4mi48+fxTA8xaVwD/j3VuA/jTOQWDW+DXU2z6OcAQ9rlOnT6Jad6
+P2El+vgLrIFbC4eJs2ry6bszqFJ4wieBVnazPCUADLSsXVwbFuO9oB4129y3Yg+U
+dE+lN24KV0kC/YIdO7c2PghaFY98CVrBX/oocHy4j122fHfboiPNh7S7n6cqJHh2
+JKKQK1qTdfULAN5ypecl27gWeM2i3ib2C5jJiOFUlwiAkZWLRJlsiJOk+b/rI5FD
+tM7yFanhEtcYumRRoSzKII3tF0h+z2AwzPdsyJDdASCzo/DmhB0fg0O8G0q/isNi
+VV2zL+w7mNmf79QsrGVA39Y+G/uKS2QPf3bGFthzYZwKH1M9hTN/do8wCCJJv7MR
+Ejnd32srumBOvGXnYtGuHnT3qRA1mj82B00bdfwCd09GGUr6mEQwfvsDOR3q4OfH
+eGCn9NkWKYvf/QAxCG9Vh7u62sUlXKS08hJcVAgBOzN10wFISTIOAvedt/q5GMvm
+nRuF/ixs6f6LNy/VgyztHoQ4vN4HBf8teDsbWSMDvlLkU6tQZjyuu8JkTjeDaqMv
+GbCzrRBldS3zMXX2OaWpZohi
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes128_ecb.pem b/samples/dsa/openssl_dsa_aes128_ecb.pem
new file mode 100644
index 0000000..4f69fa7
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes128_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-ECB,174C8C70B397BCF00CAECA7AAF7A0A73
+
+wzs0bJqGg+Scn00TgtgXyV6hopQKVWMEFnMpu6R/Sp1tbPVlr+m5+SppJFVyW3WJ
+YeFSwXzuVAsnbD9qIZpAlco1ZYpmRXaY6IfXJKYf58v2IrqkxVd6AwjGN2FloSNp
+b/DinJXJe807tNAkuBLQ/7QlkCv/BmZMeYBl60XYIH8LDF/T/ON2hREl49zr/GLY
+bwmVzgRpfl3c8QIt6Yl9uKOqCFJmMHD3YS+dT2RwuQwqY+U3DNzVoCci6Zjd+gL3
+eb/S6VstodSR55qF8Fkwt+sy5yL6XmhQaGWEgCwDwArN40MWIEpx4NaBxCcqHF7g
+o26bg6CZwY7Rv42RTHKHNPETegZneAMK+e1lNassSijak+A3ng9bxiBquWSKHe0i
+s265Rptr/GvQX0hLxmfjEjvL98dKVDZpvdBaWRqV2lS26jDPiFAHtVsXvF8uo25J
+1aS8FDHaD2DghC5aXTQRaVy1jlMTm2YZeVfiU6+7HVXBkLsVbShqEHxKylxgtB/1
+OAui+st60+o8lvRmn5dT2xnxLn81Bt4qron4pz0LdzC2xl0DqjhXyRsf7kdxr44h
+YN1YzmdU3fYFzQw+VmE8xECIjPukp+0HSb4n7BTGsWvqzntFIrzWGeRmNhjtMcwy
+YJoWGnz+WbxP3DJqSGNdFME7mNI/kaybIkOpbHLLlmgD7XWpeyGYtsU/rzrh5NXN
+YRj6Nf3TWI1zwS2xx95+/5vc5Df+sb1+/33J4hbGOx9KdfqoVlJZ16puvdTq97dF
+x8TVYxk2PfBJpvpChCsFlYBOB29F+kY2qoBKPbrvmFPsPCgI2q4gFuJ9pq1qyDbK
+pq9d1oewOOxR22VMQNGG7tL0tMmtXJ/z0n3Y1UE3aYiSG7apOhooBAQ8grpuwqbn
+mGTz6sYB8fHdCnedcxEUxxuFjXupmBcT2ulUjFZgFrG0SEMElgTDjtG21eurqPKh
+ZgxfkW+tM251WTi6sqjiQO8WYHlU7+XyO3BKfH5v3kz4qXxsmvKfh4UOfRy5f9YT
+Ft5oi1bos0soTvms0d8ckLt9Tph2wgoz3Sc++4DRcF53Ks9N6iUgtTpkEtmd/Uc2
+5+xewYmlfYO2qfiqiF/6dSVfDPjJYR/YLx8KBZ40/e0=
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes128_ofb.pem b/samples/dsa/openssl_dsa_aes128_ofb.pem
new file mode 100644
index 0000000..cddcea9
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes128_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-OFB,B32C602DACAACE3A4C55B4600D974E5F
+
+w1+kMXURdxpREW3giZg+PooayvatT1Pf1bY/h0Wcm8z0w7zRtQOyjCOdEPNxsdd5
+ZYn3qEIOO+wkw0v0PdK1AaegJfYMbMpSp/iEyFXU/LHS0FpO7o8zmUiAvdeEKAFt
+Qk90gFBiyQyvWEWsp32KQH1/eDSeSLeQbfRfDbh70DkB4nUjYMW/eFL9E/cHCmdw
+0LKUpEycc4s8i/mWCYJF+cQd4J8RHK+Ose2+5z86kHTrbFSlTBEZEXPDRHl8ZsZE
+477A6/Ndy0Mq3+NgMLSl8xacs2v3itdza3AJREVOzvnRmV+NmWtYQ4MQrJrLg2yv
+wfAf4b2r+k8Igbpzn3NCEYolecGfyEWftzTsqTutlFO7RfeW8go4v2MvEsmHTphQ
+k2qaQkdSTFaA7a2O4PKezJap4RRCJhq1d5bw7RwkCpbRshsvrKQqGdTGJxEZZfGY
+6pOt/qRL9LVCGUVdTTdje7fx9okx0LvKo62eKcUBh/AwZGE+ue28g6/77iABuVtQ
+6kgJ3lQK3AQwKislF5cBC9MAkiIomsoVOKiP6+yX74XIa7T+3aWXlsY1oX13+kMW
+zijwOrc114Sus2eS3xSCOWLYN+0GECMrh2NDGDW6tx7i3R20BuEF/IwHob1qjbkz
+hnS8KrRY+174avQDeF1lMSBz4Wfi0O1IDuxWRDRT2z31E4E8EIoJh+73NZr7w6JA
+8usK8RkiJ4ypoOPtRegXX6GBG5UYgI5bn1Ms2X5xSUGIXgG8IwjHDbAAd5xLSWp+
+01HzUsR+6wA3MxYiybTU4eOKNMviM1G4gGsKeuGrDsNnidrHfSzVyOGVVHr51xRI
+9Xie4FX/VX8/7Q5RMsA8Y2eN/yeVwXup65JRhDD5LjILVMy7aA90KX7y/s8KIYae
+n6lB7PtcpRWwhdYSYtnlrJmYmrl55d6ZQtJm2/xjnOBd+igY4YKNjh11xBL8YNo3
+wBjW4/lgrlvC7kbLxO6JIWipPr/6F3bjvmeLclTAZxjM1NU5HhTScGaEA8A4bq4+
+6Jiw9ZUw+TDCOmntkgEublcCMjcAxrawWYO/5EWuOAOkyBsa7BbfsUv3pgPugz70
+qa/CEkshP5e/1VZgFq/BNFtb
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes192_cbc.pem b/samples/dsa/openssl_dsa_aes192_cbc.pem
new file mode 100644
index 0000000..9b91632
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes192_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CBC,7FA13403627D9E1FA02FF88F6D594679
+
+hZYB09uY4gjQFEHX8KGI33EzcJijYhBMNJCR9v8UK8IcQIITOfZxYV2BmrfQhuVh
+Kcar1JrQdnc4S7+UDFIjlLV9ErBCvIUQEflP2ByDhxl892EtVcoMKB3BJ2Rgi9mk
+32KhayXo5V2bu2kOv2nTAjp91LebDz/ylmhhJhI86BL0DLjnjTEl99v9OHQsMtb9
+cXZb51mwIynmqU7Wf+PchH83Yw0WOKs4MOrCtsqO9lL7Mf/MiSSiE+S/rpKLPXY0
+4aBxP6fw+HG57gPlNAvv/qKtJu8YgZDqVXhIKNDZRTSRX+B9R1Yo1tgmJVPhk/7x
+mmYUxIb7w9nqa5OrxzFHyNvo1U5dJcXyCEhvUZ3ImR1DZt/oGJYgrPd/8YcYbsNP
+LKmTLUKI5CARZ5KcOjfM8vpKqlfpCg3Yl1FaNIjM0eAhD6XrepLj3faAJW4/YEoZ
+SGMO5atbM0ERT9sNDJTG0iMW6xGL5l/6pzfsTKI/2yMaAeWAyvg1PySNoSH7s6CC
+CfqF0w0VpQEiOPb+qjtmjBDB/VW5kNrRiBQqZAgpO6mED0jAdg9o31tyuuaFDWzX
+41C2viVvxTx5A/xOtPvaDo9EMecc+7MpPLM2VhWhPDiDBYb8PCKqBOEwIyH119MN
+gQEC0IN/itc/J9ybHLCjrF1Rp83T3/XhAaXNVU9msBBpKNjawnwsUUj8gI0JRbx/
+5ehO32sQm8wkMyP/8iKDAqBRkDT3RIEmLi8ms+ZZRmLwGBkSZZzvOK3A5Dder4bp
+dIhOOetvoN6Bs9l1i6Dds64pwsy8IcnLLeNmOag+Qh8+pVUBNZ1zUV3KSizRKh5U
+dyT6VMILd2EAUJYLXs9HNFTtHZglRb96jQ3rkHGmAepeIVnJlNGKByvDUsJQDGl/
+bGNk5Ejz93ylY8JzR1GaYyFVIUU0qY8khbo7bSn/o6II+KjyTTyTkV28jTSD5dYe
+upGHOzmqpGi3Pzaz3DXpbLcMzwYrMP9FuXuqkVWToDs87DCfGqskKtko+zlTV7/P
+eBILwUawtXMJfYntkV247FffKgS3/BNkgEE+iNthOsFMSoqX/3ESBKJdJDfKRH0J
+BkYL8O0I7OwYzfU3gCWVZ8AvAhd+nSqp4H3QUK0QM2w=
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes192_cfb.pem b/samples/dsa/openssl_dsa_aes192_cfb.pem
new file mode 100644
index 0000000..9dd5b15
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes192_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CFB,3E445502677C77AC6ED115F8EFD9BBB7
+
+fJXVVcgxhZJXZANfEWDbVmz75ocICvntATRNVgt92sHgl1B2c4cgQC4Xmu7WM/Bc
+ocUlcSpWnoHtWRDumw2cwB+fDb5k3e9qb+aL2juzHkK+kYd2mkRjW8KSG6D8HIwq
+fpvV6NQmVrxI5+n+uabwfil8Ecg9V7GD6ta0QSgt0lc8clp01se+VDacX1uCB7zG
+NtJsr1wUM0SQbEWPEcpLUoYfK0qSO0h8fpnagKrNQLfzFbk85arkpD9XBzxpNO2p
+2fYsc3xZ0RkFauSZGt6ehu0jh1TZNPYDURvSn3uVrseLyR0Gt8LWp+hjIUp9Kpo2
+fLUVaH/7wxpdCAYzo4Ub/gHPfbxo2E5qYmE1oTJyAHplaDqSg8pbwJofiXl12gMM
+IyIC3SCHZJph7xqbKa+W/X4ChxYuN23ZMZ72cmqH4tH/j9IpKrpWEeqjxaj0EwDs
+R06Sz/qAqs9iDMKTkuFTMxGhc09DV9sN4NYczEIEas7gploOdryJGMCM96RtMDS1
+gjW21w0wyfqa7ogsDJJ2/HqKL73Zfn7l0jzmqya7YwcToEfKOSP+a2Q/y3Exr4KO
+FY5PLwKvpBaFcFzJoYhAaPphUzzAQuQFgXj34f4JU9bAXbf7ol7Swcv9JP9tN/mF
+n7z55BbPfC1EiyGyDjeUDWw4XIYF6LtRK3lnvn4uSZFXLmYMJJthwwC/yS+D65LW
+vsW9uuQ2qEfEC3hVbMPP+1KMgRkb9CVbSXBH+B7UoaUkGsJYzdSDeHZHbwiHgxqH
+jb6WcjtUjh7W2VO/MnHBrLg8dnC77OnR4IiqJq/6TenuSu0N/4mm73SH7BtYAugu
+ok/2H7GYfGfWjOnd+QvG/Vjsb+l9gtB6SXYFiWuThjB/sU4kHH8LUUOmGRlC3NDz
+w4pv+cR3tS1zX+evPL0BsZ3ynDSGRbMpss7xVooxIPacFwDN8kHUnWvIBpQKAizq
+blt1owc97vidf9OnZxUMpzw28/PZ+y/vRYSPQrde3kH8mJmu1FC6tLZnqzuCSsgR
+SJSr3/8qqSj3XrAW+nj0Y2P8lItNdFXex7j/RuX3eV5QIyK7uY+z8ZP4gf5q9w54
+p+dQi7Vx8acRjbsU+r85+MRR
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes192_ecb.pem b/samples/dsa/openssl_dsa_aes192_ecb.pem
new file mode 100644
index 0000000..c7608e0
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes192_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-ECB,C625A2E97BCB192B31A8E33CB0CD857C
+
+jM0PVjU2r063OACSZgLkaS9ppOj4idZ9hgkdMi58Oi+C5bfhZavbjROyxCG0EMGz
+HnAIRJ4pkJeZTnGElmOEFbaNPb42NAvcrYXAP4XNu5FbZ2SqGKwRnjjN8z7s8+Ip
+MrCyJsWycYy2BNaksJRaDNgazjKgqQxGFlQPJ+j99E4dk5QaduOCrf6YQ2G+1Q+m
+2/uqVujTwmverPnHDNhQI0ZYMY+l8+oVcPHIY3TR3ufecvrGkjFgKH0B+/L7gWSd
+ASvldEnWuFtPMiYnqCPtLgJNKSXO2nlumLc4Gz2ruvYKI1qGPXsVLIGnxISVLUzT
+VQz7NrRYwlvSLWdQNqbrEPvEu4q1KstqIkiPRoC98vG4+VRkf9AXAGqxA+vKYktP
+2Ui/SLhoC/seh9pxYXLsmqP+8bxcNM3VsJQoUUFM2PtfyvzBtuQ7mJQTSFSXgBym
+qXvzx749S4xOot+H6r/bCh8753MMEsgsM39jBsRm1zbaBjaNFG0UBdfFigHWh1zx
+4I44pIHu1AQDexjnfaUVrZFbys0CtM/Wy/3y0I3+mar1Wg3Rc1XL1PJzwDqBoZst
+vg1h0L5OPV1c4CekFnAEx+VI6ImxENoYtZCpbpt90kz3GxRY/eS8roS/SRJ7KizC
+p9bWEsUMwJ4Jl+xvV/VtVG96nKzlU13gkI6lMATYzImK4Fh7hH/LBy/UhNVL8X76
+3fo64CCwE3YkrWEmBDdxt/K8Knj4MUPjBgy/ETVRC7ziG0rUwRSd7zLOoEALMHig
+AtNX+juPvPU7yARw317Q9lZXeytf1AmGiFGjYZR/mduAa9M415uWm6zutIJEz+q8
+KV93bm18JUaQSrX4D6m8IgNhX0EfmRYAIFnB3rv+1rsb61q+4USk0L/1vKT/fGGm
+yvXMCA10N50wGS4wovMYQIl/giMEU8e88f+gqImU1kporgESIOUYUm9tOZ80w4R6
+ITlKCzRuoptMQBGZeJIWfWNLxwYq7NXKpvjNeSOeOqQ4fxhkzEetFERG/2hnszmM
+pqwoZBZQ8bb+T6cmJD1GuxoO3ev258WIUkEZTkFYK2Q/+QKymPZO4ATSAO4N2UqQ
+4TXRqUs4i+1f/BJU0ahnSgmzrynGmskUonKxt6T87lE=
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes192_ofb.pem b/samples/dsa/openssl_dsa_aes192_ofb.pem
new file mode 100644
index 0000000..5010035
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes192_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-OFB,7E4DC037A44E5DEE4E005CED36B18C16
+
+hvLtWTLg0+cMFDo3jN0yZc8S7fE6cDdZcBK0aRy+Eg+9kWlnmR/VYqG4xaich3VQ
+wkyhNpBSAoUHY8OKkB8hYsqbGkuKxQ6Db4IJlahCTFgb0yO2C7pUrtGDTvmXVq2n
+qJ4c+4CILeyzIp5yfy0dE8CAsZZcLEdSpPvaNK0VPZEPhelm4WdqqLozYVibR0KS
+2BbVO+E7yHGC/G3xtdbduuYpID1pLwyaebUCNgblggn6FJ0G2+Iu7lndmMU4B1Wr
+phvb+Fd1kL5421u8OOKRVLS2yMtlzbK2Mz7NclEzEs1m6K/xJUzztxImAxElBiiB
+YfOw5WLy278DuD1GCBkSuAKB4XWUtlq0+tJnCzAG0yrdMloKH1m+XF3MXFiRTXgE
+k08PcZchoNgGP51Rcg77skATP9OMamcjnkMx1B8YxTx9O5Vv/oSIjGQrr+t2np2t
+JU1dHTr9QrCeadSz+My0sjlZrL3ZisAwBbu6C0Zta1P1eB+i8ORZvm9HvmadcyyE
+y5oQWv7XwSfAQup/4uuAJ8bQBunIH/ajMF1WmD8rzLcUjG8W0rnBWUtjaxxBdkWv
+xBzgMPm7Q+L/5yhL/TMH3dkUBq+Cg5VQSe9EspNRGKBUgfKYk67Y343Mv91xKtX8
+8Tmh/WlnYXDv8QBnFJZXVnf8HeSFHsHDzfTgAmWHdhisTNwmgSFvBK5ghvhvkbXI
+UIPi+FgeB7P3ccFYnmoMq5qgK0Ki4lU6v57soDrjRl/NttfXdQEhLfWO1zXNANLk
+lqEhJSvBPZY4/FiOW4kNaZg2oRswz/+Bmp3amsK5TwBcI72rnH6SW5ADqPCcTP+h
+IrH4L9wnhOXw7QLk/h58JwiEc8suj5n0PJPQeHKajizd/EpUzVAuRTAl4GMvxLCY
+rALxeRaEXfJH5i/0UQydEvdU3ZP/LTibAqStXyVlSBZmKOg0GNQ+aAiHZyBnI3oq
+QuD0KuJi84ETMLU2baRydTbVlQDr8O0vxnCNlPkFFOqVpWyOyBgMctUfFJiM5c0l
+1UT6dc2F7NF5WOuoDCVw+Jp974CJuBSRGpdQKGms1Dvjwrtnf0ycstswXHvp2ZhV
+IVeCbT4WWh4f9bp6STkdquSc
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes256_cbc.pem b/samples/dsa/openssl_dsa_aes256_cbc.pem
new file mode 100644
index 0000000..17289b2
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes256_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,307CEE18F79CA333A38CA90E75B248C5
+
+qyg9Q1cX/FGOoP0NFzrCRLwmR6bai7JzDiCLFCthciYkMIWLIVzvyTg850YD3dw3
+Wusli8EQJig8DEpFSM0WBc1Rne8U4168nKuRnFUaP+VWuD4UpNDt66cT6dMoqATD
+kZGdd+p8ReO9TK9gO/ZZU4R+q3OUpjxX44szxj/EIVSgphi8R0rRSxl/yFRnGHyO
+xfpM9NxgMvBYlyxl5w1Lp/ictuF3D505nF/uuhzGL5a+WWhSnssMFHF9vxXTu21/
+3Cy0C3Qah9eV/C2oyAU7GGsXHIfqFqsgMjQN+cTFqMyFeg6g0J7hytDAgZVBXIFw
+UuzMbxUUZU9VHcZzwqstkg5BmUI3sgW6gibBUzuJrmo7uLrCvHyj9oehSMqeuPUC
+EXFqhw6Nb+jZMkvW9J9qFYG9eg3PQsDErIdVK8aWdLrLyc+O4gycOdMbR8aq/3Z4
+TlV7Ye650EvQ13bwZghZyKel6Rjt4P1MagGriNqCcLVVsyrRXAiqjq8cyJgYtoXF
+1VMBZz8ob2FH9+kvk2sb4+T22sTYwiqAVaLnCsuJ4dmS5wdBrhfF4oyHYV2KOVgG
+64GqxiF9/whvbAWSM4cU+KslKnWGZwz53LKleafrgeFJ2P1ldqnl0on5EQ/m9bzt
++GSGwzZGRmhf5NoyhaH+OCkq/h1UP+LZ5kDJCqH/l1JZbvJQkGNKzt1OroW17GnQ
+EgihXAmhy/xOAIZkz1XKa3bNvgS1F9yreAxJAvBHB0QzZ1HrablsaTKsZOtY1Qvq
+e2OdpJFm+SrI7RUtbp787Yl9pH2cLEdto+WH8gtgXloS+b11Q7broE42w9MIJrno
+kzs6eDWafSExTvpi+29OJEtK4PNezmhOxzTUIsG0/8d9Vd2WYqrLD34ze68X8qUa
+CoIXYP8VsQLoXVzX7VnMBYTQ+YOR0Ntq6pRj07RbJrNiOt8qcWGslzE17ERuCr0+
+ZFTGy77KOksKjLksvRj4oshQjRhVYZscPNnwKODFDvOPsGFjDoU2Sg+W8kcfE6Bc
+1RQwk4N0cjkC2JXXk61QQjh+efWRBqPN6va+ixUcsZSxndCIoBk4qtqtsyTFEcC7
+LdfCC96RGnXlvroiPHvrmJYN69JAyyRrnhiYfaaC98s=
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes256_cfb.pem b/samples/dsa/openssl_dsa_aes256_cfb.pem
new file mode 100644
index 0000000..06718a5
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes256_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CFB,337D3978222A1367F5CFE08611416E9C
+
+GVmy9WG3oR1Vpfxnfpv1hFvXGzBgE+c4jplSw2BAlKnbznCPbZLc3WF/ZMv2851O
+iE/8sdcetzoAlm3jGPoDi6Y/FqMFmcbqtro7vUz/SVgi1HDI0FXjOTPtFe6xfzhv
+84qt5lz5VAUueTKFXEZHqM9tV7lHt1FX86VutNObn8pE7nAWVX/Xvq+qWUsEx0ik
+YjZjLY696pyz61hnxZE4jKZLRx/9a6vWYaVfzsEi2FLw9qAsw6ILp+xDaAeKa+Il
+YVkgDPi62NPr7cRX1WCiw+/feNYPgUfGiBNkd2mOnAr1yOXFM+YALw5V+q8I6ZKN
+k8R7skAzRZkwTJ9WaaFGD/UypYmhe2b9Jp2n0BMEn5RpW4o1DTIHmfMSUmUPp5w3
+HjbtdDUWIiuplrz7mUE2sez/3bMbcoiO2Ym9SInJKBrMFSvyasg403u4QESYQhC2
+Lwcocb5ixXoczHjef3CogL6BhL2oZwXCl3OBqpMOJJJKXUPRhN8bvgV41UIsiGtN
+TFUXqYdpbmMkxJNMGiD3mKWpSm2MMdQYnRlxNh0wXLi5sHckD/WS4yFrNsCIMVDT
+W094liK/Z7BmplY4TyqKhsRlFVQ4VOo/W0WNh7Ayp0siIfo8vHDyoQsnUkn/EUER
+UZG1lIy6/y1RSg15GWpdi1bvT9URjElh/U944LSYD28K2VU8aPKaRBokk+K3AyR6
+YhZRCBr6uIVZ8HDkBL5OW0eP69/jdbyc4MnWRa6C0d0boA7N639j+NQz9erYT6wu
+RkInmBbVfxQD6HLkMwiuU23qLP+QQTLkH7rQJmnRPSwAKEE8RiXWi4/TnYW7d0AC
+Bj8oaK6DO+J9t1pdj0IGluf52iUwAOf2Pxwvu44ovaF+yb2n3P7S5maDGLTV/xBW
+D6nEAct9cYj22/aRDTLdpOfG0L242vjQLnjrgezBLraa9eTy29hR5FU5ACH5sB72
+rxUSwoCHCJuNFSxC27QwZqeCFw51epwXxLv1CjqsQi2So12qH+vFVtL/1YrFBct0
+dzwbdNk0S6UyPRqfiOE/+Iszzahmb/GgskPJdfT5Y03FnpDWfOotpaAebrY4t6kz
+/gs8pxupvdKw4eWsxVCL9KOP
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes256_ecb.pem b/samples/dsa/openssl_dsa_aes256_ecb.pem
new file mode 100644
index 0000000..ab0f64d
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes256_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-ECB,267E98B92F05ECECABF28790E81DCFA0
+
+MkVFB5/gKxAksBI/g96MmN+ujdt0XFXC+7MI+0/OJ/H0LXlHlLpwfGlx/Je73Imt
+rOZveXf4I8sBCF1Z0Fhzb3TTTDxcastJGKWAVKaPzKkWdxNeUjx0kinbrkM7Spfa
+yG+wW+Srtfyi6LzEsbCduDK7hzfDnLbgKymdDeP0TVeJzEdXgXcV09a01GA+CEVX
+aHesQLNHyYm9nxFxK0fAnKo5r1I2JsozSWNTG3VNbiItxtfoJdXTn25I16qXjKzn
+MOn/A+RBpO+P01j4uk0q0SPJMlIYIX+RjgAoPiI5R5vSeucsdUJo1sWnSfqLc4yP
+vUG5wD/+lYrxsXiW61KdwIg3vy/ty5+GqwNgNvN0FZM8DvK+NQ9K/IpoW5RE4ioS
+ZNm1JpeGJiywsBf3Pi9mwR44tTVY0Jwa/TTQp1kEYGjhYXMIEvf+LUHwG5KO2wmD
+kDediMDUPaUx9K34eSpgIUln5d+1viMpC2VcDIg4tYjAODtGRxzgDUr3mbuoVl8f
+GqusTAdsNoIyilY44XxA2odHa4S8yXsx1f54P8fRYbA4Xo179LY1Nh7PwQPm+rI2
+mERkCsvns9jP1zJRuS1lYW1Dqjtxxq8Nt5RAsEwKQYLO4DfsuMZPblEXPAwSGb/N
+69xNs8ZFHm3KT1r7FdUrVpHk2vmqsetNa/g2wRTEuBmRCgrtTtEDWgdBNtDoHlBR
+pDIWgwNvt7oJIU0EbQkUgW8bmg1p7jxXN8Bk2QKZoOytxA4TB3fR1p92VkXzrkxn
+l+Z815BNfqnNCU5nNzLwk3jLgksZrDnLu4sXykIBC/bpP5fubnT7iJYh9h6ZGFeY
+QLUP//ssuZM2auNjTVykWUtAiglROzxnFZjMXEbujOKbm70Uj3YvAHjoKalkti9x
+MTj/vpR0xBv/iDtTFl12HIg+IEGL1PfX4xy2avvJO+XGFD4zcnrLfTMwtUJQjdQH
+dUMWP8VI266u+B6wGfcrhdCYqtvuLVUvbISU3YD/tP+esXh563kPnXd2UuaS3ErE
+/7Y/hzyUkDjJ2g37Hq3M4wbaEg/a6osDtfg73thDMadsbTLIDjHKgAgBv4umNtA8
++EaP0stzRH3ayHL/f4I5bHC8bMIAumKM6zap6tBiork=
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_aes256_ofb.pem b/samples/dsa/openssl_dsa_aes256_ofb.pem
new file mode 100644
index 0000000..7192ffc
--- /dev/null
+++ b/samples/dsa/openssl_dsa_aes256_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-OFB,A2D4D65382905DF6EEE7A315B10CF2D9
+
+CpLeywQMv8uZGrgJYM8rZ01awWHJWH/ZKkNi1rpQhaI1BAShQbIUvpY1IsMLa0/E
+g2+oj+Aa1UE4UDsAlzcfsKG9QHS8nOYWuLpU7VAyjC6wUPn0yI0sxxKRd4dmPIgW
+w3r0xO187yqLAjIZCj4y+3ANCjw+rLpZ5Zq8KAN4j6H1NEmzNoNVQbwY0hpsyxwE
+Tg7TkI5IyNKQSQC48EuZh16cJR48l36gzFOmZKr47gzS0zivvED4Vxdaey+WZkoF
+1XW4VbQGHRnLEn/I8rziic9E5pvvcZt6K2NwvzXrkS53ufFYZcgxNRxrdM4yLz+r
+20Unn2F2KqumB1RAliKo/PtudO7XfsPNc7rbF/stGhlxDWTyPU2HMX9tw3JkWDfG
+rRsG4RJOQgsx0Q73/7XPhgu1J2Wp39a/QI/IHwZ+rWIerdUPhs/MRRPoduAfSSZo
+r2z8OPJAlMWLwAjmmKDGhpTp/21n9xLo8tbvqmy8Frz+kAxAHXeHCTWUbxA+URKb
+s5NKQALX3wYHT9Xq0A27A/Zrqs5elqc/IQL58nU/Da3a3OfPB4+MNWeWU781ohhi
+VkBgMRbnQNCC8OPoeMd/At9GDEEj1rDxx49pJdMMwxXS04P43LiuNSmndCei2cQh
+/7cho8YTbdgjKF2kVCZvYXBVsu7Nn834kJw7eMH6slU+VM45jTkOTr2uLzKWrBL6
+YONiK2xdD9NlDcTsX4YRkt+dByJEcDAuvprVdnLKpFXAOWDLW6e0o0siuFIGBtgX
+NR5vA5llpOkladJk+j+dxX4u5Ql9KFPtD9uM05ik5VQCZN8pxy6On3GUeSdoAE9i
+i+rtgZofs39mZOTxhYr+Djnq3WiWntV91GImwhqiXxUBI/fs91+yy+FWphpGORaT
++Rab+cyvauBsdTAoSjjd5cNXXsztfDxEhLnZ1yWMQZxVgV7tcLevVo7e75pSZrN0
+/gMQAH1Fcxtbrdzg1fehLiqTEWp14lFyDCkqAqQ5C9niCqwyf8+6Axaukk4ImmP5
+n9eIykRezLizjA+GCe2oC1jXpVEEYVzOJpbBAwZqk/jlyNd0m01URxvhOaW1/M41
+uWDeQp7ljJrtiyMqD5P3STGR
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_blowfish_cbc.pem b/samples/dsa/openssl_dsa_blowfish_cbc.pem
new file mode 100644
index 0000000..8b71187
--- /dev/null
+++ b/samples/dsa/openssl_dsa_blowfish_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CBC,B23E9DCDF6361CCB
+
+BTPCHNUVRgsKo1up9Ktshx00vDANb05S4S0LPU/wzG8sj60db3bX7Uzr0PPy7ShH
+1zPv0PECYla1dh9nVBPOS4EQE3uHyzuDMTg0AsiR8TpysuI+a4y8XJeAhkU1DTD6
+YzmaodjbCrhautYUCzvcui/sWWXTUSWH/yrFOxaaxLpccacCssGlPc3Tmr5brPmO
+xaZvO32ii6z7WAP/WmyRoYH+BSqmUBhObolifBD5kg1ilPfCk3xMtz4lbJRWANsS
+r6YWPwo+qh1TIQWw40Kz4oQOteVNiwh/dvYGxMkd9Gs4J9nY5deKYExoWlYcci6N
+VOrGA6HBWzfFx/QWWGK77xE8yQ8HeeZUgkWwYoSyAmxjPWgCj+BT5gbYV3W9E6UR
+T3lsKGtI/lMW9N0DVcLdur0lLIBFiVbzxoUAL1SteLJ0mbu/Vnk4VhI5z5mOmSxo
+bU/HElXdjIhk7hdTU5PMNSKiAsxNh03NiPsTpEASMhz+oP8BuJZh6Zi/K3qMYH3u
+6BYmA+Ua23fFYd/kz2TclVwiQ1HQjO3+9l0aSgLhHFb3t0spYbx1Ld5+bAb8b30Q
+9w/fNab1mB6hFgaqruPErfI0K8BZ845oAiakZBfKnTRQxAlKNY5gWvSiPDWlkfIb
+uSBW6csh62iQM1/bcW0voR21NGS+WdQ3eg16vv0HMhmEXmEvtAuCGb6ZMqY117s/
+VciBymZzwdLKFjCqrLn6enYrT7uneOoq/8PaXD1rdMuKGL4W2LqGH+Q0RU+1hyBJ
+7ipTQqystqi6HUU2R1/PI4K73X0MMTB0Jfkd81S6GmjkMYCFCHmHXCdNULjbjzT4
+gppgVW5joIbLKNPHJ78lw4BuMxcAgptmtQBADnWZQNF/pBnIVAY/pdHgreIBTQ7R
+KL1/ATp3+gtGd37FOGZilhq8C4ML+w18M0iTUUfGg5svUvmtw+NpNWMijTJpu3Uo
+KqjMj3NbwCwu2b9qxwalC3qWOgAJf4Z784+i2GOvACk2Mw2QyXoZV8Qm520M+idR
+rj6DIfzEf/86TWH9IrGukDbJNB74QHgdXd9upyt4sL6uHMxPwz4nnhBB7I8B/Q59
+oB+3CBpYIANihDscUbiNSsw5/AXNtMuA
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_blowfish_cfb.pem b/samples/dsa/openssl_dsa_blowfish_cfb.pem
new file mode 100644
index 0000000..8372cff
--- /dev/null
+++ b/samples/dsa/openssl_dsa_blowfish_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CFB,A39496D20CA5F694
+
+A9ZO/WPm319cQ3hoxaEsmuGVDkMVhCuRzFfSWC4hVBsxKHd3FIw8xZpGSkEI7+aL
+cMtcyxTQn4jVV71Sw3vyb4N1+2i+DAd+63l8LztpTBQi1o2gTBqmqL9esV3shqWB
+JV7uyOi94olPea0Rf5PMRXx1bAZs9U0TV+5XHAQxM04lXRJajxiN9LBZ1OMRiUVu
+SdoHdXh077ylUQmgDaGQktWYuVH6leq7Yc9CF3nre6njFiUrpk61iPki7+/FgWzq
+vToqiYaWffy+1lB7sXcL88BtFaMWAOV5A48Mv05miTb00VbJqdKL+SDmu6j2Soxi
+Qk3k6Le0heXFHqqkURMKOrr6tepqKEjmy8WTELwMnuT5vNngMqDKpNyhdsIEJW69
++L0imi4fWIelCd7PMI1bbPAp2QsB8Rndjlfj3irVm0AtubL/rbep3JT0ezukoScd
+wLYNTlDdaLfEggry/1kYvPBMolU4xqDxg7C0quwYxLuycEFzU2QmWNtRn0xkfx+j
+ruApr4getT6q2fJznW7coiW+OE9Ik7JgtYUGEZuWFUeydDHa9PiJ34w9t/aw50Sk
+arATzKH66zM//g1zgzg31SmziKeE375skyQr2+1S9RajmdZzEUDL5ajsdrbALflf
+UPQNr0YEF92DRHsI4O39L/+k5fesiiU38u0NoKv5DDRb5T1lQeesDZCZBowQP5KP
++6o6lnj8kCeccpGX/eUukPXFl6mdddAJ/vLptHC1zaRp2dlKPRfedZkRm4Wduplh
+vQ+6oGqkjep0Q/LSRcVP69m91CZot86lAn9Ct0jfJu8o7Ua7KBeOB2k/rx1nUaZG
+BOjHQRaSvPA7FVKCP1UlT0GR2hTb/VcW3UQJ7fCY8E4hc1kPfoa/T+mf0JrHtlMm
+364YQh6KLgcsgVjsPBXnTN1+POH0Qy0xp/0VwQIQFWKwU7gsXprfs/uYx0uD2Ev1
+w9kIWLovIGmBh6HKptqTnjtdwhqueez5kb3MkrCMi3kqVmV1TEQoklz6eBbloXbX
+SyR5jivLmuaoCJOA3oQ/A+75bwcvUP4iULZbdTpM2rnURyljKNU9Hwxim0neZ0Zv
+4kiOZuhQKkGfj0gv5bRkDAZC
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_blowfish_ecb.pem b/samples/dsa/openssl_dsa_blowfish_ecb.pem
new file mode 100644
index 0000000..58acd6f
--- /dev/null
+++ b/samples/dsa/openssl_dsa_blowfish_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-ECB,6105920EB281329C
+
+ungL+71R1VG+DP1CKuROEP1pESqlLeGoX/vupWbGTWR9VoK4v/9e1Bh96r+hEobm
+LvgsV1xhWrnyRMMw+W5bSJCfBH627SxqHltgxPhyKCNAf76cTIAdxxXgLZAxjtJi
+mjuBDTNHdJ8NiAxJKLL6dr/hh+Vt1Lk9Gr/x7UdocQnhxG+IZLDSOFdXnFb8EBtK
+kmAXXyOL14Rerywi6pmbxaculi/CihuFm4u6GXvunFjtP33eObzKLRub5ktbCtol
+97rbDoAAUsPPm4efu6Fs/3CE/BfvjUf+cmOYu6pIKQil9VHtxXloXwkeykI9Kl92
+uZVT+e9WEn6oZslAzCnjT/r69+V0Bf06AP0zkdTK7lRNBhmcR9fAgHpxz52GC2Bt
+xsqEzU7d+adCy1M73tT+bA2RBUnbA6BoCDHkvtmZTGV4mkAv11tVxU9Zqeglvi/w
+6QVDQYo/b9U8GVkQFo0oh4xNaAUNdT/i1OIy7d+6UR8k1S9+r6SGVwS3er20trWN
+8mAJ3dWiy3yLreggSqEvwHSpwrUQP8uxdTZOlFAy+xmwuEb3AgT4/sHQN7sJjAN9
+ISdzp+B5tBbM3kQgvEXUZckVykM7jgyv7SJ9DoDaYXvlfOVFo1oM3aWf57DcB8KH
+WIV94r4USVElJERYHH9sR61YtTi2lIi1zuAQZKCf3ShJcgU+vh2ZZ3vRPQhAMXjZ
+0Doi5uxi7HK/MVenO1CzNmsc6XQtyTtONqlJVmBoSq3Il8phMkMXnaOeNrQsT/1X
+PzbQ6MpWEr2WkKsQn5hNA9b8BIZ+cwk9zeFbhwLH5ewjO25BWJkFra4gGFJl+HZf
+vMNFjlnxuMjqM+Fjn3YH/O08P3nF/3ZGezqTCV8OJigB4Cdfbf9OrNtJSvCVsH1q
+YB/3+KOO5mKObH0Y+k1pvwZsXMkj7exAEHh+nFLldjo7tBAycqUHK0RaZ29TOjqH
+J6/4SSzMTJL5PF9Ayjtx0Vai4sFrjRGgnvdd8tddA/bWq6JC5i0yWIWjCEu0+b1q
+q8EHdE39+gbANJn2lKsEAOOt242bsjKR+bblijaaEgZXHZyALOThcEXxn1RaFFgC
+4Iv+DftZrU8lOiEvN8w00K6GDy9gbByG
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_blowfish_ofb.pem b/samples/dsa/openssl_dsa_blowfish_ofb.pem
new file mode 100644
index 0000000..2558ae4
--- /dev/null
+++ b/samples/dsa/openssl_dsa_blowfish_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-OFB,56A8F965C6533468
+
+91TyUkVkBxdl1ZXkXezMngH3YsE2cuXhiEFySx+dWZqFWcOQ3S6izXXqvk9B5sZg
+O95SFlZ917dU+SFACzB8dqwYo0QmxvH0zaAIMBguuYib6YZVCd8/ElX0vyEEo68O
+9V856HAks6w5WZk4zTC/75skb3tdLRWgG42oBlXHW7GsL6y29Dy3xvaWHJ3vpKXF
+HygbvR/TiSzhWj/jJB6V4kCQAAm99yyMxpmo3e4Wis5AwGgf9XyHJx0gUCeyNqez
+i6UJMGnYsHl1H67ltpN13trIXRcXTUDhFTadRz/suaR1R8IEefkpsnBEPnJwBuPY
+tUQzlolPKuwbPXFukpJrhi7It7dLsDsw5DUYvyOnHkDXJ4vFAIplCKdG0+KLaYKJ
+pXI8FH6X4M1YbIPTF+k1dhCAz7Cz+cEBA5hfJfSA4p7L6f9NBPWso3DDsyAbdPx9
+JJkVPtu0ofZHzYuD9nIhRsXjK9zaQXU0szLBdtGw7rfmPp3ftXeBcXDnO2ZdXL+j
+PK6CJm0ktjnUMKY8gpWahUUfImwebQ8+uQYv+NNn61rtfCaGQWMStXaNYgq54YLs
+D5ImRdvWm936tNUCeoik0yhPVlriNC4gKswRSUxD/nNIetsPl4FB4DIS/W5fvWZf
+WYKwW1UlpC/HagbUVIuZcOrAMFTG+zLYS617lzZh7Y7K87GJH+jVwgbYSbHHFWCp
+V215NLfofwlV5pFwq8djbeEnBhKi9SbGlZUyaZKKyDoIIEnwaxg8BoModBEWHyWp
+OUmw/v81TQu6RwJYxl1C1U9n5w4yjtXr5oowgu6WRYXwWXZtevtLkHrhcuWt21ud
+Cq42ojFrb0GqIcYWDXF3Wjp4nLZ4pIqg5kadpJpcFYx+fcL++Jnxs9l8Ohqwn1br
+/UvY+gTmTwnICapIwovVjN6p6cT6MAok82oemWPZNPYXVwVkGewCH3DWqfeRYsdg
+6gDWeIwyk2Eqn4bxFz40NrNZaLqcmQPaJVRReCV7Y0jQuQWqSYKkBHgFodf2GPMg
+DRqs7doN2MW7Is6qjyc8CDDzPcSuaqUz0gzohupDfD1vAtuoC0X6U+m/8NM3yuE5
+CKE8rofcKcxmFAr52CUUsJBL
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des1_cbc.pem b/samples/dsa/openssl_dsa_des1_cbc.pem
new file mode 100644
index 0000000..f6fb1c9
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des1_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CBC,7D7F5AED62DF7398
+
+PvrGaVyP4qWxH3LR5bOjrjTZN9KEZ7eujPyBYWV8pE7+kBc01RKaHuOfntMncXPj
+cTvtvPq4z/Odrme5s5fem88QAoxB2BqM0VNviUMcCcAG+hgsYjYWjUDdSY+piAD5
+dhPcTHfSwgkA16c9pd+vNojdDKHEXzIci/gdrkJQXi9z+Orfb++NluGFUjAvQNlh
+n+wi72AVwFaSPfguwAtWAZNmL37dZO8VzuCTkhciHaJSZFtS1G5rLBIo4JzW6AZI
+PLEENN8fE9C60WYkfQB0PI27ksTS2xPF2b7MeaBwdPRU++hwZ2QwXH7nYlCWn522
+8wg3/QWuFIMdqtKaOjjlwvQxApV7OouRCxIFnolM8HvpZ7HvEVVT6oqcsJG339FJ
+Ru60QxuVsnz6ykuP2OoGTtGZNYo5cgBSpXrpUSmOp8HHblWa6+FSatNkBf5MxJvv
+pMRxcYJ7ftFCGgpKI38GgeBPkpv9Rr8PUplZlgnXkZl8trhjb0hzAAJrMqPkMQ2m
+rOgsIWF+gK6MdnZdSnY1DktPYSFCkfJt0BZMGBDXcbr8RKHeV1vJNWAPOcmTsV/y
+nwzv9EA1KHeMnT+wQ54q7jkRtDLIS+zSWt3qW0fJQzNR3BrMBrsij6GfRZ++PL3v
+4y9D+cDFVX6LMXUDLK8kxZ11A5rSuL4HROtNnIQf/MItKNK4Y5c4PAKAMGLQpPS+
+5dgmKiu6jAIKUVT4BOEjMJ0P03JZKQkPxVB9GgLQLGCq77vz6NaTWhJmz+qTdZoL
+JCvAAShdkVa5gl4hzuvKnmY9VftsPVlOUthuO4NYimnjZs6p0sXZKnxQ4J4BpbkX
+mX5Fs6RU0YTQphu2v+NFhcPpYwRiwn15CVUDW61Sb87HZ5xAzwQrlpFY0LI4TqE9
+6ITUYzgpVVAlslKHNePMcjTj78V2MImHlq7xHSVPEGkkPlsDWxG0snZRkmM9aAu2
+g8kqf8MVngWbWhxqXHA35wunnaBhpBxAgqE4r2yAhyfCJNF3B01zwjt4LeTnduj7
+1ZA6EPechsSQUGQNGBoSbO5zVbIQaRZvAl2MwPU1YWCCbjaiDDRp9bHhX8vQbI/v
+4TRfKX8FUSai83qORQ+Ncshg+gYkeCJc
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des1_cfb.pem b/samples/dsa/openssl_dsa_des1_cfb.pem
new file mode 100644
index 0000000..c3af8d5
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des1_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CFB,6215481F0FAE54A9
+
+4ZA2xcGT6hS0kQObPwTWmluIl2wTnoL2jRMbxrr7usOZSLYISprcATZWieEKLsu0
+kNNzIptFCmRDt0b8VlothTS2jBIh5nlu9LqvaUlIrVuMEn7umslWrLK8JWnHVKOO
+dMfqNcgmYlkbEfmmXLtlCbfQHT2kVlopD58yxf26FTQ+27l+hSX4wn2uD+xFUAcn
++9ZxAWQDhi2PYVKqTTPfhCPaKW7hjYdocADnIZg+1mhH++8fPxlDmBQBmMOid53Q
+WV9LI4Fps90d7GumX7qSUFZTkBKN3v+E2ahnoP2bTBQGkqWamKFTc/4uLCEGlSWU
+qXaGCy1AwPa9As1+B/jLkTstoslJppqvOooWW2R1o7JHqN44luXXQPZ+BcA7dSdf
+zRcMCpudB0AwHBy3mnUNuBlUjsf4rEpq51HPSS8duYow2I127uI8m8OCoZCaUVid
+msxVMSJIiDCiBi18EfCjMfGLtQVxJefMv2hmcAXQXSRDJTEw8Lrtm0Mtp7XK2B0A
+v8Kqpf3x+VBc770Xoy0K1/fe5oLdvJrJOLO5PVcVXIS9B/DTqIQ8ObABJPZ1sCKA
+sV8XebteS8fNXmFrVKBTmHBpUY8H5Z++VfDtKZZUBYSOqbFT+UU/+xJKlKICzFTo
+YWsmPTgFsu0Z7/PMyg/rccrb9fMWRXa8et0JGoF2NlYu+lkRb/nYPe84oS8RzZT1
+dtWJMiiom4xRgENDhV6/AmA9IuyXT3QbDfFB+ntdyk94U+Ms0ODNcdA4JmEa/f2k
+zFjtEGWHPH8Quit+zUt+8JnWSSFp0mjyA2ZtEj/6Qg5rqAZMdlpTo7rcuYOTHScn
+ic/H7V43SuMlRAM+xx1bGrNzjWUugHrVb7Kar56pSRPtSOQ00Dmz7gB8V5LU63n1
+YX3faatiPUNRG1dArcW36o9dZ5x8O5TErPHRJNYG+96UNoAzHMXoi5thuRyVbzne
+FpOqgxsryobcht7fwHuYgUq92QoY2qG6qMwHc2A3NrVFi8lJ0R83SN0lOzLebulu
++zDvrvkkRyH14uoAWi/o5IGBv1yIkO9vYApntrSO2aLnbevht9MuDJqW/Lkb579Y
+LG/sVwxTmBT6jdCgTdpd1ExE
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des1_ecb.pem b/samples/dsa/openssl_dsa_des1_ecb.pem
new file mode 100644
index 0000000..d17a90f
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des1_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-ECB,1040C4105685E404
+
+66Uasevd2pON2SFWljlVyWqmErfZn4XomzLHlUoagIwnQUEgCBCCpUscES98fini
+roGF/iaY59JnUCMieugke7/GZF1C0aXbIReqds7S6VFfu4Ni1OQTkL4rIauHrWab
+vgoE4+18OlWw6Rc0wwJ8NT/NCOmb397yTeb0w8VYERyzpwSLXxQ0BCOq4vOUX7BT
+2ABX0moazjUSyTO9BQZpABF2SshxaWFbAc3QRwH4QnO1bm7Pv7b1rvjrvPZ9LxgN
+fwjXG+yfHFBBojbEtFvgXRsSSyV5WCmAgYLgk5/nIDFSnRQGty0OuP+itX7SUK1I
+PH/ZjdIwezMKbyuon9D1AvdOEC1xiKEdmJCWSokm0djIVNmYbv4dtfrQE6hYdMtt
+C0LbsT7ef+jl0xG3k+WK24OsBVhTaqj8axIPZIVLELOPlx4EMfaFQgUjgqf5vPhO
+x6RSSRy+poFwtjI6ip/xu7ygqmcY9COXCcSffk1vpw9v+6WcMaYmDLwBTrTCNsdI
+7i6VJa1GiCrsn5o6ydGgdRNkF0N0sUfGnSzRUgd3BGd/fvxhBmcxHUnr8srrHYm7
+D54VL0EUsP33F1VF2ELl94GlWqfAj8NGBDkTbpUcqOeL/ERxdUWfX5IEc3h7fprs
+UjjjQ+d3GRliRs27m4ZuLtGeDEhDtlTC6qtKyqgVziPMwG46tcqyFzhbLCErHNW1
+07JcoDRc1LkXImSeWgjjhskUX8nc2/q5giTVtGmiWMQwEc7aYQ1wPbVAIGPQ4PE2
+XB8zvvPEaj0wXs0JjicrfzUBo6cRbdfmWIfp+ZoTUfr+gS/aZm+VYt1G7v6u7Qel
+AtoSdpN623OvqIP5ZDjOKROmAdMbXkxwwusVNQhkbdTzDYNy/yJnJqUUlhsN0VTQ
+y+O8Fz7Q7fEYIk8Euz3Uf/BTVGbLSNSA9n++CJYg1nam1S51WhCXRDckDLR0c4C8
+v3zpJvaQYW+xZUmlzrYRQgxkfzv4+j9W+kZLgvitQizXfTsuDyO8gwIt2csfGkaL
+EgX2+oITD/sGoaSoGknY42ePI3pPXHlhBjPq6ZWZ7uh6Ia90nV1j/PAcOEoAspAh
+pEdIAkFJA76qN9JBnK7lRMFXu/EWtBjD
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des1_ofb.pem b/samples/dsa/openssl_dsa_des1_ofb.pem
new file mode 100644
index 0000000..2d36cbf
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des1_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-OFB,BB20E846FFFBD3EF
+
+WeRgcZKkDTSxqvtZvx9WwUZYqXUUpY7siLG1Vm5jXPaEFOEQhmvGuNYn2cwwUYKD
+RMN5+sE51urDgI/xk6jdS9oZE6IlfkGeQSUoEOOfPVyVD/0/E2G0QTcKAAWB56K3
+setBb2ORbM2ZhetYUp1scaLObMEMQ5LrZaqtA/jUd2Pbs9D2MqafEH0Gde8e7mXy
+1fGNJWlj8XtAdmi2BeDKZHx5Hu0r/BOTic++L0Sv66wbjHw7RDji9Rdv/vyq6DIi
+0v0ZCexiNVed4mqD/3+8eGQ2z02UD7aZPy6T7E+b8kBuBi2ouB4HqgexVtz1L9x8
+VBBOBdpOLefwCZlNaeceg2kSIP9mMK919hlH472BO615YB4ugaCilUNLpvv9T85K
+s4hTB5oDcQH6W68mz44vWqSwED8JcdMYvivWY+3/zBSUvkyI8+8AErnVr8tvTX29
+aBhfegKV0MbRRRirj/EcxhUhtfgbAtllZ/Wpo0LWpIsHT0GeUfWdUerbFyh/8Tfr
+OQzC14xoLHdACDz5IDrLaLd87hZrKDJOELvzoSugg2W9NAzGbfoWJGVlvZ0miZcO
+teULyYcK/A7Wcba+jmFaXMrKVhNH0IuGcU+Pf1lYcchjAsdnrFMVRsNJ99QWlN0F
++dTyRgaiCInnmJqT83fI58dMmaJPpMeW26jItPWZWAA0vlQB1RgZ8C7i7V4keuVc
+0PYolX8WpLrrpUpJKOTdW6rmeHokJC46gOZoXEwZCSKUUgreROLgRN79RMBHKjoj
+0vSZWowgH82fNWYWQbJk5z4ldulWEVye3tQhRNsZarAWPFEteiKDTSkawmBpaA6q
+dJWiA+EdrVvnNmw5+xkbciMX0nj4xKsjRgPawdMFZaZNE3xu2LkrfGKDa1ne3JdL
+nDeyygGRDsl93oJ799maHaTLDyub0CMdyf2MssPLFklJdxwbtxNzbI0gt0NhZu43
+FDg91Z3hlAjg/Q2h1dVM22m3pnju2ygF11HUQdNExHlv5w8LWMeqWQ5j7WhSbM4c
+s2v5JURZ+jXFEf3jCs9h6pLlQNaipDkUQA/6DKHf0VbZJzKxBiRCwSP/YuQ6H3yP
+dHGRAd5CQnNc3Vv+yyRqQT56
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des2_cbc.pem b/samples/dsa/openssl_dsa_des2_cbc.pem
new file mode 100644
index 0000000..98d3682
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des2_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CBC,89A720DEE88FA71E
+
+ozUacsBZx7E1NCxbVYJJHQ0VTWl8RX0z/JzYNP58zcCIi3Cab2qlUshZP+Zb0Na9
+vlHabEqQCGsP8uLzneN6LDDaLmf+ucxKvCRrx5h8wl7DQcA5cAQhGofZuqChPqLj
+1lExS4ZaAi9lRL6aZhf6rgI/apkj+9Ky89sOqJxNhj66NgoOOh9XH1Uvrffv3jT9
+RxeVv5qYcAgfX4aIAM6KjC6iTZ8NyWmIoc8izYQycOsSAn6cqtdjmyc/264OZUd/
+1Tj5PG0q/Kinh9UBJ2F+pQgU4pDlWczXEIwtnmJ2mWyHBe2zuGWtP1uQFUIfwkEz
+KDTTFB0lm/00Xts+vGXgy2q+IvhqlOXfCkJGcP+OArLoyE8cu2xU4KS4qXUITSr0
+i3seUuTrda4aqrfyjNuM0tL/cUSEuT7aSlKdqSmRtYl9fTsmbCbndLKKuDJnxUrB
+ocXfuCEZNMQ/q/8DvwIX3l7RRIiJwqEg5+Ue/s2FTFJh4Iar/1gNQSApwToFHHhV
+XOU0pLY899B+1z10Nop7ELgJEKBK5+zMMBhB2t6nlMU3YojAH5qWEPa6D2Wr0Wu7
+x4DHqk0wEB6cDZ0PZGlWNOBP5bDB85GehAWKy73A73wYZCi9eCQnLh1Zjcjl+6T4
+fli2K+944sUKaUnY8sVT/20aXm1CRqNvgLknZMsg/eGZWX5F9+Jn/MviXmsH3LfE
+6VShEkNTFEsRUqF44Tvd2BZ6pObDPRDOkMgapzqdubujUesvb7LU3yNCRPBPngRT
+ZTXQynnbH0yfnFm6+0BYWtD5NeIzILwZfS6IRMSsCBMas5rCc7O2Iv0yhk/8K0f1
+Og1YH7pctbz1oAPmN/EgKZ1K36GTt33zfrwHpmKZ0jOWF90BQMgZ9dL+VyOMJYjL
+MiyetxwDdiP5TUUAKxXdr9t3AvxVPxL8aVjLb86kJ9HD+IgWUDqiROe88sD30Vww
+7R3sQhhl7drDGwUBj5MLCVhtE8Uli7HdaYC5CvuvlCAQN871whhk2gN27eqp81ou
+RB4kNaDK8qSn83ISnueg1jsQhUGy6B2Rx+rePxx3QwDsrMGf/u/tFJ1VcLlhmOJa
+svVKTMq88OAnZA1Hg6QlB03obSF9U6lJ
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des2_cfb.pem b/samples/dsa/openssl_dsa_des2_cfb.pem
new file mode 100644
index 0000000..edd5d8b
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des2_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CFB,AC1BA482ADC9EB3E
+
+tPu6t71kZlKyKaRiXgAMCmyxL/P6dVH/sPVY3KDFI0FsAGoPZaD8s7BkLLOy30Y1
+66kmaaWiaPjQN2g5zMrszrXh4AXazrjMrmIJ2NksNXz7aiySFafyYjyCPA+LIu/n
+KnfoE42KYEmENgMSUV9sh/nlwYS8I6LWva384BIWaG3qnFgfZ4gwgiI/R+1/lPXa
+olOpnI5szYMiV+som2E+I8lgd+Ahf2rempMnuwyWTDmUvYWwst7F5bz9XbmJyeWY
+HDDaTPy2Q1yRYBRvLTm64iA0J9j1TpJnSNm0uIRTVOEIZfOwOx20tFjo7RREunAx
+mEm+kmn4AIYhw5RQE5XQQvD42X4MLyc0M94k5pQHvgJFypXeJ4VsH8pkd4bqfy91
+qiPiKdA7nWnbedExwiwSPOhjOLkmQrXjsMVmoqqexhckJfmNOaXYtnQ8cZc50HjB
+6ccsjyLdQbLx1KT3e/NgfH4VxW4/hbbt3p0HMIxTnwt2lNG3AoKmLlOYSecuA4PB
+EE6oOauIKyJM8pwMV0hfBQ/MUQOnhHG+dbTn0kW91fRZiVPPvJiJ4NmEwD3ks3jM
+pLYZRot1Cd2ksJ79G4NXDFakB2bZ8EwtlQUrQHwW/ykPwiwpqCCha1PUzgsmG3hK
+U8bDWWQMqXtpSmItno1mF0H2TZzdbLpRAZe2lu8/mwww1qZfPE+MLPnCp050+BCw
+Hbq8fF1WVpJvsE5CKzi7Ll7bSrJ6BslrlzL4mFnnGmuz/mbBIL0MO24FNyVGKQlI
+hEzGu8lgp53pG4oSUZ+79CWBkn8mesk6iEOWcFojLKrlhnxZ7mDxBYfDp/2Bmna4
+lFt53zmQHJeYiO4J2TEXOQxvDWvcOK/SnAoLXEhUCRP9vTQm2Ahj1QMmEVvEybOd
+mRpcaJXUOgirS7Ulwc6ZhW7MoFFnS3UluI+gS0oXRW6hCm6l9poDem4etU+IsG2m
+4k6MoMLrak9lSheB1uL+xC0S9k20CZH0X8Hj5atb4R7T5+lTle/fVw1RGdfil1NK
+/ytD+CLpSV15Z6VGVGlzfXTIXYgCIgbZpFxOZk2tsdUm0dPBjR/ZhdUh4ofaxA8K
+jE8HLuW7kCkvmEfdsJxuRVVQ
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des2_ecb.pem b/samples/dsa/openssl_dsa_des2_ecb.pem
new file mode 100644
index 0000000..35c220f
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des2_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE,3D3D716B17DFBD33
+
+XDCVsv17xsOpLWONR8xKRYxnxvWs+bdU+2XCqoqH+cM/vR4+g4lqSPSAco0/LkyX
+q0/C7/BE7mN6fzUMiECYUKS2c739CBVwDJZJBVGbMNFexaQRmlSxqhmbQ60oalaG
+HZfpCLLHQvrOZ3O82aYuEfsbqJTEPkGm4lUn/5psQwudmu4qyv8GFR4wVpNcg9JB
+rDzesxi1aU6dgHSlLHrG5ot+lAITh40SCBQdwkcvixyDIi6l4FX2AyNrcQYmFGp1
+C3XaOn74ADLyo31Iy6rCb0KId6J+S+1aPUW2r1Xb6irI13/QYzIe8/fDfuyV7Ofq
+BKtHdu/oIfzl2X8BkuxJ0CEFxyyEE9majfItPnUEjX0Sn2PfOEwzq5LYYExpNuxe
+pHr9gtB+hSXC5t1b6ifv9PHErMNmBLdgLX/FT4PuL6URrn3LtydPcfW6XMkHtGgH
+zD/nnn8Kl1qXmkRbWHbREcOJB/O/Q53UwD26BsX+Sjwn2cfsgwQvZFzvmq/RwsCg
+Ej9FK80Tvn3ce+Kdt7LGUc9+KaH1OIn7qLcYu0Fhid/TzPCBPQffxpUJ1HylDaUz
+v1txJe3C//rg/42e5GUlKqf+/nzCmQeoaqZDG+VU3UKlngIYitlpwEq5fq/E8V35
+JeuHzFjYj0k9VNsOHY/4AqmEm9qi1yxb7WGINsysO+29RvfRD1bm2Zqhi/Mg7YBo
+8K1GowhW6uGFf+VCPORihMIxoT6xBU4xn2kX09EKrVdekrAi23QzslZXM6Ze0fxH
+7LlktJwah4/QFHwB5qXwmHq3lN4Nj1id+CElVZXjvbKvc4+mRd7VSn++05IFjTK5
+2r4FHifwpkGASJtVbF/7ZseaoOz9sHARx/MFSUp8kRZjOCzstWj6I0Fou51BTtRn
+1ZCey4e1eKVnV4F1XNdo27Aw9aZjF4Zn5hZfUPuUYBwN3W33l8FXRdYEoT/JpiQO
+8LS36SSZGVA0c6nanZoeDZsrPNtPJa8ANHR0QMwBDOwNr22uuJEG/nLvBfquG4HL
+Iy7nxBebe/0MXvsxK4OjjDzmYQL2msMlYffOABOVLCbtaPC/HBKUcmcpZ28WAzdN
+ArkPEcJFTgzI+hCAVG//uV59MkDnUZ+e
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des2_ofb.pem b/samples/dsa/openssl_dsa_des2_ofb.pem
new file mode 100644
index 0000000..d06c31f
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des2_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-OFB,0472499818A0CFA5
+
+A+t7NfS0c6IsREc9+AzXRaMGW5GR2Ao+WBBxXdxNJZ2n6DWTcNHYL1VZsnVOoc9z
+N2PBfTjYQkNtehp4LDnypbooUI8gJ98T33PLkJ0/L03fs5iEiULcrpBLGc9gsNoO
++f0JcI4xNfE7bGvtveliBWBsn6KeCdwrdcOXziWGQCge0pftf7m4HZ/t/0ISfjXK
+x3ftgiwrvLSnCHfp50xXdN4FGRaIj/V+C50efu/hkAaZ4rCcTxgEcvi+TKdDjmcy
+MfxWmUmeGiT0MRongCZB7XH6g4sI3nwiDASLzvZ2dBysLD0wOhR+g8yumSH2RW5V
+rTr7JQANZzdZm4MpOv2fMCHzDcKEtPd+OlYMHegwE3p0y4CLeYByT4IdyKHVLiWx
+lwAKtZ15VlREgXqBIgrtG5ooEIIjdlabIckAhRc5yOX9sXsMePRyPgQSnG+nSbQ7
+6Y1l+3XueWXjsnr6SIXI5wbszM+TFbZAU6d9tb7B63R8ancHHSUgAbmSL7QpYZxD
+oNYseUzgPv62oMbX9VxiWJ5ZgwzS+D0zGALw3Tb/YVTxI+/VZ58ITZ59I1cg26HT
+H3P1thNPIee0zz3zewMdILgQLh5RWkJhn8/oawDhVVPBba72uw2nGF2aXwbLWx7G
+eJ94GeikGHOJby/J4G+0D2lLlI90jP8KB2fVqHxENGKSMLjZFERGvpiPTgHxWcgI
+SS3ORTxuJDzqG3qFfMhFwQnq6tbOsny27scEQZeNMGecfqGLWE+oclqfKKDQDm11
+JUQnsnFAT3cNFyd2bKefeN9co9NS1UTUw1m3gDH29kwmggFLwSccTFobrIoh5/le
+qiaHdEdmd1Fvp2nMAVufwmb6G1dizT37benyr5Gzc8CHZUMibFEIhjkmG8RQ4dyb
+Byai6j2gf6rzsbKiVtKqgCgMCw5LG8xypzitCBc0+DsYBnlAyS4hXYm41eqMtMsF
+vrP5uS50iDbAMBjuIpWdlRewjxEqiLPZofjbMGwbrvDu45LQ76rwLww5OUj6567b
+FJRcXQdyt/bWqB47GnAZq8NABCtY9HG77nTgqstOqYOOsdkuZC33JHAwTwa+b8tq
+2Y7Zo35CmITqLxfjr2IT5Yeu
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des3_cbc.pem b/samples/dsa/openssl_dsa_des3_cbc.pem
new file mode 100644
index 0000000..f73edf1
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des3_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,9BF24F7ACA100D50
+
+71AQTQlq7BkcUMR0+Ghc8O2ykT347aaFUD9BYHXBW7SzEq4th3itEQQ4QxflbgR0
+2XZQE+dNK+s891XnEkf+8ZIIQc4LKr4m3P1t8UeAQvMbHRfAQ1u2/fMf5xwYMqsW
+BscjoQ0lFOcb69nb24E4taRu+MRDF2+eah2hlbHGbsTezIm1VzFRX2C4mnWyfffX
+2WyJQPlZpvOY4kkv8tRvW+nbZ0P7bRjjxrSbCeUVI8X3m0fiCJ0fMVg1MMaj8JxD
+AgIKBBIJV8SYRw3NqiGk/mIlMq4Qtl8PWEFBRf30DRD8RIqOO0yV9Czu/u1hcmxN
+x1/ZExbwOFAFwE/GU+NMegFRXC4toNIU2Xo1C84URpAvVAwwe6SiqWFTSTEHnRu2
+N/tfJlaL2yFrfRnp6mcNN3T8Rk376skXk1zml8Deh6rNU254yK2CFRgm+79W+CeR
+Gb1wxDw0GQ07Zr6/hNBfpAND4qEdyxYAfJQYOCufXiFFxWp+99TGKN4T/+Ab5D2j
+zKmpYFPJj2vuULLPGIJPnCVNjM5v2KwbFY/95Jh3JEF255TORfj2P6HETcjZr0pD
+TCk13jxgKs3mq98Vr5LGEJ4nUcm4GoZayIbeaM7heJTWmvQyP6PRZIDWi5mHs7K2
+wGUrutGZcxzLtaQkavQPf79xt+0CI9D8Nuz4FrKMS2ng+rWLzT3be46f6hJaX1KP
+cy8RLQfaWpFGBPHr8UKhicOpdbGjxxfBUM7Jlg2o1hQIWmSuj53SygZ/EQnqBV7E
+GG+Gf3RDl1Ab9ncOr2WAA5TOQ/yVBEYXy2W3TDmxuwf/fWvwF2z4DLq/J7pieEM1
+b1IuOlcDWNu6eKAhsrq0t6I/wYNB/7qOmIcMxn1dzDHjic3uO65IMH2swXmk7tuZ
+ExdHGutPDZKYG3TgMyMYk3W9YeoEZAjF3TodOYNpmtaDmftjIuxlaYzmtkQCFHGh
+cRlnPXJwaExSYrySX+1zsuqU2QaLB0AyTlAgkUdiLQOzfmHtiHt4Pgyv/o1z/PgJ
+VTVyu2IFh75H6CnSQGgNHIH6QGN3mcMIZQ5G0U2r46X+7+nnodOky09H2Gq71nQf
+vSk1M2ZoaOuo437zG8SlEuPKimz/d+PH
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des3_cfb.pem b/samples/dsa/openssl_dsa_des3_cfb.pem
new file mode 100644
index 0000000..eb957ba
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des3_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CFB,DDDE26F919588654
+
+ulZ1WOcK/yY3ugpb4uN9s8ejFImurz+p4en3zaCfEMdv93V0JT2T/49e+OvIMaOz
+4ShAD3AO5zOXkZd5AUDI5Oi7mMIH2sUmhiJ+0xZMWITbAduYvt69lCGFchpQ/YRD
+G4jT1PY4WQX9o7nN1EYyPnH/vx4Rk6lnOZz7UNpK51SBSBk9lkF/d3bH3J2+pYaN
+G8VET28OIVTs4nqNdu8nxoE8u/Y3aW3FVsFCA/ZhmBD81Odb4rHAHCqJl00ApW91
+nvpTkTjfF9+EfdOE3mfLA4R7CEVWaqnfzvNrVCOILs3qSFGKbIBPBBBJbc4d4pEm
+G+8g5gimV+oL/Q6njSi8s8yV1WWf/nqK6EKd2JJglW700V8dbGHjhGChNTM4Px+C
+RfTF+kXcQZpcsax5ULUz+4KKD2Ub5EcWumg+LAe36VVTz/zDTxhTzsm0/iN68KTM
+jzKjIY9PkVIhZikVkp4s8pL97rL9Tota4OGMacPx3C58MSwJSg7fdUehAcnj+GC6
+Nfi+iHxVpJP4QnFi4BotFxlb2FoVhoh51YdaUehqD0IsoBxrQCmT8nVaz9asJMCY
+CRXNO/2pUpNJY0iGjHfvdmT/aRf+gmat41bX/1r6Xxujf09JF1iS5v/fpYQsshZc
+N+xysjZ8Bps2Kx57XSUTz3NrwMuliJgw6ZbDYBHGSSl2lueUanNArE4iLakuf5BK
+zuf7iVNTZEww904RhnA3HnivRH2b+Q1mWxTezSYZTs2Qr62mJ5ewiFjOlv6hPUfx
+T8/ka54Am8dHsgc3LUDK4pFFR0Nk82yU52FJPbGsggKZAde2tUnDgup6gNmzEjA7
+rSWxEfg53fHda79SQzrKaPGsuWr5b+cl20rGycqN54qZafKFah2tfCzgGdVZG+Yn
+Wq5wvZK7Elmjz+URvKitFhw39yscj4TLlEQ3K/jZVu5/lsyyu3imiUholwMCSuhV
+fg667XbT1qSw8KPWoloOSDQr60d2cK8Olg9DjfMgqmDxVHMuALB+O/dhJq4Jaa9c
+e6ycERign27Fv6j09/aAGrsaB9gMXCOmMhYGSoBUptjb2dx8mN/z3fEG9ykvaDiq
+i1+9GnfRKIYzfxTa3PCpA0B+
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des3_ecb.pem b/samples/dsa/openssl_dsa_des3_ecb.pem
new file mode 100644
index 0000000..1dc8182
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des3_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3,695F5DA31042DDE2
+
+dzOyRB2M6CfzgilwOWNhrea/0Zt1EmJSCDPXO7kQz0LpP3/keHgFL14NqxQU6puh
+gYn8TKE+H2f+l8xoNhT6kdRI5OZP85NlC/RvzcIPJkriBgMeLwsRCvhxg0EujRa8
+popm8yF2E8N9YPdz2CcrUW0mttVYeSy2YO/pi5rTJBeqqIjqFYjHPEmlnoNqboQk
+aflRKFw/rZgsE4gzoMKR/yso/GmSIXj48h9G9CyLWPFIDi8LdiiBG62wxK1TDFDI
+FIcU4KY8QyHSYc3DdYJJM2kXxvSy5BxbvWkD9cZS9+CuAvDyGI9dfF6g60f2tCA2
+AxIHRn78StCNbRN1xBfkqw0BremGo8G3H8w6FrdeS1rKzzYqAe3XhDO/uN/0aRAz
+Yact4CIYbZgMRhTJh6YhWma9UfYtxslmTNkxmMptS2SvOVSbhPFSQJFIVWaN105f
+HGmLwoRwV+Xd7nLX5hcR0Sozr58m/1FYun4c4797/bcGA5nDKQ9+u/GvOtqGhIU4
+EY5mkMhqt4MdDdKozQvATqWeSlESIFBZgG5sAQWuRJ9g2Pn1N2GTveY0ofIXV575
+WsharLOALP87zUur0E92LoBrbFAS7/nJ7T7F1Ye8ZoG88qs+vJy8SUVCrDjUqfgL
+90YHTKvmq3fJ+DO+40pLU+aiRBPin65h+5J0jW7f+eGpJV1S5dxIYKW0D1+PgcP5
+URVYuN+cGWROH4DN7zyIFPh1lls0GtAf1to+zBy9QYUFAjt2lB/oL/d8RRso4rHG
+8cUdXilKzAApI63nq0pKN2k9hAH5wGzxg3vWJCbsrXuqExsgZ0EFLR1IOX5ISCCZ
+g6TKiLDDSFBfWKTsix169JzCCptFwE+u8lY1b0A2ApCClXeS5+HvWlC/vtkuqCKj
+V51xSR7ltzosktG/gSc6wesbp0RlldK3Ee1l5Ld3sgoxFZd8aBuMVVfvqz0Li0ac
+883Yr9+nSvc9WspdytrfjcbUxmWtBxsDtVqhuIM4eNusUPY/L6FJhfX2kgjc8RNf
+MNJXiMOaTmQfVCTmKZDF1EN+4IZfdrudL+UoesTzasdlDXGKc5gCecWiQpn/hKto
+6YwKToh84r1R4gDcQGM+DL6wa1W5bVbD
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_des3_ofb.pem b/samples/dsa/openssl_dsa_des3_ofb.pem
new file mode 100644
index 0000000..86f2019
--- /dev/null
+++ b/samples/dsa/openssl_dsa_des3_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-OFB,BB994897E99A8F6F
+
+Gx0S/6H98EIJK9lM7TBQrFejxjBVE0kcbBTVNTCJCuJ1Ik0s6+OqG1OFOLdXJWva
+M+k0WEWKhTAXtrrbzPiu01u+OVpIQ3xhgzt0rcU8UigfLLvMdqXoyuUTzCYHBraA
+ByJ0+Z9nK5r/OAJkq4gnRfhsDajZgOy8rZAdyIui9rom5emcx1GsnpW8WdRCuu5l
+kHEyaG5nHtUyZobZk1kNbkqelByCAFndV/eook4kycEytZWNPpFP+tUaXma92vDV
+sg3h2qODMr9ElrbvKYujOuFoO77BYM4oxlE/WtWpD29hmxaIgmnlvwUI7HerpZg8
+DbKYV/8ncRolxoE1GqO2dM2nLKaNKra+n5REJBpUDjwe/eV6dwcj5Uvk9nocEt55
+3qtmPbevuXga9mL5iTN8dm5RgrkzCX4LBu5fB3WviuseUBAqpKgq73RCutNM2gDm
+5CkV7Iar6tV+LgiUcgoo8RAnJbysFT6jQkGPYhABFKzdzrFFDDQUBpcLo6hgHpyb
+uQqjVXR69JFxdQpJSuc6cH60jzRQOvgwpCzpRiJL0mgXNXv51K87ucEzM81Z0UpG
+O4GYnsbo7PQfeLAE1PjP2B3xj8kgcRxWbHkQ/vIHTEAtJcXmAquULi+mNKAFb578
+qlBs77sLICgtpqBUzfoiH1ozcKHOJ3XB3yPYt7WKIxn3/rwqrgRDrPbyrrDmV+FC
+veepr8m8ZssbZjKy3z1js+jcvjKJOY6U/7Uc7IfZ6AjBXrkJIDEtn9RPoexG+av/
+P/LDsCF0ChhP44KZi5q5TLNvAmbvNL/7oogaSq9nw5hJYLiu2gScOAAv1h/j9yhE
+f2mz/xTHjr35m3Ax6wLPk2yS53PATS7XXQtWY8E0LJz7gOkSDvolwnyc5aRgS9WF
+H8DyqWi8vYzVLNd1qM1mAR55qrVhWnmlDmw+f2OJmP+6MNAoptW9nsUaeOk5xJVy
+QNSwJCjzp6ujIn5UhmrS2u59HW3hiW0J/O7aalBXYQxUv/qllKkrNmX8HlB/1r2C
+IniTw/Rd33TsNTBx8tqq9IpnAG4s51xHBeXT0+Sd4zNh+fIqAYLNuMllHMlM/oFu
+A7+h4TYAxEccchEha3GD6CMl
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_rc2_128_cbc.pem b/samples/dsa/openssl_dsa_rc2_128_cbc.pem
new file mode 100644
index 0000000..8a7d018
--- /dev/null
+++ b/samples/dsa/openssl_dsa_rc2_128_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CBC,B0CBF8975CC514AC
+
+eH3gBb3Shpdi9fkBr66H3xWR0XnIrKhPU1KABtoaYxE3N7su3duXHlx4zpc3YyO3
+s2YwjN64PdGYgFdwrznf97SjdI+MSJgu2wMxxTwJwOltEPBdbvNWEpq8SLdfdlDv
++zndoR7YnMIhQPp5Hch07dhwpY0hn3RELxYf32ALEbe4+xG8/LZWUBoKdgOn+trk
+1Oh0VB3eupjtsdxDWMMN3Ar+l/1AfdBoaQcHg3UdO52U+mTc38QAaMA+9Gplkz+Z
+YwjWz4tyltvTDWGAYGuhxTPVt3IoSewGVHWxKezFujNEhj6wuJBTlpN5T1pALfbD
+JUiGEmBXOPcxwa3QKmVKJFcA+p5eOYY15sqsIhcaXxPgzjO6JQWMErkaOnyB9sHg
+fQTXHwMau2HqzjOM8Qa/lQyv9nf45IFupKoTT6Kja2WzAVxd9KGW+NZSAa+okRSr
+GQrsXrJBFl3+wKpXN3alj94GK6aqCBiyd3d+pp2NyM9TorZhfWxbQamPmQVaU4aF
++nJjB+lW30wPZM6Ik4UqsgXolYXZCtV4cOaZ7g9ub2AYmYCA6yIagRFfjuEs0/f2
+MNN+qu1Z0sg0oCCpqO9kVcnnC4jIaXvU0egZVlGZ51GP7iR5VsLmi3VTbebnsvT7
+x8XYI1WHYuANsSBNRJj7vmrolzVErsX90FInNcnc7o43KQGyeR4E+vSdqoLHbk3A
+2HL9YLDV5cdvGafL6faVKFxUaA5CWCFVtrV6MPJAm/xWs5nu3wr6aNsDk/0R4mqi
+vzQe9EjkMprrihpXqFGpTaehJQFgLaE3FwnxPeUFawqdKIqaKf+stx3i24LkDSPs
+ukLiYS7cPcDYXN9kI6a0fqGtT/gL7NVa/jxsrl5+da/alvm/Ai7TJsUUi8dMzqIy
+85Hv6xWyPrwCbar4Ehq1CopxWvINo1AnvajIkBHvh4EtK7B51stOO6yNEV7spYxb
+nze92IMAtRNWO/yp/p/nccy9PB8/e2v41T8EN4MJuDxGX4k4cG0k2IGzBDcBM1pC
+YfmkHzMBGPsq3CQ85balLEWQTgR5nr/8+TabxyloED/Sw7mLM4gqMmn2KukzMxT6
+qeiFiGtmv2TbD7OWkaLj1Mth/ns1Of8U
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_rc2_128_cfb.pem b/samples/dsa/openssl_dsa_rc2_128_cfb.pem
new file mode 100644
index 0000000..acd0a47
--- /dev/null
+++ b/samples/dsa/openssl_dsa_rc2_128_cfb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CFB,CB9482EEE6EC0DA2
+
+Bo62wJPRVVYQKoP0egdW3dLX4yU/Dbkx8TtIsNxNFhdwpGWtEGzervoU73+6aaWF
+LME/HVPUh+iZPKh9HuwSiP0GtwJzCv8arDp09mxGJ7XFcqz3AS7T+K9A1OclVa5o
+LwQ6ynBtCsmgiVlS/haNjeONqCtpy0kERgathUclwQCLTnQBZmu/l2Pk8Gdtc1Tc
+osmKc6BDlPOyofTt/UnrhVuZxasrS7tKEnVn/iZr5mjUZAqmC2mJcWT5YNahJpfO
+rawRjukIUOm0feFwov45+joTSIGDsNTYD3OV/+BF4ZgBMm33ApAE31JFoweUcI03
+2l+WS5qtmcwuOYGp0Np0BWg09KVwNbIghfiVUEjnqy55PCVOFH1RZrmHhPndCvHQ
+BwAaac0yAtd5vFWjeUf+pTbDmkA44g5f5aO9uQuB58WWkB8JCFpGZLizK4ISy5ay
+dE8+SjVGiMSZBDfAmiEokoYymc7L8bkTIl5Jo4TuMmtFcHnfohZd6Nue3aRzNZHJ
+E/V81IxIytHRlMl/dZjSujPw9FgmXSip/U1s8ESIVOVoy93HnaifgRfkkGggxp4l
+S8QqBvJTAJrQ9ygO3PBjgdKGi1XWvhH1Y5EwPJ6Wor4zzltftELEs1O9xfBT/zeV
+GENfUZZU+5V5ICm4K844WoiTkH5OIWAi/ZLK9XRqchaGWvMpv9UwBy3c0KOx1O4f
+j1/8pbXDv1iey2USNL/Nbw3nanIG0dIbUZ2g2U/FeKtfCfVHu5LJY+v6njKl58X4
+mthqvCZyyJy2U31MYUUDN/lgNffwLnzFc1AxYyxDZwviKmAIN+Ylh5jbxuElCS1T
+bpVd1+4aber+qv9Ar9G/PJEt9ZdHR3RB/tsEXv7ORke+fVzlKFQu9PKo4k25U/mn
+qfBcwlut9rMu19xsjbowqHyYJbenyrF55d00pp6P037cOKLStJECtpgir6HgTpo2
+Oyavx3OIH7ypvcyaqhFUqZI2EiGOdBwbSBp/jCqOrnAwTKo9uMcnmrsKj6EpjJzO
+VGK0DoieTEQ9VzGbqZKK34NHidE4j/MYW9lGKAADSy7Ey0CllvumHiICWOn9aJYy
+ObB64C3p8NFEcW5SrTzPtXeD
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_rc2_128_ecb.pem b/samples/dsa/openssl_dsa_rc2_128_ecb.pem
new file mode 100644
index 0000000..1ded3d7
--- /dev/null
+++ b/samples/dsa/openssl_dsa_rc2_128_ecb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-ECB,4C5CF049EFF2E116
+
+M9XRNeRQW2K6U0bfpl3axdvsuTmsiFLkZ4C/76MLePY0HxePs3icSW82+t6awIpG
+gHfei8zevNlF331hGPW81XZAl8OaXWi+iGhIfKAInLKY//DBVI5dMTQUKTwBa87k
+oby7hLD+V4lVKr9o/tf2A43QjEkScVlxcofEnWUG84LkgXalsloaIAt7iu4qUMTA
+C1gTbkwex6bId97wvPQLvhFiOyrpsi5Nm98vEeJwMdb6dMNfLAd3Stjvhh5dGGaR
+BsRwDqgrkycYj6pOT0Zvg9fBxwLYeMk7PPo0bTEdY4itvpHXaRHcogsBJ62qnsFM
+mxk1opz6U0W9xKSNTCwLzg9xinRPXGDP5jz0zqE1nlQ1lrsPcsY+omKdaL/SGYlN
+vxDbm725eOoi1H0jsTGJsgcKJ7sKd6LTUEIAEsUvRAN+ro2zLhxteDP+gpCxTNRr
+ElOLddlDm6TB55lBkZVrH/0k/QQQ+L0lBi5Kgg/hE6oanMRGeKQvxhxRuBbK6tZB
+e0b0lffgZR0m49i3A+fTxa68lb6Lexggp6LAkheh6qOVAzSDWbk00fJ9SWNWO4oC
+9FNqu1yafLt3Xiyqv7iD1EOyGhYF8NDvbMpu+gM7qwbTPMjgXf9N9g+AxSbvrmHR
+5zGtJd+8BtU+139ZlsEv+cux1yxkYEypKm5MHfaa783b2zKuyOTMgOStvSOUgGhz
+c9dlWYPkgdgRkAMHzfIigHr9rQssde7pR7ZMlw75PxI7BI2ZF1Vj4weIkwH0SKFE
+fui/C67Uf78OHx4cVPANDk6cf4Ow8buH/vWjEX0p/jpOfNT9ZA6Otj0CyIQ56MjU
+L4nwFU7GqCbVkJtsHLI4sZmP4kH/3zuqVtwRTzQbQAWeTi6RCSwa8/amAStTPcX2
+WPRezgAtNzS1MBhileGuTP+opGdGOOp4AeCCJdFBzkEacRXylxdY7PUsCZI7mRSZ
+7AL1n9jbUbbgnl6zmqn7fybigjaTpLNSkVPOvVBxnNXxOW4n2HD4vA+q3a4d212X
+fWI+/y7mbYLLRs1LPPgjSLfPQ7Ye1Cj4KWy45Z9YBUtjdsEbaaHNp8TidgJKJuMJ
++sDQ3lvtJdIZZy26tzLf3ryE/+2KMTwG
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_rc2_128_ofb.pem b/samples/dsa/openssl_dsa_rc2_128_ofb.pem
new file mode 100644
index 0000000..331542c
--- /dev/null
+++ b/samples/dsa/openssl_dsa_rc2_128_ofb.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-OFB,F01B181DC9520301
+
+azqFQnexfYYO2tX4qlC6XLU2tPX5EdwOHsruz4uzVJmYFyRLlrgG57KkahVjWupu
+AHkkjhr9d9m/0/t2vFy5JEnF9WWcNA1nxqzfsaIKmnuCULzYzMWu1cFfTV2DZoAn
+npdxa/eYmcGRZ0u3aZHRGpGtP1y2sKvWmUInYCc69oigiEn1qyDkRE/tDAREh7C6
+DWRcva94GLj1igIHc61lBugZKBlchv+q8t02Ga1slM10QRg2dgAlF8uCPZe+NLUk
+8uOifATkKTsA8OsUgn9nRK9dH4FuZeD64NMCszOw7mYtjJ7YW0J0wYgC9BuEUcNm
+QTxellBcs/qSdi4pZWsO9JXxvoc0lTmvoiS0rL+JlB/UfubVQYq+C7ScVJeTUNKL
+6fF8hvfQzqDDjqx+qP4SgboAmIbL7tTJBeABnnhCOtaY5vSuT0l96rIQm/EZdlWD
+hXKcrhawaq6pqh/mV2S16e2gDRQyUX+jKvumTQhjN1+AkIb7EMR1ZLJFX1l343Fj
+5/V4D2+H3EZhbCdkz4uI6I0swDasUjtigcn19kOy5t1r49zpTJ3wxQptLRx4AXUZ
+zjVXVebGyFYSdu+Lks1VC9WDeisBW18kCg5IpOz3eo9ULBBQZnzSKS30OXlyO000
+/1Em8FPKSKYeST3SmI1aDObXOG/s4tyKTCj+e2VKROq8hDhJQUYUP0AgYkAnwURR
++XylYEfUrW9v758Kk3u82ZhEen/lLUQhWeXkzhVi44Lgih3Bjsm3jP5f7KO/5KfM
+UqECKIHR/p/H/klXPNmdFo919AFGcnxFjQCyhlv0Bl8FSc5FUkRl9TTLu+h5m/p2
+ONV63odsVGt2q/HmL+3hojX/BxSEP/8Mq1JHR4Dk0qqUpSxRtDw0XE9/LU6s9NZp
+zm6lkr5E2U6EN677bmem5QoxObNvc88EXGr0EvoWPnhh20lD3vQok7GBucnycoj0
+9NMmRUIflnj47quAGXI6LuTSzKqOOCZC4yNvdyRdil3DgyLLefr99m2WEe0HolDu
+pIyUsgHMlZC/YRVzqP/6DklhKDcvgWbBeqqhV1r/30rRkegHdsWiAEjmJadlBrJF
+szJZpa9obMH/q0xUH3AXXCkS
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_rc2_40_cbc.pem b/samples/dsa/openssl_dsa_rc2_40_cbc.pem
new file mode 100644
index 0000000..d44bc86
--- /dev/null
+++ b/samples/dsa/openssl_dsa_rc2_40_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-40-CBC,7AFE1927D7FEE9F6
+
+WgKt23n2XggL+3rzABzjmOq8sdOYfFuuYUzP6UNH3zdXRt/fh24/WRgRw+WCa5/l
+3Tt0/spkkMsgkkDwPPVLu0MUhfoUQyErK0F+8HeEdA82C7uGIgst4E2MS4bRXPR6
+w9U2R88xdUaljjahEbSMUG7JXecjL0WG+zLVDpDqMdlKNcMz1tnQbO1JNLZCJlfX
+ZlVPslMmTTxs1sqYgDhkAgh3FwSsKMj51nvedVCq2bAtSmgnz/bFDLT4c6N4iLf5
+MXP5ZUMUtWCac1hXayVw4koOkuPELKi2/1vWe7qDWJfqhKmRT2DV0Z1GKPjQp3Q6
+kGnD8oVxbKfCQDI6PSMOeBcWu40Y1yTbBHBFJO5+MdWsNOQI6CZGJCHNu2ZbOd+w
+tIcxZZjy5d4uY869PxxVxO8TmCRUn9hham6qfTw5Mmh7bOyxqID3fXlyrcE7KRel
+dlL9eQuLcA7wtH5vqpy6V28yWculvP7qmXAGUd1gqSYHUs8kipf46ecFwieCNPEH
+x/6hDl38UsuixchyyJTp5u9L5cKPy5PWXv773xcPguk01YhlmqrpTNZsdoJ/CTBg
+gal+o01rXd6snhp7IwSAppCPwh4YJumwdPjF6jUlmB/2AStF6kGaOA6BbJ/lQlCa
+cHAUaVlTZEyzSGShBGJUAN2AughiOq+2POgr5IgeoC0NL8ieMg7bMYjn7+Np4yZN
+KGmT1jZo7OmyVdh9mheahXTT4Axihfmy+uPTECuGjq4X3DVv79OvSFRpHXIXLnX9
+QkizsJKZc6v3FM6o5tbMDbJyelzaj8Xn8ANrugYMC1R4XImDSel6Bgxni2gHuTEc
+WrrILWnNSmNjz/yziFdu5VuQmYaJ1e50uenmOxiSQhL+53UzhhGCrw4ooAOSF5or
+s87oY1HO2aYq784A5UZVYGA6mYFjDDQSsbwp1LYomjoTrwoJML3P9x5SnaSrkEEC
+3Gm0R/t7SkdMmJhRc28uYarO2qdwyBuhoYRxw9Z6bXeaUN2WhJ7hILCL0KKZE4vB
+DuKxE/KgD8ijKpkUn+6fizWau6Lm5mqxyMyEDnCDkvlvv7DMoqZRJvVWSddNMd6t
+T94SaIiCDOY3SuQCi1361GGbVH2dXH+X
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_rc2_64_cbc.pem b/samples/dsa/openssl_dsa_rc2_64_cbc.pem
new file mode 100644
index 0000000..4a1ec98
--- /dev/null
+++ b/samples/dsa/openssl_dsa_rc2_64_cbc.pem
@@ -0,0 +1,23 @@
+-----BEGIN DSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-64-CBC,6646FC6A291EFE41
+
+KWLSTeo6nX30rQ3WbgL/13WAEMCtaC32ksYorVhlN4ijjiDu5gEnmfLRNYK4c3LH
+IUJawIdZvHSVxjrKNjmKA18w+4kedYCCL9NbNswd5eO18wldFR5NlSI2FGggzANN
+OwJoHUOXggYxhc2/xbYHpQpl7gvJqZtAjyewyTDYeTC3VDFoB/JywQ/8vv1MN8Ce
+Zx1k6preAQrnqo/LEIm+GPUa9flzWZlCGTIC+obNkjJGZPuUKLM/1TqNsrum33aa
+gFwnz//khQULylIRwxfuOMCHTslFmrs/7MLLbJQyTa99S9kc+s2VDlaKWUn0BVe/
+MoCseykcuIcskavuj01SYySJU1YHBTu7RvhuYO8AQmnsAP3gWQUMvKy9aXmzsoC2
+0Nk3QCZiG+1hN423So4NPOh42OWbqrDls9PKhXvQ8H+58rAxW2s7OTN29Klo39ek
+w8SFjMEtt9kLNpwBCJrIlolXvhD5WQu6XbqI0CtoOrh2Ote1c4uN88HyIUi1Y2Op
+QsfLkKyx7yJcJrz356Ab5lbJKVpKJW+frEHI7rLlfJrj88uzsh1B7oPL/4fhaj84
+vNUfadRJ25ZivBiHHdUTrKk9CLsIDS/1DWM6sDclYjXiA7kgGNwJupOb2L6VEKPv
+eimiJ9ooKq00E96Dc8s23FteQqySNaUAcqDnAkS+ck6pXQECZs4uD79k4pck1SX4
+O20OIPo79pzcWrmYOrTIXH6ttOcB3lUQtB1fmcMT5RSJYVSKtgBxLPKhLcL18xfb
+1HbDkpdUqS0R/nK7ecMd/LP+UmMKPUyMUTfTUnlXZzsNsgIBkm1eDn9RkOGaV+oc
+wau6FWmxVSPs9Inb+7A+B/2bP0qyYnciKX41I/PClKGitm52ScJyrEN0XJhQ0O+C
+mPp9weJI3IwpDn/Mc46NQO9uk4rC2P9o1zfJXC38PlEDEC66a1Y6SEQOVN6iYkYm
+rVytxWjD4o5vC+GwYJPYrmkOg/SQK1AlK8TSpNC5TeRcZ8YIbPLRfKRUQvUVtFS0
+fyPK9zdariwubkiG1a9/NWCF9gN1/DPKFYy+p5Au2ICD0iTtOND9I/Yw8dqsjzsF
+4jhYQ+No+ytLYc4Zo+8s1RO7yduFz7XQ
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/openssl_dsa_unencrypted.der b/samples/dsa/openssl_dsa_unencrypted.der
new file mode 100644
index 0000000..32e51eb
Binary files /dev/null and b/samples/dsa/openssl_dsa_unencrypted.der differ
diff --git a/samples/dsa/openssl_dsa_unencrypted.pem b/samples/dsa/openssl_dsa_unencrypted.pem
new file mode 100644
index 0000000..ee815db
--- /dev/null
+++ b/samples/dsa/openssl_dsa_unencrypted.pem
@@ -0,0 +1,20 @@
+-----BEGIN DSA PRIVATE KEY-----
+MIIDPgIBAAKCAQEAyKItMopMK218pcmy6PkrMVXAv5dt07TdGBuNhVWpQ52ldK9X
+mL7CPKpo4Dy85EZRPvRNyOnhe+LRJZ+ReKntpEkEiar/ZsKVkUthPsiUMpoM5S79
+JK8iT8F9HdFjIFKaXGySBZ4xcrj8HQ/v75iolYCso+66Ybgjs9/nsWS0UQyGE6rc
+ibx7xPAtcbaGZUBaBtdkNER7+P2ueJwej89aNZxj+AKuvrWrArq6/5zOIhGR12wQ
+EQQjj7FQ66ZFivJ/AYsv1yXDS7mZBNp5eMuxk8Kmis/++HKcP7tdbVRnlfTGdBuN
+BMyOcBTIsE11jwikcI+KIbr9cEZoaikkm4KyuwIVAP4DZEC+/JZJ0PHSEtJTt6uz
+yn1hAoIBAHhLbqDib7zqaFBrNnbaBSNiltY3GxWM6uQT88NH9YWz3wXRb6i4KJFH
+9NtLbK0RF7MoQVprJY6LuGQHZ/e61Fs2EabDwT4vB2HT619fVUvDndbuSW6qfUR4
+y9kbG7zLkE4Mnym/ikmUwLABLA67cZUS9yjtcRXGpOkiTAQfCGBeUH6nWOFEaWjI
+fGNMQ5awKvZhIvGyN4Zvd+mE+199s/kAsCKFux2Sq9tYw3qS0Tw2IEebHsHvX7A3
+bvxV6p7czVxlO9+O0w7bBTekPpw1BnCYmPyy0H36g/7aF2V70UCWzER8zT1Pfh7d
+3P0hLqHYzX375l/7oxuDawtcDAV++iwCggEASajPdllHVQ8JvKdPH6qDkjC5XJTZ
+RK46mYm1cCu8Q9Dy9ZfL67CcJBpwKVHNC3sXmk4XPfs91AZf/t01qbMJvCrR8NHs
+jRyJkNIaMyDeWcFmO0KmMi374BQpFyIDQ6mK1y9BilneZ6gHDdfHMsKniLFW+SQf
+9hlwlArIPYuELu7riJhNcuRUTJEfybDHwM4/ht0IFbyUIFl00mMdTrozk+e/esEs
+QdWbx2UBjNs8meZPivFbT2HpQF1I0qZhtn3e7jcR5YatBQ3e4abnu1RrDc73q7d4
+g2SYQK3PmIWwxiFhJQTzeiQtl5rKzEn76knAydOtPVRgjXWzHUoW6Az0qwIVAMvw
+thRrEZxNdxELdnwW3rpYBm6B
+-----END DSA PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8_dsa_unencrypted.der b/samples/dsa/pkcs8_dsa_unencrypted.der
new file mode 100644
index 0000000..66d0ea8
Binary files /dev/null and b/samples/dsa/pkcs8_dsa_unencrypted.der differ
diff --git a/samples/dsa/pkcs8_dsa_unencrypted.pem b/samples/dsa/pkcs8_dsa_unencrypted.pem
new file mode 100644
index 0000000..22b8e3c
--- /dev/null
+++ b/samples/dsa/pkcs8_dsa_unencrypted.pem
@@ -0,0 +1,15 @@
+-----BEGIN PRIVATE KEY-----
+MIICTQIBADCCAi0GByqGSM44BAEwggIgAoIBAQDIoi0yikwrbXylybLo+SsxVcC/
+l23TtN0YG42FValDnaV0r1eYvsI8qmjgPLzkRlE+9E3I6eF74tEln5F4qe2kSQSJ
+qv9mwpWRS2E+yJQymgzlLv0kryJPwX0d0WMgUppcbJIFnjFyuPwdD+/vmKiVgKyj
+7rphuCOz3+exZLRRDIYTqtyJvHvE8C1xtoZlQFoG12Q0RHv4/a54nB6Pz1o1nGP4
+Aq6+tasCurr/nM4iEZHXbBARBCOPsVDrpkWK8n8Biy/XJcNLuZkE2nl4y7GTwqaK
+z/74cpw/u11tVGeV9MZ0G40EzI5wFMiwTXWPCKRwj4ohuv1wRmhqKSSbgrK7AhUA
+/gNkQL78lknQ8dIS0lO3q7PKfWECggEAeEtuoOJvvOpoUGs2dtoFI2KW1jcbFYzq
+5BPzw0f1hbPfBdFvqLgokUf020tsrREXsyhBWmsljou4ZAdn97rUWzYRpsPBPi8H
+YdPrX19VS8Od1u5Jbqp9RHjL2RsbvMuQTgyfKb+KSZTAsAEsDrtxlRL3KO1xFcak
+6SJMBB8IYF5QfqdY4URpaMh8Y0xDlrAq9mEi8bI3hm936YT7X32z+QCwIoW7HZKr
+21jDepLRPDYgR5sewe9fsDdu/FXqntzNXGU7347TDtsFN6Q+nDUGcJiY/LLQffqD
+/toXZXvRQJbMRHzNPU9+Ht3c/SEuodjNffvmX/ujG4NrC1wMBX76LAQXAhUAy/C2
+FGsRnE13EQt2fBbeulgGboE=
+-----END PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_md2_des1_cbc.der b/samples/dsa/pkcs8v1_dsa_md2_des1_cbc.der
new file mode 100644
index 0000000..b6afff4
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_md2_des1_cbc.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_md2_des1_cbc.pem b/samples/dsa/pkcs8v1_dsa_md2_des1_cbc.pem
new file mode 100644
index 0000000..8c2115e
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_md2_des1_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICeTAbBgkqhkiG9w0BBQEwDgQILnlhJxK+WWMCAggABIICWNqg8COg3x5fM2G/
+GrG28BE081hCiuAlNwMAeP+Akp0UNVbWJUFDGmpuMPmOY8vXlPfSJFI5FzCr9Wt1
+PIEtw66CoNvjN59Qb8EclEx/DaEv7rI74zpqp/gSkufYww8O87fPPk+qtEr0s0P/
+Ed+8rv/BERaaRa5nPx+7XhQ/VFeWgCPRNICmSB3z5CX2lvujY9rhw5cdiEkARg/N
+YwFwnx/L/ogBVntWHRoKkJj77TXXd4+Wx8wD+kyB7dvKQZg4Z9DhQSlQtKoDcUeX
+SCLdd9yRiuixDXGI0XMThmMnRfB7G2bT/BfucKCWvlPn2fsZKsdI7QOKLJm3b+Ud
+PrHc1z1HAlHhnlaBSWux/ZFxGrSuPS03z5lYfZEDzV0uFxCP9r9QYOEumfuiUAEk
+uIjoT8vfiSdL/ftONMx7yOIBnuVcW0KUO1K3wepccGIaOHd1oYJeCNab4yLELu2o
+qannuyLofxkY+F5N4j6cgw6FOpB2LBHIEzKNmz6S6GJLRaeUzIMzGD0fAsnaulx2
+HZqUNJRnPLPN721Ejwu14Dj2O1r2/4GpVUUzJu7ZmVLPHbfQxXXx8hy9Gp+v3woQ
+D2N1qjA6E0YMM9yfEtPJhLYH6JWG4t0X0ThFKe2ATIdoMFq9Jou9evksLrjNcNGE
+L78pgcuQ98R7YniY53t2tBpwrklrfCN5RMUPIuCM6JfUKyZngnnwPFus8xiwl8b3
+1Cm9fnlQkeZDjG7GkMuR8SIfydboEg4RGVdvdxlA9+hoybkOruxIsyzNwSO+VLnZ
+7Xa76zHGwT42cZHEyw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_md2_rc2_64_cbc.der b/samples/dsa/pkcs8v1_dsa_md2_rc2_64_cbc.der
new file mode 100644
index 0000000..f811b8d
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_md2_rc2_64_cbc.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_md2_rc2_64_cbc.pem b/samples/dsa/pkcs8v1_dsa_md2_rc2_64_cbc.pem
new file mode 100644
index 0000000..c2c9efc
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_md2_rc2_64_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICeTAbBgkqhkiG9w0BBQQwDgQI70W+LvOB544CAggABIICWEnwZx+DsIKrb0WM
+p/+Fs1/XRo6e6aVFMACsmmbBvWaKqRpdrKb1kfQC/Fnprq2m+PouqdZOBujXcgGt
+Z0wzGJsO/rTQivfAtxQagSQus1c5OrXBvYC5FlIjSIS5sPOjqhpF9WkcsAvp2YZm
+TBYbzfzMMMfth1FD78LDYL3FgxnKFZLvxAmx1JNJPOPPihDDSUFR88riDR1Fig8j
+PeDA86iMGy9ruApr5UXP9GRsli64HrhgLbP4EArTQUnvSZz/ADjljce9K93Ntds7
+9lUIJgzpGAi3L+dCnhxdQGLamDCbzNvBvdsWqStQCh8sCoKtvoAiF/B7Q/lQgNTx
+PE89LluCNtPkKd6sU2FwqL1Yi8mnDmBr4xVLECOlbEyp/rdLdf2D2Uwv6+7at5tt
+dUokGy6lAO6sAPe5bVoAbhiWQozfaezfL/SwAQRDzvSfeIx8L1OFPFtinTx2pKYa
+glzLFJrjAPnQlcwao7j+6D0gP/O5tgFkYmNN8LfWwocDPNr5/V23jPBJwi6kDKOi
+wmFgLu5/ZJo4X7wNnbXuVMBS770ML4TjbgO3hNZgaIqXD9AhrNhRCHPsdiAUEp0n
+I0xwyrQdYj9zjjuo/9uVJ9b64+wRtBIROTobTajjQKs/pASG/tLSDYBpkx1RLuMM
+BqSSyx7D8+r8iSBBVUDGGUcFml0PC91ACUo+KQWqHQ8ERbg/kjeAbOQzUfeknhWm
+8yh5HEc2WpD3bwSy2cbIPgQ/A2icC+LV6juwEDuKWCGWnJCDGzA1SFY/NOmBbCrT
+Mxq6M6a9kkf1KnJYtA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_md5_des1_cbc.der b/samples/dsa/pkcs8v1_dsa_md5_des1_cbc.der
new file mode 100644
index 0000000..4b6eba1
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_md5_des1_cbc.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_md5_des1_cbc.pem b/samples/dsa/pkcs8v1_dsa_md5_des1_cbc.pem
new file mode 100644
index 0000000..39c76c5
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_md5_des1_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICeTAbBgkqhkiG9w0BBQMwDgQIWNmWjbywMD0CAggABIICWHcMAiGPtw2iCZUE
+IbuPuw56XzQVzgDvAWYucbrIxXgLVKhoI0yVxpba8Vck2a1z1sTDmPVAd3VVFH4s
+hiKWfItjkuxkAKz2VbUeZRijTCIEAJiLSB29hIBEJSjYwjrM8TjjH/6Qe/iDJ5ZF
+lHBzawtL5DYj7d04vkvBfprbNdyzx/2ClIX8G/6GV290Bhem+xytPNv1iZkNE9se
+zxPVfB+bj40zFkWataAD7mgJdjOzXfCZJtyEcj1gsyALW+QiLUqiaDQyiB0ygjLQ
+BKVYd2OSHnvaCzl+hH+swfFXb7N0Bu0ip5+0vCdgvV3g3kbeFh4zLhU8PFd/NFGz
+Lz+ggi4VvXfoX/AeuiDxazKwyEnqkiX84VeR2LFhxosfdAk1f+kMmGM3WDOXo87P
+F6BuJQojPkizO90pUZthsY0DESqxt5Hno35VBNKpusOLDeKzqSN8onjZJpA8054n
+fg6k3qM0HLsHL/nur5NS4mSIeLMd9jWlNTaWn9ErHprqTYqHNdHn0pHFDBLm6El0
+7tUuGfOBbxstQI6RApxiIuW5JGwmvkHdlImZr0Dlll4jfjM96ybvAi8WkoMN2geg
+CQ1i22/muW1k/fmlKrGaqzPE11glsRcGG1jhp9EHwcbWDI2ZDvseL/N7PivDkdga
+QOEiuDv0bzNdpAle95OCAtFhEBxO9moksMOm8p5G93lAmvJvV5BAsZlzj7y7Tybw
+eKZnXGK3CfUXdaoGGqbT6G/vCHgpN3Y3833g/QMqmgRKwgZvhRQYJivR62mb24/f
+zlmQDSgtENDag/LzYg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_md5_rc2_64_cbc.der b/samples/dsa/pkcs8v1_dsa_md5_rc2_64_cbc.der
new file mode 100644
index 0000000..a9dfab6
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_md5_rc2_64_cbc.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_md5_rc2_64_cbc.pem b/samples/dsa/pkcs8v1_dsa_md5_rc2_64_cbc.pem
new file mode 100644
index 0000000..5ff8802
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_md5_rc2_64_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICeTAbBgkqhkiG9w0BBQYwDgQI8PQy9izofhwCAggABIICWE4fHw0T09n+EgDG
+t8tPYTSshSAHYi8EoFIvqyB7DNnZ6goes6H24JN03lFF+FIvC6rwYq5et8Ugde4O
+Cyk90bDUBRFUT7hcc2zsxyTXvUaEBCCPfaVnn8TnEzaQi0UnVvuKiSvKJ0bBY/8y
+bN0O/yaPKppwpegumrrxABAf8muqh/jB/p91OPMuLrmtp01chrRNakVKOlz05zJ5
+sQ//dphwrUn/5KaaUjk7H+jTHuFReb4R4MvzEUMu+P8Xf4WNk6eFxlWsVWeuDoeZ
+1TruVIJMDW1khv2dsh+fGVtmIn7x90dKnIQkT26R7R8btPnB3WmLY1JYtZW2zmR0
+so5sU6KhCKI3xbMh4C7zgAxu6R+Et09HvpuOme6vjjfCs1A3y3F+f1OS0R35BVXX
+8pctPGCL/rlPwSXXx9UmDMCQYDhbfDJBb8CqA8/nf+I3X7p4A1M3GuXJTgC13E33
+Vy/QDLT3yUWbZKQOypDR/b4Q/mYeMJweaF/JJUe4oeNsVjSZsBL/NV4niRy9ZIcZ
+xUMEQx32k8K5V00S40BwgLUDsuncsVY4ME0VvE7eXhVtYwVJ590ay5QRhuOTKg9/
+ilohSE3pBDikP54y0ng0Kd13T18DrVgYxb+j9Dktq3RkMbzgctevIVChuYVJC/j7
+YQkCBjfNihzFDq1E4cCfTfhxLtPp+UjaWnnGvUgwuqxbRKcAKMKxL/Yu0/tBvjjT
+yxdptn61fZMGYNdx7XJZg0rpNo6Qseje1McTLrtLMrX22L2I1Ut1Mo2r9qlpKCpm
+3aZVBh/y9biFn8U6rw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_des1_cbc.der b/samples/dsa/pkcs8v1_dsa_sha1_des1_cbc.der
new file mode 100644
index 0000000..792669e
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_sha1_des1_cbc.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_des1_cbc.pem b/samples/dsa/pkcs8v1_dsa_sha1_des1_cbc.pem
new file mode 100644
index 0000000..674fe1a
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_sha1_des1_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICeTAbBgkqhkiG9w0BBQowDgQI2I9eXNtoy3gCAggABIICWB1+Jzm6a83jaMaq
+1SEE+0zERuQvg60nuzH52rSQCGU95tClKJNalXWj4CrTg9QeId0FT0H4LMA2VR3V
+jbu0F3zeP2+8wV+PxcArDB7vVsIE27/8cGbqMzNJ/2bxxpUd9z5NfO/Ez4yCVRhc
+B157Fa6xjrMhE8a5kRZm1Cb+GJTwys1/HlpyeCN40ZmPvRqo1bOd+bUHpXDMu5Yg
+MaVuz2tne78HORpE20ddHyYX+X6I1+z6cJ64Jp6Ohc2cxGA/ihxIY6ZndAtYvHYv
+QQNTzri7LiNh/Lh+MHO8ToMjLkxdEY2jcC/3YHowiTA6ZaxjDUyPAXISj1o+5vW/
+hzCSbiJ/WO6aBu5iLhlMf++b2TkLll11PHeq7VbAE4Ljfi1mUQpsQR4mL9RXaKiT
+pxUyu0JJOPtYVlHIJqFl9mlq4dF+fBmGddrqHbZm0Dfkjqu9KzeeCVTz1wZoByqe
+r2sNFEEUKS1jLfPWytnKeEpAT2Q17BzmYZ5n/l4yEqjIP2wCkwVua90XnUvfThGi
+EkK+EVhlkxoMC07GaCM2QMh8pUVTXaX6Y2g+6JSvgl66unGTWgu9m23Py20mlwU9
+AjfOjq+6KTUCyj/r1FP6Z2qfigCVx6QCWqb/cKiCUuFAIuuLvat4CeoJIElqJqVw
+ZSZlzUJHb1jY4FrGQzQ37r938H9sxNZoUWZBdZr+xpfClbCsR6otezoiewFX1Hht
+SXL0nOsHRhXfOgTw5FLTJwU2gIcSQHZK5ulb5z+jLMuEzDWJueOj5gbG0DaDEwFq
+TYY6+GzHjmiuQnCNdQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_des2_cbc.der b/samples/dsa/pkcs8v1_dsa_sha1_des2_cbc.der
new file mode 100644
index 0000000..75d37c4
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_sha1_des2_cbc.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_des2_cbc.pem b/samples/dsa/pkcs8v1_dsa_sha1_des2_cbc.pem
new file mode 100644
index 0000000..0f8ac47
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_sha1_des2_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICejAcBgoqhkiG9w0BDAEEMA4ECBuhyw497mDPAgIIAASCAlgVSYSosi331Kp5
+/HuB+fawVN8+6yIdh9F7amRjaJDcNYEisZDrWTmygXgEdEFzJaoQ1eicxIBVis6+
+V968aeRKcF1VtEdB+varexHsCKPv0TEEx8zCHUwHtt7z8F1oZ3ITrb6GNDouEqSO
+3wm1MGEwcx10632ePnLe7pozwjHEYStYKlwOM80qdL48evXRm1ZzZRW+XvzDZTaa
+XriWXzRHMvZ+kV53oo8JJjE+XPUKWM5RvAFOoYTn8f4hzG3hI8a0Y78wzwFFbXTN
+e5xu6YlefTOUnnmbKh9NPlAyASn429nMs0kT2Y/a2arikQImKH9NDgh1NOk02ICJ
+xbG/eFvbch9Yz9jqiCPs8LxNkpCHZiwaXi0UkKx7ayPISIST8YwO8+RfhxG84hzs
+Ub8+Xf7UO9Rnc3vAXqG7l7j325OtB5cvID951YRfWxJ7I3ZWrgswiCFnXYP+0E7D
+Lyd/P++9cfFs5VZBgvw4i71CsFvYzL3INXCYD4CNykwE9A9Zj7hZzZ+TUiybg67e
+5Yyw5xZd/l0aO5akDW/H7i3v81Ng9dbxD4IZ/c2zNp87R9MkKkASjrLt63DBxnRE
+Gc0bgIu3DuufwHjAYaL51St9DzlaF0lag+qIq0999R5arqTecRSggRdSCETMWrzN
+ljiAoU85VHpfUgFCJREtLmhGijJfamTkpRnhaGqRlRE2Muwnmi/lyHJnuxQyGkhg
+lZzPsyU2jJovg98As3GSVX03fNPI8rK+fsmljJgMlNaD1oJcWGo7MDuP1d9LRZYZ
+fdcquhQmth262zbNGT0=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_des3_cbc.der b/samples/dsa/pkcs8v1_dsa_sha1_des3_cbc.der
new file mode 100644
index 0000000..68b0a1a
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_sha1_des3_cbc.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_des3_cbc.pem b/samples/dsa/pkcs8v1_dsa_sha1_des3_cbc.pem
new file mode 100644
index 0000000..acf3660
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_sha1_des3_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICejAcBgoqhkiG9w0BDAEDMA4ECM6ngp6E+lnbAgIIAASCAlhrFWJC8cJUasbL
+3SAaPd9yEfDHIZ94HihcFP8XHWZ5wEIw6F5gQd+FZS6PRJwxHIiZ+1v0iUs8KT0+
+e348cNrwaySjdzzbwlMUFR9CecmX/3dlaOLfiU8X4+TaZ3nXTvwyXkQon0Z4djgx
+7KUHt95t/c+FP0pXGboYmf5Aj23CXV3Jquy2RUKEPueUuqQ34AstgBlul2Sia/p0
+3kH2k/KZiPVRoKEwnUP66IOuWi/M3EfORM80RcWzAiBWuvRao7zqxFeYolXX0BS0
+V6v9ZiVv9NeLHMry5GNQ08Yz6jQwJN0pdM3Dj8qi/2FL0B6YX7eWc56V3wHubwdO
+7xx2ogYWLWybu7180g9FK+If/mkAUtVGcxqMm/j5wbmOOE1w6BAYaSxmxAeL3kEu
+r3g5r0vpbvTyDOBixXlrxQl0xsdME27YkC9IZWn+WetcBheOo76a79eblE0Qs6pH
+wBXnL4ZTcBVxDFoO2AjY6stioqYFRMAP1BliCBQIim380K3mgjNFhZ1jC0+HFNA1
+RO/xFAs0ytM0UlEz12Jk9z1DwrNX5nnNLLsNm49AADlrK0Dnfv5ues2eI+dK0noc
+zdQT7IeKBHU859iSqmepwtygyImM5TGIy4gxGD1xqJnv8cqFKE/ormCZBhuEI38O
+c7xXqeR/MbXE1VdV/M2E4SLvGmC738+q16wWG9kzGPcgk4yGzsHOGE3aRkaSYm1O
+ffekfyJR4M0h5gO+hT1X1fB4SToEwx5/+RIUTsNLl9+PkgZBXDU0rmW5hYRZrL2a
+RaU8WZui7X7WWAB3UrE=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.der b/samples/dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.der
new file mode 100644
index 0000000..f79b30e
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.pem b/samples/dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.pem
new file mode 100644
index 0000000..3dd4b75
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_sha1_rc2_128_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICejAcBgoqhkiG9w0BDAEFMA4ECFpivEsiPIHZAgIIAASCAli2TjjB4dAYatF7
+PLjdvx5RjdCm9l9DdWTHrSb4YVamt51U69itpQbWAk5LctxkNfhTsxsy1asZGSkI
++7qB3wXl3vycPQAyU3/jECK6XM4ML6OXE5fZ8W09ump/Y0yhQcj34unJ78T5T17N
+k/T61tovhh5HYDg+IcY63ZVUy9gllpMPavPdS1H3DNJBeV2+AMgOc+YmgvHYFOpd
+WcRGFqMe7QZ8M7XG9ru3S02NVfpVjioFHQcbRe8F2YW4lh2MkYXwMS6b+LFHsQc+
+9PPHqRVIH6HXuK0WrvMJ2DNMMAK4FwkvHwEi5poiXF1MGRq5BxDUcdBbKdM/v2zA
+veiAAAr+p1mti+1rWjcjHPfpWGLhdOmh6sGTI2Cmg3Z49DzT+bgWa9dmvfBaZOYu
+JcoNAkVMTD1bENktIHkjdxJG/+St/9q+NVdaQXB4ZPfkVeuAvcmwUgyyPggJKjT/
+YhRaBeKYHisG6MJo5JAIjeo6bi2eAo/9mdYwYwbvXPSu22n4LCQIyVbfF3Thfatz
+IRTmRX5F8E4zHz1rG5A8qwVgr1Bx3sM53Gbpu2orv1vDw5MFX/K2/q7W/uMI0CAS
+RBCW5VqP+MlqEO3UzIR/AU/wkN7rMAryLamEPnVDfAFKiScAUDewmdnHuRz0PSnt
+3+KPLxPr+0V43AnqiJzVEQLcUWB5b+B3+PLaUg96fe86B6LZnvTAaY9cooFCCB8d
+/ehmeeWUMDnHvOnv7yf/7ZdaDNoiyBenZsSZoAVGu6gr6D4guqocWeAKJ17vbKl1
+c7dkl0vwmLaS/4S2Tns=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.der b/samples/dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.der
new file mode 100644
index 0000000..c29f0cc
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.pem b/samples/dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.pem
new file mode 100644
index 0000000..dafc030
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_sha1_rc2_40_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICejAcBgoqhkiG9w0BDAEGMA4ECJsw2lYbcvERAgIIAASCAli3go11vsjJ3Gj+
+XTEOzG1k8m/n7LqUh95evnpUhaS08O8a/HX5DLfMSrA9cAAba+TNW1C2VDAcvsQY
+eYz8++Bb/evbtv4YJiSgUMqKtGAR0HeAnS46JgqwNEeARCK9Z5aJSSXKSIaJX9+K
+h81ppHdBURXapFTTqlsLDS5m0MS7NGzKYx6CEBrjKO4qXlphQvyKatBbnRL1+xk4
+EPnYHY6uNHBVuMf2zuc4N6j03N11sjYdRBSOnBrwjAXrMb/nCEqhJXRNN/cDBqGT
+v/ixYBYvLzh0zxoW/RqpzhtXLyIrAKBaN+HATgbcacQJoIq42ow5S3jxE74IzeiJ
+rqnvJY5t40146oMjMlPH3dYh/8I5BHF6S4gpFSs/knyYL55VrY8yU1QC5frsS7a8
+wehrIqrE0WssKzuWhUCZHXQN1Y3ywo7GmxjKqUadhZtwdyCEUKWvaimI11ISa0rz
+FxYw2Sx43UBoOTzSagCwv2jHibuU8V59QyNakZvdYoy9VupIxIQARJVAkcGCLn2H
+TP8m4OGnzfYyqXJGfHqIu43gbfztp7qDnlXCDvpI26T60g6vwtTa6G8ACV4K4evD
+x5OUE8jxA2mvKnV+STJOna4KGsadZV/j9v5MH63YI4DGTCVnDUVMb2/MlegDATVm
+cFn0A0CA6TMA0MuK0FogtbnSG99FYdEcpw7zxO+mzWufvYdewfT4mHDhILpuZSpc
+qm2FO/OnErsZw4U4/ZKql3wUWAsam0vvHQekRAKocUHgLMoAvmLzEgW+xOpgUpbw
+HXOKalNLA8Jw2hQ7aB4=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.der b/samples/dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.der
new file mode 100644
index 0000000..f51c856
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.pem b/samples/dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.pem
new file mode 100644
index 0000000..a6027f4
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_sha1_rc2_64_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICeTAbBgkqhkiG9w0BBQswDgQITUmepoEoZ4ACAggABIICWHldPT37g3sHtvvV
+ICHi12nOx12AAv4vP1fDXzyUPp/PmGIYymbCC7gOA4XdgPnNfYcsWvq99nY7zoSD
+j3vbSk4vBa/8d5Pen2hmJO8rjD6jrLqMIofviIxK70H6CE+rPpbyhgO8IAPhm9cy
+f76yH9q3qZw5i0K9CiSFQHOaiwepu2tBgu/v7ls4DasNKP+0wZ7bNMHg1AxQYRGe
+kmoXsyxrAH/ndShv1Saqu+zGY381E7/QSzQyxGb5DSzB1qQ5n/QHjZz1dwRljXln
+YNNDSYUbXueMsl7kmuzZHGMhVmlcq5XH9mbRxgI1+8h4TETbRbohHwhWkO4on476
+Vsm5ty7eJN+QVptiXM3UFCnPyXLScT10xi8bqoJXG96HbzYz0D96SrvHpN00pv/5
+GSA0DWdF7mGVLISumVPG/rAxyCY+l4RT3wb+e1cozJ69YtyzHMSOLWKCRKi4pnvp
+l4cHT9vUStY2odFNgD8kVZSGEsLjJYlbjSeA2ODle0fXwU25c8AVhdIoZNI9LYld
+MAggWH24CdEKGC8AxPjVpStg9NTIEppqwT4OROyRnk1OSibXZhAfyT7Dm2rQc2E9
+CMWa1fExB9lPo3jyufeww3hBt5BTbV6xrKwFpodxFBD+FAzbEdM/8+W7jljaou7r
+kdE+5kHKT6YAnUeACRnsZU04h8ZPq6MzQ/wlR6179BjCgagQmPpIf0CfrUNZOrQg
+ssRgQ8sq7z7h/ziPqoqDaxEZS1SzQMoVuO0P9S9mW3hLCmikIUQHCGZ2ZhK17D5T
+bdVtaimI9jw7vHpTxA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_rc4_128.der b/samples/dsa/pkcs8v1_dsa_sha1_rc4_128.der
new file mode 100644
index 0000000..101ef9e
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_sha1_rc4_128.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_rc4_128.pem b/samples/dsa/pkcs8v1_dsa_sha1_rc4_128.pem
new file mode 100644
index 0000000..7e14a22
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_sha1_rc4_128.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICczAcBgoqhkiG9w0BDAEBMA4ECPTj3whspub+AgIIAASCAlHPexOq5Jioh4/2
+9/DdnqDmv730znWAXFC1oubdtMYGs8HQjAZNObYdgUHoRcao8/DqVLJ4m7LY0RdB
+lPGwDzCtHQRMNep2Z9CtNRhfuZ24/3F+lgfjgvZGOYVSVAFr43ltcfrRZlEny3+8
+YAoa/QrLF/viQip3JuiniOn+cwSQ70KZaE4V6PXiqKxYQ6+uZzB+c0HM3WIKwwjx
+ZKiDu20LVyVeApsPrrS2SUJs4EVYaslCCsKlvZ2g6fDAYQiiwX2u3/0f2jO5g5Hn
+HTaYTj19zpe4mx9K3P/d+sOTEaI6lvv7RVoZOAFs9ILNpy1fr/uvl8AhzR2UPvlM
+0jhNn+NNuSFsDwoD0Fw8tuMvXghcw8imxid5eQ2iFIPcUhH6gPtVpqtRZsnSsW1h
+pUES9TYSPT4QwDjXqrcjmbg9o3ypNDA4emCWLhUuIcqw4zAUg9ww4gWTZmKOJogq
+NqpCf8/OZ68jFpzutpDqRbjLIJfMONJ7jK0XW9gtg1PhrapSlfETZS5tMPaJqMdj
+sa/juRQ9mmm/K7Ogzocyhui9FpIcOKtR9mfZPpdP3JVE0Xws0/c72JxOa/dyNsiu
+Q1CfGNSyL899lLyFJ1TJRAfifcrYMMRbR6W/BCxEm7yO5zbdtuzaI7/EmSO0uQ30
+DdPICp+2MphPX6ASo2v+u5Ra1nvzhZ4df1ST3LEM8+aFeEIm0yGFNn/RQE701EBB
+e+KzkcMtcPlQe5tjdb9ol7FMZd033ET9+n0nodb97F5p1ZqGWCF55jgllB/Tq48g
+uL0AiLI0BQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_rc4_40.der b/samples/dsa/pkcs8v1_dsa_sha1_rc4_40.der
new file mode 100644
index 0000000..e49f3da
Binary files /dev/null and b/samples/dsa/pkcs8v1_dsa_sha1_rc4_40.der differ
diff --git a/samples/dsa/pkcs8v1_dsa_sha1_rc4_40.pem b/samples/dsa/pkcs8v1_dsa_sha1_rc4_40.pem
new file mode 100644
index 0000000..af91ca4
--- /dev/null
+++ b/samples/dsa/pkcs8v1_dsa_sha1_rc4_40.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICczAcBgoqhkiG9w0BDAECMA4ECE2PR4rrfglfAgIIAASCAlFpGatgV+VXUbs9
+VnqsgAgPIVvDn8FYT3rPeK4qMfNjJ2u9bt8cP51QPsJReeUFUxVMY4T0jG4NQjuc
+sw3M4jc9ukerdZoSDpF/HwWfI79gAqh7ekIziCTO7ZTiXKmS2SfQdEjpU7dHI4+8
+Zvk4iUskMgXayVYg+yaP/nZlBjVQB08TSvl7kxIo4dlay8J33Fj7JDqZNYEaymCD
+U0CVUvvfCw8ZqxVYbLIEGChu0w+Vjy2TvTm3C9iQ3vrGsYuSN5gyYwGXpOwCdG4z
+UfTZjUBu3nQQKDuD5Kh9c8aw7bgZbSVQFCW4yc8yzXa4nDqFOg9Akr3vBGhsrbBA
+ksi57crWE8pqa14D8L44Yb8bj1ceO2qPMQc1CI94NeZRiGsQ4XRr5fB4OT6+jd+E
+T2ceQkIVonN+808/jyInVmgCMwgx7mZ2NcNvrBFIABv1v5rkJwtXC/Or0r2nQgwR
+/SoMfreNBQhBe7Y/Qr9ayuQIels6omLP8pX7rd3ahR5SLPxRudjWNzaEzrHgRaiL
+nYeOtUqVEQoAr1CPylzWmd3xdhSXFNlPlCd+DzM8nkiy//qqHyob/DCwH4o/r18D
+kvg2q+HMCseuH/QbsZKLkTqAnjrSvp9CMEDyQ+XrCHrAq+YuWgjTCegIavD3LE67
+o2NKOV5GBoRCDWBIyjUY5fmS8To5S5qVWw5YDqk+O8L6iS+lLk8yiCaFiYM1D/Ys
+7VXSHCYfs3ZADRGqNUncVzQzsD1zNC0wdEXUYhvxkPUi9r2XIqDNN4Do0ztg34el
+AeTZ8rklcQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes128_cbc.der b/samples/dsa/pkcs8v2_dsa_aes128_cbc.der
new file mode 100644
index 0000000..6edf1a7
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes128_cbc.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes128_cbc.pem b/samples/dsa/pkcs8v2_dsa_aes128_cbc.pem
new file mode 100644
index 0000000..24c9ac8
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes128_cbc.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICrzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIVT9pRMUZAPwCAggA
+MB0GCWCGSAFlAwQBAgQQh2Ut0m0ZJC+riWEInObeSgSCAmAhqKgYzBa2hbJaNgrr
+K9xxqtZJeIOz6ZiRZOcSyaHLKmpS6FA0MBz6VDHNytKmZY69qzXYdspd8istAaJa
+1BzY85MFkShWheRo7aRc4fj1WZdbsElBfjUhUezZqqsFQqGblrPZZnJDyMNh5yQW
+r+9h+sGsbO8ZONckKHGIlQBoZmju+3IY17W7xCC1FLztUE3+OdUng9L97PSmIpnz
+2cYcFdQZa5f6Y3b78g+veS3XdEzHXETkpt7srpvSvIZy9HcCX9YDDseZBU/1Ny6u
+zNoGScH90K16oXCHoHzHmbJy4XsRcWiUnPqKIqS8AytoqD39IDCPzdoY4BTbgH6K
+zv+jQPzI3NaMtRJpEpOZ/546tDw5ysg4i6lE9KDg17ImA4hHlBHrSkVfhwhwDokm
+abONpmtFCCakNMggvVaiWAc1Mh2DceVIQVlDtItGtNZBOTfoGPXRrcb2+A8XljBO
+BRz2LEQIdtlbKdZqc5GxTWlyGz4lweIxRPu259oMuQr4dLGYx322wqT92o1VscQo
+NSG57GmH6lTEHASCuilvQq+n/6LfcaiQnF47Q7A9MFvgC3nJ6+LESuhXUz8EIn5t
+8xvxOgAVY7grbV0+ja+eBJXLl3PKdh8/CY0BGBF4QlmtTMczqWHIYUXygkA6E8By
+oR1uvNjtAT3h1VvbhFSo1cc91GnjPOPcaq7lFSuaKY/2rxphBb0OoRxp5pVjbf/i
+VpWP6bMiw9yrY2yJGcjDairL/BE5p30BnKXzeOtbaDHdmZ1JYvfqgWgqilNEEdlO
+Nyqb+J5VE5CT+fCVpchlGcPMDQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes128_cfb.der b/samples/dsa/pkcs8v2_dsa_aes128_cfb.der
new file mode 100644
index 0000000..1e68bae
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes128_cfb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes128_cfb.pem b/samples/dsa/pkcs8v2_dsa_aes128_cfb.pem
new file mode 100644
index 0000000..be7f84e
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes128_cfb.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICoDBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI8gVAKqHLSqUCAggA
+MB0GCWCGSAFlAwQBBAQQyXjtzzM4bHUQb2p2D9nT9ASCAlGaMXLjbDixyccz3TFC
+MOeSV3CmZ9RzfYFdZ01CrGPqXGyElfWhG/cEfH6DMmiAqtYTuEoYH4SkwJbvFmZJ
+J8dEGPAnHzpi0JBHsoxllJnoost8wgF4V5V/yAsklbts/EC7ZWVjekoAT/0o+Xxr
+La+pAYH3TAJQBYi2+mXTCsnRWMcUVQyzCCU5wJxAjoqmW9FFe6Jc5ej+eCkIYmCm
+569VwpinVhN+scLNOCc8DF3tn22ARz3ca1QyeJ74Y4hv4MCuNJXTJVBpeg6kzwAV
+ovB1hfRIoK7A2f4O0iT7/7NeFvXoUXTwQMWh0RpTN+V8EIsVaNF2fdTadj0GDnRz
+g5em0MTLuln9/4aZPQsyDqNdMTzo5mzXpdQk3tfGJT28kJG8IKYGkx1OcaDNN6HP
+uSjvqgfV4ZyEQm0spzWccyPevnrAUqwFjG9fBmbObLMwdMooSt9/Q4PkoCfft97k
+XwPVN+S5J5QvBxdTsn/nFXDUMIpfAxVfkSlcmUBemu1TQyuM035khznhdUkoRQvk
+fQiEMGx/r9RI3XfiNjIzQxjdg5TG2g1n9TTDg85GPedEeGpvQS/eRzfcTyhxnuHe
+rNWmkCEgqt6AsJS40ZcT5Y3wiDIlBjO/A/oItQq90Es+lblizBzrFgT4Lw3Pp0Aw
+DnTmpz+DfNNyFaHC/AOiNesKU1iK1SKwm36sjA3jQ2dpp4AwSYqFY1G8xgcHFoch
+2Ftg6igz2//TRhEFdyv4Odgtrqp17n3yqYel9YNjFSm8Ox1Rvgy9JioKqTwiq0mA
+FEHptQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes128_ecb.der b/samples/dsa/pkcs8v2_dsa_aes128_ecb.der
new file mode 100644
index 0000000..bf07867
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes128_ecb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes128_ecb.pem b/samples/dsa/pkcs8v2_dsa_aes128_ecb.pem
new file mode 100644
index 0000000..0ef40bb
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes128_ecb.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICrzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIaU8h+/kZXn8CAggA
+MB0GCWCGSAFlAwQBAQQQAAAAAAAAAAAAAAAAAAAAAASCAmCh2crl4UYag/ZgKQO9
+P4M9uFFmCcrNaVkEihHZobQ65/H3ouOk5SY8y4A04i16Gt2v3cHuT+uj9JkU/6mL
+debfDvGDAHO9/9vxQkSqZzvYorc3CV8SSsQdtJNB7QVkzGGuSz50AG3OqUYCRUIY
+5xrFjwkgO/p1eTraXU/ZLdS79rFNq5Y9xpg5xLKONEIrOhNIoCfApW/fMiZ7mNo3
+p+eaqFwu0qYm5ah+ssLIsN5IJS4uX/TBi5QENJMlCGSCQP96f+SM/BNUN8he3Y0d
+SEj9lLaxk7x0fIEbkm2v7cgpTO07wGVwgrF5hduPswEz0vpR9hI8FjaYRGWTN9Ws
+nhCPTpDHKIpYTcWtfa0JyYhcQ2xGIh8oWKa31v8vIpey+f7g3CUmV5ehFANII8FP
+2DVl8JWkCG5Y1ti0B3yKY2m3b8OVFGlgN2OykmqNHmaW33VDS/L6C6qvP1myArnp
+5MJRjUTKL2HGwJNyG9gykpECp+DG9W8uHWNWhQsvQp69T3tDY7+V2ZBct92dXWFo
+4URUr0/6JnhSjY8c60dHYjRnMZHVtCpGNCiWEHohrKURtqV+SJBTOagGdl0Itef1
+kYQ78PN+rnjy+dvNCR4FZL72nhwMY1ESibDnqcelYePYH1nCCoXCCZf+u4lNJX+/
+3axj0xAMpbyA5D5NbWXJ2OFCAsMhFitWJ5TOcfRyNMlRPdGqZAsw7I40Qw8+GGjf
+a/G5DC/Y121Vp/MlzgXkPQCs3/C/Z/itof6NvVpHL0HA54FIKglQvryybBq0oiq3
+PK7Td42p1YOJ8Ehi62QJnVFd9w==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes128_ofb.der b/samples/dsa/pkcs8v2_dsa_aes128_ofb.der
new file mode 100644
index 0000000..e70eca8
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes128_ofb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes128_ofb.pem b/samples/dsa/pkcs8v2_dsa_aes128_ofb.pem
new file mode 100644
index 0000000..2efac45
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes128_ofb.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICoDBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIrZNAt1U6TfcCAggA
+MB0GCWCGSAFlAwQBAwQQidHP60HVqIm9iweIcXnC1wSCAlFyQKlM4PNky2ejPLFE
+GBoZZwMY8rK0RYx4SjloG1k67xZpzb2uTa/W8TSirQnUkpWJIk0fICCH/39OJ7lC
+OQ/XdwcvL/6dgEE7U7kK3snAfy2DuAJx8eMVOxjUCnM6T6aQML1vFJRgXoZRTgA3
+ua1OL+ilWXUia0MHmctnoEkgHQql0n1fK6U/mvZh4T9faaIwPwtRmhqVufkcIkvu
+64mijzWCldhyGZLBCrN7KhUnPRcfYLEb535+PvktSIW3LTtskDchZQ3RUneAf++w
+DZau4eCAjD3I7YJCPxLxoMpvzlJvMbeOQR14XxnkH+Nfh+KTeTYRDW75Qh/liXs+
+FVZpc9V8c2+1tRH6Biwt7WK9Yusbuvn8dKzGtNsxtJq8obLDbmfC0+JRsPRM7fXn
+3gAIAn8VSBFSN1Zftxyhz9Xt/Jm4dFUR6h2Xp/1QObfO35OFnbPD2T3L1/37SDxg
+SeQrDejyM0Hm3RL1MAAyFs0wXIoL5IGTCeMWSZUSiiq2Cuw3Z9AgljjhtF23CXTM
+FFH0N3926GQInmHFJfw5BHokY0uiz5T53getE7sbHYmPOgFG8yufJz517Jhebm4s
+kNr6pkvbbTFk4k+TEopkmPOjIRJqE4l8XBfCXBnQGpeIR8DEeAc9eWPuansD2+Rb
+q0S1k5Wa1BnpNmnlt+zpDmf8xbL4y4BSNqk/U0Jnil54xX/RcSeX86TkREwpcz2r
+urnox8sM666j3gEVBU9y8whnjOMEKYrwNQOiC1b9v5HyWDXHCG6SDS8Xxxj4L9Jl
+LxHgeQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes192_cbc.der b/samples/dsa/pkcs8v2_dsa_aes192_cbc.der
new file mode 100644
index 0000000..b6d73a8
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes192_cbc.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes192_cbc.pem b/samples/dsa/pkcs8v2_dsa_aes192_cbc.pem
new file mode 100644
index 0000000..e27d863
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes192_cbc.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICrzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIZmGICQBO0F4CAggA
+MB0GCWCGSAFlAwQBFgQQlmyTdrgzQmqR+VD8QdAHogSCAmDXl0vqwCjNFFHE9op+
+3sr+aRGYFeTFbwvh06ENmlxiW2FVZMaJM2BaZ9W6VkSrEUs6j5m1uDLloEsGalzp
+FFbgSUG0KeqaTflaZHdjHKtB0CoBzR88Ee8o0hcRazs4w1sh9QVx9PAOzUKPSpOw
+0og7ACKAk0q1doUu6PoNRURshI9nCM2/ON99YbdjeMPMPoFth7PEGdXiFzeWl88m
+kCb6s+u6XHUIrAynUNM6btpjNYeMqRlejXqPdEacTWLlxhiZim5hHcTIj7uihQax
+qP0BJVoiv4sfm7ktrszIfwdIIajSwaiekB9MM45pe7vp6RvYxKvd4Geny/bSLVvm
+dt505dXBD5S5Km7oz68vJIzYUcXY7NEi2VRbNzM2WwtO9rDQchiz4i1zvomtLs6E
+MqEZfhml9ay1bEn/fLNCJuTtxB8d5JWqZSOkd1Mtrz5ZgdpIMiuoGEM6VrdIU/PZ
+5oVU1tPxym3kNH/R07ne8+ILfp4UBJFqwKGiqKEoYeJPotmxZ02Kx3PUbGds6xSG
+DRkVfZj8/I9Hb3M75btFKAEqAYOQp/2kJsbqyC+Cr/0OCirrsc5jUmtiYQR5PRqG
+I0IWLwyT/uZS+MFQc+kxjNv92ciDaXDDN1CF43cC6CKIa28cCs1Ryk0DgE591MFM
+vbefGteomOi1BkIFjGOM5XHZrZPUnf/YFoKs1GTrE3szMXTisx7CndsBNh32Xoeg
+PO3ljMt8CtX+qtBwBnp39PKcVz7Gjehav5AbQM3cuVDNl7EWcBqYHpSHntZua2hH
+MnQADADRgaNknIy8LOSQ5pVD6g==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes192_cfb.der b/samples/dsa/pkcs8v2_dsa_aes192_cfb.der
new file mode 100644
index 0000000..7577516
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes192_cfb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes192_cfb.pem b/samples/dsa/pkcs8v2_dsa_aes192_cfb.pem
new file mode 100644
index 0000000..f6092d8
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes192_cfb.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICoDBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQItU3Io6IcujwCAggA
+MB0GCWCGSAFlAwQBGAQQv9xQKusfF5mrGHGN5+nlywSCAlHBOOksXFxcOKg8f5hg
+0mlb8qbw/vzLjMD5Qiz9Aenv9vMArtF9GNUxiBWl1bnJjEsgREuA794NhfDeShAS
+jcD0YwQLVZ9lPoL7Loi+icp1hu0gKHhfNxmwfQt+UKkmwHxP1NYOLX550xTdcQiD
+Cax+CFUIhu/7iBJR8CLHKXWFt7Wss1YdQQy489smzCKReZmeedSWTpDpXSAz+lYz
++RURI6jhV6peuO1ChDLJGvtHwWl327CqBfcthegv1OA/E8sGYXy21/8iLMOEdJHH
+sJbrO90HI/txx7trwz+9XcXVbemwkW7jfF21CIPUXVCdnjdaRMY1jBaNj0s9jvSM
+db8+9D4r7QWz9Co2KOx+2QoqUMorq6Z2tdsw+uM6hJI/3qUHG+/F5oRi0yx6sz8y
+NWSsahJW5+0QE6MeAJZElYDokSRx6154kRbYO3BPQfEkgs7BQ4PPmyJWAs155Df8
+E+D7XDbT51kaQwYGhzHJwCT+3DghkSd+5ZxEWVpoEfjrtq12cl0MTHmL3sX4DRKM
+y8INcE5ndxjCKekTdbEvNyK7yjwktkjwgJW5QF+n9TWn+zPFxvDHi5zhMkfpOhPZ
+jlu4Ci8LcksqiYf0C5mb00RDY8JWkDI1HzNNw+9cZLsjmlLs4IDQaSshGI4D7f16
+uhqoJP6p98BhnAE114iM60lW0E1bpguDYqVF5iDTWWpjed27+CzO9RBej4F2c95O
+/LlziWkRdxajvcvyBlR1E/AbF15NnDzFsy07jI3zpEndc3tYbYZ8RG7Y2PLW7N9O
+TZScPg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes192_ecb.der b/samples/dsa/pkcs8v2_dsa_aes192_ecb.der
new file mode 100644
index 0000000..772bf00
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes192_ecb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes192_ecb.pem b/samples/dsa/pkcs8v2_dsa_aes192_ecb.pem
new file mode 100644
index 0000000..a237a1b
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes192_ecb.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICrzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI4eXCz1GJbssCAggA
+MB0GCWCGSAFlAwQBFQQQAAAAAAAAAAAAAAAAAAAAAASCAmAToI3InDEJNaUCgY1E
++sf2a+o0LCMAokx7yJNU59t1BoIQk8sP28lznNCRRE5mudPR+RbYcB0nqw6lYqHK
+e6uZ4TbrAgMd3cxV0PRS9nzyvy9VDfbZGjTcZQjQy5I4yf4NoXLu9+GXZ9ND20bX
+fODHItoQaYbOStB78DQ8ZPvKcv3h+YcDRmfulQEyNjEMfShjyE2wxJsAXyVOBC7v
+uDLUlXzYU2SufDg7n/vMbQuJgWWcXL9OIf/Fhxu0sfyh3hiw7WkojP07lyFdhPQ7
+QY8a5vL3MdVnYMlmkBumvwRkoHLZmwvSzgz39i5qFTd5E8cr/uJ7OoFLE+xQxBgU
+OOLGXXnMf6zpadqTol5jENvvW6YvzMLxPsZE+vbl7DP+XzlXpnEcfgOFJnXWyxFu
+NMdOOqbk5JNQ4mNc3WO5LtTyS4amDLhmnk6+g7d5daDV7CZjT6PvGBGX/M9UYTWn
+SttVV8cnljB+KLIN+s9n07v2OH1MLxyyHrIjHIIx4XC4o75tfJfqwGqJT9m9nna3
+OugtsIGnPMDfuSsFaFWpBo9HvJr9vfzkjuBeOzokzXDwdq2bQflDOnMZ+BcpF70c
+6qnYDGj/duvrYOD8JDcr0sJQYAgF7dTDtGdE72XB6tyYN6q4DtUV9M0JUwBxFBSR
+pq/J8N6vquQ9oDcXqw3NJKe39FQOTiGtEvYpf/Aa+BKybjRwouwhjeqOTTf6P0Pe
+GGUPjDmXe3lKiU4lqPZ8YgMyb9JplYwH5gx5cFhbjQBCWCAaJQGZgE42+x6vLLpi
+Jz139T6ggaLBNb1Z2sfhWoeozQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes192_ofb.der b/samples/dsa/pkcs8v2_dsa_aes192_ofb.der
new file mode 100644
index 0000000..e3f3000
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes192_ofb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes192_ofb.pem b/samples/dsa/pkcs8v2_dsa_aes192_ofb.pem
new file mode 100644
index 0000000..e10fe62
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes192_ofb.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICoDBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIyro6EoodcAsCAggA
+MB0GCWCGSAFlAwQBFwQQago17Qje81NeNh6Lb9K1JQSCAlEuFmc2phK7H+1Fl7cM
+a8bP4EFCg3cgwUOmqGZLj0IYwfHib4x+xVTc1xVjQMV0QdCru73o0+8+MpKb3Tvr
+WQS+kN4D3sw8WkOeTqB0zXQ6lHwZ0BVkGqRduLu/8nL0q5MCsmCSHDY6kd79Nnk8
+ClPTGONEiZOHy9Kv1nLWTClQCvtrtSNDqVd61Jg91s54L4Xjn7k2B4rLrp4dORM5
+Nfcz5rbQXcVv0wF2NZWHaZUDxp4Ca+xabwju0TV9YVMzu3PCUAWhwLMgNZ9pyyer
+iK+EXCtirmkDqpRCajLdJ+1WAY5lSm3hOXIijL4UEypVY1d/aJk6IBly/KdCXlR2
+gOqzYcKsM7kI5VM2DoCNMVxuafzxi/pqInXn6TUhcwZeTY5eXE7FjN0Ih9vqo4+m
+78ixBCFbovyTOBknEo2ly6EKPra2Y2UpE+I5ay+ZmFZ0JTrl99IsV8WIFHEtA3fU
++g0KRHxKDE1e8mdDHqeR4OJlJs5uhudRL5eo8X8rW+syFUvLk06fOHenr0M+o1Wq
+XaINGg8Vxfr4IDQf/JOGc543IhcYCJHTUKPRqW/FLGUHzqllAHYnvkP7ExvWYgwG
+XQSsSv9H5pZ9morvt8ymLc1ujON6Xmcn1AGgqG/OVuTpiSJ9/RYS3I/l4ezkECwt
+EY4g1ZCvtLj/2lg7GKVPPjCXEU8Np0ek0lv4U0URCFD/clTkMl2xMkwDwyH4dK7X
+FEtNU1HQc5OshjXzoyBQ0e9xrNw7qVhBgYlumfSvPuU0ucwYT2374M1Lg7uvTIRl
+S+tjhg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes256_cbc.der b/samples/dsa/pkcs8v2_dsa_aes256_cbc.der
new file mode 100644
index 0000000..71f2441
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes256_cbc.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes256_cbc.pem b/samples/dsa/pkcs8v2_dsa_aes256_cbc.pem
new file mode 100644
index 0000000..c685f88
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes256_cbc.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICrzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIYf686YwXqLcCAggA
+MB0GCWCGSAFlAwQBKgQQri4tfjkmhqskQWKEZGvMnwSCAmBbHumpuZoaypjiOxGS
+HgMHZqnUxR0C/BiVnEcC66rBPjlCjlyAQ9I98i0e/01Wb1pHay6F9vsm+Vj+hzB1
+GuM9TahBuXAQAjleUHjik34gKzewSWeRYEIAN/ywNYHHLJJ3+ogoI3fgCNLnXXb8
+9orQCgkZHCY+cffL/yR4jrFcOIQJmhvsNDmP7IaKZCH00H4mgWC4dI04KnhmTczq
+XX5xqcoNll1viTehM0OEpocsRm1OOwBIO5O2d6iOwxuo+4I5FtTHELsnVP5yii7m
+oIzOa2Tg+v8uVgrAxFsJ3eLkuBJx6dvS3iM9aRJvDPX8jxcR+Fb5cepsEmNydT7l
+diDtMil/QKWSZWVRnPCVD2KClA5nVG/BzX5jJPDj55ryvlYUFdEqrTPXrZ8Vvkkc
+AFqPc6+IHBXEeaVYh/lRfTmVS2MU2tIpW6QPIIUA0WSSFm0CxxzDEE24txL9+D+M
+jjtPu6yTeYDTlQUo0eNzOE6A7xGUT2dI4IopBvyrcgnmUSdsVNifAPoL1uO43aku
+8kKsZHy9cKs4l7J30m8xXUBkBrqpA0T+TRB0YPdJZ69okBv8J3BHuARSeQNxF/l9
+ANTy58CDjaoubtP7izw5AVpcljXTnM4cMvFRnimCpugx85o80bmZ5VNPWlhdDZF9
+oS5fsgfuonv4UNgyXKQIMiY+W3n8DKfdkoHSlqjn/D7ANda6rwovtKhSkg+4Z1dE
+7YF6aV/6Mkd/5/LyNmc8rP33ORUN2anHCATbn1zeEno8+A3GYB/5a5ZvAsX7+Lx3
+z/Z9Np/PFhy7wIN39oUFc4aaGg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes256_cfb.der b/samples/dsa/pkcs8v2_dsa_aes256_cfb.der
new file mode 100644
index 0000000..967c799
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes256_cfb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes256_cfb.pem b/samples/dsa/pkcs8v2_dsa_aes256_cfb.pem
new file mode 100644
index 0000000..dd625a4
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes256_cfb.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICoDBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQItCbXuFZgB00CAggA
+MB0GCWCGSAFlAwQBLAQQ6YyWngfQjfCH/nPHx16UAQSCAlHHhF7hJaPcC0sG9rBA
+3btgv+iuZZcISp9gpSAUioVRNRjrukDGLGv99njCbDZUSSplpj9vubQXAHk0Ugwn
+D3SkXkFpt0bll/AZ4ZloXSLXO5Y1d+UijXb80N5re20GKrN4V99yuS/dtc/kerAO
+mv+l9T5cIWPwamO9xzFScB74f1d54Cg+DBxt+afV0NHGwBhUZXtGsKmah+xgSO2s
+cN9EJyhFAFWI43wugkUCJsyIZA/2mX8KI04hroiPf1yKk78siOIPHf/yDdef/Y81
+cBFAiaaMAar2o5iKzbc/7CYwXVLwCr+gk/Tq+rmk/qphG1sKonhaGs+akBUt5qca
+VtKcQio9BMGRhwZlJF5QEzoGif6HuKVsRpSBDdAiVn+tgmv+ubtjc3yodfmw5C75
+tpToo24TdnZ7gYFOH1bKRavF/UuM+2EBMzgJH7s1CI8Jrlt8uTwumXYwo9/VumiB
+MZvU8Ky4qO3qIslY2nkLs+OBSVgdcbVwltJDcePL9uEY+UoAWZnDcUIbKqKvfTKb
+8gl6P31tp+MRokgy8Xw0oOy0jhDY++68COhuv2i9Tq6mcUYTwCybif0pqqX4xIIX
+ND/MJMT9Na4JYv4KR7w3nBCyDrkNws7d13zopl2Cpti9FJB2XZA8oo3avl6YJJ3j
+wLQoqGxADC00ffXDKjSw9B30iDhUYKRcbwKo5YxJKY66x0MY/rfZQcX8SQbBB0zT
+ph1BpRh+PQUIHHoArCRsYYZo17R+tAbnxn99dSlP3ZESkfYIlOyUoED2+AaKDTQj
+N8u2og==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes256_ecb.der b/samples/dsa/pkcs8v2_dsa_aes256_ecb.der
new file mode 100644
index 0000000..675254a
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes256_ecb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes256_ecb.pem b/samples/dsa/pkcs8v2_dsa_aes256_ecb.pem
new file mode 100644
index 0000000..f63bbe1
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes256_ecb.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICrzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIPDwBoMog+vgCAggA
+MB0GCWCGSAFlAwQBKQQQAAAAAAAAAAAAAAAAAAAAAASCAmB+CKtEXun0FkPeuzre
+HWHD3lD1neK8YpJLPWgI7pJAui2mYiZcbAW2HOsC9NGXZYMuv5/eWsAwrbU+SV2Z
+gkNx0wDi3bOt+mW4ng4svXWedTRchW2MHIE2xOVWT1ETA8i2mLg1/xbflWrpGNPV
+ZqzwvDUW6SY9P9PRebTp2ssggRQ59s6XvzVHRO8/O6rTf9WkE8bzeWXTD5YVsLeQ
+QNoNCfa3dMflOCY3PgpJ9Kfye5JTP5MV90gGL3iUrXR8I7kbNh5UlnZgWuvB7bbG
+Fe4jAxDL1iYjdTOwfNk2kb/q9674wXzeUK9/D9EFTs29qM78IyWXnxG8MvzFCCrY
+xAGbNU9C+41Zylf2hDeOcW3vsaAwJwZkS+297E7LtweXlz8zaQiYEO324StKCBES
+J5UCEm1L77zTYYXPhby988ZkWgQ/qHU8Cv3j0F0HaWwkGo1VvchLwUj3MvE2RDjO
+13yy4DIjT36kEA39iZeF33qSB0cPN3pUsOFKB3OR8DoLMGidnN4ErMndKtMTPGyn
+ppSPGZhZgnoXYXTNll1okBqUcPRY87sN2HLyMDPNehxUzBnEK1JMNXbQWqzOqWCN
+QSbRJnaRLQxec6EfTsfmC2taCJlLdUdTsJgGkH/Zk0ZHNV4izG6gP1nztirpX3YG
+JPQgG0QTFxW6sCm3I8H1XBBVB9mOuGw1Nrb+rk0cjNQnJpTnaEerbdMgmIxhsmBX
+50eMTa6XlwtEiZA6B+/f5huBv8l64v/JrWRkLYsQW1s8iBSOTZgY56Lfj9gmlPhQ
+PMP9BS3aytaYhLEfkSl59/OExA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_aes256_ofb.der b/samples/dsa/pkcs8v2_dsa_aes256_ofb.der
new file mode 100644
index 0000000..d32080b
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_aes256_ofb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_aes256_ofb.pem b/samples/dsa/pkcs8v2_dsa_aes256_ofb.pem
new file mode 100644
index 0000000..4ba3f46
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_aes256_ofb.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICoDBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIejP9qnm498ACAggA
+MB0GCWCGSAFlAwQBKwQQcaXLlr9tbaJT/ZMRwZfdgASCAlFlUGkJFPwG6DNpnm4X
+YGNe08E49EI7XJoTecIqOaAwcozx2uXyo8+6KdsPkUG3xfEmZyiPijSAThvL5vQo
+IYpnQPjI0KUSzFhYwRwU2o45V4rmPfkyr/ghqbArU6fHSeSfHZ8TLaAPkfF4YUSE
+MYwdG9Hh/sRjaEgAxNsnqMA4ahAWv5grKLYa+h5LnvVDqU+Ub4wL9x23V7/aB8Y9
+BuKT3b8dD7b5v6RXsgT5wuv7yGOAtuHRBkf40dbznFfsyso2a222plvvkzkorisX
+1W7zCVI4LRumSVkOc67yl2HknxM02R+iACQ1EhM7qC0YmglqZlLzBUuX9EHzOvJg
+cP+CqFw66TtGl44dlipffySfs7naPvXPLlf4n5ZwQ4JeoPbNKXpIXO+btw4BOISs
+BS6ipHbfnYDUy2WR3fYhP7rjTP6YJc67ObAy0SWCb8MxOYLb/Bx0pzFX4VykX1Hj
+Zu8OHdnFbcecPgDXgK3ka+6pSiLNSR8+momRZIq6NL5h+lYQkt9oKasf5qspGvAl
+rC3jSgRmQ39jaPTrZPaQYrTbUYwKZHKPb2rB1KYaCewgVu1UXIEZwk+5sL0wcWC/
+HhlGRiF8aRNHpwvJOaXRarXBrqe7un3KbFhp65zQ6WgOA/QUNT1XA5EfQPGFE6HQ
+fWMStgkLWIWtoMuaxQqPE/BOMjwOxQo4FmtqMnUywck0nglxRz7mkSt8tY/Igcka
+2tJUgwe7faG11YEW0nuFW9JgR8nMn1BoY0rKHiRroEYvmwA2B3InhJ7Y6qgMmj6+
+jJTrvg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_blowfish_cbc.der b/samples/dsa/pkcs8v2_dsa_blowfish_cbc.der
new file mode 100644
index 0000000..544b2e0
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_blowfish_cbc.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_blowfish_cbc.pem b/samples/dsa/pkcs8v2_dsa_blowfish_cbc.pem
new file mode 100644
index 0000000..73edf17
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_blowfish_cbc.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICnzBBBgkqhkiG9w0BBQ0wNDAbBgkqhkiG9w0BBQwwDgQIO8fmVZptTFUCAggA
+MBUGCSsGAQQBl1UBAgQIpmZqVdyl28MEggJYFaMnV7GvxdtOL0oduTx2NT99aQ39
+isC7W3/7Looumt14SGXLmB/B5lpU7CpkhQdKflKnh+kUw8b35snYq9DUpXKmwKQ8
+OLG6osiPkNbeX+UXqRZ1KB2n45oUTmkeiws1lXovwElqDLlqDRxve/Ks0/Y1WBSN
+mR1lZealI2Ut1E+1KjJFBi/1zJIIFaH+Mvau4R6/vab0Lh/XR7XfakmMrweOH8Zj
+1/bRLUnuYPo8R1MGFGbWRipxgQ1bvxsIAreuewTkdC2S2PYHvGnAdCC8hcLV8mJ0
+/q9tf030ho/M50VIXa7cNS6N/beLXye9L/wBozi8ZzmI4LlEC8nR8OVgkPgKfS82
+mGY5wWVkXiRBx9nMuTjBKRV8MpAjzYz48BpX21UXr/LZEsJ/PKfmy0OYN0TiPNhn
+WAZtHhe84abP3vMfMbNlfHgakfbH31HGAVVWHysSRTeeY6NZqah0CxtlLTPU6+R9
+88cZKG7v0HP6YoW+0Jyh8vmSzrepbcSDWSB/1ToHCjOiNaLcF+SOwyP477bZiAOf
+2AFzu33iFZUo5VaNYAfKiwUkwo3MMs3jxZH6hP07/GJIDPU06N8Phiw5K5R/riv0
+ZKrayJBVMXhnCsf70Q1YWd6UFrGFgGsZyhr97FDiQLjOpT1kGTPFDCgMoWX2AbNO
+gH+kTQGXyRp/FoWFG4stuzMoMbpfH3TrG1b3CG5DloG6PEvyqbXjtKJp3eMer1+S
+JNwu3qwn+/+jRpV/wWaxFYfbidO6QVNypbJu/zLxNwPj+g8fwDU4V6FpNmQRu4xM
+bBzR
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_des1_cbc.der b/samples/dsa/pkcs8v2_dsa_des1_cbc.der
new file mode 100644
index 0000000..8facb1c
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_des1_cbc.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_des1_cbc.pem b/samples/dsa/pkcs8v2_dsa_des1_cbc.pem
new file mode 100644
index 0000000..081b384
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_des1_cbc.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICmzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIvknMDSuj5Y0CAggA
+MBEGBSsOAwIHBAh7q0KSczfiTgSCAlgdfxa+tG7vg2LymyI6rl/+npMdBxHn3iX2
+a9AsFbqctw7kCE/SzhwWnEl4IHOvHYVZ0vBCYHbwMm+deZUZLFIR9cExVSOX9lOl
+9sf3s/RocdapAQTHPlLMTn3lMHYYQKywRHdbdyYFOGGZJNMVwZ4O1yZ0AZaAbFqi
+JglfKzRrRuE8u+/byHZbGq/2xaV80l2O4FenDWcOi3GxZW7DmKVcLRqFeYZ0ZyGL
+5ta3sz37XOpFL7q62GPsG7F9Es9Z49DkPDMwyseidK7bFHVkp+WFpsdA0+/V52X4
+m3r0Y35XBeD18CGAqE5l2BlUot+ddh6wjNp8+VJx+f7fgRKKNCgbcgcTwAilFJfv
+DP83G2vHO1i5MV65CiK/cCbEMeme7e4uW5IFO+PyvY9VWgudw/uo8HRKMUMlvz4B
+btG8Zuwr95o57E1C0VyOYHceqa521y7KxiUdD/CM/ktYp5BB7l0cfnnVI7NHHxil
+DViqjtRGWAfdgseG2lkgy9ke5cbD/P3p+lt/pma94/wEJEFSD7d17+Wp65rj+64w
+9HdEvwyN9AlluBPraciWZPzaf0xGqqQ5s8MQYOvm1XLIgupWGlFL8bR3oOrcq7Ea
+O+6TTEAgJYTxQMQKTscZsXFNtBjwiiVOdPOydYiC2qIKSKEIowsZbkDJp7D7ZF9+
+H2olIK+BB3EAe+98QBsEPICwc/40lKxU3y4L8usgEulvE5sgLnYZrX6BsyWqTKeT
+P/Hish6ijo2wQ2wVtPINOqrT+NhGI3zYOtLMMUlRyZU6YCg1Jzw/ajjcnJxXbAU=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_des1_cfb.der b/samples/dsa/pkcs8v2_dsa_des1_cfb.der
new file mode 100644
index 0000000..93f00ad
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_des1_cfb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_des1_cfb.pem b/samples/dsa/pkcs8v2_dsa_des1_cfb.pem
new file mode 100644
index 0000000..7df7a52
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_des1_cfb.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIClDA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIT8vKpxOwlw0CAggA
+MBEGBSsOAwIJBAgpDzkbHIm/IASCAlHxdvd6wK/40oaT73deAeXNns9WnYDRNiOh
+rCc7PoUfz7nXhhHJ+4eniHbsP9C0h89zL9MFuNZxtD0GQdAQu+w1Awu+IX7RxPc7
+wernjf/9zM6Zrz2Fj4p/EjqVi5NJHGjpCgUQOtgaipRyUZwRLUeRtZZAozTmBRcN
+2+oJGSnJ1kLMwbM+j/0Q/FVuelhGGR15yh6kFOY94UauxSWX11M09d8LlduGM/9t
+bx5jArxuM/t0gFfkLrQsZ+0TPhinor3HNE0k9KhzhxcgGA7g2RcvJRXL/XQTig56
+J6ykHhXLi+dxMBx2bHXKJNTZ/1xNFankGDhJesynjoWAOD5oowTB+5KMEWmihdlG
+IQBkJmqxENNdguG5bylwtqg/iEPOKrggqUuZ9wAR/NOi2Dnp+Oe3Dt5jLem6XHLv
+sgZrouIc8pG+nKMwxANfBZ+XcGQE0QHtE3LS5W5AHa6hkSw6VVHg3JJE3heVYdNE
+lNg/lZolldR9dMQ3rEQvayUqelhDQfxy3di29cw2nsVaaBgQyl2XeFhUeWskEICA
+rYXz4bV6aR1F4CxjmliX3Vsj369Y0x7lJxoyk6d/urUVgEdNUaELoCQ6bXs4VD1D
+5h4aN2iVRHRxPCxNIINzwHK6QDM1jlp2W1Tqk7UQvQwxmTXkpqREby8DOvJsBP+D
+kPk+bGcKLPeCb4f9q2sJhkCSDamENtQ4KB2QmahFlplKZr9tdBnSRIIDA9MLpAfk
+rnp8hD5KFVl/FB8oonI0KphoZ7hyQG5MttDfJidlOH+pPvJuazUMDA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_des1_ecb.der b/samples/dsa/pkcs8v2_dsa_des1_ecb.der
new file mode 100644
index 0000000..0cd9962
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_des1_ecb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_des1_ecb.pem b/samples/dsa/pkcs8v2_dsa_des1_ecb.pem
new file mode 100644
index 0000000..8f4a03d
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_des1_ecb.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICmzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIJN51OJttWjkCAggA
+MBEGBSsOAwIGBAgAAAAAAAAAAASCAljQ3CT/RuzXtjbAq0BFhInN/gljOnYT6mHA
+MecNI+QRyXgjjipIQ0G3uqrAL2aMzQYZbNd31zcpI7+F7yy0PKWlr6kl/mU/P/zt
+zTzjAFEVWLY/cG1mscejYg1aru7OChzP8OSq2qV4cr4RFdxt8Jgkq1gwmQ/IsQsA
+KefKbeQdcj5y+27A32L/aK4R0hTEkLpVh3rwFaUcOXXnQnww3m/dGxVZfCG+RFKY
+cyhgFlKlHKkv51fOYnLShzTNbSOIdkx1Sim9rOuIuUT4nI+enom9NlLynKH5Mc11
+HY93RRX62/Yepd/+g0RDE4wuAXjK5YCgGtPaQxhz5WQvpq50c0WXAonFhYKoojza
+D5dB7qn2bfhgVam/lmnqantsafvy5sQFJAlnDT/gn7P9QYrYZWqSc78Ln27OQF10
+VTr/mjAQyUnxAGrZj/2LoLouFkw/K1ryahH/nFzbaChyhZ7EnsO2gNT12cp915sa
+5sw60r1L9G4YUxapILD3xJMVMH75yR1kHwGJvQjfmEyM62LLFenWQA7hxBp08AMj
+dMcUambSKhl0Mzj01vEk6JAyxp5oX+/vVEaxKO8sLb53d3p/9AxPrmT1oQbANs+F
+Ju003wwarcq3hez8C/Q/01jaXJJOjv7wmAHH4/2SDajFGyobgGSiHsJspD24uNED
+dhZZrYtSsodAPSBU/enpHxH8oc62E3897nlUOtc5FtVZPoh/AGJPUzwCdDwwsAoO
+jYUrUKNdEvTrjwwjAt0PWTbVVDq6IoxBUHbk1BbIoQqHcPzyQFIm3ciVKS5SeiM=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_des1_ofb.der b/samples/dsa/pkcs8v2_dsa_des1_ofb.der
new file mode 100644
index 0000000..7ea4251
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_des1_ofb.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_des1_ofb.pem b/samples/dsa/pkcs8v2_dsa_des1_ofb.pem
new file mode 100644
index 0000000..116c352
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_des1_ofb.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIClDA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQImwccDkLMI1cCAggA
+MBEGBSsOAwIIBAihhtOLmLYIYgSCAlGnW7biQAKuL4Ypqr0RCpHdKfU3YxUgFJCr
+rEuxTEV1ttS3u58Adj7ldaFgUpFIfsaGbpsPeEw+nxHRnZ76xrck6l3MvFxW+WPM
+osKcaITYCNg7TSyzqR33CxMzkdH4FmEVr55nyR1ir2JcQ8QG7/nBN8YTNBpACJIR
+F3kzP3BGz1aAS8ef7v22BcMYkVNb0DJ38z5SUryTqEOwUPWPpNiKaA0chE6nrwjD
+8xlaMPowUjE97bcj+eIQM9hm7Gcwcv5Z4qHPd6NiwRstg0X9GL00wyFjukCV4GJp
+CRK41XwTmyrb6mYGLS6TFRg96R+VyYmB6DL5rCGFuT5oeVIh1FP1TdflOMK8z/sU
+Qftz6Y3ILLbKMGXUVQG6rrXxSD017sBlqK4iPntANH/Ogh6WN2VGeAsRw82ty2YY
+1jJIlEJa7kMFJRZgvboFZf9jsePd8crxMHvyefAGbJcoHvSEku3wZQ2Nil1ddW++
+IvNq6xyNUiYVgCOUtA/7bB0kP6mUpG2tU3MS+C8SknS8lLxcS+Et6yjj1Z+2gEN/
+R1Se9nrhfyUdI/boPmwfmwcVlPnCPI0HlcqHy04oSJVDJlOlOpSkw4cPZCgBIMmq
+N2KgtLYXK6xQQKwVM1RGyqBXEOkngXkddNdwl1PcG5UUxsliw6cDtgZUuv5D6Xht
+9IlxB1eRN+w4kVLRsh+cZCFIUdqiTky3VEBGtO2ohSkBw5Hz6gaqIDZbUqFfal3V
+rS/MLKUOCUwxKUBr8mvwjRUm17caIGnHZVuXUhJtt3MDB+Su107+Eg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.der b/samples/dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.der
new file mode 100644
index 0000000..7005d4c
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.pem b/samples/dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.pem
new file mode 100644
index 0000000..e98e115
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_des2_ecb_SEEMS_WRONG.pem
@@ -0,0 +1,16 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICmzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIz6I345rIqbYCAggA
+MBEGBSsOAwIRBAgAAAAAAAAAAASCAlha7ykjKoRo9RdbHoFnA8gTksfk//hKNzBi
+tdl0MKBYMlDbzG1p548W0hO6OlU5oO1KE27x3hRmKfi+RMGq83MqHbME6OB2bOQL
+QL0xDMI6kpRi4adH8JgOAA46YQFEj5zRDcZg2XOfrGGJOu/fF6Ne4ALrXkewcMIv
+iaFib19vpCHqe5E9ixvDyX/RQRxN2r12II7UctmZyZhqNEHJtp7ZuOROm3M83HuQ
+bMEMLAeNgHslXBDPhrx/ByXi6LmhJJPXk3wAySNwSKCF7bpTtIb51SUDAE2pRaw4
+PrshVZ4hnt9s+xEPz3a7Rs56F06HRyXT4YgXsJsVm6Fmg1DqQwC18aV0ioTEeJ80
+h92btKTg9wJ1+Av/FWIf0scIUnhBmzAC6A0h4mRueSC9xbcQvBb4QquFeDYhxiA6
+MtFS5MtZ4guYyMJlKpKF97c5gfheglxDA/iWrb3TN4dz+eM2D7uBQjfzugF0zQRI
+2VGSO+hRyLlF9/ooozjJ0OO/gVEKz0j8ks6fZ7Ol5ctryT/tGYxhfVR5YPpEW8hk
+iSiEh7QluPGGhjrC955IZBXkfmFqN67X1L9UlExuePj7sPtQjznaLs7rK3fZ9vRm
+9x0JILZOis+I5MOfeoVqDzEtUNI51rpJl8bpt/BOlM0jdnohAIjPPICFZMeBfEzQ
+RmH6VuPWwMhV1KjMQPcoZT5BPl5fxUcpqpLeY86bsCdSHfYJVBBxo1iet8+mC3VK
+mGXwucHoDMh1oGNkPToCCD7x34zMBBDvm9oKyjy51ub9kztWUUctnkDrb0IyEFs=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_des3_cbc.der b/samples/dsa/pkcs8v2_dsa_des3_cbc.der
new file mode 100644
index 0000000..57ec533
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_des3_cbc.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_des3_cbc.pem b/samples/dsa/pkcs8v2_dsa_des3_cbc.pem
new file mode 100644
index 0000000..33e7665
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_des3_cbc.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICnjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIsclhoXWd7bkCAggA
+MBQGCCqGSIb3DQMHBAgsjKjs6xPhKwSCAlgtME7PW1sMaRjbUecyCKazv2QgvwUn
+Z4s2J5pNf8ORBuBdil5lNu+T/9GvdiEGo4R1uA866403Nc2KA8ZpfgOwNPSUn/wb
+iMdCg5S18mvgFT+1Mh1Mz1EUp+RfnVYRI0MlpvKoQf/vFqmEbUVSuQJsq6aBXs/R
+2cJqC6pBGoSAZ0kQza2P1RJ4cTvgf+1OJj4aL8+OMK1rMmYLLkrl0qF+2pppj/nn
+b3djuBPYCN1WbM7Alk8/pxttZxlPnsywBzFAnEYAyAsDAvsAcnx6MeVSnlT6Z91r
+T88AqXREN8c6N+QP9S93K8nBhJ3VSAFRwnqWYG9S/M5itBl636Lna8fwIWmYuOAe
+9+pDA8Ki+aqLDMsz4Aqw1LJ1cOtnjr4Y9ebReo90/hpGVWrASfmQ/Vq+lboz5bSM
+385UyoA+jyiveHVsFctN4rQJLQeIwNWL74jy4RaFRbnoFqlR3HwjLANcnVK3Yx1M
+Hvkvayd+ozj8LsqMjQei5uaxZjet9EhFLJhIMeRq4AnbE+5t2O8MVUhirlq7kENQ
+ZJW9hZF6KARC0dPRIL3Cr0TRYt3Cxci+ZvQOxmcRNUf4rXIe0ySHNVoiYETJ6m2a
+HwQlY3fIDkmGPylTVlp9yax0SWn8ySdVXPFEUiMLZWme8BMeCyWoBrMTwHQESNke
+dUCA30SeNXuDVlY5KX3EsxESNOd427P6SEqEtZAAsiIvXwGUdsKlIPCTs3xG/aP8
+uQzl0E/LoHrT4QuXzDm1IIJlAM6MIV/fYThJ+KRBXegx2YxBY8LgsOlcqvrdjfg+
+zko=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_rc2_128_cbc.der b/samples/dsa/pkcs8v2_dsa_rc2_128_cbc.der
new file mode 100644
index 0000000..fe6a921
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_rc2_128_cbc.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_rc2_128_cbc.pem b/samples/dsa/pkcs8v2_dsa_rc2_128_cbc.pem
new file mode 100644
index 0000000..8bc30f7
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_rc2_128_cbc.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICpjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIQKUAK0PkWtsCAggA
+AgEQMBkGCCqGSIb3DQMCMA0CAToECNtxT/+Pqog1BIICWIY6YcTRO+YYTzYH6AW+
+ST1mb7WaW1MPFF1Fgmr59u2pm1OvH9Cq1ylcSZUJ7xYHcpBC5iigjitcJIo7KrIP
+PdOh5ZMhebNYVREjWL5drrlUEQpM+R5MFsYo8t3Solz9tgujZhYBBNO5b9xMdKu1
+iddJAerTssjJNonHzh0M54wHJ8DthO1hHuF0ljUitIXSKDwQQiKu6nGMdQejgxcM
+RZ+jmm2RwgDBlTnQumR3FUInRjUDdsfC2u7EPyJOKCBEi+V1Knz8dnvfgbwr6yVC
+ka9kjm3zDqbijs2si6tnRdNxXPob8Yld0jwfKuhzoNPQTSLDTm8jtnu8Jlj2WOk9
++pCJPMfPECH1eE0DlVAQEjIDmrQIw5ZEpdMpkOfReaHujT8AiyvcjmxqcgFgNosR
+q757fi/LhQlYi59gpNAKxhAV9rB+5iANDF2ILg9KtIWxg1cFuls6ll4oT13YR+oM
+5+iiTAWwUoVLlKwNAAuUyyvofTHV7oRDnl9p27ZnsBI7DWYKBRirMBcYfatBxWub
+/AeFhXFtCA+LptKuPXepvYbtr4A/A/1bFW9cbKSGNDJ5mxQLofKXeQ0R2oOxbFxN
+F5OJNeg3y1K/GPFw2SMRaf+kPK0K2pm4jkLASM48hwOnfEu0X/lgBVRHIqqekdYq
+pVcGaR1yTBycviabU1grfI49mUbj2EbmUAaIPevN6SFg/gscMOObxZCFiddX38yT
+Pmx13vDnPpKIDh1qrWsDh3ShvjC0y0vVG89ZSDsSph7JSQsT9lKfJZovKkOIoxty
+e/CYyA30P+jUJA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_rc2_40_cbc.der b/samples/dsa/pkcs8v2_dsa_rc2_40_cbc.der
new file mode 100644
index 0000000..fa93428
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_rc2_40_cbc.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_rc2_40_cbc.pem b/samples/dsa/pkcs8v2_dsa_rc2_40_cbc.pem
new file mode 100644
index 0000000..551357b
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_rc2_40_cbc.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICpzBJBgkqhkiG9w0BBQ0wPDAeBgkqhkiG9w0BBQwwEQQIlYIY7do+vY8CAggA
+AgEFMBoGCCqGSIb3DQMCMA4CAgCgBAiYdTRbZ4lQVASCAljYj8mWvuSo7R5pG4RC
+sakmf8knGoSCAKWX4IkyVrOT1tglQpj/TATeNqmykOmF7x96QedoTbTQSFJCDhFR
+ieIyiGYdJYJOOZ0PbwrRKzFJe9RPMC0HxNOSYWq8Ghq801r5SpMgB0GuKsXQIawj
+OazhGWkzKD7G8khfM/AFS3DivxV4gAV7e3PcGeEpXDipDW8wFmGpnva0rUSiQj87
+j5AGeo9R/5QFAhf4KvKLdKeT9BcU4N1lVToibTAImoTNMp9eJdUU43Jf0JWOp18M
+Ws4eP3Cs8xreo8qyB9T4AJ95UFSuPQRCLe2SwjNOgguwzdc0s1nbrFj4bMhphT6+
+ic2aQDXQbTtzahqZz5/UvbzuC3FJ/8AFCrTcxKCRaqKKm3vx2mRGjps1dQaxdq7f
+ePRK+kvThzv6A061rv1PnJF2oi+GOjLzFix7rJjXFvZ79btV7qbb1k1qrAuJzmN4
+rC+iurxT6Nx303PzsSHxr1Rzi9wn3SznFqIRz9K0brhGbG3CqeVsoFnI79K7bB0b
+Rm79vsm9P9zCyJamYYhcQ5fMtXhzvRAfmh0rZjUE+QsPbr60U2JamjYUj28BW/2y
+FPdidr/hFC0Ol/AfQkQJjLG2QGiorFN5QxrBHjeQMAi5AES0/RjW7SH9y6mLKr4+
+vjBEf0adW+kR7PC9Q8An7IVqeQ9vC8FP888fmAbwtxXaQKCp7p1bCLpgg9rlkCdu
+F+WN87Cf9lhR1/ElicLueEryOAlmRWvZwXV4OC6WNQ/meE2EUfkoC0tJXe/2Dw6z
+XXW4BLa4C32ynWQ=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa/pkcs8v2_dsa_rc2_64_cbc.der b/samples/dsa/pkcs8v2_dsa_rc2_64_cbc.der
new file mode 100644
index 0000000..861d040
Binary files /dev/null and b/samples/dsa/pkcs8v2_dsa_rc2_64_cbc.der differ
diff --git a/samples/dsa/pkcs8v2_dsa_rc2_64_cbc.pem b/samples/dsa/pkcs8v2_dsa_rc2_64_cbc.pem
new file mode 100644
index 0000000..aabe3ab
--- /dev/null
+++ b/samples/dsa/pkcs8v2_dsa_rc2_64_cbc.pem
@@ -0,0 +1,17 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIICpjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQI9j+oZ2rYhkYCAggA
+AgEIMBkGCCqGSIb3DQMCMA0CAXgECBbPri4fuLQqBIICWMCy6hNMdpB/4DhIM67V
+cr4F7cZuXn4nIxpKa9B/Z7EaHJnwVShwECCrz7wOVsP0M5uZYrfZ7NXCbz2ESXI8
+B7jCwcMf8/8U2uSlTtyWmJLTrukBifvPtzy4hPYUCiNobtcEipOB/DnLE/c8w7kC
+UR3o6wuHvsaqKcSNminUY0VfyfRWJ+orTBqK1cGQtrtg+6bMYZbJQeKgJeM6BuvJ
+0/yxw4jGMfX/bqqqjPl8PtSchOtSqLCDfMjHQu5IlQUxRYzrqde7KAxWztmBRSHw
+VtWsUKHizEZuOWTC8ZF4LLHHLOpuRr4ChIRihKYjtLp0xgj464RMyvT26gUtSmKS
+v7iPJInt08oOwTxABU9TIgEG7aVp/PHuLwofR6gHJO+vEvdygMpcL38VYp/6E9iL
+NRDr7oGc5IqS65H5pPrwXmtej4A128N9deVzbHJ2v9jEmpfZlFg/FhH5hPccy9Lt
+6dC5xAK18zK4QQ8GWKpa2WJaTiTHWdpd06KHKaisNBUVY48etslcsGSo/XZRlDE1
+aOXGyOY8GKWnhWKfHVDw0Wlg1nIROhm0TvHXWH/IwdaaCAWQL+9o3ObNc7pLPQ+j
+4kpebB4DnbwBZuNAA2QqzjyPPk7s2S0kVWrgf6X3PBd+Tt44GtyMR/jgdLoVzPka
+aPgJLAHYl5/X8h/VuUOnOI+vCfr6E+cyRbs03GOXDv8/Ugeb6QQMKTfU/czidNSB
+9aINJZslQnuHLxlFbmO4VQ0uVUvNWlp1fBzf+MDFeXY3WFNo7YDpclCjQwf1gd6T
+T4qym0e+jm9iYg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/dsa_result.html b/samples/dsa_result.html
new file mode 100644
index 0000000..c618ea0
--- /dev/null
+++ b/samples/dsa_result.html
@@ -0,0 +1,38 @@
+<html>
+<head>
+<title>Not-Yet-Commons-SSL - Decrypting DSA Private Keys in Java</title>
+<style type="text/css">
+h1, h2, h3 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+.nav span.hl a { color: white; }
+li.top { margin-top: 10px; }
+ul.openssl { float: left; width: 100px; margin-top: 8px; }
+ul.pkcs8 { float: left; width: 200px; margin-top: 8px; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="../index.html">main</a> |
+<a href="../ssl.html">ssl</a> |
+<span class="hl"><a href="../pkcs8.html">pkcs8</a></span> |
+<a href="../pbe.html">pbe</a> |
+<a href="../rmi.html">rmi</a> |
+<a href="../utilities.html">utilities</a> |
+<a href="../source.html">source</a> |
+<a href="../javadocs/">javadocs</a> |
+<a href="../download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>Decrypting DSA Private Keys in Java</h2>
+<p>Don't forget to install your JVM's <a href="http://java.sun.com/javase/downloads/">Unlimited Strength Jurisdiction Policy Files</a>
+if you want the AES-192 and AES-256 tests to pass.</p>
+<!--#include virtual="dsa.html" -->
+</body>
+</html>
diff --git a/samples/pbe.tests b/samples/pbe.tests
new file mode 100644
index 0000000..046ec46
--- /dev/null
+++ b/samples/pbe.tests
@@ -0,0 +1,45 @@
+target=/home/julius/dev/commons-ssl/samples/pbe/java
+
+aes-128
+aes-192
+aes-256
+bf
+camellia-128
+camellia-192
+camellia-256
+cast5
+des
+des-ede
+des-ede3
+idea
+rc2
+rc4
+rc5
+
+# Naming variations:
+aes128
+aes192
+aes256
+blowfish
+camellia128
+camellia192
+camellia256
+des2
+des3
+gost
+rc2-40
+rc2-64
+rc4-40
+rijndael
+
+
+# OpenSSL doesn't support these yet:
+cast6
+gost28147
+rc6
+seed
+serpent
+skipjack
+tea
+twofish
+xtea
diff --git a/samples/pbe/README.txt b/samples/pbe/README.txt
new file mode 100644
index 0000000..c1bb157
--- /dev/null
+++ b/samples/pbe/README.txt
@@ -0,0 +1,36 @@
+
+not-yet-commons-ssl PBE tests
+=====================================
+by Julius Davies
+July 4th, 2007
+
+
+README
+-------------------------------------
+
+Underneath this directory are 500+ small files used for testing
+commons-ssl's ability to interop with OpenSSL's password-based
+symmetric encryption (see OpenSSL's 'enc' command).
+
+Each file is encrypted using the cipher in its filename. The
+password is always "changeit", and every file decrypts to the
+phrase "Hello World!" in UTF-8 with no trailing line-feed.
+
+The files underneath "pbe/java/" were created using commons-ssl's
+org.apache.commons.ssl.PBETestCreate utility, along with
+samples/pbe.tests as the single command-line argument. These
+files were created using pure java. It is useful to see whether
+commons-ssl can decrypt files it created itself, as well as to see
+if OpenSSL can also decrypt them.
+
+The files underneath "pbe/openssl/" were created using OpenSSL.
+Take a look at the "samples/createPBESamples.sh" shell script
+to see how these were created. You'll probably need to build
+your own version of OpenSSL from source to use some of the
+ciphers (idea, rc5, for example).
+
+org.apache.commons.ssl.OpenSSLTest tries to decrypt both the
+"pbe/java/" and the "pbe/openssl/" files, and reports on any
+failures.
+
+
diff --git a/samples/pbe/java/aes-128-cbc.base64 b/samples/pbe/java/aes-128-cbc.base64
new file mode 100644
index 0000000..854990a
--- /dev/null
+++ b/samples/pbe/java/aes-128-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX18tgSw33f+3SBISyYVeIkFpwZ/7fyE6IGA=
diff --git a/samples/pbe/java/aes-128-cbc.raw b/samples/pbe/java/aes-128-cbc.raw
new file mode 100644
index 0000000..f7fc29f
--- /dev/null
+++ b/samples/pbe/java/aes-128-cbc.raw
@@ -0,0 +1 @@
+Salted__ь�ͻ��S��|^�bzԏG�a3}�
\ No newline at end of file
diff --git a/samples/pbe/java/aes-128-cfb.base64 b/samples/pbe/java/aes-128-cfb.base64
new file mode 100644
index 0000000..c949990
--- /dev/null
+++ b/samples/pbe/java/aes-128-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+aEXYNHZXWHd599zBpykFGRkhdvw==
diff --git a/samples/pbe/java/aes-128-cfb.raw b/samples/pbe/java/aes-128-cfb.raw
new file mode 100644
index 0000000..feee3a4
--- /dev/null
+++ b/samples/pbe/java/aes-128-cfb.raw
@@ -0,0 +1 @@
+Salted__��Y$5��[�=Q>)�"�_�
\ No newline at end of file
diff --git a/samples/pbe/java/aes-128-cfb8.base64 b/samples/pbe/java/aes-128-cfb8.base64
new file mode 100644
index 0000000..024bab6
--- /dev/null
+++ b/samples/pbe/java/aes-128-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+LUWFrYVLxL7Ig+S+sGlA2HXQFnw==
diff --git a/samples/pbe/java/aes-128-cfb8.raw b/samples/pbe/java/aes-128-cfb8.raw
new file mode 100644
index 0000000..229db5d
--- /dev/null
+++ b/samples/pbe/java/aes-128-cfb8.raw
@@ -0,0 +1 @@
+Salted__q����b�ӥ!��B_���
\ No newline at end of file
diff --git a/samples/pbe/java/aes-128-ecb.base64 b/samples/pbe/java/aes-128-ecb.base64
new file mode 100644
index 0000000..9146001
--- /dev/null
+++ b/samples/pbe/java/aes-128-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+2C1jR9HIDttUbQ5if/FugiwJWHnvw9nE=
diff --git a/samples/pbe/java/aes-128-ecb.raw b/samples/pbe/java/aes-128-ecb.raw
new file mode 100644
index 0000000..1065ef4
--- /dev/null
+++ b/samples/pbe/java/aes-128-ecb.raw
@@ -0,0 +1 @@
+Salted__�$U�ƽ!�
8� 'Mi��q�r
\ No newline at end of file
diff --git a/samples/pbe/java/aes-128-ofb.base64 b/samples/pbe/java/aes-128-ofb.base64
new file mode 100644
index 0000000..f7459a0
--- /dev/null
+++ b/samples/pbe/java/aes-128-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19aJ6WDYWY7FPQIkpp/6FgjhHrxHQ==
diff --git a/samples/pbe/java/aes-128-ofb.raw b/samples/pbe/java/aes-128-ofb.raw
new file mode 100644
index 0000000..f475a8b
--- /dev/null
+++ b/samples/pbe/java/aes-128-ofb.raw
@@ -0,0 +1 @@
+Salted__
-H4I�Ȗ �fzV��j�l�
\ No newline at end of file
diff --git a/samples/pbe/java/aes-128.base64 b/samples/pbe/java/aes-128.base64
new file mode 100644
index 0000000..4cb1703
--- /dev/null
+++ b/samples/pbe/java/aes-128.base64
@@ -0,0 +1 @@
+U2FsdGVkX18FP9Ocup5k311G9zgGlCnh9zas3Xdj0tU=
diff --git a/samples/pbe/java/aes-128.raw b/samples/pbe/java/aes-128.raw
new file mode 100644
index 0000000..0a36280
--- /dev/null
+++ b/samples/pbe/java/aes-128.raw
@@ -0,0 +1 @@
+Salted__��.�}���*=*<�G�]���
\ No newline at end of file
diff --git a/samples/pbe/java/aes-192-cbc.base64 b/samples/pbe/java/aes-192-cbc.base64
new file mode 100644
index 0000000..d402ec3
--- /dev/null
+++ b/samples/pbe/java/aes-192-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/Pw8ptccG+s6ZDELJSrvJ2ZctgWQGJFAA=
diff --git a/samples/pbe/java/aes-192-cbc.raw b/samples/pbe/java/aes-192-cbc.raw
new file mode 100644
index 0000000..09d5789
--- /dev/null
+++ b/samples/pbe/java/aes-192-cbc.raw
@@ -0,0 +1 @@
+Salted__�Y��$�����?a�ByF����;�
\ No newline at end of file
diff --git a/samples/pbe/java/aes-192-cfb.base64 b/samples/pbe/java/aes-192-cfb.base64
new file mode 100644
index 0000000..fa4e9b4
--- /dev/null
+++ b/samples/pbe/java/aes-192-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18f1Q3JHkC82JVsgDi+mCM9dsLoDw==
diff --git a/samples/pbe/java/aes-192-cfb.raw b/samples/pbe/java/aes-192-cfb.raw
new file mode 100644
index 0000000..f569c15
--- /dev/null
+++ b/samples/pbe/java/aes-192-cfb.raw
@@ -0,0 +1 @@
+Salted__�����6���W]�ntD4�N$
\ No newline at end of file
diff --git a/samples/pbe/java/aes-192-cfb8.base64 b/samples/pbe/java/aes-192-cfb8.base64
new file mode 100644
index 0000000..d51d5dd
--- /dev/null
+++ b/samples/pbe/java/aes-192-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX19ly+xGnMtLS9cfR8LfWky7HRNtnQ==
diff --git a/samples/pbe/java/aes-192-cfb8.raw b/samples/pbe/java/aes-192-cfb8.raw
new file mode 100644
index 0000000..96e1460
--- /dev/null
+++ b/samples/pbe/java/aes-192-cfb8.raw
@@ -0,0 +1 @@
+Salted__����?��l6-
(nu��uI
\ No newline at end of file
diff --git a/samples/pbe/java/aes-192-ecb.base64 b/samples/pbe/java/aes-192-ecb.base64
new file mode 100644
index 0000000..a401033
--- /dev/null
+++ b/samples/pbe/java/aes-192-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+2N1TfkuHLaGKTV8UbxAQ4q6Zq2yPyI0s=
diff --git a/samples/pbe/java/aes-192-ecb.raw b/samples/pbe/java/aes-192-ecb.raw
new file mode 100644
index 0000000..85fc440
--- /dev/null
+++ b/samples/pbe/java/aes-192-ecb.raw
@@ -0,0 +1,2 @@
+Salted__�^$D�>5�51g�,z�ۍ
+�!�
\ No newline at end of file
diff --git a/samples/pbe/java/aes-192-ofb.base64 b/samples/pbe/java/aes-192-ofb.base64
new file mode 100644
index 0000000..73a53e9
--- /dev/null
+++ b/samples/pbe/java/aes-192-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/Amis2JdWVZwzVHM396jtsZbIEJw==
diff --git a/samples/pbe/java/aes-192-ofb.raw b/samples/pbe/java/aes-192-ofb.raw
new file mode 100644
index 0000000..510475f
--- /dev/null
+++ b/samples/pbe/java/aes-192-ofb.raw
@@ -0,0 +1 @@
+Salted__�IH��x�J��
�����!(
\ No newline at end of file
diff --git a/samples/pbe/java/aes-192.base64 b/samples/pbe/java/aes-192.base64
new file mode 100644
index 0000000..c8236dc
--- /dev/null
+++ b/samples/pbe/java/aes-192.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+fyoUNT8WlenheACOWMcd++BG67BrAVZY=
diff --git a/samples/pbe/java/aes-192.raw b/samples/pbe/java/aes-192.raw
new file mode 100644
index 0000000..3a0bb76
--- /dev/null
+++ b/samples/pbe/java/aes-192.raw
@@ -0,0 +1 @@
+Salted__n����4�m�_m�q��Q��F�
\ No newline at end of file
diff --git a/samples/pbe/java/aes-256-cbc.base64 b/samples/pbe/java/aes-256-cbc.base64
new file mode 100644
index 0000000..5d2c32f
--- /dev/null
+++ b/samples/pbe/java/aes-256-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+83KKHWiQjV2cPLD4vnvX7jB9nzF7KSr4=
diff --git a/samples/pbe/java/aes-256-cbc.raw b/samples/pbe/java/aes-256-cbc.raw
new file mode 100644
index 0000000..4c4b343
--- /dev/null
+++ b/samples/pbe/java/aes-256-cbc.raw
@@ -0,0 +1 @@
+Salted__w����+
V�I���o��Bc�c�k"
\ No newline at end of file
diff --git a/samples/pbe/java/aes-256-cfb.base64 b/samples/pbe/java/aes-256-cfb.base64
new file mode 100644
index 0000000..b0b632f
--- /dev/null
+++ b/samples/pbe/java/aes-256-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/r2qI9504wQdQk+10DnjuZx74VWA==
diff --git a/samples/pbe/java/aes-256-cfb.raw b/samples/pbe/java/aes-256-cfb.raw
new file mode 100644
index 0000000..16db14d
--- /dev/null
+++ b/samples/pbe/java/aes-256-cfb.raw
@@ -0,0 +1 @@
+Salted__W����R�V�d}����
\ No newline at end of file
diff --git a/samples/pbe/java/aes-256-cfb8.base64 b/samples/pbe/java/aes-256-cfb8.base64
new file mode 100644
index 0000000..f8a92e2
--- /dev/null
+++ b/samples/pbe/java/aes-256-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18OrQNbniV4S+jfRZg7flFPHiT5MA==
diff --git a/samples/pbe/java/aes-256-cfb8.raw b/samples/pbe/java/aes-256-cfb8.raw
new file mode 100644
index 0000000..0b3431f
--- /dev/null
+++ b/samples/pbe/java/aes-256-cfb8.raw
@@ -0,0 +1 @@
+Salted__�
j�����(�&!��W��
\ No newline at end of file
diff --git a/samples/pbe/java/aes-256-ecb.base64 b/samples/pbe/java/aes-256-ecb.base64
new file mode 100644
index 0000000..8e754c1
--- /dev/null
+++ b/samples/pbe/java/aes-256-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19UgKG5AJSnofrockP9DOx0X0UEIRrcpwI=
diff --git a/samples/pbe/java/aes-256-ecb.raw b/samples/pbe/java/aes-256-ecb.raw
new file mode 100644
index 0000000..3805337
--- /dev/null
+++ b/samples/pbe/java/aes-256-ecb.raw
@@ -0,0 +1 @@
+Salted__��H���"
E|�9m@��#��ϖ�m
\ No newline at end of file
diff --git a/samples/pbe/java/aes-256-ofb.base64 b/samples/pbe/java/aes-256-ofb.base64
new file mode 100644
index 0000000..143a65a
--- /dev/null
+++ b/samples/pbe/java/aes-256-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18MFvQbl2SXe0fhKwTF9mjNmN9f4A==
diff --git a/samples/pbe/java/aes-256-ofb.raw b/samples/pbe/java/aes-256-ofb.raw
new file mode 100644
index 0000000..44d53ef
--- /dev/null
+++ b/samples/pbe/java/aes-256-ofb.raw
@@ -0,0 +1 @@
+Salted__ުqۮ�
?R�8�El���
\ No newline at end of file
diff --git a/samples/pbe/java/aes-256.base64 b/samples/pbe/java/aes-256.base64
new file mode 100644
index 0000000..8f901f5
--- /dev/null
+++ b/samples/pbe/java/aes-256.base64
@@ -0,0 +1 @@
+U2FsdGVkX19M77p3hPsAsk2LeJM6zIQBMmTpmjGdaHY=
diff --git a/samples/pbe/java/aes-256.raw b/samples/pbe/java/aes-256.raw
new file mode 100644
index 0000000..e64d1e0
--- /dev/null
+++ b/samples/pbe/java/aes-256.raw
@@ -0,0 +1 @@
+Salted__�xA������s]��I�թ*S
\ No newline at end of file
diff --git a/samples/pbe/java/aes128-cbc.base64 b/samples/pbe/java/aes128-cbc.base64
new file mode 100644
index 0000000..f57f204
--- /dev/null
+++ b/samples/pbe/java/aes128-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+yeIg0SOvBDsjJmBCufP4ga2BB4rRsXio=
diff --git a/samples/pbe/java/aes128-cbc.raw b/samples/pbe/java/aes128-cbc.raw
new file mode 100644
index 0000000..bb10166
--- /dev/null
+++ b/samples/pbe/java/aes128-cbc.raw
@@ -0,0 +1 @@
+Salted__���p��
>3ο�h�VJ�{)�H�}v
\ No newline at end of file
diff --git a/samples/pbe/java/aes128-cfb.base64 b/samples/pbe/java/aes128-cfb.base64
new file mode 100644
index 0000000..93ce4ab
--- /dev/null
+++ b/samples/pbe/java/aes128-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19tWJZmJ48v/XfHfnB2w1e//fdR8Q==
diff --git a/samples/pbe/java/aes128-cfb.raw b/samples/pbe/java/aes128-cfb.raw
new file mode 100644
index 0000000..735aba0
--- /dev/null
+++ b/samples/pbe/java/aes128-cfb.raw
@@ -0,0 +1 @@
+Salted__g����1[碤���
\ No newline at end of file
diff --git a/samples/pbe/java/aes128-cfb8.base64 b/samples/pbe/java/aes128-cfb8.base64
new file mode 100644
index 0000000..d85ad96
--- /dev/null
+++ b/samples/pbe/java/aes128-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+XyvFXsj5UFwtv8gyG1oIXvve+oQ==
diff --git a/samples/pbe/java/aes128-cfb8.raw b/samples/pbe/java/aes128-cfb8.raw
new file mode 100644
index 0000000..1fe531f
--- /dev/null
+++ b/samples/pbe/java/aes128-cfb8.raw
@@ -0,0 +1 @@
+Salted__d?�ٗ�5�ד��������
\ No newline at end of file
diff --git a/samples/pbe/java/aes128-ecb.base64 b/samples/pbe/java/aes128-ecb.base64
new file mode 100644
index 0000000..5b43322
--- /dev/null
+++ b/samples/pbe/java/aes128-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/UoGJhhyX4cVn2rw/7X7fgdqhhgiWlp7M=
diff --git a/samples/pbe/java/aes128-ecb.raw b/samples/pbe/java/aes128-ecb.raw
new file mode 100644
index 0000000..50dffdc
--- /dev/null
+++ b/samples/pbe/java/aes128-ecb.raw
@@ -0,0 +1 @@
+Salted__iќW�gS�k�+>��7�?�
\ No newline at end of file
diff --git a/samples/pbe/java/aes128-ofb.base64 b/samples/pbe/java/aes128-ofb.base64
new file mode 100644
index 0000000..8b8a266
--- /dev/null
+++ b/samples/pbe/java/aes128-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/lTN4sZ1doqxbZpX0IC10FLDCaUA==
diff --git a/samples/pbe/java/aes128-ofb.raw b/samples/pbe/java/aes128-ofb.raw
new file mode 100644
index 0000000..61ca060
--- /dev/null
+++ b/samples/pbe/java/aes128-ofb.raw
@@ -0,0 +1 @@
+Salted__<��Y��s�xq�U؏��D
\ No newline at end of file
diff --git a/samples/pbe/java/aes128.base64 b/samples/pbe/java/aes128.base64
new file mode 100644
index 0000000..203a047
--- /dev/null
+++ b/samples/pbe/java/aes128.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/1UuVXOj3RtEMceVcMua7qDQw0530YPTU=
diff --git a/samples/pbe/java/aes128.raw b/samples/pbe/java/aes128.raw
new file mode 100644
index 0000000..d533a8b
--- /dev/null
+++ b/samples/pbe/java/aes128.raw
@@ -0,0 +1 @@
+Salted__��Os��u�dS�� J$�ik{�
\ No newline at end of file
diff --git a/samples/pbe/java/aes192-cbc.base64 b/samples/pbe/java/aes192-cbc.base64
new file mode 100644
index 0000000..85a50be
--- /dev/null
+++ b/samples/pbe/java/aes192-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19Gp+yjlyN/zD/rgggvOVVFY4SmgOZCmRM=
diff --git a/samples/pbe/java/aes192-cbc.raw b/samples/pbe/java/aes192-cbc.raw
new file mode 100644
index 0000000..7ac614e
Binary files /dev/null and b/samples/pbe/java/aes192-cbc.raw differ
diff --git a/samples/pbe/java/aes192-cfb.base64 b/samples/pbe/java/aes192-cfb.base64
new file mode 100644
index 0000000..c70e576
--- /dev/null
+++ b/samples/pbe/java/aes192-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/im+oIYCd9d7VAJxwuyTKpXnatBA==
diff --git a/samples/pbe/java/aes192-cfb.raw b/samples/pbe/java/aes192-cfb.raw
new file mode 100644
index 0000000..926bbdc
--- /dev/null
+++ b/samples/pbe/java/aes192-cfb.raw
@@ -0,0 +1,2 @@
+Salted__
+�]WW�aM�+`��o�
\ No newline at end of file
diff --git a/samples/pbe/java/aes192-cfb8.base64 b/samples/pbe/java/aes192-cfb8.base64
new file mode 100644
index 0000000..e968571
--- /dev/null
+++ b/samples/pbe/java/aes192-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX186iw+KCu0VBo9RdYAKHo9vNfDSFQ==
diff --git a/samples/pbe/java/aes192-cfb8.raw b/samples/pbe/java/aes192-cfb8.raw
new file mode 100644
index 0000000..a71a670
--- /dev/null
+++ b/samples/pbe/java/aes192-cfb8.raw
@@ -0,0 +1 @@
+Salted__��N��{��a��
�
\ No newline at end of file
diff --git a/samples/pbe/java/aes192-ecb.base64 b/samples/pbe/java/aes192-ecb.base64
new file mode 100644
index 0000000..eaa6ef9
--- /dev/null
+++ b/samples/pbe/java/aes192-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1++cAjnHEiPvcYEXga2MZ/nPphLkC9FDpI=
diff --git a/samples/pbe/java/aes192-ecb.raw b/samples/pbe/java/aes192-ecb.raw
new file mode 100644
index 0000000..f59bb04
--- /dev/null
+++ b/samples/pbe/java/aes192-ecb.raw
@@ -0,0 +1 @@
+Salted__8��X?V�
���
�c�T��є�B��
\ No newline at end of file
diff --git a/samples/pbe/java/aes192-ofb.base64 b/samples/pbe/java/aes192-ofb.base64
new file mode 100644
index 0000000..2055b4f
--- /dev/null
+++ b/samples/pbe/java/aes192-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+tB5EoA+99EgMjaRsrhrIdu+4MgA==
diff --git a/samples/pbe/java/aes192-ofb.raw b/samples/pbe/java/aes192-ofb.raw
new file mode 100644
index 0000000..c13e590
--- /dev/null
+++ b/samples/pbe/java/aes192-ofb.raw
@@ -0,0 +1 @@
+Salted__AQ(��h1�!�a�U�$C7�
\ No newline at end of file
diff --git a/samples/pbe/java/aes192.base64 b/samples/pbe/java/aes192.base64
new file mode 100644
index 0000000..709506b
--- /dev/null
+++ b/samples/pbe/java/aes192.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/FEWgPPq4v5tSeC0JqBLLTmnm3mZyVQy8=
diff --git a/samples/pbe/java/aes192.raw b/samples/pbe/java/aes192.raw
new file mode 100644
index 0000000..efbca29
--- /dev/null
+++ b/samples/pbe/java/aes192.raw
@@ -0,0 +1 @@
+Salted__hJ�~~�
�G8#��WcQҠ���
\ No newline at end of file
diff --git a/samples/pbe/java/aes256-cbc.base64 b/samples/pbe/java/aes256-cbc.base64
new file mode 100644
index 0000000..38172a2
--- /dev/null
+++ b/samples/pbe/java/aes256-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+1PFX6yjmLx//GKR/kI0JcI4BvOsFo54U=
diff --git a/samples/pbe/java/aes256-cbc.raw b/samples/pbe/java/aes256-cbc.raw
new file mode 100644
index 0000000..2536117
--- /dev/null
+++ b/samples/pbe/java/aes256-cbc.raw
@@ -0,0 +1 @@
+Salted__1w����?�X2rϡ�)\�I֦%+
\ No newline at end of file
diff --git a/samples/pbe/java/aes256-cfb.base64 b/samples/pbe/java/aes256-cfb.base64
new file mode 100644
index 0000000..dadb997
--- /dev/null
+++ b/samples/pbe/java/aes256-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX183eIcxGvreiWgqXZzCXPTHbs9t1w==
diff --git a/samples/pbe/java/aes256-cfb.raw b/samples/pbe/java/aes256-cfb.raw
new file mode 100644
index 0000000..7ab062b
--- /dev/null
+++ b/samples/pbe/java/aes256-cfb.raw
@@ -0,0 +1,2 @@
+Salted__�T��qS
+KeU�!����$�
\ No newline at end of file
diff --git a/samples/pbe/java/aes256-cfb8.base64 b/samples/pbe/java/aes256-cfb8.base64
new file mode 100644
index 0000000..44b6c5d
--- /dev/null
+++ b/samples/pbe/java/aes256-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX19seCs2x8/p8t0Dzsg0jG5HJpiyug==
diff --git a/samples/pbe/java/aes256-cfb8.raw b/samples/pbe/java/aes256-cfb8.raw
new file mode 100644
index 0000000..f40fb94
--- /dev/null
+++ b/samples/pbe/java/aes256-cfb8.raw
@@ -0,0 +1 @@
+Salted___�oU�����6
����
\ No newline at end of file
diff --git a/samples/pbe/java/aes256-ecb.base64 b/samples/pbe/java/aes256-ecb.base64
new file mode 100644
index 0000000..1c42841
--- /dev/null
+++ b/samples/pbe/java/aes256-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+CklO63OMjBE7V60TyZdccAvOZSoHvdoY=
diff --git a/samples/pbe/java/aes256-ecb.raw b/samples/pbe/java/aes256-ecb.raw
new file mode 100644
index 0000000..9feac0e
--- /dev/null
+++ b/samples/pbe/java/aes256-ecb.raw
@@ -0,0 +1 @@
+Salted__���8�gs����_pT�ù���I7�
\ No newline at end of file
diff --git a/samples/pbe/java/aes256-ofb.base64 b/samples/pbe/java/aes256-ofb.base64
new file mode 100644
index 0000000..dc623be
--- /dev/null
+++ b/samples/pbe/java/aes256-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18MiDOnBD5OkXH/C+Ua2qcjGnVsNQ==
diff --git a/samples/pbe/java/aes256-ofb.raw b/samples/pbe/java/aes256-ofb.raw
new file mode 100644
index 0000000..53e8bd6
--- /dev/null
+++ b/samples/pbe/java/aes256-ofb.raw
@@ -0,0 +1 @@
+Salted__����Ł(�z����� �|
\ No newline at end of file
diff --git a/samples/pbe/java/aes256.base64 b/samples/pbe/java/aes256.base64
new file mode 100644
index 0000000..2370b34
--- /dev/null
+++ b/samples/pbe/java/aes256.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/qurIuLg/OPdk3l+HU2cYuOfjbKPyU2IQ=
diff --git a/samples/pbe/java/aes256.raw b/samples/pbe/java/aes256.raw
new file mode 100644
index 0000000..30b0252
--- /dev/null
+++ b/samples/pbe/java/aes256.raw
@@ -0,0 +1 @@
+Salted__4��'Tx��8%kJ"F3�Q
\ No newline at end of file
diff --git a/samples/pbe/java/bf-cbc.base64 b/samples/pbe/java/bf-cbc.base64
new file mode 100644
index 0000000..ded04a6
--- /dev/null
+++ b/samples/pbe/java/bf-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX18ezFO/IyruCLWgSXb8ub3xpSJ7ZKoGI+8=
diff --git a/samples/pbe/java/bf-cbc.raw b/samples/pbe/java/bf-cbc.raw
new file mode 100644
index 0000000..db3a502
--- /dev/null
+++ b/samples/pbe/java/bf-cbc.raw
@@ -0,0 +1 @@
+Salted__�>�K���g���9���;S�s���
\ No newline at end of file
diff --git a/samples/pbe/java/bf-cfb.base64 b/samples/pbe/java/bf-cfb.base64
new file mode 100644
index 0000000..135cdad
--- /dev/null
+++ b/samples/pbe/java/bf-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+yi+2LyrXPbswy1jL1yAnXX+MjPA==
diff --git a/samples/pbe/java/bf-cfb.raw b/samples/pbe/java/bf-cfb.raw
new file mode 100644
index 0000000..6784823
--- /dev/null
+++ b/samples/pbe/java/bf-cfb.raw
@@ -0,0 +1 @@
+Salted__�#5�P���Es�ҿ��
\ No newline at end of file
diff --git a/samples/pbe/java/bf-cfb8.base64 b/samples/pbe/java/bf-cfb8.base64
new file mode 100644
index 0000000..622299b
--- /dev/null
+++ b/samples/pbe/java/bf-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18Uyb5uwUSF5vlUwT8sTYUUUquHwA==
diff --git a/samples/pbe/java/bf-cfb8.raw b/samples/pbe/java/bf-cfb8.raw
new file mode 100644
index 0000000..00c7c39
--- /dev/null
+++ b/samples/pbe/java/bf-cfb8.raw
@@ -0,0 +1 @@
+Salted__V:�&'3)�T���_��ŕ�5
\ No newline at end of file
diff --git a/samples/pbe/java/bf-ecb.base64 b/samples/pbe/java/bf-ecb.base64
new file mode 100644
index 0000000..fc5d780
--- /dev/null
+++ b/samples/pbe/java/bf-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX181gpdrxNUzjZWSJrri+XaHTk8J2BiwgiY=
diff --git a/samples/pbe/java/bf-ecb.raw b/samples/pbe/java/bf-ecb.raw
new file mode 100644
index 0000000..8ed9cf4
--- /dev/null
+++ b/samples/pbe/java/bf-ecb.raw
@@ -0,0 +1 @@
+Salted__�76�f���{Ou�PXJ�R��:A�
\ No newline at end of file
diff --git a/samples/pbe/java/bf-ofb.base64 b/samples/pbe/java/bf-ofb.base64
new file mode 100644
index 0000000..e86bec9
--- /dev/null
+++ b/samples/pbe/java/bf-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/Lzlz4ROS2VIJm3BDuISIlhXyqIA==
diff --git a/samples/pbe/java/bf-ofb.raw b/samples/pbe/java/bf-ofb.raw
new file mode 100644
index 0000000..2c55382
--- /dev/null
+++ b/samples/pbe/java/bf-ofb.raw
@@ -0,0 +1 @@
+Salted__T�<���H�F��>�U���B
\ No newline at end of file
diff --git a/samples/pbe/java/bf.base64 b/samples/pbe/java/bf.base64
new file mode 100644
index 0000000..8d02877
--- /dev/null
+++ b/samples/pbe/java/bf.base64
@@ -0,0 +1 @@
+U2FsdGVkX19e7ErlyQFrRuAvkXC+RpF8qq4NUNtwP0Y=
diff --git a/samples/pbe/java/bf.raw b/samples/pbe/java/bf.raw
new file mode 100644
index 0000000..5368738
--- /dev/null
+++ b/samples/pbe/java/bf.raw
@@ -0,0 +1 @@
+Salted__m
O�T5
T�ؾ��!���Zw|6�
\ No newline at end of file
diff --git a/samples/pbe/java/blowfish-cbc.base64 b/samples/pbe/java/blowfish-cbc.base64
new file mode 100644
index 0000000..4a9bc76
--- /dev/null
+++ b/samples/pbe/java/blowfish-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/X9q7FxWKC+Nt4r1Tbx9Lq8iGgpYLA9VU=
diff --git a/samples/pbe/java/blowfish-cbc.raw b/samples/pbe/java/blowfish-cbc.raw
new file mode 100644
index 0000000..cbb2039
--- /dev/null
+++ b/samples/pbe/java/blowfish-cbc.raw
@@ -0,0 +1 @@
+Salted__B�uk��$2�6+d.�����'�H
\ No newline at end of file
diff --git a/samples/pbe/java/blowfish-cfb.base64 b/samples/pbe/java/blowfish-cfb.base64
new file mode 100644
index 0000000..e5cd0bf
--- /dev/null
+++ b/samples/pbe/java/blowfish-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+BMJfwsI5pN/TlN21qZpmkKZ+ZCQ==
diff --git a/samples/pbe/java/blowfish-cfb.raw b/samples/pbe/java/blowfish-cfb.raw
new file mode 100644
index 0000000..760e562
--- /dev/null
+++ b/samples/pbe/java/blowfish-cfb.raw
@@ -0,0 +1 @@
+Salted__�F��<A�A� �j�c+��z
\ No newline at end of file
diff --git a/samples/pbe/java/blowfish-cfb8.base64 b/samples/pbe/java/blowfish-cfb8.base64
new file mode 100644
index 0000000..06efdcf
--- /dev/null
+++ b/samples/pbe/java/blowfish-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX19QNGPN4Mb7Bj9fdwfr2ICVZxIqyw==
diff --git a/samples/pbe/java/blowfish-cfb8.raw b/samples/pbe/java/blowfish-cfb8.raw
new file mode 100644
index 0000000..e13828b
--- /dev/null
+++ b/samples/pbe/java/blowfish-cfb8.raw
@@ -0,0 +1 @@
+Salted__K��
T�ݬ
F{$L/�
\ No newline at end of file
diff --git a/samples/pbe/java/blowfish-ecb.base64 b/samples/pbe/java/blowfish-ecb.base64
new file mode 100644
index 0000000..28b6573
--- /dev/null
+++ b/samples/pbe/java/blowfish-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/n+y1mOrx0j2A70eSTKaG7xu+WCNzzEkI=
diff --git a/samples/pbe/java/blowfish-ecb.raw b/samples/pbe/java/blowfish-ecb.raw
new file mode 100644
index 0000000..6ed74b3
--- /dev/null
+++ b/samples/pbe/java/blowfish-ecb.raw
@@ -0,0 +1 @@
+Salted__�̍3�s2X����Ϗy
���o�
\ No newline at end of file
diff --git a/samples/pbe/java/blowfish-ofb.base64 b/samples/pbe/java/blowfish-ofb.base64
new file mode 100644
index 0000000..2f02531
--- /dev/null
+++ b/samples/pbe/java/blowfish-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18skzs84vkC6FRTjlxDau6lzgx3Jg==
diff --git a/samples/pbe/java/blowfish-ofb.raw b/samples/pbe/java/blowfish-ofb.raw
new file mode 100644
index 0000000..754bf21
--- /dev/null
+++ b/samples/pbe/java/blowfish-ofb.raw
@@ -0,0 +1,2 @@
+Salted__���
+郖0`��]��
\ No newline at end of file
diff --git a/samples/pbe/java/blowfish.base64 b/samples/pbe/java/blowfish.base64
new file mode 100644
index 0000000..a490a9c
--- /dev/null
+++ b/samples/pbe/java/blowfish.base64
@@ -0,0 +1 @@
+U2FsdGVkX18wu3hD9dgyO87j8nRXmczPqDItEunKLUQ=
diff --git a/samples/pbe/java/blowfish.raw b/samples/pbe/java/blowfish.raw
new file mode 100644
index 0000000..fe880fe
--- /dev/null
+++ b/samples/pbe/java/blowfish.raw
@@ -0,0 +1 @@
+Salted__�E�
�rW1��އ�#�R�@�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-128-cbc.base64 b/samples/pbe/java/camellia-128-cbc.base64
new file mode 100644
index 0000000..8985e91
--- /dev/null
+++ b/samples/pbe/java/camellia-128-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX18UUwHvDEACb8VSquyKXfA9Ht7vMiGa/Sc=
diff --git a/samples/pbe/java/camellia-128-cbc.raw b/samples/pbe/java/camellia-128-cbc.raw
new file mode 100644
index 0000000..7f72b0a
--- /dev/null
+++ b/samples/pbe/java/camellia-128-cbc.raw
@@ -0,0 +1 @@
+Salted__�fF�kP{vJ �Bݐ1���|=�͑
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-128-cfb.base64 b/samples/pbe/java/camellia-128-cfb.base64
new file mode 100644
index 0000000..0a86dab
--- /dev/null
+++ b/samples/pbe/java/camellia-128-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/Q+yrw31FhRJYcii+47v+ekN09bg==
diff --git a/samples/pbe/java/camellia-128-cfb.raw b/samples/pbe/java/camellia-128-cfb.raw
new file mode 100644
index 0000000..f574d0f
Binary files /dev/null and b/samples/pbe/java/camellia-128-cfb.raw differ
diff --git a/samples/pbe/java/camellia-128-cfb8.base64 b/samples/pbe/java/camellia-128-cfb8.base64
new file mode 100644
index 0000000..b259ca7
--- /dev/null
+++ b/samples/pbe/java/camellia-128-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18/hQSHjwmpABUe/TaPQPR3gockqw==
diff --git a/samples/pbe/java/camellia-128-cfb8.raw b/samples/pbe/java/camellia-128-cfb8.raw
new file mode 100644
index 0000000..e0f16ea
--- /dev/null
+++ b/samples/pbe/java/camellia-128-cfb8.raw
@@ -0,0 +1 @@
+Salted__'1&{��v/U�$�N���
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-128-ecb.base64 b/samples/pbe/java/camellia-128-ecb.base64
new file mode 100644
index 0000000..be0e863
--- /dev/null
+++ b/samples/pbe/java/camellia-128-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19NFzHbs8FHT8Cv99Xgj1ZhPx5CY072tZA=
diff --git a/samples/pbe/java/camellia-128-ecb.raw b/samples/pbe/java/camellia-128-ecb.raw
new file mode 100644
index 0000000..adfafc5
--- /dev/null
+++ b/samples/pbe/java/camellia-128-ecb.raw
@@ -0,0 +1 @@
+Salted__����1�f0`8F��U
+PeE �#
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-128-ofb.base64 b/samples/pbe/java/camellia-128-ofb.base64
new file mode 100644
index 0000000..4c35120
--- /dev/null
+++ b/samples/pbe/java/camellia-128-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18Q5WKPCdvjapTYHjJhZQQuPBrkcA==
diff --git a/samples/pbe/java/camellia-128-ofb.raw b/samples/pbe/java/camellia-128-ofb.raw
new file mode 100644
index 0000000..529bc7d
--- /dev/null
+++ b/samples/pbe/java/camellia-128-ofb.raw
@@ -0,0 +1 @@
+Salted__#�A��=��ɷɭ.
�g��(
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-128.base64 b/samples/pbe/java/camellia-128.base64
new file mode 100644
index 0000000..09d8760
--- /dev/null
+++ b/samples/pbe/java/camellia-128.base64
@@ -0,0 +1 @@
+U2FsdGVkX18pM4u/Qtl2csttKUV+nu0wBwTi3joioNA=
diff --git a/samples/pbe/java/camellia-128.raw b/samples/pbe/java/camellia-128.raw
new file mode 100644
index 0000000..a9c64ac
--- /dev/null
+++ b/samples/pbe/java/camellia-128.raw
@@ -0,0 +1 @@
+Salted__e{yə;_f`c�5
3 E�q|�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-192-cbc.base64 b/samples/pbe/java/camellia-192-cbc.base64
new file mode 100644
index 0000000..4fab5d0
--- /dev/null
+++ b/samples/pbe/java/camellia-192-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19hH0OOcN4S/DJcOixmApLIQKyU1wgtpOQ=
diff --git a/samples/pbe/java/camellia-192-cbc.raw b/samples/pbe/java/camellia-192-cbc.raw
new file mode 100644
index 0000000..ac75809
--- /dev/null
+++ b/samples/pbe/java/camellia-192-cbc.raw
@@ -0,0 +1 @@
+Salted__�A�IY��v�-3��d����
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-192-cfb.base64 b/samples/pbe/java/camellia-192-cfb.base64
new file mode 100644
index 0000000..e3dee68
--- /dev/null
+++ b/samples/pbe/java/camellia-192-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+4PAXIOayucO/VkxrUWXLbch6StA==
diff --git a/samples/pbe/java/camellia-192-cfb.raw b/samples/pbe/java/camellia-192-cfb.raw
new file mode 100644
index 0000000..6a6c380
--- /dev/null
+++ b/samples/pbe/java/camellia-192-cfb.raw
@@ -0,0 +1,2 @@
+Salted__��
�)
D
+��f�SB�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-192-cfb8.base64 b/samples/pbe/java/camellia-192-cfb8.base64
new file mode 100644
index 0000000..625f35e
--- /dev/null
+++ b/samples/pbe/java/camellia-192-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+5lUexVeB0SO+iMPa6ZwZk66DKag==
diff --git a/samples/pbe/java/camellia-192-cfb8.raw b/samples/pbe/java/camellia-192-cfb8.raw
new file mode 100644
index 0000000..e8ecfa6
--- /dev/null
+++ b/samples/pbe/java/camellia-192-cfb8.raw
@@ -0,0 +1 @@
+Salted__�y�
6NӜ:!dVH
��
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-192-ecb.base64 b/samples/pbe/java/camellia-192-ecb.base64
new file mode 100644
index 0000000..97f32b5
--- /dev/null
+++ b/samples/pbe/java/camellia-192-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/fOdsaCQa26731P7m0VWbMA5c3Lhs3CjU=
diff --git a/samples/pbe/java/camellia-192-ecb.raw b/samples/pbe/java/camellia-192-ecb.raw
new file mode 100644
index 0000000..ebc6b97
--- /dev/null
+++ b/samples/pbe/java/camellia-192-ecb.raw
@@ -0,0 +1 @@
+Salted__�U��s{&^�s<��{4Z�Zr�b
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-192-ofb.base64 b/samples/pbe/java/camellia-192-ofb.base64
new file mode 100644
index 0000000..5959fa1
--- /dev/null
+++ b/samples/pbe/java/camellia-192-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+atqsl2Yfj4LlRabl6AlyTOUhm5Q==
diff --git a/samples/pbe/java/camellia-192-ofb.raw b/samples/pbe/java/camellia-192-ofb.raw
new file mode 100644
index 0000000..2a23190
--- /dev/null
+++ b/samples/pbe/java/camellia-192-ofb.raw
@@ -0,0 +1 @@
+Salted__�Ez@����{H�~͍���
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-192.base64 b/samples/pbe/java/camellia-192.base64
new file mode 100644
index 0000000..f3beeb2
--- /dev/null
+++ b/samples/pbe/java/camellia-192.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/XopevJykDpkmcOdCQ0WjGxvSOKCvrheI=
diff --git a/samples/pbe/java/camellia-192.raw b/samples/pbe/java/camellia-192.raw
new file mode 100644
index 0000000..0044d7f
--- /dev/null
+++ b/samples/pbe/java/camellia-192.raw
@@ -0,0 +1 @@
+Salted__OJ�)
O��z�1n��%Z�G�g
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-256-cbc.base64 b/samples/pbe/java/camellia-256-cbc.base64
new file mode 100644
index 0000000..0765452
--- /dev/null
+++ b/samples/pbe/java/camellia-256-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX192V/ik6+M1vv4ezzXSKP/mrjtXi1XFaFM=
diff --git a/samples/pbe/java/camellia-256-cbc.raw b/samples/pbe/java/camellia-256-cbc.raw
new file mode 100644
index 0000000..eaf4c12
--- /dev/null
+++ b/samples/pbe/java/camellia-256-cbc.raw
@@ -0,0 +1 @@
+Salted__�!�+���ܼn'>�x��T3���H�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-256-cfb.base64 b/samples/pbe/java/camellia-256-cfb.base64
new file mode 100644
index 0000000..5cb9834
--- /dev/null
+++ b/samples/pbe/java/camellia-256-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18uQkCC3dp9kV1C1HcQ+iR7DNDkNQ==
diff --git a/samples/pbe/java/camellia-256-cfb.raw b/samples/pbe/java/camellia-256-cfb.raw
new file mode 100644
index 0000000..19415b5
--- /dev/null
+++ b/samples/pbe/java/camellia-256-cfb.raw
@@ -0,0 +1 @@
+Salted___���\��{I����/Ɖ
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-256-cfb8.base64 b/samples/pbe/java/camellia-256-cfb8.base64
new file mode 100644
index 0000000..e9b247f
--- /dev/null
+++ b/samples/pbe/java/camellia-256-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/AjinqENb4F5Qz5UoLF4euYSUXtg==
diff --git a/samples/pbe/java/camellia-256-cfb8.raw b/samples/pbe/java/camellia-256-cfb8.raw
new file mode 100644
index 0000000..696b584
--- /dev/null
+++ b/samples/pbe/java/camellia-256-cfb8.raw
@@ -0,0 +1 @@
+Salted__I?k�x}�̀��Y��2��G
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-256-ecb.base64 b/samples/pbe/java/camellia-256-ecb.base64
new file mode 100644
index 0000000..fa856d9
--- /dev/null
+++ b/samples/pbe/java/camellia-256-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+LDceo9kKIBEFjQgELUkN7Kub52saETYE=
diff --git a/samples/pbe/java/camellia-256-ecb.raw b/samples/pbe/java/camellia-256-ecb.raw
new file mode 100644
index 0000000..ffbd183
--- /dev/null
+++ b/samples/pbe/java/camellia-256-ecb.raw
@@ -0,0 +1 @@
+Salted__<���aUA<�6��V�<��B
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-256-ofb.base64 b/samples/pbe/java/camellia-256-ofb.base64
new file mode 100644
index 0000000..919b311
--- /dev/null
+++ b/samples/pbe/java/camellia-256-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+GkVrOLtvxbkF+hFDSsmAp6IIi/g==
diff --git a/samples/pbe/java/camellia-256-ofb.raw b/samples/pbe/java/camellia-256-ofb.raw
new file mode 100644
index 0000000..1102772
--- /dev/null
+++ b/samples/pbe/java/camellia-256-ofb.raw
@@ -0,0 +1 @@
+Salted__����5Y��Je��,�w�$
\ No newline at end of file
diff --git a/samples/pbe/java/camellia-256.base64 b/samples/pbe/java/camellia-256.base64
new file mode 100644
index 0000000..918ac17
--- /dev/null
+++ b/samples/pbe/java/camellia-256.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/j884tRPxO0F0El64xyT3n+W83Wb9Z9nc=
diff --git a/samples/pbe/java/camellia-256.raw b/samples/pbe/java/camellia-256.raw
new file mode 100644
index 0000000..50d7b8a
--- /dev/null
+++ b/samples/pbe/java/camellia-256.raw
@@ -0,0 +1 @@
+Salted__cvls6S��\�<{
��.�Wv, ��
\ No newline at end of file
diff --git a/samples/pbe/java/camellia128-cbc.base64 b/samples/pbe/java/camellia128-cbc.base64
new file mode 100644
index 0000000..2a964ad
--- /dev/null
+++ b/samples/pbe/java/camellia128-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+90QGejW9gW74l1S1eCmxQTa83xaYf5cg=
diff --git a/samples/pbe/java/camellia128-cbc.raw b/samples/pbe/java/camellia128-cbc.raw
new file mode 100644
index 0000000..428af0c
--- /dev/null
+++ b/samples/pbe/java/camellia128-cbc.raw
@@ -0,0 +1 @@
+Salted__wT�ػ��-zp��R�;^�P��õT
\ No newline at end of file
diff --git a/samples/pbe/java/camellia128-cfb.base64 b/samples/pbe/java/camellia128-cfb.base64
new file mode 100644
index 0000000..07fc3cd
--- /dev/null
+++ b/samples/pbe/java/camellia128-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18OWnOuxyR4YO6FGRH/7yqDm3CmLQ==
diff --git a/samples/pbe/java/camellia128-cfb.raw b/samples/pbe/java/camellia128-cfb.raw
new file mode 100644
index 0000000..c3f0470
--- /dev/null
+++ b/samples/pbe/java/camellia128-cfb.raw
@@ -0,0 +1 @@
+Salted__
睍_T�K�/^a�{�CՕ�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia128-cfb8.base64 b/samples/pbe/java/camellia128-cfb8.base64
new file mode 100644
index 0000000..8362065
--- /dev/null
+++ b/samples/pbe/java/camellia128-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18DU/8DbLesx+kp1xFyVzbL0oOGGw==
diff --git a/samples/pbe/java/camellia128-cfb8.raw b/samples/pbe/java/camellia128-cfb8.raw
new file mode 100644
index 0000000..1a9483e
--- /dev/null
+++ b/samples/pbe/java/camellia128-cfb8.raw
@@ -0,0 +1 @@
+Salted__{��<����@w���Cc�~T
\ No newline at end of file
diff --git a/samples/pbe/java/camellia128-ecb.base64 b/samples/pbe/java/camellia128-ecb.base64
new file mode 100644
index 0000000..9556b3b
--- /dev/null
+++ b/samples/pbe/java/camellia128-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+1iqH8lq6+SuZgeWxcbUoZ4dBYxTjVQ1I=
diff --git a/samples/pbe/java/camellia128-ecb.raw b/samples/pbe/java/camellia128-ecb.raw
new file mode 100644
index 0000000..fde676e
--- /dev/null
+++ b/samples/pbe/java/camellia128-ecb.raw
@@ -0,0 +1 @@
+Salted__j�q/3��i��l1!���\5
d�`�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia128-ofb.base64 b/samples/pbe/java/camellia128-ofb.base64
new file mode 100644
index 0000000..89f0255
--- /dev/null
+++ b/samples/pbe/java/camellia128-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX189RpQrEO2Xy/3zDHr7Or6Tg0c/AQ==
diff --git a/samples/pbe/java/camellia128-ofb.raw b/samples/pbe/java/camellia128-ofb.raw
new file mode 100644
index 0000000..37caed2
--- /dev/null
+++ b/samples/pbe/java/camellia128-ofb.raw
@@ -0,0 +1 @@
+Salted__
kr���^�����2f��D
\ No newline at end of file
diff --git a/samples/pbe/java/camellia128.base64 b/samples/pbe/java/camellia128.base64
new file mode 100644
index 0000000..66c6feb
--- /dev/null
+++ b/samples/pbe/java/camellia128.base64
@@ -0,0 +1 @@
+U2FsdGVkX19fNMlxVQ+gfD1AF55ct5dna+5gIcFnHMI=
diff --git a/samples/pbe/java/camellia128.raw b/samples/pbe/java/camellia128.raw
new file mode 100644
index 0000000..e6f4e0a
--- /dev/null
+++ b/samples/pbe/java/camellia128.raw
@@ -0,0 +1 @@
+Salted__?A���//��YE�WA���C�V
\ No newline at end of file
diff --git a/samples/pbe/java/camellia192-cbc.base64 b/samples/pbe/java/camellia192-cbc.base64
new file mode 100644
index 0000000..41f445b
--- /dev/null
+++ b/samples/pbe/java/camellia192-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/bDUbd0pqAOeDb1gNIpKqi3DK4iwO7YoA=
diff --git a/samples/pbe/java/camellia192-cbc.raw b/samples/pbe/java/camellia192-cbc.raw
new file mode 100644
index 0000000..29212ab
--- /dev/null
+++ b/samples/pbe/java/camellia192-cbc.raw
@@ -0,0 +1 @@
+Salted__+2!�ԭ�G
I)Ѿ��[�oRZ�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia192-cfb.base64 b/samples/pbe/java/camellia192-cfb.base64
new file mode 100644
index 0000000..615f4b3
--- /dev/null
+++ b/samples/pbe/java/camellia192-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/jPapheHbcuHbq060VPb/lVaN60Q==
diff --git a/samples/pbe/java/camellia192-cfb.raw b/samples/pbe/java/camellia192-cfb.raw
new file mode 100644
index 0000000..bba9f78
--- /dev/null
+++ b/samples/pbe/java/camellia192-cfb.raw
@@ -0,0 +1 @@
+Salted__�̱�*oV��&`����t�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia192-cfb8.base64 b/samples/pbe/java/camellia192-cfb8.base64
new file mode 100644
index 0000000..7c5829d
--- /dev/null
+++ b/samples/pbe/java/camellia192-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/L73xES8AWci9th/emGwI9bSXU0A==
diff --git a/samples/pbe/java/camellia192-cfb8.raw b/samples/pbe/java/camellia192-cfb8.raw
new file mode 100644
index 0000000..dd34c2d
--- /dev/null
+++ b/samples/pbe/java/camellia192-cfb8.raw
@@ -0,0 +1 @@
+Salted__���h"��..�����.v?�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia192-ecb.base64 b/samples/pbe/java/camellia192-ecb.base64
new file mode 100644
index 0000000..0313532
--- /dev/null
+++ b/samples/pbe/java/camellia192-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+THzBGYxZA+1R9rza4Lv9SrWl/sPmmkso=
diff --git a/samples/pbe/java/camellia192-ecb.raw b/samples/pbe/java/camellia192-ecb.raw
new file mode 100644
index 0000000..76ffb51
--- /dev/null
+++ b/samples/pbe/java/camellia192-ecb.raw
@@ -0,0 +1 @@
+Salted__VX$����H(g����FO
yE�ā
\ No newline at end of file
diff --git a/samples/pbe/java/camellia192-ofb.base64 b/samples/pbe/java/camellia192-ofb.base64
new file mode 100644
index 0000000..f0a66bf
--- /dev/null
+++ b/samples/pbe/java/camellia192-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+fbFYKjBd8c3PMWewNTe+qTHYxjw==
diff --git a/samples/pbe/java/camellia192-ofb.raw b/samples/pbe/java/camellia192-ofb.raw
new file mode 100644
index 0000000..a9806c8
--- /dev/null
+++ b/samples/pbe/java/camellia192-ofb.raw
@@ -0,0 +1 @@
+Salted__�t��%T�PK||ACi�º�=
\ No newline at end of file
diff --git a/samples/pbe/java/camellia192.base64 b/samples/pbe/java/camellia192.base64
new file mode 100644
index 0000000..3adc735
--- /dev/null
+++ b/samples/pbe/java/camellia192.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/7J6aNaQ3OKgOvbscFo5no/fy72MJk5Fc=
diff --git a/samples/pbe/java/camellia192.raw b/samples/pbe/java/camellia192.raw
new file mode 100644
index 0000000..4546f6d
--- /dev/null
+++ b/samples/pbe/java/camellia192.raw
@@ -0,0 +1 @@
+Salted__�opD�ƌ�u)۷�c�0d���T
\ No newline at end of file
diff --git a/samples/pbe/java/camellia256-cbc.base64 b/samples/pbe/java/camellia256-cbc.base64
new file mode 100644
index 0000000..20369ea
--- /dev/null
+++ b/samples/pbe/java/camellia256-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+l901jK4fyHQe8zTyOALNfuKuDLDNjNpI=
diff --git a/samples/pbe/java/camellia256-cbc.raw b/samples/pbe/java/camellia256-cbc.raw
new file mode 100644
index 0000000..4d58a2f
--- /dev/null
+++ b/samples/pbe/java/camellia256-cbc.raw
@@ -0,0 +1 @@
+Salted__�.�F'��
�
R.oRe ���#p�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia256-cfb.base64 b/samples/pbe/java/camellia256-cfb.base64
new file mode 100644
index 0000000..aeed858
--- /dev/null
+++ b/samples/pbe/java/camellia256-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX197NNyKW2xVNRjtMbyMbMKc89L68w==
diff --git a/samples/pbe/java/camellia256-cfb.raw b/samples/pbe/java/camellia256-cfb.raw
new file mode 100644
index 0000000..3678157
--- /dev/null
+++ b/samples/pbe/java/camellia256-cfb.raw
@@ -0,0 +1 @@
+Salted__g�gA�Z��h�Q�<>7��
\ No newline at end of file
diff --git a/samples/pbe/java/camellia256-cfb8.base64 b/samples/pbe/java/camellia256-cfb8.base64
new file mode 100644
index 0000000..cedb3d3
--- /dev/null
+++ b/samples/pbe/java/camellia256-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/zIoOUOwApRSAN5J0Sr/j+Swe5nw==
diff --git a/samples/pbe/java/camellia256-cfb8.raw b/samples/pbe/java/camellia256-cfb8.raw
new file mode 100644
index 0000000..688f31e
--- /dev/null
+++ b/samples/pbe/java/camellia256-cfb8.raw
@@ -0,0 +1 @@
+Salted__(�]��ò~i�����,�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia256-ecb.base64 b/samples/pbe/java/camellia256-ecb.base64
new file mode 100644
index 0000000..c8bd5c5
--- /dev/null
+++ b/samples/pbe/java/camellia256-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19Tln+csf9eJsEYdZC45soI+sOC4dMfd4c=
diff --git a/samples/pbe/java/camellia256-ecb.raw b/samples/pbe/java/camellia256-ecb.raw
new file mode 100644
index 0000000..27cf65b
--- /dev/null
+++ b/samples/pbe/java/camellia256-ecb.raw
@@ -0,0 +1 @@
+Salted__�0.�0'/������K�d!qX�MP�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia256-ofb.base64 b/samples/pbe/java/camellia256-ofb.base64
new file mode 100644
index 0000000..593bd2b
--- /dev/null
+++ b/samples/pbe/java/camellia256-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1896Yqjj8AfXnc0eFYKai5KxoCXzQ==
diff --git a/samples/pbe/java/camellia256-ofb.raw b/samples/pbe/java/camellia256-ofb.raw
new file mode 100644
index 0000000..d49ef81
--- /dev/null
+++ b/samples/pbe/java/camellia256-ofb.raw
@@ -0,0 +1 @@
+Salted__���U�Ԟ��*+C�g2�Tl�
\ No newline at end of file
diff --git a/samples/pbe/java/camellia256.base64 b/samples/pbe/java/camellia256.base64
new file mode 100644
index 0000000..990ca5c
--- /dev/null
+++ b/samples/pbe/java/camellia256.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+oGF8zlK3aSF//rgeWimAvobywbD+PD0g=
diff --git a/samples/pbe/java/camellia256.raw b/samples/pbe/java/camellia256.raw
new file mode 100644
index 0000000..83f0ac5
--- /dev/null
+++ b/samples/pbe/java/camellia256.raw
@@ -0,0 +1 @@
+Salted__x���
�i������.� ��A
\ No newline at end of file
diff --git a/samples/pbe/java/cast5-cbc.base64 b/samples/pbe/java/cast5-cbc.base64
new file mode 100644
index 0000000..3a217bc
--- /dev/null
+++ b/samples/pbe/java/cast5-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/aeco/gkhE72hth3Mn74hFGnCdFZfi3Q4=
diff --git a/samples/pbe/java/cast5-cbc.raw b/samples/pbe/java/cast5-cbc.raw
new file mode 100644
index 0000000..429fb3a
--- /dev/null
+++ b/samples/pbe/java/cast5-cbc.raw
@@ -0,0 +1 @@
+Salted__���%�cQL�
�O�Ŋ7�6�F*C
\ No newline at end of file
diff --git a/samples/pbe/java/cast5-cfb.base64 b/samples/pbe/java/cast5-cfb.base64
new file mode 100644
index 0000000..cc97783
--- /dev/null
+++ b/samples/pbe/java/cast5-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+EbjjSoQ/tSg0b+dJNWWAkSFlARQ==
diff --git a/samples/pbe/java/cast5-cfb.raw b/samples/pbe/java/cast5-cfb.raw
new file mode 100644
index 0000000..ae2cbbb
--- /dev/null
+++ b/samples/pbe/java/cast5-cfb.raw
@@ -0,0 +1 @@
+Salted__��ˉ
z�B�x%
��j
\ No newline at end of file
diff --git a/samples/pbe/java/cast5-cfb8.base64 b/samples/pbe/java/cast5-cfb8.base64
new file mode 100644
index 0000000..fc3803e
--- /dev/null
+++ b/samples/pbe/java/cast5-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18+YZ72SS+beeJ0eEqzEUWLKoBz+g==
diff --git a/samples/pbe/java/cast5-cfb8.raw b/samples/pbe/java/cast5-cfb8.raw
new file mode 100644
index 0000000..f24154d
--- /dev/null
+++ b/samples/pbe/java/cast5-cfb8.raw
@@ -0,0 +1 @@
+Salted__$/��+1
������3�>�
\ No newline at end of file
diff --git a/samples/pbe/java/cast5-ecb.base64 b/samples/pbe/java/cast5-ecb.base64
new file mode 100644
index 0000000..448937a
--- /dev/null
+++ b/samples/pbe/java/cast5-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1++7eyxWebJMaj41x5xlLEDODwl+wrhRaI=
diff --git a/samples/pbe/java/cast5-ecb.raw b/samples/pbe/java/cast5-ecb.raw
new file mode 100644
index 0000000..a94ff03
--- /dev/null
+++ b/samples/pbe/java/cast5-ecb.raw
@@ -0,0 +1 @@
+Salted__�
.�ݷG"���{�d
8غ*v
\ No newline at end of file
diff --git a/samples/pbe/java/cast5-ofb.base64 b/samples/pbe/java/cast5-ofb.base64
new file mode 100644
index 0000000..22dddf4
--- /dev/null
+++ b/samples/pbe/java/cast5-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19hCVMpUfZQxakwK4dFKSTQuguAUw==
diff --git a/samples/pbe/java/cast5-ofb.raw b/samples/pbe/java/cast5-ofb.raw
new file mode 100644
index 0000000..e20f9fe
--- /dev/null
+++ b/samples/pbe/java/cast5-ofb.raw
@@ -0,0 +1 @@
+Salted__��cr�f��aO^��q�.�
\ No newline at end of file
diff --git a/samples/pbe/java/cast5.base64 b/samples/pbe/java/cast5.base64
new file mode 100644
index 0000000..44daae6
--- /dev/null
+++ b/samples/pbe/java/cast5.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+ezI1ZQcPD4e1zE7jkWZlGFmScgZFucHY=
diff --git a/samples/pbe/java/cast5.raw b/samples/pbe/java/cast5.raw
new file mode 100644
index 0000000..dfbaaff
--- /dev/null
+++ b/samples/pbe/java/cast5.raw
@@ -0,0 +1,2 @@
+Salted__
+;�yl�����WI��^���˯�Y
\ No newline at end of file
diff --git a/samples/pbe/java/cast6-cbc.base64 b/samples/pbe/java/cast6-cbc.base64
new file mode 100644
index 0000000..3608069
--- /dev/null
+++ b/samples/pbe/java/cast6-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/a8L9HYZcz3S1WhQ3o0R0ebahweJnv+IU=
diff --git a/samples/pbe/java/cast6-cbc.raw b/samples/pbe/java/cast6-cbc.raw
new file mode 100644
index 0000000..6bf7b34
--- /dev/null
+++ b/samples/pbe/java/cast6-cbc.raw
@@ -0,0 +1 @@
+Salted__��Nۥ�뼫��Ԓ�;z!"��
P}
\ No newline at end of file
diff --git a/samples/pbe/java/cast6-cfb.base64 b/samples/pbe/java/cast6-cfb.base64
new file mode 100644
index 0000000..adcf160
--- /dev/null
+++ b/samples/pbe/java/cast6-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+YfAvrxD0wSn/fpojGN9tJkg9DgA==
diff --git a/samples/pbe/java/cast6-cfb.raw b/samples/pbe/java/cast6-cfb.raw
new file mode 100644
index 0000000..8846469
--- /dev/null
+++ b/samples/pbe/java/cast6-cfb.raw
@@ -0,0 +1 @@
+Salted__���v91�^@7xRw�)R���
\ No newline at end of file
diff --git a/samples/pbe/java/cast6-cfb8.base64 b/samples/pbe/java/cast6-cfb8.base64
new file mode 100644
index 0000000..11bfab4
--- /dev/null
+++ b/samples/pbe/java/cast6-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+LpuG379U9ZMFOh0FUkcWovxPSqA==
diff --git a/samples/pbe/java/cast6-cfb8.raw b/samples/pbe/java/cast6-cfb8.raw
new file mode 100644
index 0000000..0522ed0
--- /dev/null
+++ b/samples/pbe/java/cast6-cfb8.raw
@@ -0,0 +1 @@
+Salted__�1�Ku�SvZo��Hvl
\ No newline at end of file
diff --git a/samples/pbe/java/cast6-ecb.base64 b/samples/pbe/java/cast6-ecb.base64
new file mode 100644
index 0000000..603266d
--- /dev/null
+++ b/samples/pbe/java/cast6-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX192UiTkDb8gI6sTTfy7VGsbT30KNWOT02M=
diff --git a/samples/pbe/java/cast6-ecb.raw b/samples/pbe/java/cast6-ecb.raw
new file mode 100644
index 0000000..44148b7
--- /dev/null
+++ b/samples/pbe/java/cast6-ecb.raw
@@ -0,0 +1 @@
+Salted__g0�@|��
��U��8Y�(j/�
\ No newline at end of file
diff --git a/samples/pbe/java/cast6-ofb.base64 b/samples/pbe/java/cast6-ofb.base64
new file mode 100644
index 0000000..08722f1
--- /dev/null
+++ b/samples/pbe/java/cast6-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18Y0QSZwFfDFhEAflkjtX4PXaaifQ==
diff --git a/samples/pbe/java/cast6-ofb.raw b/samples/pbe/java/cast6-ofb.raw
new file mode 100644
index 0000000..42ce837
--- /dev/null
+++ b/samples/pbe/java/cast6-ofb.raw
@@ -0,0 +1 @@
+Salted__]�!�ɽ��L��,_�h�
\ No newline at end of file
diff --git a/samples/pbe/java/cast6.base64 b/samples/pbe/java/cast6.base64
new file mode 100644
index 0000000..cee1c7a
--- /dev/null
+++ b/samples/pbe/java/cast6.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+QGJCVEnV4Fw5TlflsQhmEM67/RwhUcLY=
diff --git a/samples/pbe/java/cast6.raw b/samples/pbe/java/cast6.raw
new file mode 100644
index 0000000..b4c8ce3
--- /dev/null
+++ b/samples/pbe/java/cast6.raw
@@ -0,0 +1 @@
+Salted__��*�P}C�������b�.B�/�
\ No newline at end of file
diff --git a/samples/pbe/java/des-cbc.base64 b/samples/pbe/java/des-cbc.base64
new file mode 100644
index 0000000..69c2e01
--- /dev/null
+++ b/samples/pbe/java/des-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+qcAmoytN0qF45xG/KHt6ANo7zZXDN4L4=
diff --git a/samples/pbe/java/des-cbc.raw b/samples/pbe/java/des-cbc.raw
new file mode 100644
index 0000000..941dbdd
--- /dev/null
+++ b/samples/pbe/java/des-cbc.raw
@@ -0,0 +1 @@
+Salted__Bg�e�g�uنヌ�y
�Q��"
\ No newline at end of file
diff --git a/samples/pbe/java/des-cfb.base64 b/samples/pbe/java/des-cfb.base64
new file mode 100644
index 0000000..8da3e5c
--- /dev/null
+++ b/samples/pbe/java/des-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+f4Sv6TZeWD5LH6tNPJJgMk4LuRQ==
diff --git a/samples/pbe/java/des-cfb.raw b/samples/pbe/java/des-cfb.raw
new file mode 100644
index 0000000..b11801f
--- /dev/null
+++ b/samples/pbe/java/des-cfb.raw
@@ -0,0 +1 @@
+Salted__��
�Bj�fz O���zl�R�
\ No newline at end of file
diff --git a/samples/pbe/java/des-cfb8.base64 b/samples/pbe/java/des-cfb8.base64
new file mode 100644
index 0000000..bd26500
--- /dev/null
+++ b/samples/pbe/java/des-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18oeqMoo7b5vmE3Z5rV+qaIXfMqPg==
diff --git a/samples/pbe/java/des-cfb8.raw b/samples/pbe/java/des-cfb8.raw
new file mode 100644
index 0000000..4735615
--- /dev/null
+++ b/samples/pbe/java/des-cfb8.raw
@@ -0,0 +1 @@
+Salted__R�xBk+ɏ�� �YR�5��
\ No newline at end of file
diff --git a/samples/pbe/java/des-ecb.base64 b/samples/pbe/java/des-ecb.base64
new file mode 100644
index 0000000..6f88f13
--- /dev/null
+++ b/samples/pbe/java/des-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+pxNg2EC2+QBrrWM5OKERPVnMbHzxo1RE=
diff --git a/samples/pbe/java/des-ecb.raw b/samples/pbe/java/des-ecb.raw
new file mode 100644
index 0000000..ccfe47e
--- /dev/null
+++ b/samples/pbe/java/des-ecb.raw
@@ -0,0 +1 @@
+Salted__��r���5��C�n�3�"y*]h
\ No newline at end of file
diff --git a/samples/pbe/java/des-ede-cbc.base64 b/samples/pbe/java/des-ede-cbc.base64
new file mode 100644
index 0000000..58f7b77
--- /dev/null
+++ b/samples/pbe/java/des-ede-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/y6JQizURIjWY6ofYIXeNloyn5rmiqFTs=
diff --git a/samples/pbe/java/des-ede-cbc.raw b/samples/pbe/java/des-ede-cbc.raw
new file mode 100644
index 0000000..e410264
--- /dev/null
+++ b/samples/pbe/java/des-ede-cbc.raw
@@ -0,0 +1 @@
+Salted__ޞjcg�P��j�Cipk���eJ��
Y
\ No newline at end of file
diff --git a/samples/pbe/java/des-ede-cfb.base64 b/samples/pbe/java/des-ede-cfb.base64
new file mode 100644
index 0000000..5fc132f
--- /dev/null
+++ b/samples/pbe/java/des-ede-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19f4EqhjsuGrFvzsLFuUFAF7Bcr4Q==
diff --git a/samples/pbe/java/des-ede-cfb.raw b/samples/pbe/java/des-ede-cfb.raw
new file mode 100644
index 0000000..2489621
Binary files /dev/null and b/samples/pbe/java/des-ede-cfb.raw differ
diff --git a/samples/pbe/java/des-ede-cfb8.base64 b/samples/pbe/java/des-ede-cfb8.base64
new file mode 100644
index 0000000..5e8deb6
--- /dev/null
+++ b/samples/pbe/java/des-ede-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/VT6B35AlNLqWnVLQ9idrEG9x1eA==
diff --git a/samples/pbe/java/des-ede-cfb8.raw b/samples/pbe/java/des-ede-cfb8.raw
new file mode 100644
index 0000000..7398675
--- /dev/null
+++ b/samples/pbe/java/des-ede-cfb8.raw
@@ -0,0 +1 @@
+Salted__.w�{�SX��{j���M(�d�
\ No newline at end of file
diff --git a/samples/pbe/java/des-ede-ecb.base64 b/samples/pbe/java/des-ede-ecb.base64
new file mode 100644
index 0000000..0033fee
--- /dev/null
+++ b/samples/pbe/java/des-ede-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+Vfd7fjmNvFt3xWsYqPqTanguapFpJA+g=
diff --git a/samples/pbe/java/des-ede-ecb.raw b/samples/pbe/java/des-ede-ecb.raw
new file mode 100644
index 0000000..d99acfb
--- /dev/null
+++ b/samples/pbe/java/des-ede-ecb.raw
@@ -0,0 +1 @@
+Salted__��%�`�����a:�H��)
\ No newline at end of file
diff --git a/samples/pbe/java/des-ede-ofb.base64 b/samples/pbe/java/des-ede-ofb.base64
new file mode 100644
index 0000000..50a8747
--- /dev/null
+++ b/samples/pbe/java/des-ede-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19ZQ1NUWofkQ1zmOoujP13zEGJvJw==
diff --git a/samples/pbe/java/des-ede-ofb.raw b/samples/pbe/java/des-ede-ofb.raw
new file mode 100644
index 0000000..9c7e058
--- /dev/null
+++ b/samples/pbe/java/des-ede-ofb.raw
@@ -0,0 +1 @@
+Salted__�t%�
���d��1���d���
\ No newline at end of file
diff --git a/samples/pbe/java/des-ede.base64 b/samples/pbe/java/des-ede.base64
new file mode 100644
index 0000000..f404eaa
--- /dev/null
+++ b/samples/pbe/java/des-ede.base64
@@ -0,0 +1 @@
+U2FsdGVkX19E2uLiiey3EfQKaOsj6LBxjGMvHXxlpWY=
diff --git a/samples/pbe/java/des-ede.raw b/samples/pbe/java/des-ede.raw
new file mode 100644
index 0000000..623a797
Binary files /dev/null and b/samples/pbe/java/des-ede.raw differ
diff --git a/samples/pbe/java/des-ede3-cbc.base64 b/samples/pbe/java/des-ede3-cbc.base64
new file mode 100644
index 0000000..5dab2c3
--- /dev/null
+++ b/samples/pbe/java/des-ede3-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/O0qdSWL/hUKtdgqExwqh+KXFQet9g8BI=
diff --git a/samples/pbe/java/des-ede3-cbc.raw b/samples/pbe/java/des-ede3-cbc.raw
new file mode 100644
index 0000000..185f518
--- /dev/null
+++ b/samples/pbe/java/des-ede3-cbc.raw
@@ -0,0 +1 @@
+Salted__��q��D�Y# �
w���$ٝ�T�y
\ No newline at end of file
diff --git a/samples/pbe/java/des-ede3-cfb.base64 b/samples/pbe/java/des-ede3-cfb.base64
new file mode 100644
index 0000000..05e05e3
--- /dev/null
+++ b/samples/pbe/java/des-ede3-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19BwdOPwBsmzE/cH0yaVKBZhS/Icg==
diff --git a/samples/pbe/java/des-ede3-cfb.raw b/samples/pbe/java/des-ede3-cfb.raw
new file mode 100644
index 0000000..0df9165
--- /dev/null
+++ b/samples/pbe/java/des-ede3-cfb.raw
@@ -0,0 +1 @@
+Salted__�61�T&{�`ӭa
:�
\ No newline at end of file
diff --git a/samples/pbe/java/des-ede3-cfb8.base64 b/samples/pbe/java/des-ede3-cfb8.base64
new file mode 100644
index 0000000..f6e8818
--- /dev/null
+++ b/samples/pbe/java/des-ede3-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18dDuhVBwLJsMxfDYa/MTjTruLYQg==
diff --git a/samples/pbe/java/des-ede3-cfb8.raw b/samples/pbe/java/des-ede3-cfb8.raw
new file mode 100644
index 0000000..21e3b70
--- /dev/null
+++ b/samples/pbe/java/des-ede3-cfb8.raw
@@ -0,0 +1 @@
+Salted__��E�S�z�ԑjC�uBW��o
\ No newline at end of file
diff --git a/samples/pbe/java/des-ede3-ecb.base64 b/samples/pbe/java/des-ede3-ecb.base64
new file mode 100644
index 0000000..7e5e36e
--- /dev/null
+++ b/samples/pbe/java/des-ede3-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+WHqIW/MnLOisXHvYhVw3lxReySmIMF+E=
diff --git a/samples/pbe/java/des-ede3-ecb.raw b/samples/pbe/java/des-ede3-ecb.raw
new file mode 100644
index 0000000..b0d3e54
--- /dev/null
+++ b/samples/pbe/java/des-ede3-ecb.raw
@@ -0,0 +1 @@
+Salted__,K���M�PN{�$+����[@&��
\ No newline at end of file
diff --git a/samples/pbe/java/des-ede3-ofb.base64 b/samples/pbe/java/des-ede3-ofb.base64
new file mode 100644
index 0000000..1b70a4d
--- /dev/null
+++ b/samples/pbe/java/des-ede3-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19dgoM0LLrk/zilPkGQ5k1KVeUK2A==
diff --git a/samples/pbe/java/des-ede3-ofb.raw b/samples/pbe/java/des-ede3-ofb.raw
new file mode 100644
index 0000000..e1a45f0
--- /dev/null
+++ b/samples/pbe/java/des-ede3-ofb.raw
@@ -0,0 +1 @@
+Salted__�'o�$�ό{�D��U�3�
\ No newline at end of file
diff --git a/samples/pbe/java/des-ede3.base64 b/samples/pbe/java/des-ede3.base64
new file mode 100644
index 0000000..99dd748
--- /dev/null
+++ b/samples/pbe/java/des-ede3.base64
@@ -0,0 +1 @@
+U2FsdGVkX19yAldtM0VmBsI9Ytjp5QsU6Mzz6K5Cx6k=
diff --git a/samples/pbe/java/des-ede3.raw b/samples/pbe/java/des-ede3.raw
new file mode 100644
index 0000000..53f40c5
Binary files /dev/null and b/samples/pbe/java/des-ede3.raw differ
diff --git a/samples/pbe/java/des-ofb.base64 b/samples/pbe/java/des-ofb.base64
new file mode 100644
index 0000000..828218d
--- /dev/null
+++ b/samples/pbe/java/des-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+XADd70ffqUEeA1VFhMGkpmHOvUA==
diff --git a/samples/pbe/java/des-ofb.raw b/samples/pbe/java/des-ofb.raw
new file mode 100644
index 0000000..abff396
--- /dev/null
+++ b/samples/pbe/java/des-ofb.raw
@@ -0,0 +1 @@
+Salted__(<�-���e'�
"��j�i��
\ No newline at end of file
diff --git a/samples/pbe/java/des.base64 b/samples/pbe/java/des.base64
new file mode 100644
index 0000000..0e222ab
--- /dev/null
+++ b/samples/pbe/java/des.base64
@@ -0,0 +1 @@
+U2FsdGVkX18lyzI2kQJMPmBsJbfD/qTe1glRDiV+eg8=
diff --git a/samples/pbe/java/des.raw b/samples/pbe/java/des.raw
new file mode 100644
index 0000000..de71e30
--- /dev/null
+++ b/samples/pbe/java/des.raw
@@ -0,0 +1 @@
+Salted__�F��5�9tj
��>3o�M061�
\ No newline at end of file
diff --git a/samples/pbe/java/des2-cbc.base64 b/samples/pbe/java/des2-cbc.base64
new file mode 100644
index 0000000..93206dd
--- /dev/null
+++ b/samples/pbe/java/des2-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19xx1chMmdJ8eFZxjVhq1fhRhtsaysJZK8=
diff --git a/samples/pbe/java/des2-cbc.raw b/samples/pbe/java/des2-cbc.raw
new file mode 100644
index 0000000..b02ab71
--- /dev/null
+++ b/samples/pbe/java/des2-cbc.raw
@@ -0,0 +1 @@
+Salted___����S�"�{b�UD�ߜ�LA
\ No newline at end of file
diff --git a/samples/pbe/java/des2-cfb.base64 b/samples/pbe/java/des2-cfb.base64
new file mode 100644
index 0000000..8ccc633
--- /dev/null
+++ b/samples/pbe/java/des2-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19CzdoZuqHCDLC8y4aOcB27o896yA==
diff --git a/samples/pbe/java/des2-cfb.raw b/samples/pbe/java/des2-cfb.raw
new file mode 100644
index 0000000..2bf1f0f
--- /dev/null
+++ b/samples/pbe/java/des2-cfb.raw
@@ -0,0 +1 @@
+Salted__ 5��&|7F8�f�L��F��
\ No newline at end of file
diff --git a/samples/pbe/java/des2-cfb8.base64 b/samples/pbe/java/des2-cfb8.base64
new file mode 100644
index 0000000..3aa1ec4
--- /dev/null
+++ b/samples/pbe/java/des2-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+1JccDxVEzyR2M1fq0siQ30vISew==
diff --git a/samples/pbe/java/des2-cfb8.raw b/samples/pbe/java/des2-cfb8.raw
new file mode 100644
index 0000000..1f8b413
--- /dev/null
+++ b/samples/pbe/java/des2-cfb8.raw
@@ -0,0 +1 @@
+Salted__0�h}C�F�O�W
=�n�
\ No newline at end of file
diff --git a/samples/pbe/java/des2-ecb.base64 b/samples/pbe/java/des2-ecb.base64
new file mode 100644
index 0000000..f7a2dfe
--- /dev/null
+++ b/samples/pbe/java/des2-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+jiXx0gK6/kNCYTrQp3coct+4/tool1DI=
diff --git a/samples/pbe/java/des2-ecb.raw b/samples/pbe/java/des2-ecb.raw
new file mode 100644
index 0000000..acfb9ad
Binary files /dev/null and b/samples/pbe/java/des2-ecb.raw differ
diff --git a/samples/pbe/java/des2-ofb.base64 b/samples/pbe/java/des2-ofb.base64
new file mode 100644
index 0000000..03ee845
--- /dev/null
+++ b/samples/pbe/java/des2-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19e9Hf5gd5q/jxs4KvuQAFaqdvqDw==
diff --git a/samples/pbe/java/des2-ofb.raw b/samples/pbe/java/des2-ofb.raw
new file mode 100644
index 0000000..23a4da2
--- /dev/null
+++ b/samples/pbe/java/des2-ofb.raw
@@ -0,0 +1 @@
+Salted__��e��Q��g���1
'�s
\ No newline at end of file
diff --git a/samples/pbe/java/des2.base64 b/samples/pbe/java/des2.base64
new file mode 100644
index 0000000..e303ade
--- /dev/null
+++ b/samples/pbe/java/des2.base64
@@ -0,0 +1 @@
+U2FsdGVkX19r7Ho+1z5PhaPFqGv1u9oS5pbEQTcSdSM=
diff --git a/samples/pbe/java/des2.raw b/samples/pbe/java/des2.raw
new file mode 100644
index 0000000..c7b83e7
--- /dev/null
+++ b/samples/pbe/java/des2.raw
@@ -0,0 +1 @@
+Salted__���0���ӶB��ʲ��I�� ;
\ No newline at end of file
diff --git a/samples/pbe/java/des3-cbc.base64 b/samples/pbe/java/des3-cbc.base64
new file mode 100644
index 0000000..213899d
--- /dev/null
+++ b/samples/pbe/java/des3-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX18FEUvYvCXnt3hL0NJYuxBUDTYkJs46F3I=
diff --git a/samples/pbe/java/des3-cbc.raw b/samples/pbe/java/des3-cbc.raw
new file mode 100644
index 0000000..cf578c5
--- /dev/null
+++ b/samples/pbe/java/des3-cbc.raw
@@ -0,0 +1 @@
+Salted__A+��@ZUi
s�7M�o
+�
�n
\ No newline at end of file
diff --git a/samples/pbe/java/des3-cfb.base64 b/samples/pbe/java/des3-cfb.base64
new file mode 100644
index 0000000..3ca902b
--- /dev/null
+++ b/samples/pbe/java/des3-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+uL6LyO88LVW6JSU1QggtMqXcJhA==
diff --git a/samples/pbe/java/des3-cfb.raw b/samples/pbe/java/des3-cfb.raw
new file mode 100644
index 0000000..3db917d
--- /dev/null
+++ b/samples/pbe/java/des3-cfb.raw
@@ -0,0 +1 @@
+Salted__xC�l��%�7�y[��=�@��
\ No newline at end of file
diff --git a/samples/pbe/java/des3-cfb8.base64 b/samples/pbe/java/des3-cfb8.base64
new file mode 100644
index 0000000..1706aae
--- /dev/null
+++ b/samples/pbe/java/des3-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+UVIXNkusZ2L9LJETZrgLvYQLx2Q==
diff --git a/samples/pbe/java/des3-cfb8.raw b/samples/pbe/java/des3-cfb8.raw
new file mode 100644
index 0000000..35ef3a9
--- /dev/null
+++ b/samples/pbe/java/des3-cfb8.raw
@@ -0,0 +1 @@
+Salted__5b��bA����r��;=ܨ
\ No newline at end of file
diff --git a/samples/pbe/java/des3-ecb.base64 b/samples/pbe/java/des3-ecb.base64
new file mode 100644
index 0000000..b196590
--- /dev/null
+++ b/samples/pbe/java/des3-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/AmsUU5AMZi+SKgNJLzbdL7ksOeW4C2Gs=
diff --git a/samples/pbe/java/des3-ecb.raw b/samples/pbe/java/des3-ecb.raw
new file mode 100644
index 0000000..d6a2aec
--- /dev/null
+++ b/samples/pbe/java/des3-ecb.raw
@@ -0,0 +1 @@
+Salted__���2ɱF�xi]�
����p��`�
\ No newline at end of file
diff --git a/samples/pbe/java/des3-ofb.base64 b/samples/pbe/java/des3-ofb.base64
new file mode 100644
index 0000000..ed5b9f6
--- /dev/null
+++ b/samples/pbe/java/des3-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+EdDdizgXHrefX3aa7etL0mlBz4A==
diff --git a/samples/pbe/java/des3-ofb.raw b/samples/pbe/java/des3-ofb.raw
new file mode 100644
index 0000000..863bb04
--- /dev/null
+++ b/samples/pbe/java/des3-ofb.raw
@@ -0,0 +1 @@
+Salted__���h
�Up֍"X��]
\ No newline at end of file
diff --git a/samples/pbe/java/des3.base64 b/samples/pbe/java/des3.base64
new file mode 100644
index 0000000..dd14563
--- /dev/null
+++ b/samples/pbe/java/des3.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/VhtA8kn/sl5vKUPdn26Y2HJ9GqS0yIO4=
diff --git a/samples/pbe/java/des3.raw b/samples/pbe/java/des3.raw
new file mode 100644
index 0000000..c6c0603
--- /dev/null
+++ b/samples/pbe/java/des3.raw
@@ -0,0 +1 @@
+Salted__r�*���k'�2ڼ_�yd1���O
\ No newline at end of file
diff --git a/samples/pbe/java/gost-cbc.base64 b/samples/pbe/java/gost-cbc.base64
new file mode 100644
index 0000000..99379d5
--- /dev/null
+++ b/samples/pbe/java/gost-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19CcOxqNCX3h+qaxYPx4f/RSMkfhfcg3+U=
diff --git a/samples/pbe/java/gost-cbc.raw b/samples/pbe/java/gost-cbc.raw
new file mode 100644
index 0000000..5f2ca5c
--- /dev/null
+++ b/samples/pbe/java/gost-cbc.raw
@@ -0,0 +1 @@
+Salted__X&{�ʱ@+;���p�Òs����YL
\ No newline at end of file
diff --git a/samples/pbe/java/gost-cfb.base64 b/samples/pbe/java/gost-cfb.base64
new file mode 100644
index 0000000..34568e6
--- /dev/null
+++ b/samples/pbe/java/gost-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/UW5yNAn/CqR2XRuNBN7eL0fykgw==
diff --git a/samples/pbe/java/gost-cfb.raw b/samples/pbe/java/gost-cfb.raw
new file mode 100644
index 0000000..4feda43
--- /dev/null
+++ b/samples/pbe/java/gost-cfb.raw
@@ -0,0 +1 @@
+Salted__h�u}S1��KPf.h@�!
\ No newline at end of file
diff --git a/samples/pbe/java/gost-cfb8.base64 b/samples/pbe/java/gost-cfb8.base64
new file mode 100644
index 0000000..b2cd2ad
--- /dev/null
+++ b/samples/pbe/java/gost-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18ENqZkND8kNxny3GS40O7vA+01RA==
diff --git a/samples/pbe/java/gost-cfb8.raw b/samples/pbe/java/gost-cfb8.raw
new file mode 100644
index 0000000..5d0f56a
--- /dev/null
+++ b/samples/pbe/java/gost-cfb8.raw
@@ -0,0 +1 @@
+Salted__�H�4g (�`tcC
"��
\ No newline at end of file
diff --git a/samples/pbe/java/gost-ecb.base64 b/samples/pbe/java/gost-ecb.base64
new file mode 100644
index 0000000..c3d8b5b
--- /dev/null
+++ b/samples/pbe/java/gost-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18SHI4bsA0ISfwzG74m3pq8LYHueA4kHX8=
diff --git a/samples/pbe/java/gost-ecb.raw b/samples/pbe/java/gost-ecb.raw
new file mode 100644
index 0000000..4f52e3e
--- /dev/null
+++ b/samples/pbe/java/gost-ecb.raw
@@ -0,0 +1 @@
+Salted__<x�hwtf�]��e{��߱��
�
\ No newline at end of file
diff --git a/samples/pbe/java/gost-ofb.base64 b/samples/pbe/java/gost-ofb.base64
new file mode 100644
index 0000000..74d3d7f
--- /dev/null
+++ b/samples/pbe/java/gost-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/9caqCTHUYTMBXGcmTvpbwc1hFYQ==
diff --git a/samples/pbe/java/gost-ofb.raw b/samples/pbe/java/gost-ofb.raw
new file mode 100644
index 0000000..f302d1b
--- /dev/null
+++ b/samples/pbe/java/gost-ofb.raw
@@ -0,0 +1 @@
+Salted__�̩�Ԑ|��:������A7!�
\ No newline at end of file
diff --git a/samples/pbe/java/gost.base64 b/samples/pbe/java/gost.base64
new file mode 100644
index 0000000..7f608d4
--- /dev/null
+++ b/samples/pbe/java/gost.base64
@@ -0,0 +1 @@
+U2FsdGVkX19cp6LdmpT4Cy3MXExvnqpHAacdX1t49N8=
diff --git a/samples/pbe/java/gost.raw b/samples/pbe/java/gost.raw
new file mode 100644
index 0000000..b102fa1
--- /dev/null
+++ b/samples/pbe/java/gost.raw
@@ -0,0 +1,2 @@
+Salted__s�b ������n
����ʼ�
+��
\ No newline at end of file
diff --git a/samples/pbe/java/gost28147-cbc.base64 b/samples/pbe/java/gost28147-cbc.base64
new file mode 100644
index 0000000..a255c2b
--- /dev/null
+++ b/samples/pbe/java/gost28147-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+H27MlUg1vPsoZxpMW0YhUDsU83uBZto4=
diff --git a/samples/pbe/java/gost28147-cbc.raw b/samples/pbe/java/gost28147-cbc.raw
new file mode 100644
index 0000000..98ee138
--- /dev/null
+++ b/samples/pbe/java/gost28147-cbc.raw
@@ -0,0 +1 @@
+Salted__���.�
K�dظ��d��
���5 �
\ No newline at end of file
diff --git a/samples/pbe/java/gost28147-cfb.base64 b/samples/pbe/java/gost28147-cfb.base64
new file mode 100644
index 0000000..afb0b19
--- /dev/null
+++ b/samples/pbe/java/gost28147-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX193E/5JnaVMzKSTVGJnVoHkW//6UQ==
diff --git a/samples/pbe/java/gost28147-cfb.raw b/samples/pbe/java/gost28147-cfb.raw
new file mode 100644
index 0000000..50d10b4
--- /dev/null
+++ b/samples/pbe/java/gost28147-cfb.raw
@@ -0,0 +1 @@
+Salted__PI*�֍���N��
p����
\ No newline at end of file
diff --git a/samples/pbe/java/gost28147-cfb8.base64 b/samples/pbe/java/gost28147-cfb8.base64
new file mode 100644
index 0000000..8805e99
--- /dev/null
+++ b/samples/pbe/java/gost28147-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+z2bNQFuQbctEp67XJS/07x7y7Ug==
diff --git a/samples/pbe/java/gost28147-cfb8.raw b/samples/pbe/java/gost28147-cfb8.raw
new file mode 100644
index 0000000..3a077e2
--- /dev/null
+++ b/samples/pbe/java/gost28147-cfb8.raw
@@ -0,0 +1 @@
+Salted__W��J���yPQ��ЇQ�3��
\ No newline at end of file
diff --git a/samples/pbe/java/gost28147-ecb.base64 b/samples/pbe/java/gost28147-ecb.base64
new file mode 100644
index 0000000..d600b33
--- /dev/null
+++ b/samples/pbe/java/gost28147-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/3aDVY8d8z2yMpkDMJRMidVosy7139sZQ=
diff --git a/samples/pbe/java/gost28147-ecb.raw b/samples/pbe/java/gost28147-ecb.raw
new file mode 100644
index 0000000..95b75d5
--- /dev/null
+++ b/samples/pbe/java/gost28147-ecb.raw
@@ -0,0 +1 @@
+Salted__;����3����_ ���Wf,�8�
\ No newline at end of file
diff --git a/samples/pbe/java/gost28147-ofb.base64 b/samples/pbe/java/gost28147-ofb.base64
new file mode 100644
index 0000000..0a10ee5
--- /dev/null
+++ b/samples/pbe/java/gost28147-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/SzYHi7r+5pJl69a2iG5kSddrZ7Q==
diff --git a/samples/pbe/java/gost28147-ofb.raw b/samples/pbe/java/gost28147-ofb.raw
new file mode 100644
index 0000000..31eecf6
--- /dev/null
+++ b/samples/pbe/java/gost28147-ofb.raw
@@ -0,0 +1 @@
+Salted__%����;G��
�=|`�ZS
\ No newline at end of file
diff --git a/samples/pbe/java/gost28147.base64 b/samples/pbe/java/gost28147.base64
new file mode 100644
index 0000000..fd0fbb5
--- /dev/null
+++ b/samples/pbe/java/gost28147.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+NdJZXG4amPV/2Bb1A+BwpJjIk0xIlfhc=
diff --git a/samples/pbe/java/gost28147.raw b/samples/pbe/java/gost28147.raw
new file mode 100644
index 0000000..55b3429
Binary files /dev/null and b/samples/pbe/java/gost28147.raw differ
diff --git a/samples/pbe/java/idea-cbc.base64 b/samples/pbe/java/idea-cbc.base64
new file mode 100644
index 0000000..c06ddfd
--- /dev/null
+++ b/samples/pbe/java/idea-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/OtjE6TFh2zaXkr8avX9DMGUMTVYdjgho=
diff --git a/samples/pbe/java/idea-cbc.raw b/samples/pbe/java/idea-cbc.raw
new file mode 100644
index 0000000..91c10c4
--- /dev/null
+++ b/samples/pbe/java/idea-cbc.raw
@@ -0,0 +1 @@
+Salted__�ϵ����ˤ¨����f�b��
\ No newline at end of file
diff --git a/samples/pbe/java/idea-cfb.base64 b/samples/pbe/java/idea-cfb.base64
new file mode 100644
index 0000000..504b806
--- /dev/null
+++ b/samples/pbe/java/idea-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19PDheUQ+fz6/gv42IkjuN4yxYh/A==
diff --git a/samples/pbe/java/idea-cfb.raw b/samples/pbe/java/idea-cfb.raw
new file mode 100644
index 0000000..2a3ad57
--- /dev/null
+++ b/samples/pbe/java/idea-cfb.raw
@@ -0,0 +1,2 @@
+Salted__��
+��XT
e
<��;��w~�
\ No newline at end of file
diff --git a/samples/pbe/java/idea-cfb8.base64 b/samples/pbe/java/idea-cfb8.base64
new file mode 100644
index 0000000..d0fd71a
--- /dev/null
+++ b/samples/pbe/java/idea-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18WT/xrbSMFJZRt2HoN8QG9ikk/iw==
diff --git a/samples/pbe/java/idea-cfb8.raw b/samples/pbe/java/idea-cfb8.raw
new file mode 100644
index 0000000..d4179bb
--- /dev/null
+++ b/samples/pbe/java/idea-cfb8.raw
@@ -0,0 +1 @@
+Salted__q�_�k��ÂW�djO���
\ No newline at end of file
diff --git a/samples/pbe/java/idea-ecb.base64 b/samples/pbe/java/idea-ecb.base64
new file mode 100644
index 0000000..c4d6ae2
--- /dev/null
+++ b/samples/pbe/java/idea-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/zs/wt9YPU+8vAh/1Qseii6vrmPoLMhGA=
diff --git a/samples/pbe/java/idea-ecb.raw b/samples/pbe/java/idea-ecb.raw
new file mode 100644
index 0000000..1de519d
--- /dev/null
+++ b/samples/pbe/java/idea-ecb.raw
@@ -0,0 +1,2 @@
+Salted__:���s>�l�k�hdV���
+DmQ�
\ No newline at end of file
diff --git a/samples/pbe/java/idea-ofb.base64 b/samples/pbe/java/idea-ofb.base64
new file mode 100644
index 0000000..55dd20a
--- /dev/null
+++ b/samples/pbe/java/idea-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+XANwaL1bEFrkxDddSGCleBTJQQg==
diff --git a/samples/pbe/java/idea-ofb.raw b/samples/pbe/java/idea-ofb.raw
new file mode 100644
index 0000000..f0a286c
--- /dev/null
+++ b/samples/pbe/java/idea-ofb.raw
@@ -0,0 +1 @@
+Salted__��U���b��;Co8Y
�QX
\ No newline at end of file
diff --git a/samples/pbe/java/idea.base64 b/samples/pbe/java/idea.base64
new file mode 100644
index 0000000..5fc1bb9
--- /dev/null
+++ b/samples/pbe/java/idea.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+MBtM2j7TXdcefSxcgR2yvj+OqX4pDZXk=
diff --git a/samples/pbe/java/idea.raw b/samples/pbe/java/idea.raw
new file mode 100644
index 0000000..7e71623
--- /dev/null
+++ b/samples/pbe/java/idea.raw
@@ -0,0 +1 @@
+Salted__��KI��}��<-�.ƾ���9
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-40-cbc.base64 b/samples/pbe/java/rc2-40-cbc.base64
new file mode 100644
index 0000000..31f33fa
--- /dev/null
+++ b/samples/pbe/java/rc2-40-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1890fJi9gA9RVpNI1DwMT1Vt51TkZmLyWs=
diff --git a/samples/pbe/java/rc2-40-cbc.raw b/samples/pbe/java/rc2-40-cbc.raw
new file mode 100644
index 0000000..25e5f9c
--- /dev/null
+++ b/samples/pbe/java/rc2-40-cbc.raw
@@ -0,0 +1 @@
+Salted__. ����b��y��6���[�Y9�I
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-40-cfb.base64 b/samples/pbe/java/rc2-40-cfb.base64
new file mode 100644
index 0000000..9f43934
--- /dev/null
+++ b/samples/pbe/java/rc2-40-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/9CTBQbekwaKie03cWICyZs3KtFg==
diff --git a/samples/pbe/java/rc2-40-cfb.raw b/samples/pbe/java/rc2-40-cfb.raw
new file mode 100644
index 0000000..34c84f6
--- /dev/null
+++ b/samples/pbe/java/rc2-40-cfb.raw
@@ -0,0 +1 @@
+Salted__�q�sqhT:�,@�%Ck��S
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-40-cfb8.base64 b/samples/pbe/java/rc2-40-cfb8.base64
new file mode 100644
index 0000000..dfd79ae
--- /dev/null
+++ b/samples/pbe/java/rc2-40-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX19rhbzIzceTg9Ye5JJVdmxmGjzhDQ==
diff --git a/samples/pbe/java/rc2-40-cfb8.raw b/samples/pbe/java/rc2-40-cfb8.raw
new file mode 100644
index 0000000..abcd263
--- /dev/null
+++ b/samples/pbe/java/rc2-40-cfb8.raw
@@ -0,0 +1 @@
+Salted__H��H.����a���
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-40-ecb.base64 b/samples/pbe/java/rc2-40-ecb.base64
new file mode 100644
index 0000000..4bed16c
--- /dev/null
+++ b/samples/pbe/java/rc2-40-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19daAkC+zMJJplpf0zSowdMulhlBsFnUVs=
diff --git a/samples/pbe/java/rc2-40-ecb.raw b/samples/pbe/java/rc2-40-ecb.raw
new file mode 100644
index 0000000..1de429d
--- /dev/null
+++ b/samples/pbe/java/rc2-40-ecb.raw
@@ -0,0 +1 @@
+Salted__97����./����H%ˮ��A��7�
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-40-ofb.base64 b/samples/pbe/java/rc2-40-ofb.base64
new file mode 100644
index 0000000..2a2f8fb
--- /dev/null
+++ b/samples/pbe/java/rc2-40-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/19LIip0bg3xxQnKt+Kl0/34+i2A==
diff --git a/samples/pbe/java/rc2-40-ofb.raw b/samples/pbe/java/rc2-40-ofb.raw
new file mode 100644
index 0000000..a6a97aa
--- /dev/null
+++ b/samples/pbe/java/rc2-40-ofb.raw
@@ -0,0 +1 @@
+Salted__A��j�V�r���ˋ�G$��
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-40.base64 b/samples/pbe/java/rc2-40.base64
new file mode 100644
index 0000000..e9a220d
--- /dev/null
+++ b/samples/pbe/java/rc2-40.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/3SRnzRmiIg1wLwR1/h+fXX+1e/GY202U=
diff --git a/samples/pbe/java/rc2-40.raw b/samples/pbe/java/rc2-40.raw
new file mode 100644
index 0000000..9e5c6c7
--- /dev/null
+++ b/samples/pbe/java/rc2-40.raw
@@ -0,0 +1 @@
+Salted__kn�� �-�&�gLΰ�W��
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-64-cbc.base64 b/samples/pbe/java/rc2-64-cbc.base64
new file mode 100644
index 0000000..88c35c7
--- /dev/null
+++ b/samples/pbe/java/rc2-64-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19HgGgtz1lOzUsGkcd7YnWH7iB+t0TCPc4=
diff --git a/samples/pbe/java/rc2-64-cbc.raw b/samples/pbe/java/rc2-64-cbc.raw
new file mode 100644
index 0000000..ef12322
--- /dev/null
+++ b/samples/pbe/java/rc2-64-cbc.raw
@@ -0,0 +1 @@
+Salted__��)Y������L�ee
�?$���B�
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-64-cfb.base64 b/samples/pbe/java/rc2-64-cfb.base64
new file mode 100644
index 0000000..ce92402
--- /dev/null
+++ b/samples/pbe/java/rc2-64-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+jFsOQfhGb6EMTiO5PogMI/TDEVQ==
diff --git a/samples/pbe/java/rc2-64-cfb.raw b/samples/pbe/java/rc2-64-cfb.raw
new file mode 100644
index 0000000..092dbcb
--- /dev/null
+++ b/samples/pbe/java/rc2-64-cfb.raw
@@ -0,0 +1 @@
+Salted__W����$
X��]pR���
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-64-cfb8.base64 b/samples/pbe/java/rc2-64-cfb8.base64
new file mode 100644
index 0000000..9eff43f
--- /dev/null
+++ b/samples/pbe/java/rc2-64-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18Vx4yMujZVjPpd9Fi1bSg/jF7Bxw==
diff --git a/samples/pbe/java/rc2-64-cfb8.raw b/samples/pbe/java/rc2-64-cfb8.raw
new file mode 100644
index 0000000..269c7cc
Binary files /dev/null and b/samples/pbe/java/rc2-64-cfb8.raw differ
diff --git a/samples/pbe/java/rc2-64-ecb.base64 b/samples/pbe/java/rc2-64-ecb.base64
new file mode 100644
index 0000000..6adf1b2
--- /dev/null
+++ b/samples/pbe/java/rc2-64-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19V5eWa4V73IGlV+5qb1zawiN+vnAiYmzY=
diff --git a/samples/pbe/java/rc2-64-ecb.raw b/samples/pbe/java/rc2-64-ecb.raw
new file mode 100644
index 0000000..936afba
--- /dev/null
+++ b/samples/pbe/java/rc2-64-ecb.raw
@@ -0,0 +1 @@
+Salted__B�.A�l����Mv:��c�X�\
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-64-ofb.base64 b/samples/pbe/java/rc2-64-ofb.base64
new file mode 100644
index 0000000..496a220
--- /dev/null
+++ b/samples/pbe/java/rc2-64-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19GOsgWvk8zkm+x4QV5m1s4fdPu5Q==
diff --git a/samples/pbe/java/rc2-64-ofb.raw b/samples/pbe/java/rc2-64-ofb.raw
new file mode 100644
index 0000000..2d0e2af
--- /dev/null
+++ b/samples/pbe/java/rc2-64-ofb.raw
@@ -0,0 +1 @@
+Salted__ LV㛖O����v1ġ6�t}
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-64.base64 b/samples/pbe/java/rc2-64.base64
new file mode 100644
index 0000000..ba7b424
--- /dev/null
+++ b/samples/pbe/java/rc2-64.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+t696swrI4UPV7oNFDYmU87F0CoP6Vb+Q=
diff --git a/samples/pbe/java/rc2-64.raw b/samples/pbe/java/rc2-64.raw
new file mode 100644
index 0000000..302cb49
--- /dev/null
+++ b/samples/pbe/java/rc2-64.raw
@@ -0,0 +1 @@
+Salted__�$�V��T����Gj0�>A�
���U
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-cbc.base64 b/samples/pbe/java/rc2-cbc.base64
new file mode 100644
index 0000000..eea5829
--- /dev/null
+++ b/samples/pbe/java/rc2-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19jUXYEywuyoP7NBdjrrZCqtJrFnXTPlaU=
diff --git a/samples/pbe/java/rc2-cbc.raw b/samples/pbe/java/rc2-cbc.raw
new file mode 100644
index 0000000..c2c1b61
Binary files /dev/null and b/samples/pbe/java/rc2-cbc.raw differ
diff --git a/samples/pbe/java/rc2-cfb.base64 b/samples/pbe/java/rc2-cfb.base64
new file mode 100644
index 0000000..6a25c21
--- /dev/null
+++ b/samples/pbe/java/rc2-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19N7VML8H7g1oM010jHxsI+4J3Eaw==
diff --git a/samples/pbe/java/rc2-cfb.raw b/samples/pbe/java/rc2-cfb.raw
new file mode 100644
index 0000000..c0cf0cd
--- /dev/null
+++ b/samples/pbe/java/rc2-cfb.raw
@@ -0,0 +1 @@
+Salted__
��9
�n�ܦ�w�L�E��
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-cfb8.base64 b/samples/pbe/java/rc2-cfb8.base64
new file mode 100644
index 0000000..4242b15
--- /dev/null
+++ b/samples/pbe/java/rc2-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX19Hc+EZIfLJzpgBhsT2O+8yMoQG+g==
diff --git a/samples/pbe/java/rc2-cfb8.raw b/samples/pbe/java/rc2-cfb8.raw
new file mode 100644
index 0000000..a6eeb8b
--- /dev/null
+++ b/samples/pbe/java/rc2-cfb8.raw
@@ -0,0 +1 @@
+Salted__X�z�S�ˊ���*M>H+�\
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-ecb.base64 b/samples/pbe/java/rc2-ecb.base64
new file mode 100644
index 0000000..626d757
--- /dev/null
+++ b/samples/pbe/java/rc2-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX180vh9QgndcQX7pLj7vY6mjoFKdPy4DKKU=
diff --git a/samples/pbe/java/rc2-ecb.raw b/samples/pbe/java/rc2-ecb.raw
new file mode 100644
index 0000000..1360879
--- /dev/null
+++ b/samples/pbe/java/rc2-ecb.raw
@@ -0,0 +1 @@
+Salted__!)��u���ti��7P�t�ü_�
\ No newline at end of file
diff --git a/samples/pbe/java/rc2-ofb.base64 b/samples/pbe/java/rc2-ofb.base64
new file mode 100644
index 0000000..313ae46
--- /dev/null
+++ b/samples/pbe/java/rc2-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/iYmfwemCc/BruXulvHyLEqbOOgA==
diff --git a/samples/pbe/java/rc2-ofb.raw b/samples/pbe/java/rc2-ofb.raw
new file mode 100644
index 0000000..6bd7cdb
--- /dev/null
+++ b/samples/pbe/java/rc2-ofb.raw
@@ -0,0 +1 @@
+Salted__�z�ޢ
�jV�����os��
\ No newline at end of file
diff --git a/samples/pbe/java/rc2.base64 b/samples/pbe/java/rc2.base64
new file mode 100644
index 0000000..82dd662
--- /dev/null
+++ b/samples/pbe/java/rc2.base64
@@ -0,0 +1 @@
+U2FsdGVkX19N6rCXehC+nOA5hSXpAYzwLaWrUbjVjOw=
diff --git a/samples/pbe/java/rc2.raw b/samples/pbe/java/rc2.raw
new file mode 100644
index 0000000..30ddfb1
--- /dev/null
+++ b/samples/pbe/java/rc2.raw
@@ -0,0 +1 @@
+Salted__
∎�-�����r~��g"��)�
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-40-cbc.base64 b/samples/pbe/java/rc4-40-cbc.base64
new file mode 100644
index 0000000..fc22b6a
--- /dev/null
+++ b/samples/pbe/java/rc4-40-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX188GJJ5CN6i9uoi+gQ7MGXRI5hARw==
diff --git a/samples/pbe/java/rc4-40-cbc.raw b/samples/pbe/java/rc4-40-cbc.raw
new file mode 100644
index 0000000..7023417
--- /dev/null
+++ b/samples/pbe/java/rc4-40-cbc.raw
@@ -0,0 +1 @@
+Salted__K�<�PGR�t�'�o
�=iA!
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-40-cfb.base64 b/samples/pbe/java/rc4-40-cfb.base64
new file mode 100644
index 0000000..53c2751
--- /dev/null
+++ b/samples/pbe/java/rc4-40-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18odI9YC5G2YEXRbhdC4oAEZBoy8A==
diff --git a/samples/pbe/java/rc4-40-cfb.raw b/samples/pbe/java/rc4-40-cfb.raw
new file mode 100644
index 0000000..30a67c9
--- /dev/null
+++ b/samples/pbe/java/rc4-40-cfb.raw
@@ -0,0 +1 @@
+Salted__
�$�Z�(*b"�| ����
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-40-cfb1.base64 b/samples/pbe/java/rc4-40-cfb1.base64
new file mode 100644
index 0000000..a1aa595
--- /dev/null
+++ b/samples/pbe/java/rc4-40-cfb1.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/CZmQzq0Vy8q9v/UuFyivWuzzy/A==
diff --git a/samples/pbe/java/rc4-40-cfb1.raw b/samples/pbe/java/rc4-40-cfb1.raw
new file mode 100644
index 0000000..89067c5
--- /dev/null
+++ b/samples/pbe/java/rc4-40-cfb1.raw
@@ -0,0 +1 @@
+Salted__��3��!����������ʞ
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-40-cfb8.base64 b/samples/pbe/java/rc4-40-cfb8.base64
new file mode 100644
index 0000000..596499d
--- /dev/null
+++ b/samples/pbe/java/rc4-40-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1941/BbLOytQil4JxUbYgHhVRVTPw==
diff --git a/samples/pbe/java/rc4-40-cfb8.raw b/samples/pbe/java/rc4-40-cfb8.raw
new file mode 100644
index 0000000..cc8ec48
--- /dev/null
+++ b/samples/pbe/java/rc4-40-cfb8.raw
@@ -0,0 +1 @@
+Salted__�
�A�;EK�9��G7{��
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-40-ecb.base64 b/samples/pbe/java/rc4-40-ecb.base64
new file mode 100644
index 0000000..addd651
--- /dev/null
+++ b/samples/pbe/java/rc4-40-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/wRwxSIU9NSFlHZQri5prYSp2VBQ==
diff --git a/samples/pbe/java/rc4-40-ecb.raw b/samples/pbe/java/rc4-40-ecb.raw
new file mode 100644
index 0000000..d00c121
--- /dev/null
+++ b/samples/pbe/java/rc4-40-ecb.raw
@@ -0,0 +1 @@
+Salted__r�]�濷�S>>�3�p��#�
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-40-ofb.base64 b/samples/pbe/java/rc4-40-ofb.base64
new file mode 100644
index 0000000..0d6cc65
--- /dev/null
+++ b/samples/pbe/java/rc4-40-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19CkHOXcKSEyr7u+cfZdee1OIHuzw==
diff --git a/samples/pbe/java/rc4-40-ofb.raw b/samples/pbe/java/rc4-40-ofb.raw
new file mode 100644
index 0000000..bcf956b
--- /dev/null
+++ b/samples/pbe/java/rc4-40-ofb.raw
@@ -0,0 +1 @@
+Salted__T�N�/��|�wN�9:v��`�
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-40.base64 b/samples/pbe/java/rc4-40.base64
new file mode 100644
index 0000000..12a7b89
--- /dev/null
+++ b/samples/pbe/java/rc4-40.base64
@@ -0,0 +1 @@
+U2FsdGVkX18EeGBBjdefS3HAHTqHfBG/3hCTAQ==
diff --git a/samples/pbe/java/rc4-40.raw b/samples/pbe/java/rc4-40.raw
new file mode 100644
index 0000000..a49d2fa
--- /dev/null
+++ b/samples/pbe/java/rc4-40.raw
@@ -0,0 +1 @@
+Salted__�Q��_����y)j4�^U[�W
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-cbc.base64 b/samples/pbe/java/rc4-cbc.base64
new file mode 100644
index 0000000..b57ddee
--- /dev/null
+++ b/samples/pbe/java/rc4-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19MH6/8ont1oCPgPGGrD07Uk2KFbw==
diff --git a/samples/pbe/java/rc4-cbc.raw b/samples/pbe/java/rc4-cbc.raw
new file mode 100644
index 0000000..58ad2d4
--- /dev/null
+++ b/samples/pbe/java/rc4-cbc.raw
@@ -0,0 +1 @@
+Salted__?f���U�P2eQ�E�@&�
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-cfb.base64 b/samples/pbe/java/rc4-cfb.base64
new file mode 100644
index 0000000..75b19e3
--- /dev/null
+++ b/samples/pbe/java/rc4-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+XwaTkDMWYpe00BhDb6r23ndwWcg==
diff --git a/samples/pbe/java/rc4-cfb.raw b/samples/pbe/java/rc4-cfb.raw
new file mode 100644
index 0000000..1763fa5
--- /dev/null
+++ b/samples/pbe/java/rc4-cfb.raw
@@ -0,0 +1 @@
+Salted__)TC_�̯�s|4#��|�ҭ�D
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-cfb1.base64 b/samples/pbe/java/rc4-cfb1.base64
new file mode 100644
index 0000000..3c075dc
--- /dev/null
+++ b/samples/pbe/java/rc4-cfb1.base64
@@ -0,0 +1 @@
+U2FsdGVkX19awuk1DmUWgwPY/aEmbOiOBEOl1A==
diff --git a/samples/pbe/java/rc4-cfb1.raw b/samples/pbe/java/rc4-cfb1.raw
new file mode 100644
index 0000000..ff8dc08
--- /dev/null
+++ b/samples/pbe/java/rc4-cfb1.raw
@@ -0,0 +1 @@
+Salted__�nh<�<���_����
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-cfb8.base64 b/samples/pbe/java/rc4-cfb8.base64
new file mode 100644
index 0000000..ccae1fb
--- /dev/null
+++ b/samples/pbe/java/rc4-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+5qdQ+OTXJaPidwUyxZIJ3poe4WA==
diff --git a/samples/pbe/java/rc4-cfb8.raw b/samples/pbe/java/rc4-cfb8.raw
new file mode 100644
index 0000000..d7297b4
--- /dev/null
+++ b/samples/pbe/java/rc4-cfb8.raw
@@ -0,0 +1 @@
+Salted__윰�])��-�s�
� ��|W�
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-ecb.base64 b/samples/pbe/java/rc4-ecb.base64
new file mode 100644
index 0000000..8bf1eaa
--- /dev/null
+++ b/samples/pbe/java/rc4-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1//ZrZ/vbEZ3DLSgWD+riJhXeUBmw==
diff --git a/samples/pbe/java/rc4-ecb.raw b/samples/pbe/java/rc4-ecb.raw
new file mode 100644
index 0000000..f002c75
--- /dev/null
+++ b/samples/pbe/java/rc4-ecb.raw
@@ -0,0 +1 @@
+Salted__"Q��|��`\I�E&���*w
\ No newline at end of file
diff --git a/samples/pbe/java/rc4-ofb.base64 b/samples/pbe/java/rc4-ofb.base64
new file mode 100644
index 0000000..84a89be
--- /dev/null
+++ b/samples/pbe/java/rc4-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18Im3cQogwsf8Bmi3Putex1tcWQ3Q==
diff --git a/samples/pbe/java/rc4-ofb.raw b/samples/pbe/java/rc4-ofb.raw
new file mode 100644
index 0000000..3e40896
--- /dev/null
+++ b/samples/pbe/java/rc4-ofb.raw
@@ -0,0 +1 @@
+Salted__x��2S���#����]m��
\ No newline at end of file
diff --git a/samples/pbe/java/rc4.base64 b/samples/pbe/java/rc4.base64
new file mode 100644
index 0000000..020815e
--- /dev/null
+++ b/samples/pbe/java/rc4.base64
@@ -0,0 +1 @@
+U2FsdGVkX19dOFVejkLubJRxOAgiRXIhdtQjpg==
diff --git a/samples/pbe/java/rc4.raw b/samples/pbe/java/rc4.raw
new file mode 100644
index 0000000..3cd0f3d
Binary files /dev/null and b/samples/pbe/java/rc4.raw differ
diff --git a/samples/pbe/java/rc5-cbc.base64 b/samples/pbe/java/rc5-cbc.base64
new file mode 100644
index 0000000..efa9b01
--- /dev/null
+++ b/samples/pbe/java/rc5-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19KZE6NwDpGJggjEqCSssSdGBuqdMMS/ac=
diff --git a/samples/pbe/java/rc5-cbc.raw b/samples/pbe/java/rc5-cbc.raw
new file mode 100644
index 0000000..9ad3978
Binary files /dev/null and b/samples/pbe/java/rc5-cbc.raw differ
diff --git a/samples/pbe/java/rc5-cfb.base64 b/samples/pbe/java/rc5-cfb.base64
new file mode 100644
index 0000000..58d6a84
--- /dev/null
+++ b/samples/pbe/java/rc5-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/iYdy7fAxq6MgXfbbdhgpV0ZzMbA==
diff --git a/samples/pbe/java/rc5-cfb.raw b/samples/pbe/java/rc5-cfb.raw
new file mode 100644
index 0000000..2e140fc
--- /dev/null
+++ b/samples/pbe/java/rc5-cfb.raw
@@ -0,0 +1 @@
+Salted__-��7x�j�k�?�o��on�
\ No newline at end of file
diff --git a/samples/pbe/java/rc5-cfb8.base64 b/samples/pbe/java/rc5-cfb8.base64
new file mode 100644
index 0000000..5751c8d
--- /dev/null
+++ b/samples/pbe/java/rc5-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+QRrNDT8pf9MjdWWXbv9prbDMeLw==
diff --git a/samples/pbe/java/rc5-cfb8.raw b/samples/pbe/java/rc5-cfb8.raw
new file mode 100644
index 0000000..7e749c1
--- /dev/null
+++ b/samples/pbe/java/rc5-cfb8.raw
@@ -0,0 +1 @@
+Salted__���r��%����E��3�
\ No newline at end of file
diff --git a/samples/pbe/java/rc5-ecb.base64 b/samples/pbe/java/rc5-ecb.base64
new file mode 100644
index 0000000..37d8f49
--- /dev/null
+++ b/samples/pbe/java/rc5-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/9FfJfiaw3Io0Z0jxcNcn2z7/nwS5fW2U=
diff --git a/samples/pbe/java/rc5-ecb.raw b/samples/pbe/java/rc5-ecb.raw
new file mode 100644
index 0000000..6c71c4d
--- /dev/null
+++ b/samples/pbe/java/rc5-ecb.raw
@@ -0,0 +1 @@
+Salted__���SpH2����$��Q,E!�
�
\ No newline at end of file
diff --git a/samples/pbe/java/rc5-ofb.base64 b/samples/pbe/java/rc5-ofb.base64
new file mode 100644
index 0000000..e34064b
--- /dev/null
+++ b/samples/pbe/java/rc5-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19Wu2kziJkCUV0k3gLs9ST+Khhj7A==
diff --git a/samples/pbe/java/rc5-ofb.raw b/samples/pbe/java/rc5-ofb.raw
new file mode 100644
index 0000000..5aeed79
--- /dev/null
+++ b/samples/pbe/java/rc5-ofb.raw
@@ -0,0 +1 @@
+Salted__��˿s���^"@�
���3
\ No newline at end of file
diff --git a/samples/pbe/java/rc5.base64 b/samples/pbe/java/rc5.base64
new file mode 100644
index 0000000..5be614d
--- /dev/null
+++ b/samples/pbe/java/rc5.base64
@@ -0,0 +1 @@
+U2FsdGVkX19OPlXT1mBB8+CHrhbv+wgMQQRO6W9JmNA=
diff --git a/samples/pbe/java/rc5.raw b/samples/pbe/java/rc5.raw
new file mode 100644
index 0000000..a477e0e
--- /dev/null
+++ b/samples/pbe/java/rc5.raw
@@ -0,0 +1,2 @@
+Salted__
+��1�T���9��m��;��,D:�c�
\ No newline at end of file
diff --git a/samples/pbe/java/rc6-cbc.base64 b/samples/pbe/java/rc6-cbc.base64
new file mode 100644
index 0000000..6c77177
--- /dev/null
+++ b/samples/pbe/java/rc6-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX18zJfLwtPs3eGSOXxsDSLwxRwt88FMa8KQ=
diff --git a/samples/pbe/java/rc6-cbc.raw b/samples/pbe/java/rc6-cbc.raw
new file mode 100644
index 0000000..b8a9c69
--- /dev/null
+++ b/samples/pbe/java/rc6-cbc.raw
@@ -0,0 +1 @@
+Salted__~qy}ݜ�C4;��P#:�b�.
\ No newline at end of file
diff --git a/samples/pbe/java/rc6-cfb.base64 b/samples/pbe/java/rc6-cfb.base64
new file mode 100644
index 0000000..00b2115
--- /dev/null
+++ b/samples/pbe/java/rc6-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19+sI9PaxTdpflralMAgc1WiI0LxA==
diff --git a/samples/pbe/java/rc6-cfb.raw b/samples/pbe/java/rc6-cfb.raw
new file mode 100644
index 0000000..668db94
--- /dev/null
+++ b/samples/pbe/java/rc6-cfb.raw
@@ -0,0 +1 @@
+Salted__��VQ�3U2�Pr()+S菌¢
\ No newline at end of file
diff --git a/samples/pbe/java/rc6-cfb8.base64 b/samples/pbe/java/rc6-cfb8.base64
new file mode 100644
index 0000000..5967372
--- /dev/null
+++ b/samples/pbe/java/rc6-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX19XSdlrGG6E+A5QqcShux77c0qGeg==
diff --git a/samples/pbe/java/rc6-cfb8.raw b/samples/pbe/java/rc6-cfb8.raw
new file mode 100644
index 0000000..8465eb0
--- /dev/null
+++ b/samples/pbe/java/rc6-cfb8.raw
@@ -0,0 +1 @@
+Salted__;>�0G�n��`w��u���
\ No newline at end of file
diff --git a/samples/pbe/java/rc6-ecb.base64 b/samples/pbe/java/rc6-ecb.base64
new file mode 100644
index 0000000..ba70f6b
--- /dev/null
+++ b/samples/pbe/java/rc6-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18hZXJjY4Ph0hTUfIl2u55YV6eJ6DTx23U=
diff --git a/samples/pbe/java/rc6-ecb.raw b/samples/pbe/java/rc6-ecb.raw
new file mode 100644
index 0000000..7ff49eb
--- /dev/null
+++ b/samples/pbe/java/rc6-ecb.raw
@@ -0,0 +1 @@
+Salted__�
�EX�ػ#�w\u7U�\%�
\ No newline at end of file
diff --git a/samples/pbe/java/rc6-ofb.base64 b/samples/pbe/java/rc6-ofb.base64
new file mode 100644
index 0000000..5f7c88d
--- /dev/null
+++ b/samples/pbe/java/rc6-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18myTpYCRMSdywhJDrjGBHrXcT/qQ==
diff --git a/samples/pbe/java/rc6-ofb.raw b/samples/pbe/java/rc6-ofb.raw
new file mode 100644
index 0000000..a7ea4c1
--- /dev/null
+++ b/samples/pbe/java/rc6-ofb.raw
@@ -0,0 +1 @@
+Salted__�""]@�=z\��о�ʻ��
\ No newline at end of file
diff --git a/samples/pbe/java/rc6.base64 b/samples/pbe/java/rc6.base64
new file mode 100644
index 0000000..54fe771
--- /dev/null
+++ b/samples/pbe/java/rc6.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/rTycJEafQGVSXJ1+kU3PDaSyyaK7Tw1M=
diff --git a/samples/pbe/java/rc6.raw b/samples/pbe/java/rc6.raw
new file mode 100644
index 0000000..d053f09
--- /dev/null
+++ b/samples/pbe/java/rc6.raw
@@ -0,0 +1 @@
+Salted__iC��\�0?M���.�·
����
\ No newline at end of file
diff --git a/samples/pbe/java/rijndael-cbc.base64 b/samples/pbe/java/rijndael-cbc.base64
new file mode 100644
index 0000000..a85d699
--- /dev/null
+++ b/samples/pbe/java/rijndael-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+GLUqDaOBL1q65jZRVV94LQvz++bpKfrg=
diff --git a/samples/pbe/java/rijndael-cbc.raw b/samples/pbe/java/rijndael-cbc.raw
new file mode 100644
index 0000000..702ae5d
--- /dev/null
+++ b/samples/pbe/java/rijndael-cbc.raw
@@ -0,0 +1 @@
+Salted__�l��*�`=N� `
��#/��9u
\ No newline at end of file
diff --git a/samples/pbe/java/rijndael-cfb.base64 b/samples/pbe/java/rijndael-cfb.base64
new file mode 100644
index 0000000..112de2e
--- /dev/null
+++ b/samples/pbe/java/rijndael-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+w0kb82u6IyxyLvDdjN8TFhrKQnA==
diff --git a/samples/pbe/java/rijndael-cfb.raw b/samples/pbe/java/rijndael-cfb.raw
new file mode 100644
index 0000000..86a6b98
--- /dev/null
+++ b/samples/pbe/java/rijndael-cfb.raw
@@ -0,0 +1 @@
+Salted__�J��ff~��%Hi�;�
\ No newline at end of file
diff --git a/samples/pbe/java/rijndael-cfb8.base64 b/samples/pbe/java/rijndael-cfb8.base64
new file mode 100644
index 0000000..c24b2f8
--- /dev/null
+++ b/samples/pbe/java/rijndael-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/3OymmQVbiQVPgAZxjBlz0dH7cWQ==
diff --git a/samples/pbe/java/rijndael-cfb8.raw b/samples/pbe/java/rijndael-cfb8.raw
new file mode 100644
index 0000000..15427a6
--- /dev/null
+++ b/samples/pbe/java/rijndael-cfb8.raw
@@ -0,0 +1 @@
+Salted__
��P���@u(�s=yi
\ No newline at end of file
diff --git a/samples/pbe/java/rijndael-ecb.base64 b/samples/pbe/java/rijndael-ecb.base64
new file mode 100644
index 0000000..3ebeb0a
--- /dev/null
+++ b/samples/pbe/java/rijndael-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19AiEISrLHP341MAjkYJYdHL34x/fD3nfY=
diff --git a/samples/pbe/java/rijndael-ecb.raw b/samples/pbe/java/rijndael-ecb.raw
new file mode 100644
index 0000000..8567a88
--- /dev/null
+++ b/samples/pbe/java/rijndael-ecb.raw
@@ -0,0 +1 @@
+Salted__M��Ɇ�3�?�Uj�Է�f�i
\ No newline at end of file
diff --git a/samples/pbe/java/rijndael-ofb.base64 b/samples/pbe/java/rijndael-ofb.base64
new file mode 100644
index 0000000..8ec0178
--- /dev/null
+++ b/samples/pbe/java/rijndael-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+tQE34suS3sGO91eEI9xeZJnHbhg==
diff --git a/samples/pbe/java/rijndael-ofb.raw b/samples/pbe/java/rijndael-ofb.raw
new file mode 100644
index 0000000..2970b00
Binary files /dev/null and b/samples/pbe/java/rijndael-ofb.raw differ
diff --git a/samples/pbe/java/rijndael.base64 b/samples/pbe/java/rijndael.base64
new file mode 100644
index 0000000..60ff618
--- /dev/null
+++ b/samples/pbe/java/rijndael.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/eW6CyBkiyuzAXOEQZYQ5b5SJiCxzQz7U=
diff --git a/samples/pbe/java/rijndael.raw b/samples/pbe/java/rijndael.raw
new file mode 100644
index 0000000..7112d3c
--- /dev/null
+++ b/samples/pbe/java/rijndael.raw
@@ -0,0 +1 @@
+Salted__�T��#�㣚�������7X�e�
\ No newline at end of file
diff --git a/samples/pbe/java/seed-cbc.base64 b/samples/pbe/java/seed-cbc.base64
new file mode 100644
index 0000000..642f982
--- /dev/null
+++ b/samples/pbe/java/seed-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+Qg5j8oNBcizevw2S/9a304WcUojYHEb8=
diff --git a/samples/pbe/java/seed-cbc.raw b/samples/pbe/java/seed-cbc.raw
new file mode 100644
index 0000000..1e50ac5
--- /dev/null
+++ b/samples/pbe/java/seed-cbc.raw
@@ -0,0 +1 @@
+Salted__����jt_�u��&�� K�
\ No newline at end of file
diff --git a/samples/pbe/java/seed-cfb.base64 b/samples/pbe/java/seed-cfb.base64
new file mode 100644
index 0000000..cf796db
--- /dev/null
+++ b/samples/pbe/java/seed-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19wAkjNdLumDxGUBRFnlpxxfBa+xw==
diff --git a/samples/pbe/java/seed-cfb.raw b/samples/pbe/java/seed-cfb.raw
new file mode 100644
index 0000000..1d9e9cd
--- /dev/null
+++ b/samples/pbe/java/seed-cfb.raw
@@ -0,0 +1 @@
+Salted__U��R.��G��I��F����
\ No newline at end of file
diff --git a/samples/pbe/java/seed-cfb8.base64 b/samples/pbe/java/seed-cfb8.base64
new file mode 100644
index 0000000..42bdb16
--- /dev/null
+++ b/samples/pbe/java/seed-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18MxdLUbBHz6J3ImvUkHx1Mi7HgeQ==
diff --git a/samples/pbe/java/seed-cfb8.raw b/samples/pbe/java/seed-cfb8.raw
new file mode 100644
index 0000000..19912d7
--- /dev/null
+++ b/samples/pbe/java/seed-cfb8.raw
@@ -0,0 +1 @@
+Salted__k��Evq�����3n��
\ No newline at end of file
diff --git a/samples/pbe/java/seed-ecb.base64 b/samples/pbe/java/seed-ecb.base64
new file mode 100644
index 0000000..9739df3
--- /dev/null
+++ b/samples/pbe/java/seed-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/o+GDLgPn9NGJaxPBdnMY6dWlgEGdICbk=
diff --git a/samples/pbe/java/seed-ecb.raw b/samples/pbe/java/seed-ecb.raw
new file mode 100644
index 0000000..9c44997
--- /dev/null
+++ b/samples/pbe/java/seed-ecb.raw
@@ -0,0 +1 @@
+Salted__kZ��E����w
�
�#?��~]�
\ No newline at end of file
diff --git a/samples/pbe/java/seed-ofb.base64 b/samples/pbe/java/seed-ofb.base64
new file mode 100644
index 0000000..8f090ec
--- /dev/null
+++ b/samples/pbe/java/seed-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+Sm91Ol7VDaRp3AkCLVd66x/Pkhw==
diff --git a/samples/pbe/java/seed-ofb.raw b/samples/pbe/java/seed-ofb.raw
new file mode 100644
index 0000000..73e4be8
Binary files /dev/null and b/samples/pbe/java/seed-ofb.raw differ
diff --git a/samples/pbe/java/seed.base64 b/samples/pbe/java/seed.base64
new file mode 100644
index 0000000..393dfd5
--- /dev/null
+++ b/samples/pbe/java/seed.base64
@@ -0,0 +1 @@
+U2FsdGVkX19j1iVitL5B8/SoJbot/q0ZoJCh/crgiaQ=
diff --git a/samples/pbe/java/seed.raw b/samples/pbe/java/seed.raw
new file mode 100644
index 0000000..4c27a0c
--- /dev/null
+++ b/samples/pbe/java/seed.raw
@@ -0,0 +1 @@
+Salted__�%�/�+G�dT�-uVL�w�'�k�
\ No newline at end of file
diff --git a/samples/pbe/java/serpent-cbc.base64 b/samples/pbe/java/serpent-cbc.base64
new file mode 100644
index 0000000..2b6cf49
--- /dev/null
+++ b/samples/pbe/java/serpent-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/Ruex6zZXcKY7UzTOEYf0rOS7jWiPN44E=
diff --git a/samples/pbe/java/serpent-cbc.raw b/samples/pbe/java/serpent-cbc.raw
new file mode 100644
index 0000000..19bd450
--- /dev/null
+++ b/samples/pbe/java/serpent-cbc.raw
@@ -0,0 +1 @@
+Salted__'���"�25�2G\ѝ5��%;`�'
\ No newline at end of file
diff --git a/samples/pbe/java/serpent-cfb.base64 b/samples/pbe/java/serpent-cfb.base64
new file mode 100644
index 0000000..26319af
--- /dev/null
+++ b/samples/pbe/java/serpent-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+XdD1519g75daA+/McW1GrmcrcsQ==
diff --git a/samples/pbe/java/serpent-cfb.raw b/samples/pbe/java/serpent-cfb.raw
new file mode 100644
index 0000000..227d506
Binary files /dev/null and b/samples/pbe/java/serpent-cfb.raw differ
diff --git a/samples/pbe/java/serpent-cfb8.base64 b/samples/pbe/java/serpent-cfb8.base64
new file mode 100644
index 0000000..e35a611
--- /dev/null
+++ b/samples/pbe/java/serpent-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX19rsyCIbjU+kC1yUp68/DYighdcZA==
diff --git a/samples/pbe/java/serpent-cfb8.raw b/samples/pbe/java/serpent-cfb8.raw
new file mode 100644
index 0000000..cfbdd0b
--- /dev/null
+++ b/samples/pbe/java/serpent-cfb8.raw
@@ -0,0 +1 @@
+Salted__�g��h��2v��髢L��
\ No newline at end of file
diff --git a/samples/pbe/java/serpent-ecb.base64 b/samples/pbe/java/serpent-ecb.base64
new file mode 100644
index 0000000..404db36
--- /dev/null
+++ b/samples/pbe/java/serpent-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1958euEvux9tp6qt8zLCDmYDyBVVSTjY88=
diff --git a/samples/pbe/java/serpent-ecb.raw b/samples/pbe/java/serpent-ecb.raw
new file mode 100644
index 0000000..ac78ceb
--- /dev/null
+++ b/samples/pbe/java/serpent-ecb.raw
@@ -0,0 +1 @@
+Salted__ņ��w��X��D]I�<a��S�x
\ No newline at end of file
diff --git a/samples/pbe/java/serpent-ofb.base64 b/samples/pbe/java/serpent-ofb.base64
new file mode 100644
index 0000000..cc9c2ae
--- /dev/null
+++ b/samples/pbe/java/serpent-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/s6i6U5jeXh15/PrVKKpyIRNbuIg==
diff --git a/samples/pbe/java/serpent-ofb.raw b/samples/pbe/java/serpent-ofb.raw
new file mode 100644
index 0000000..9c9db35
--- /dev/null
+++ b/samples/pbe/java/serpent-ofb.raw
@@ -0,0 +1 @@
+Salted__t�"���
����]�j�y��C
\ No newline at end of file
diff --git a/samples/pbe/java/serpent.base64 b/samples/pbe/java/serpent.base64
new file mode 100644
index 0000000..5a21227
--- /dev/null
+++ b/samples/pbe/java/serpent.base64
@@ -0,0 +1 @@
+U2FsdGVkX195qujaNzq14jxKvx+Lw8SHyaLJs4TQ8J0=
diff --git a/samples/pbe/java/serpent.raw b/samples/pbe/java/serpent.raw
new file mode 100644
index 0000000..7aea741
--- /dev/null
+++ b/samples/pbe/java/serpent.raw
@@ -0,0 +1,2 @@
+Salted__�:���7q�;
+����]cr�>
\ No newline at end of file
diff --git a/samples/pbe/java/skipjack-cbc.base64 b/samples/pbe/java/skipjack-cbc.base64
new file mode 100644
index 0000000..4adcdef
--- /dev/null
+++ b/samples/pbe/java/skipjack-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+zMjVYCvOD+ewdBROea+7dkdJFDQQwW0E=
diff --git a/samples/pbe/java/skipjack-cbc.raw b/samples/pbe/java/skipjack-cbc.raw
new file mode 100644
index 0000000..9f8a32c
--- /dev/null
+++ b/samples/pbe/java/skipjack-cbc.raw
@@ -0,0 +1 @@
+Salted__���YN�[��y!�>O�#ذ��Dw
\ No newline at end of file
diff --git a/samples/pbe/java/skipjack-cfb.base64 b/samples/pbe/java/skipjack-cfb.base64
new file mode 100644
index 0000000..45d51f7
--- /dev/null
+++ b/samples/pbe/java/skipjack-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19n4zca8LfA6iiKCnoRiQ/Okw7uww==
diff --git a/samples/pbe/java/skipjack-cfb.raw b/samples/pbe/java/skipjack-cfb.raw
new file mode 100644
index 0000000..30950e0
--- /dev/null
+++ b/samples/pbe/java/skipjack-cfb.raw
@@ -0,0 +1 @@
+Salted__fL��(���i���e�) �
\ No newline at end of file
diff --git a/samples/pbe/java/skipjack-cfb8.base64 b/samples/pbe/java/skipjack-cfb8.base64
new file mode 100644
index 0000000..ffe939f
--- /dev/null
+++ b/samples/pbe/java/skipjack-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18dc5fJxg3eO18jgj+CCBW8bEiBBg==
diff --git a/samples/pbe/java/skipjack-cfb8.raw b/samples/pbe/java/skipjack-cfb8.raw
new file mode 100644
index 0000000..b88eb97
--- /dev/null
+++ b/samples/pbe/java/skipjack-cfb8.raw
@@ -0,0 +1 @@
+Salted__�J{�>�_���t��n7���8�
\ No newline at end of file
diff --git a/samples/pbe/java/skipjack-ecb.base64 b/samples/pbe/java/skipjack-ecb.base64
new file mode 100644
index 0000000..043f64f
--- /dev/null
+++ b/samples/pbe/java/skipjack-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18Twzi0wluhUpj2mqCmsKpBAyG9NW3+9V0=
diff --git a/samples/pbe/java/skipjack-ecb.raw b/samples/pbe/java/skipjack-ecb.raw
new file mode 100644
index 0000000..d70ffe4
--- /dev/null
+++ b/samples/pbe/java/skipjack-ecb.raw
@@ -0,0 +1 @@
+Salted__��ؓCkG]�V�[n,�<���#���
\ No newline at end of file
diff --git a/samples/pbe/java/skipjack-ofb.base64 b/samples/pbe/java/skipjack-ofb.base64
new file mode 100644
index 0000000..185d89f
--- /dev/null
+++ b/samples/pbe/java/skipjack-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19+3i3BJd+8b2P4kc84XE0bvdKynw==
diff --git a/samples/pbe/java/skipjack-ofb.raw b/samples/pbe/java/skipjack-ofb.raw
new file mode 100644
index 0000000..39e4f27
--- /dev/null
+++ b/samples/pbe/java/skipjack-ofb.raw
@@ -0,0 +1 @@
+Salted__�T3�>f��O��B�IN�û
\ No newline at end of file
diff --git a/samples/pbe/java/skipjack.base64 b/samples/pbe/java/skipjack.base64
new file mode 100644
index 0000000..2ae32ac
--- /dev/null
+++ b/samples/pbe/java/skipjack.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+GkkE/WR9HWr/3hK1+f0vCb2EwMPxvNws=
diff --git a/samples/pbe/java/skipjack.raw b/samples/pbe/java/skipjack.raw
new file mode 100644
index 0000000..cf464a1
--- /dev/null
+++ b/samples/pbe/java/skipjack.raw
@@ -0,0 +1 @@
+Salted__�DC����!rɨ���\&94�-k�
\ No newline at end of file
diff --git a/samples/pbe/java/tea-cbc.base64 b/samples/pbe/java/tea-cbc.base64
new file mode 100644
index 0000000..3be186e
--- /dev/null
+++ b/samples/pbe/java/tea-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+N4jlJF5HA4CqXCaLMdgjGr4gCcWcMV6I=
diff --git a/samples/pbe/java/tea-cbc.raw b/samples/pbe/java/tea-cbc.raw
new file mode 100644
index 0000000..15879f1
--- /dev/null
+++ b/samples/pbe/java/tea-cbc.raw
@@ -0,0 +1 @@
+Salted__l�Ư�|àK�t�p�1RO����
\ No newline at end of file
diff --git a/samples/pbe/java/tea-cfb.base64 b/samples/pbe/java/tea-cfb.base64
new file mode 100644
index 0000000..b7c9f91
--- /dev/null
+++ b/samples/pbe/java/tea-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1//9v7c5qa6brx3B1IL8/k3DN9OeQ==
diff --git a/samples/pbe/java/tea-cfb.raw b/samples/pbe/java/tea-cfb.raw
new file mode 100644
index 0000000..5841c0f
Binary files /dev/null and b/samples/pbe/java/tea-cfb.raw differ
diff --git a/samples/pbe/java/tea-cfb8.base64 b/samples/pbe/java/tea-cfb8.base64
new file mode 100644
index 0000000..ac42414
--- /dev/null
+++ b/samples/pbe/java/tea-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18nOAp7ZtTx3hwVuGU7PvXkKXGp2Q==
diff --git a/samples/pbe/java/tea-cfb8.raw b/samples/pbe/java/tea-cfb8.raw
new file mode 100644
index 0000000..c2ec5a1
Binary files /dev/null and b/samples/pbe/java/tea-cfb8.raw differ
diff --git a/samples/pbe/java/tea-ecb.base64 b/samples/pbe/java/tea-ecb.base64
new file mode 100644
index 0000000..b441619
--- /dev/null
+++ b/samples/pbe/java/tea-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18Nw7PSpP/e7N9eqS3VYCLU86sqN+sQs14=
diff --git a/samples/pbe/java/tea-ecb.raw b/samples/pbe/java/tea-ecb.raw
new file mode 100644
index 0000000..382ba5b
--- /dev/null
+++ b/samples/pbe/java/tea-ecb.raw
@@ -0,0 +1 @@
+Salted__����l�o���z;�#��WZ
W
\ No newline at end of file
diff --git a/samples/pbe/java/tea-ofb.base64 b/samples/pbe/java/tea-ofb.base64
new file mode 100644
index 0000000..e2d5026
--- /dev/null
+++ b/samples/pbe/java/tea-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18s9wJ3sg0L3FXWk7UwG2uqu11RgQ==
diff --git a/samples/pbe/java/tea-ofb.raw b/samples/pbe/java/tea-ofb.raw
new file mode 100644
index 0000000..f59f0e4
--- /dev/null
+++ b/samples/pbe/java/tea-ofb.raw
@@ -0,0 +1 @@
+Salted__Ϳ��z�vZ�Ƞ\��P
\ No newline at end of file
diff --git a/samples/pbe/java/tea.base64 b/samples/pbe/java/tea.base64
new file mode 100644
index 0000000..1a5a668
--- /dev/null
+++ b/samples/pbe/java/tea.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+sNDAL8YtooObpna/OX8DLzocbyvmSess=
diff --git a/samples/pbe/java/tea.raw b/samples/pbe/java/tea.raw
new file mode 100644
index 0000000..3e84eb9
--- /dev/null
+++ b/samples/pbe/java/tea.raw
@@ -0,0 +1 @@
+Salted__�[q ��7y��,�"s�`ΖUN��
\ No newline at end of file
diff --git a/samples/pbe/java/twofish-cbc.base64 b/samples/pbe/java/twofish-cbc.base64
new file mode 100644
index 0000000..c54ee99
--- /dev/null
+++ b/samples/pbe/java/twofish-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/NNaFelxgWYsIzd+iFdfvLUZ250HQHQtI=
diff --git a/samples/pbe/java/twofish-cbc.raw b/samples/pbe/java/twofish-cbc.raw
new file mode 100644
index 0000000..d52b77e
--- /dev/null
+++ b/samples/pbe/java/twofish-cbc.raw
@@ -0,0 +1,2 @@
+Salted__|e�l�����;i�
+��3�-�P
\ No newline at end of file
diff --git a/samples/pbe/java/twofish-cfb.base64 b/samples/pbe/java/twofish-cfb.base64
new file mode 100644
index 0000000..4170c55
--- /dev/null
+++ b/samples/pbe/java/twofish-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+j+QSgLHLu0GHIqdiVkVL+yobuaA==
diff --git a/samples/pbe/java/twofish-cfb.raw b/samples/pbe/java/twofish-cfb.raw
new file mode 100644
index 0000000..01ebdf9
--- /dev/null
+++ b/samples/pbe/java/twofish-cfb.raw
@@ -0,0 +1 @@
+Salted__0L/'����p���B5X�6
\ No newline at end of file
diff --git a/samples/pbe/java/twofish-cfb8.base64 b/samples/pbe/java/twofish-cfb8.base64
new file mode 100644
index 0000000..196e081
--- /dev/null
+++ b/samples/pbe/java/twofish-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/XCJv/O97fxn6yxzDAR/9H9C6THQ==
diff --git a/samples/pbe/java/twofish-cfb8.raw b/samples/pbe/java/twofish-cfb8.raw
new file mode 100644
index 0000000..9e1d1ea
Binary files /dev/null and b/samples/pbe/java/twofish-cfb8.raw differ
diff --git a/samples/pbe/java/twofish-ecb.base64 b/samples/pbe/java/twofish-ecb.base64
new file mode 100644
index 0000000..e1d44e7
--- /dev/null
+++ b/samples/pbe/java/twofish-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX195dmAFm0b+1i24kugg4ou+e+HMPufBeuk=
diff --git a/samples/pbe/java/twofish-ecb.raw b/samples/pbe/java/twofish-ecb.raw
new file mode 100644
index 0000000..3182afd
--- /dev/null
+++ b/samples/pbe/java/twofish-ecb.raw
@@ -0,0 +1 @@
+Salted__l��{��ݑl����>q��i.
\ No newline at end of file
diff --git a/samples/pbe/java/twofish-ofb.base64 b/samples/pbe/java/twofish-ofb.base64
new file mode 100644
index 0000000..cced7ad
--- /dev/null
+++ b/samples/pbe/java/twofish-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19kjJcggRCb+18SAEJhmDWvlLMW7A==
diff --git a/samples/pbe/java/twofish-ofb.raw b/samples/pbe/java/twofish-ofb.raw
new file mode 100644
index 0000000..47949d4
--- /dev/null
+++ b/samples/pbe/java/twofish-ofb.raw
@@ -0,0 +1 @@
+Salted__Ϝ
5e���p�qz at -�?��
\ No newline at end of file
diff --git a/samples/pbe/java/twofish.base64 b/samples/pbe/java/twofish.base64
new file mode 100644
index 0000000..c6241b0
--- /dev/null
+++ b/samples/pbe/java/twofish.base64
@@ -0,0 +1 @@
+U2FsdGVkX19CoOnVar7VaeII23EgP4ipAZ2XodKcQF0=
diff --git a/samples/pbe/java/twofish.raw b/samples/pbe/java/twofish.raw
new file mode 100644
index 0000000..bae695e
--- /dev/null
+++ b/samples/pbe/java/twofish.raw
@@ -0,0 +1 @@
+Salted__��\�/ޠX��RK����
R�=�
\ No newline at end of file
diff --git a/samples/pbe/java/xtea-cbc.base64 b/samples/pbe/java/xtea-cbc.base64
new file mode 100644
index 0000000..8ca76da
--- /dev/null
+++ b/samples/pbe/java/xtea-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/VPpaWg1t9N5RSoA8Xg0Yfg7T9nRjNIm4=
diff --git a/samples/pbe/java/xtea-cbc.raw b/samples/pbe/java/xtea-cbc.raw
new file mode 100644
index 0000000..fef76ec
--- /dev/null
+++ b/samples/pbe/java/xtea-cbc.raw
@@ -0,0 +1 @@
+Salted__b�8M�SM����n� uZK���
\ No newline at end of file
diff --git a/samples/pbe/java/xtea-cfb.base64 b/samples/pbe/java/xtea-cfb.base64
new file mode 100644
index 0000000..7b45427
--- /dev/null
+++ b/samples/pbe/java/xtea-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+i85TvEyps5v51kOIKVH7BHrItnA==
diff --git a/samples/pbe/java/xtea-cfb.raw b/samples/pbe/java/xtea-cfb.raw
new file mode 100644
index 0000000..97a140a
--- /dev/null
+++ b/samples/pbe/java/xtea-cfb.raw
@@ -0,0 +1 @@
+Salted__x��g�W1��H�b-�1��
\ No newline at end of file
diff --git a/samples/pbe/java/xtea-cfb8.base64 b/samples/pbe/java/xtea-cfb8.base64
new file mode 100644
index 0000000..21f524e
--- /dev/null
+++ b/samples/pbe/java/xtea-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+fypkqSyuSpEfZKx80/3qRpV22Qg==
diff --git a/samples/pbe/java/xtea-cfb8.raw b/samples/pbe/java/xtea-cfb8.raw
new file mode 100644
index 0000000..0c019e2
Binary files /dev/null and b/samples/pbe/java/xtea-cfb8.raw differ
diff --git a/samples/pbe/java/xtea-ecb.base64 b/samples/pbe/java/xtea-ecb.base64
new file mode 100644
index 0000000..6267b57
--- /dev/null
+++ b/samples/pbe/java/xtea-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19jhcs+AOGFPsPKqKHpCkbqCG75AptTPo0=
diff --git a/samples/pbe/java/xtea-ecb.raw b/samples/pbe/java/xtea-ecb.raw
new file mode 100644
index 0000000..473b409
--- /dev/null
+++ b/samples/pbe/java/xtea-ecb.raw
@@ -0,0 +1 @@
+Salted__[��.�x^�XR@���S�b��
\ No newline at end of file
diff --git a/samples/pbe/java/xtea-ofb.base64 b/samples/pbe/java/xtea-ofb.base64
new file mode 100644
index 0000000..7022151
--- /dev/null
+++ b/samples/pbe/java/xtea-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18tAwVVVBYZnOl6r0cv/RuAtekpXA==
diff --git a/samples/pbe/java/xtea-ofb.raw b/samples/pbe/java/xtea-ofb.raw
new file mode 100644
index 0000000..371e663
--- /dev/null
+++ b/samples/pbe/java/xtea-ofb.raw
@@ -0,0 +1 @@
+Salted__���JC
��G�N��f��nO
\ No newline at end of file
diff --git a/samples/pbe/java/xtea.base64 b/samples/pbe/java/xtea.base64
new file mode 100644
index 0000000..69a1592
--- /dev/null
+++ b/samples/pbe/java/xtea.base64
@@ -0,0 +1 @@
+U2FsdGVkX19j1TDNjQKQw1rE1KFHZns5eBmCvWeX01I=
diff --git a/samples/pbe/java/xtea.raw b/samples/pbe/java/xtea.raw
new file mode 100644
index 0000000..990f578
--- /dev/null
+++ b/samples/pbe/java/xtea.raw
@@ -0,0 +1 @@
+Salted__ɣ��.f�
>*��Q�F�^�Q�
\ No newline at end of file
diff --git a/samples/pbe/openssl/README.txt b/samples/pbe/openssl/README.txt
new file mode 100644
index 0000000..7853cd5
--- /dev/null
+++ b/samples/pbe/openssl/README.txt
@@ -0,0 +1,5 @@
+Password for decrypting any of these files is
+always "changeit".
+
+These files should always decrypt to "Hello World!"
+
diff --git a/samples/pbe/openssl/aes-128-cbc.base64 b/samples/pbe/openssl/aes-128-cbc.base64
new file mode 100644
index 0000000..1632bb7
--- /dev/null
+++ b/samples/pbe/openssl/aes-128-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/CR0ZIen7XtLIONFKXoUUwlU0il7SZIxg=
diff --git a/samples/pbe/openssl/aes-128-cbc.raw b/samples/pbe/openssl/aes-128-cbc.raw
new file mode 100644
index 0000000..1212ec6
Binary files /dev/null and b/samples/pbe/openssl/aes-128-cbc.raw differ
diff --git a/samples/pbe/openssl/aes-128-cfb.base64 b/samples/pbe/openssl/aes-128-cfb.base64
new file mode 100644
index 0000000..8df5dd9
--- /dev/null
+++ b/samples/pbe/openssl/aes-128-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19+j8Eer0XidAqV7fHKVgbwxnDk4A==
diff --git a/samples/pbe/openssl/aes-128-cfb.raw b/samples/pbe/openssl/aes-128-cfb.raw
new file mode 100644
index 0000000..653204a
--- /dev/null
+++ b/samples/pbe/openssl/aes-128-cfb.raw
@@ -0,0 +1 @@
+Salted__�_��U\A��UT�+�!�
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-128-cfb1.base64 b/samples/pbe/openssl/aes-128-cfb1.base64
new file mode 100644
index 0000000..4d00f4a
--- /dev/null
+++ b/samples/pbe/openssl/aes-128-cfb1.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+dSFH+j10CyNLwAAAAAAAAAAAAAA==
diff --git a/samples/pbe/openssl/aes-128-cfb1.raw b/samples/pbe/openssl/aes-128-cfb1.raw
new file mode 100644
index 0000000..484e62b
Binary files /dev/null and b/samples/pbe/openssl/aes-128-cfb1.raw differ
diff --git a/samples/pbe/openssl/aes-128-cfb8.base64 b/samples/pbe/openssl/aes-128-cfb8.base64
new file mode 100644
index 0000000..ad0474e
--- /dev/null
+++ b/samples/pbe/openssl/aes-128-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/OSxAyDPgMDgjTvEekGK61k0rV+Q==
diff --git a/samples/pbe/openssl/aes-128-cfb8.raw b/samples/pbe/openssl/aes-128-cfb8.raw
new file mode 100644
index 0000000..7333a96
--- /dev/null
+++ b/samples/pbe/openssl/aes-128-cfb8.raw
@@ -0,0 +1,2 @@
+Salted__쑶��6�Icp�
+�r}��Y
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-128-ecb.base64 b/samples/pbe/openssl/aes-128-ecb.base64
new file mode 100644
index 0000000..4dc065d
--- /dev/null
+++ b/samples/pbe/openssl/aes-128-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18J3uzuGOGrPMUHrmhquo/97Ps1kOKjvfU=
diff --git a/samples/pbe/openssl/aes-128-ecb.raw b/samples/pbe/openssl/aes-128-ecb.raw
new file mode 100644
index 0000000..631a48a
--- /dev/null
+++ b/samples/pbe/openssl/aes-128-ecb.raw
@@ -0,0 +1 @@
+Salted__�y �؛u$�3��W�
R����h�
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-128-ofb.base64 b/samples/pbe/openssl/aes-128-ofb.base64
new file mode 100644
index 0000000..86459ac
--- /dev/null
+++ b/samples/pbe/openssl/aes-128-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX181diQQs5GELPtmU73gs87cGoGFSg==
diff --git a/samples/pbe/openssl/aes-128-ofb.raw b/samples/pbe/openssl/aes-128-ofb.raw
new file mode 100644
index 0000000..ca86443
--- /dev/null
+++ b/samples/pbe/openssl/aes-128-ofb.raw
@@ -0,0 +1 @@
+Salted__�[�2��H���GC.Z���
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-192-cbc.base64 b/samples/pbe/openssl/aes-192-cbc.base64
new file mode 100644
index 0000000..44c5f3a
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/k5HwF+FgOGOXs9fCuT9hSxEDuIYSblP8=
diff --git a/samples/pbe/openssl/aes-192-cbc.raw b/samples/pbe/openssl/aes-192-cbc.raw
new file mode 100644
index 0000000..e90973f
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-cbc.raw
@@ -0,0 +1 @@
+Salted__u5�&�GG31O�?q�Wt��͂
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-192-cfb.base64 b/samples/pbe/openssl/aes-192-cfb.base64
new file mode 100644
index 0000000..6d914f5
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/KIq1c4o4UvUpKK4s9SJz5jI11qg==
diff --git a/samples/pbe/openssl/aes-192-cfb.raw b/samples/pbe/openssl/aes-192-cfb.raw
new file mode 100644
index 0000000..347e984
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-cfb.raw
@@ -0,0 +1 @@
+Salted__g�f��{�-���]�h�U
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-192-cfb1.base64 b/samples/pbe/openssl/aes-192-cfb1.base64
new file mode 100644
index 0000000..eccff7f
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-cfb1.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/QY2zPpdXFQu3gAAAAAAAAAAAAAA==
diff --git a/samples/pbe/openssl/aes-192-cfb1.raw b/samples/pbe/openssl/aes-192-cfb1.raw
new file mode 100644
index 0000000..659e076
Binary files /dev/null and b/samples/pbe/openssl/aes-192-cfb1.raw differ
diff --git a/samples/pbe/openssl/aes-192-cfb8.base64 b/samples/pbe/openssl/aes-192-cfb8.base64
new file mode 100644
index 0000000..8e04487
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18ORFdc9Vqh1g5OMXEdJTZKJ5Nrug==
diff --git a/samples/pbe/openssl/aes-192-cfb8.raw b/samples/pbe/openssl/aes-192-cfb8.raw
new file mode 100644
index 0000000..85132cc
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-cfb8.raw
@@ -0,0 +1 @@
+Salted__u֟
�ҧ�Ä������Vr
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-192-ecb.base64 b/samples/pbe/openssl/aes-192-ecb.base64
new file mode 100644
index 0000000..95e9676
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18OqCEgXpiMyN4wc4mB+S9tTMLxtkPATgM=
diff --git a/samples/pbe/openssl/aes-192-ecb.raw b/samples/pbe/openssl/aes-192-ecb.raw
new file mode 100644
index 0000000..5fb0ba4
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-ecb.raw
@@ -0,0 +1 @@
+Salted__8��ͺF�v)+QX}��8lZ�S5�
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-192-ofb.base64 b/samples/pbe/openssl/aes-192-ofb.base64
new file mode 100644
index 0000000..0916cb0
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/OuNnbiSdlHOGGT9o6tIG29p+k3g==
diff --git a/samples/pbe/openssl/aes-192-ofb.raw b/samples/pbe/openssl/aes-192-ofb.raw
new file mode 100644
index 0000000..1ac4b1b
--- /dev/null
+++ b/samples/pbe/openssl/aes-192-ofb.raw
@@ -0,0 +1 @@
+Salted__H�'܊���Rp]h��#��a
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-256-cbc.base64 b/samples/pbe/openssl/aes-256-cbc.base64
new file mode 100644
index 0000000..880daac
--- /dev/null
+++ b/samples/pbe/openssl/aes-256-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/cfccZKdAm5MwO9uPkX/p2+WtVIvafIA8=
diff --git a/samples/pbe/openssl/aes-256-cbc.raw b/samples/pbe/openssl/aes-256-cbc.raw
new file mode 100644
index 0000000..e1808d4
--- /dev/null
+++ b/samples/pbe/openssl/aes-256-cbc.raw
@@ -0,0 +1 @@
+Salted__2�,<Kj+�H�:�eȠ¿$�)9)+
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-256-cfb.base64 b/samples/pbe/openssl/aes-256-cfb.base64
new file mode 100644
index 0000000..33d1dd6
--- /dev/null
+++ b/samples/pbe/openssl/aes-256-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19xnj0ssEJbv5hcgr6/57WDT6+lxA==
diff --git a/samples/pbe/openssl/aes-256-cfb.raw b/samples/pbe/openssl/aes-256-cfb.raw
new file mode 100644
index 0000000..ee4f70f
--- /dev/null
+++ b/samples/pbe/openssl/aes-256-cfb.raw
@@ -0,0 +1 @@
+Salted__f�����!��
@�vs�
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-256-cfb1.base64 b/samples/pbe/openssl/aes-256-cfb1.base64
new file mode 100644
index 0000000..965ed83
--- /dev/null
+++ b/samples/pbe/openssl/aes-256-cfb1.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+jQxVlHdV1CqSwAAAAAAAAAAAAAA==
diff --git a/samples/pbe/openssl/aes-256-cfb1.raw b/samples/pbe/openssl/aes-256-cfb1.raw
new file mode 100644
index 0000000..d483aea
Binary files /dev/null and b/samples/pbe/openssl/aes-256-cfb1.raw differ
diff --git a/samples/pbe/openssl/aes-256-cfb8.base64 b/samples/pbe/openssl/aes-256-cfb8.base64
new file mode 100644
index 0000000..14b6174
--- /dev/null
+++ b/samples/pbe/openssl/aes-256-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/vk1JozaSOqDGDIm8vAV6e2hL3Vw==
diff --git a/samples/pbe/openssl/aes-256-cfb8.raw b/samples/pbe/openssl/aes-256-cfb8.raw
new file mode 100644
index 0000000..814fd2e
--- /dev/null
+++ b/samples/pbe/openssl/aes-256-cfb8.raw
@@ -0,0 +1 @@
+Salted__���e��*�� B��5�
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes-256-ecb.base64 b/samples/pbe/openssl/aes-256-ecb.base64
new file mode 100644
index 0000000..e27987d
--- /dev/null
+++ b/samples/pbe/openssl/aes-256-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18EBM0NsnydQq6slUNeyknxvEGAA2QCOgY=
diff --git a/samples/pbe/openssl/aes-256-ecb.raw b/samples/pbe/openssl/aes-256-ecb.raw
new file mode 100644
index 0000000..703bc0e
Binary files /dev/null and b/samples/pbe/openssl/aes-256-ecb.raw differ
diff --git a/samples/pbe/openssl/aes-256-ofb.base64 b/samples/pbe/openssl/aes-256-ofb.base64
new file mode 100644
index 0000000..bbc278c
--- /dev/null
+++ b/samples/pbe/openssl/aes-256-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+C5homVRhjJYpwt6mPV9cVW3vGZw==
diff --git a/samples/pbe/openssl/aes-256-ofb.raw b/samples/pbe/openssl/aes-256-ofb.raw
new file mode 100644
index 0000000..dc1a75b
--- /dev/null
+++ b/samples/pbe/openssl/aes-256-ofb.raw
@@ -0,0 +1 @@
+Salted__
N��<:l��/��������
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes128.base64 b/samples/pbe/openssl/aes128.base64
new file mode 100644
index 0000000..f79f113
--- /dev/null
+++ b/samples/pbe/openssl/aes128.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/5U/WWiPGrmTZRWZPyDHOMKMN5Je/kKbI=
diff --git a/samples/pbe/openssl/aes128.raw b/samples/pbe/openssl/aes128.raw
new file mode 100644
index 0000000..13c9415
Binary files /dev/null and b/samples/pbe/openssl/aes128.raw differ
diff --git a/samples/pbe/openssl/aes192.base64 b/samples/pbe/openssl/aes192.base64
new file mode 100644
index 0000000..ae9b529
--- /dev/null
+++ b/samples/pbe/openssl/aes192.base64
@@ -0,0 +1 @@
+U2FsdGVkX192xm+Zu1nX/gx0WarzSZhjXXNYkkC46Mw=
diff --git a/samples/pbe/openssl/aes192.raw b/samples/pbe/openssl/aes192.raw
new file mode 100644
index 0000000..0f9234e
--- /dev/null
+++ b/samples/pbe/openssl/aes192.raw
@@ -0,0 +1,3 @@
+Salted__��V�Eq
+����
+'�Kyy�
\ No newline at end of file
diff --git a/samples/pbe/openssl/aes256.base64 b/samples/pbe/openssl/aes256.base64
new file mode 100644
index 0000000..94b9d5f
--- /dev/null
+++ b/samples/pbe/openssl/aes256.base64
@@ -0,0 +1 @@
+U2FsdGVkX19ZErtOI0xWaZpeebrblB6HNZSVB4QwbvU=
diff --git a/samples/pbe/openssl/aes256.raw b/samples/pbe/openssl/aes256.raw
new file mode 100644
index 0000000..8c95e24
Binary files /dev/null and b/samples/pbe/openssl/aes256.raw differ
diff --git a/samples/pbe/openssl/bf-cbc.base64 b/samples/pbe/openssl/bf-cbc.base64
new file mode 100644
index 0000000..a315959
--- /dev/null
+++ b/samples/pbe/openssl/bf-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX18BCvjqlyAGSuP+yp4jdcjowm3aEV95ypM=
diff --git a/samples/pbe/openssl/bf-cbc.raw b/samples/pbe/openssl/bf-cbc.raw
new file mode 100644
index 0000000..64011a8
--- /dev/null
+++ b/samples/pbe/openssl/bf-cbc.raw
@@ -0,0 +1 @@
+Salted__
���a߃\�bec��,kH;%X=�
\ No newline at end of file
diff --git a/samples/pbe/openssl/bf-cfb.base64 b/samples/pbe/openssl/bf-cfb.base64
new file mode 100644
index 0000000..735d13b
--- /dev/null
+++ b/samples/pbe/openssl/bf-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+34fmh8JsQX+N3TaSXOnZ2wCmDRQ==
diff --git a/samples/pbe/openssl/bf-cfb.raw b/samples/pbe/openssl/bf-cfb.raw
new file mode 100644
index 0000000..53be327
Binary files /dev/null and b/samples/pbe/openssl/bf-cfb.raw differ
diff --git a/samples/pbe/openssl/bf-ecb.base64 b/samples/pbe/openssl/bf-ecb.base64
new file mode 100644
index 0000000..228042c
--- /dev/null
+++ b/samples/pbe/openssl/bf-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19JnXUueE7stEFnIl75kA0KiJf8PoXw8t8=
diff --git a/samples/pbe/openssl/bf-ecb.raw b/samples/pbe/openssl/bf-ecb.raw
new file mode 100644
index 0000000..57477bd
--- /dev/null
+++ b/samples/pbe/openssl/bf-ecb.raw
@@ -0,0 +1 @@
+Salted__�����3�w7={���@�����<
\ No newline at end of file
diff --git a/samples/pbe/openssl/bf-ofb.base64 b/samples/pbe/openssl/bf-ofb.base64
new file mode 100644
index 0000000..65220e5
--- /dev/null
+++ b/samples/pbe/openssl/bf-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/qY/rlPjfOD14R0xNPzgRWMfw07A==
diff --git a/samples/pbe/openssl/bf-ofb.raw b/samples/pbe/openssl/bf-ofb.raw
new file mode 100644
index 0000000..69fde74
--- /dev/null
+++ b/samples/pbe/openssl/bf-ofb.raw
@@ -0,0 +1 @@
+Salted__�0�-�M�����0*��(�
\ No newline at end of file
diff --git a/samples/pbe/openssl/bf.base64 b/samples/pbe/openssl/bf.base64
new file mode 100644
index 0000000..01788ae
--- /dev/null
+++ b/samples/pbe/openssl/bf.base64
@@ -0,0 +1 @@
+U2FsdGVkX18qjls17bp4yNuuyQ74RlpoY6QqRT9QAkk=
diff --git a/samples/pbe/openssl/bf.raw b/samples/pbe/openssl/bf.raw
new file mode 100644
index 0000000..51edd1a
--- /dev/null
+++ b/samples/pbe/openssl/bf.raw
@@ -0,0 +1 @@
+Salted__��c�����K�������HF
\ No newline at end of file
diff --git a/samples/pbe/openssl/blowfish.base64 b/samples/pbe/openssl/blowfish.base64
new file mode 100644
index 0000000..88fe735
--- /dev/null
+++ b/samples/pbe/openssl/blowfish.base64
@@ -0,0 +1 @@
+U2FsdGVkX18DFToo8Zb5k2/Q6hl6N7OwZotaTEWTrBw=
diff --git a/samples/pbe/openssl/blowfish.raw b/samples/pbe/openssl/blowfish.raw
new file mode 100644
index 0000000..c34fa5f
--- /dev/null
+++ b/samples/pbe/openssl/blowfish.raw
@@ -0,0 +1 @@
+Salted__�w�b{
�R��(~��� 6I:�iW
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-128-cbc.base64 b/samples/pbe/openssl/camellia-128-cbc.base64
new file mode 100644
index 0000000..1b54479
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX191lwXrmRQxE0TrCNbeupylcJZ8VtJv2/M=
diff --git a/samples/pbe/openssl/camellia-128-cbc.raw b/samples/pbe/openssl/camellia-128-cbc.raw
new file mode 100644
index 0000000..6c374a6
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-cbc.raw
@@ -0,0 +1 @@
+Salted__�V�
�T"��O�VI�y:k=�
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-128-cfb.base64 b/samples/pbe/openssl/camellia-128-cfb.base64
new file mode 100644
index 0000000..9df07c4
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19L18gNUQSx/Y+VPZuAf+Ey6dVHIw==
diff --git a/samples/pbe/openssl/camellia-128-cfb.raw b/samples/pbe/openssl/camellia-128-cfb.raw
new file mode 100644
index 0000000..c534d38
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-cfb.raw
@@ -0,0 +1 @@
+Salted__ː��4x�`��U��
��:
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-128-cfb1.base64 b/samples/pbe/openssl/camellia-128-cfb1.base64
new file mode 100644
index 0000000..8b42799
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-cfb1.base64
@@ -0,0 +1 @@
+U2FsdGVkX19Ye+SfFNdm7U5wAAAAAAAAAAAAAA==
diff --git a/samples/pbe/openssl/camellia-128-cfb1.raw b/samples/pbe/openssl/camellia-128-cfb1.raw
new file mode 100644
index 0000000..492135f
Binary files /dev/null and b/samples/pbe/openssl/camellia-128-cfb1.raw differ
diff --git a/samples/pbe/openssl/camellia-128-cfb8.base64 b/samples/pbe/openssl/camellia-128-cfb8.base64
new file mode 100644
index 0000000..6b4b38b
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/ou3Wg0Obl2o0/fa+WwNAF+tyS0w==
diff --git a/samples/pbe/openssl/camellia-128-cfb8.raw b/samples/pbe/openssl/camellia-128-cfb8.raw
new file mode 100644
index 0000000..4d83619
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-cfb8.raw
@@ -0,0 +1 @@
+Salted__��s��
�f�q���
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-128-ecb.base64 b/samples/pbe/openssl/camellia-128-ecb.base64
new file mode 100644
index 0000000..597a7cd
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18AQ2nB+n58DNaX4mwTdbokFdol6VP2Sig=
diff --git a/samples/pbe/openssl/camellia-128-ecb.raw b/samples/pbe/openssl/camellia-128-ecb.raw
new file mode 100644
index 0000000..968b5c3
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-ecb.raw
@@ -0,0 +1 @@
+Salted__+'ș*Z�0�j�ooL��湱 l
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-128-ofb.base64 b/samples/pbe/openssl/camellia-128-ofb.base64
new file mode 100644
index 0000000..e1c76d2
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/mQuHRAAq74ZdRlcfcZTTx17sySg==
diff --git a/samples/pbe/openssl/camellia-128-ofb.raw b/samples/pbe/openssl/camellia-128-ofb.raw
new file mode 100644
index 0000000..594b5a5
--- /dev/null
+++ b/samples/pbe/openssl/camellia-128-ofb.raw
@@ -0,0 +1 @@
+Salted__&r)������M�߾x�01
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-192-cbc.base64 b/samples/pbe/openssl/camellia-192-cbc.base64
new file mode 100644
index 0000000..202059b
--- /dev/null
+++ b/samples/pbe/openssl/camellia-192-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+hcRQ4/yt8SNxOpXHyALH3sLeBJJ3dmd4=
diff --git a/samples/pbe/openssl/camellia-192-cbc.raw b/samples/pbe/openssl/camellia-192-cbc.raw
new file mode 100644
index 0000000..a7bc8ca
--- /dev/null
+++ b/samples/pbe/openssl/camellia-192-cbc.raw
@@ -0,0 +1 @@
+Salted__?)�Uտ�S���
"uTD�S۟��
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-192-cfb.base64 b/samples/pbe/openssl/camellia-192-cfb.base64
new file mode 100644
index 0000000..f6f63e6
--- /dev/null
+++ b/samples/pbe/openssl/camellia-192-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19M//cM++R922+a3AvqtTYN3sD+TA==
diff --git a/samples/pbe/openssl/camellia-192-cfb.raw b/samples/pbe/openssl/camellia-192-cfb.raw
new file mode 100644
index 0000000..6bf189d
--- /dev/null
+++ b/samples/pbe/openssl/camellia-192-cfb.raw
@@ -0,0 +1 @@
+Salted__ê^9��^�q�Y
̹]Xع
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-192-cfb1.base64 b/samples/pbe/openssl/camellia-192-cfb1.base64
new file mode 100644
index 0000000..9769a5e
--- /dev/null
+++ b/samples/pbe/openssl/camellia-192-cfb1.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/hZdJojga9mvBAAAAAAAAAAAAAAA==
diff --git a/samples/pbe/openssl/camellia-192-cfb1.raw b/samples/pbe/openssl/camellia-192-cfb1.raw
new file mode 100644
index 0000000..5cfb273
Binary files /dev/null and b/samples/pbe/openssl/camellia-192-cfb1.raw differ
diff --git a/samples/pbe/openssl/camellia-192-cfb8.base64 b/samples/pbe/openssl/camellia-192-cfb8.base64
new file mode 100644
index 0000000..f4791ee
--- /dev/null
+++ b/samples/pbe/openssl/camellia-192-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+mqlN2aCBpyLgeXRQtqNX90++Jvw==
diff --git a/samples/pbe/openssl/camellia-192-cfb8.raw b/samples/pbe/openssl/camellia-192-cfb8.raw
new file mode 100644
index 0000000..7f9e80e
--- /dev/null
+++ b/samples/pbe/openssl/camellia-192-cfb8.raw
@@ -0,0 +1 @@
+Salted__4���x��/*���+���,
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-192-ecb.base64 b/samples/pbe/openssl/camellia-192-ecb.base64
new file mode 100644
index 0000000..be235fb
--- /dev/null
+++ b/samples/pbe/openssl/camellia-192-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/1ByOMlVpW5gJ+hUEuYBQCf3p21m5hvHw=
diff --git a/samples/pbe/openssl/camellia-192-ecb.raw b/samples/pbe/openssl/camellia-192-ecb.raw
new file mode 100644
index 0000000..6e723d2
--- /dev/null
+++ b/samples/pbe/openssl/camellia-192-ecb.raw
@@ -0,0 +1 @@
+Salted__E�m"k�ؽy��!i�2Df�K
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-192-ofb.base64 b/samples/pbe/openssl/camellia-192-ofb.base64
new file mode 100644
index 0000000..87999b7
--- /dev/null
+++ b/samples/pbe/openssl/camellia-192-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19fDggOe33p5O85aMJg4Ic9Q86QEg==
diff --git a/samples/pbe/openssl/camellia-192-ofb.raw b/samples/pbe/openssl/camellia-192-ofb.raw
new file mode 100644
index 0000000..594b9f8
Binary files /dev/null and b/samples/pbe/openssl/camellia-192-ofb.raw differ
diff --git a/samples/pbe/openssl/camellia-256-cbc.base64 b/samples/pbe/openssl/camellia-256-cbc.base64
new file mode 100644
index 0000000..ed2f582
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+xIS0t1hNR/OB6/3SpUooUlyjAKlwsumY=
diff --git a/samples/pbe/openssl/camellia-256-cbc.raw b/samples/pbe/openssl/camellia-256-cbc.raw
new file mode 100644
index 0000000..c024af7
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-cbc.raw
@@ -0,0 +1 @@
+Salted__�؝b�Q�ǔ�R�W���o
�'�t�W
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-256-cfb.base64 b/samples/pbe/openssl/camellia-256-cfb.base64
new file mode 100644
index 0000000..5b68815
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19iJ77g6jgSSAAP5e/bIe7O6Iq/Sg==
diff --git a/samples/pbe/openssl/camellia-256-cfb.raw b/samples/pbe/openssl/camellia-256-cfb.raw
new file mode 100644
index 0000000..3d15c99
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-cfb.raw
@@ -0,0 +1,2 @@
+Salted__���y�_H�d��
+�Rn�
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-256-cfb1.base64 b/samples/pbe/openssl/camellia-256-cfb1.base64
new file mode 100644
index 0000000..e515ceb
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-cfb1.base64
@@ -0,0 +1 @@
+U2FsdGVkX19Vi0yGB2BogY+AAAAAAAAAAAAAAA==
diff --git a/samples/pbe/openssl/camellia-256-cfb1.raw b/samples/pbe/openssl/camellia-256-cfb1.raw
new file mode 100644
index 0000000..48ad2b7
Binary files /dev/null and b/samples/pbe/openssl/camellia-256-cfb1.raw differ
diff --git a/samples/pbe/openssl/camellia-256-cfb8.base64 b/samples/pbe/openssl/camellia-256-cfb8.base64
new file mode 100644
index 0000000..08a553e
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX191muRJTezui22cEiJu1qyPJ2FSHw==
diff --git a/samples/pbe/openssl/camellia-256-cfb8.raw b/samples/pbe/openssl/camellia-256-cfb8.raw
new file mode 100644
index 0000000..205ba19
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-cfb8.raw
@@ -0,0 +1 @@
+Salted__94��:�آ����m���^
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-256-ecb.base64 b/samples/pbe/openssl/camellia-256-ecb.base64
new file mode 100644
index 0000000..254449c
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX199maVIVUYl/KMF5PrquhZxKT0JzrtYhAE=
diff --git a/samples/pbe/openssl/camellia-256-ecb.raw b/samples/pbe/openssl/camellia-256-ecb.raw
new file mode 100644
index 0000000..007f44b
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-ecb.raw
@@ -0,0 +1 @@
+Salted__����H�}��H
�Q�<�?��H:��
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia-256-ofb.base64 b/samples/pbe/openssl/camellia-256-ofb.base64
new file mode 100644
index 0000000..dc89309
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18Bp7PrPYIPJ8C6M/MHVO9p6tdNsw==
diff --git a/samples/pbe/openssl/camellia-256-ofb.raw b/samples/pbe/openssl/camellia-256-ofb.raw
new file mode 100644
index 0000000..d9b84d7
--- /dev/null
+++ b/samples/pbe/openssl/camellia-256-ofb.raw
@@ -0,0 +1 @@
+Salted__Plc fe �dۄ��1�
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia128.base64 b/samples/pbe/openssl/camellia128.base64
new file mode 100644
index 0000000..19e6457
--- /dev/null
+++ b/samples/pbe/openssl/camellia128.base64
@@ -0,0 +1 @@
+U2FsdGVkX197osioYPDn0yIAybXX/iMReMRmK2x+LxU=
diff --git a/samples/pbe/openssl/camellia128.raw b/samples/pbe/openssl/camellia128.raw
new file mode 100644
index 0000000..a2f64eb
--- /dev/null
+++ b/samples/pbe/openssl/camellia128.raw
@@ -0,0 +1 @@
+Salted__|з-ڽâ��&�Ծ�ڒ
��
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia192.base64 b/samples/pbe/openssl/camellia192.base64
new file mode 100644
index 0000000..dfd0702
--- /dev/null
+++ b/samples/pbe/openssl/camellia192.base64
@@ -0,0 +1 @@
+U2FsdGVkX19kg7hmBLX4JWKGyLehExxM3FGoZ4XAfU0=
diff --git a/samples/pbe/openssl/camellia192.raw b/samples/pbe/openssl/camellia192.raw
new file mode 100644
index 0000000..5741fe7
--- /dev/null
+++ b/samples/pbe/openssl/camellia192.raw
@@ -0,0 +1 @@
+Salted__�̝q����V�.�$a�/��/[|
\ No newline at end of file
diff --git a/samples/pbe/openssl/camellia256.base64 b/samples/pbe/openssl/camellia256.base64
new file mode 100644
index 0000000..91136bd
--- /dev/null
+++ b/samples/pbe/openssl/camellia256.base64
@@ -0,0 +1 @@
+U2FsdGVkX18ehKu2fdaQXkfnCZH9lwMev/u+fenDBxI=
diff --git a/samples/pbe/openssl/camellia256.raw b/samples/pbe/openssl/camellia256.raw
new file mode 100644
index 0000000..fca569e
Binary files /dev/null and b/samples/pbe/openssl/camellia256.raw differ
diff --git a/samples/pbe/openssl/cast-cbc.base64 b/samples/pbe/openssl/cast-cbc.base64
new file mode 100644
index 0000000..aee53d5
--- /dev/null
+++ b/samples/pbe/openssl/cast-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/fJ/tvKiV81WYcgGVM1Frl2fiI5VLK4Es=
diff --git a/samples/pbe/openssl/cast-cbc.raw b/samples/pbe/openssl/cast-cbc.raw
new file mode 100644
index 0000000..b8a2de3
Binary files /dev/null and b/samples/pbe/openssl/cast-cbc.raw differ
diff --git a/samples/pbe/openssl/cast.base64 b/samples/pbe/openssl/cast.base64
new file mode 100644
index 0000000..8cce378
--- /dev/null
+++ b/samples/pbe/openssl/cast.base64
@@ -0,0 +1 @@
+U2FsdGVkX18qMeuo5SMoJooS+Pt8lZGrLFnBTyll78U=
diff --git a/samples/pbe/openssl/cast.raw b/samples/pbe/openssl/cast.raw
new file mode 100644
index 0000000..ced1e03
--- /dev/null
+++ b/samples/pbe/openssl/cast.raw
@@ -0,0 +1 @@
+Salted__{A����a83��Ȱ���z�I̕
�
\ No newline at end of file
diff --git a/samples/pbe/openssl/cast5-cbc.base64 b/samples/pbe/openssl/cast5-cbc.base64
new file mode 100644
index 0000000..44a28a7
--- /dev/null
+++ b/samples/pbe/openssl/cast5-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+kjmfi9mnlAwiucUKi8XXfh3Z117F3uAY=
diff --git a/samples/pbe/openssl/cast5-cbc.raw b/samples/pbe/openssl/cast5-cbc.raw
new file mode 100644
index 0000000..f7243b3
--- /dev/null
+++ b/samples/pbe/openssl/cast5-cbc.raw
@@ -0,0 +1,2 @@
+Salted__���"�U
+�U(��&��4�zd�%
\ No newline at end of file
diff --git a/samples/pbe/openssl/cast5-cfb.base64 b/samples/pbe/openssl/cast5-cfb.base64
new file mode 100644
index 0000000..ccc5bca
--- /dev/null
+++ b/samples/pbe/openssl/cast5-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+TNbM051700oXXbN9XQ8JaH5vu8Q==
diff --git a/samples/pbe/openssl/cast5-cfb.raw b/samples/pbe/openssl/cast5-cfb.raw
new file mode 100644
index 0000000..3cb7503
--- /dev/null
+++ b/samples/pbe/openssl/cast5-cfb.raw
@@ -0,0 +1 @@
+Salted__�~��}]�ٕ668�-�gy��
\ No newline at end of file
diff --git a/samples/pbe/openssl/cast5-ecb.base64 b/samples/pbe/openssl/cast5-ecb.base64
new file mode 100644
index 0000000..248caff
--- /dev/null
+++ b/samples/pbe/openssl/cast5-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/SSY+Kvv1K5sXb+F8webiiprWDK4eVnNQ=
diff --git a/samples/pbe/openssl/cast5-ecb.raw b/samples/pbe/openssl/cast5-ecb.raw
new file mode 100644
index 0000000..af6aee5
--- /dev/null
+++ b/samples/pbe/openssl/cast5-ecb.raw
@@ -0,0 +1 @@
+Salted__�*��%�����D
_,�t�0��*
\ No newline at end of file
diff --git a/samples/pbe/openssl/cast5-ofb.base64 b/samples/pbe/openssl/cast5-ofb.base64
new file mode 100644
index 0000000..1fe008a
--- /dev/null
+++ b/samples/pbe/openssl/cast5-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1800C0YbS7y8aO10eGQB5pMPkxpHA==
diff --git a/samples/pbe/openssl/cast5-ofb.raw b/samples/pbe/openssl/cast5-ofb.raw
new file mode 100644
index 0000000..f42345c
--- /dev/null
+++ b/samples/pbe/openssl/cast5-ofb.raw
@@ -0,0 +1,2 @@
+Salted__���~K���
+�!G6uuY�
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-cbc.base64 b/samples/pbe/openssl/des-cbc.base64
new file mode 100644
index 0000000..264b65a
--- /dev/null
+++ b/samples/pbe/openssl/des-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19tMkO5uwIwhT233JWfPEA34ZbDTyeg+x8=
diff --git a/samples/pbe/openssl/des-cbc.raw b/samples/pbe/openssl/des-cbc.raw
new file mode 100644
index 0000000..84888b5
--- /dev/null
+++ b/samples/pbe/openssl/des-cbc.raw
@@ -0,0 +1 @@
+Salted__4�YjU8�d�7׃k�jâLr(
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-cfb.base64 b/samples/pbe/openssl/des-cfb.base64
new file mode 100644
index 0000000..1941567
--- /dev/null
+++ b/samples/pbe/openssl/des-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+bar1f5XcN2jRf4uGp1tVS75anLw==
diff --git a/samples/pbe/openssl/des-cfb.raw b/samples/pbe/openssl/des-cfb.raw
new file mode 100644
index 0000000..2c8eb57
--- /dev/null
+++ b/samples/pbe/openssl/des-cfb.raw
@@ -0,0 +1 @@
+Salted__�N��m��b��U+"��.
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-cfb1.base64 b/samples/pbe/openssl/des-cfb1.base64
new file mode 100644
index 0000000..3df3081
--- /dev/null
+++ b/samples/pbe/openssl/des-cfb1.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+q/8Tq539aM3mwAAAAAAAAAAAAAA==
diff --git a/samples/pbe/openssl/des-cfb1.raw b/samples/pbe/openssl/des-cfb1.raw
new file mode 100644
index 0000000..fa6ce59
Binary files /dev/null and b/samples/pbe/openssl/des-cfb1.raw differ
diff --git a/samples/pbe/openssl/des-cfb8.base64 b/samples/pbe/openssl/des-cfb8.base64
new file mode 100644
index 0000000..5e1c3e5
--- /dev/null
+++ b/samples/pbe/openssl/des-cfb8.base64
@@ -0,0 +1 @@
+U2FsdGVkX18j8MF73qCoRMNpfhNZvVM1fu4r8w==
diff --git a/samples/pbe/openssl/des-cfb8.raw b/samples/pbe/openssl/des-cfb8.raw
new file mode 100644
index 0000000..b2962ba
--- /dev/null
+++ b/samples/pbe/openssl/des-cfb8.raw
@@ -0,0 +1 @@
+Salted__'����X>�~G�P�]C��
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-ecb.base64 b/samples/pbe/openssl/des-ecb.base64
new file mode 100644
index 0000000..e733bd4
--- /dev/null
+++ b/samples/pbe/openssl/des-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19Wcc1l+wXUlVCAWcfwjT84SxciiCAE/2Y=
diff --git a/samples/pbe/openssl/des-ecb.raw b/samples/pbe/openssl/des-ecb.raw
new file mode 100644
index 0000000..0ddd6e9
Binary files /dev/null and b/samples/pbe/openssl/des-ecb.raw differ
diff --git a/samples/pbe/openssl/des-ede-cbc.base64 b/samples/pbe/openssl/des-ede-cbc.base64
new file mode 100644
index 0000000..6870ed5
--- /dev/null
+++ b/samples/pbe/openssl/des-ede-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19CwfOjnni1RYXijIQlic2fCBGhM0Ym2Lk=
diff --git a/samples/pbe/openssl/des-ede-cbc.raw b/samples/pbe/openssl/des-ede-cbc.raw
new file mode 100644
index 0000000..a06630e
--- /dev/null
+++ b/samples/pbe/openssl/des-ede-cbc.raw
@@ -0,0 +1 @@
+Salted__bMqD�nI�hK)cs�9��j���u
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-ede-cfb.base64 b/samples/pbe/openssl/des-ede-cfb.base64
new file mode 100644
index 0000000..5eec8f9
--- /dev/null
+++ b/samples/pbe/openssl/des-ede-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18PsrrurG1uhCD2QkpLZYUeEtH1Vw==
diff --git a/samples/pbe/openssl/des-ede-cfb.raw b/samples/pbe/openssl/des-ede-cfb.raw
new file mode 100644
index 0000000..6580777
--- /dev/null
+++ b/samples/pbe/openssl/des-ede-cfb.raw
@@ -0,0 +1 @@
+Salted__��.���A�YX�hcłV���
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-ede-ofb.base64 b/samples/pbe/openssl/des-ede-ofb.base64
new file mode 100644
index 0000000..39bb1fa
--- /dev/null
+++ b/samples/pbe/openssl/des-ede-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/rhq/q4yJ1ffD6Ghc69IWn4GsqcA==
diff --git a/samples/pbe/openssl/des-ede-ofb.raw b/samples/pbe/openssl/des-ede-ofb.raw
new file mode 100644
index 0000000..81a7523
--- /dev/null
+++ b/samples/pbe/openssl/des-ede-ofb.raw
@@ -0,0 +1 @@
+Salted__��4HV6��y%VY���{KL
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-ede.base64 b/samples/pbe/openssl/des-ede.base64
new file mode 100644
index 0000000..ac9c3be
--- /dev/null
+++ b/samples/pbe/openssl/des-ede.base64
@@ -0,0 +1 @@
+U2FsdGVkX18r2UMwx1RbibeBdeNvjm9YOszrJZoXRIE=
diff --git a/samples/pbe/openssl/des-ede.raw b/samples/pbe/openssl/des-ede.raw
new file mode 100644
index 0000000..b1f7dd4
--- /dev/null
+++ b/samples/pbe/openssl/des-ede.raw
@@ -0,0 +1 @@
+Salted__��<p?M��ĝ��`ǽ gTx���
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-ede3-cbc.base64 b/samples/pbe/openssl/des-ede3-cbc.base64
new file mode 100644
index 0000000..de2152d
--- /dev/null
+++ b/samples/pbe/openssl/des-ede3-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX18jj2kcvpaYme9ZFVUXQeeMX7OM15bPVbI=
diff --git a/samples/pbe/openssl/des-ede3-cbc.raw b/samples/pbe/openssl/des-ede3-cbc.raw
new file mode 100644
index 0000000..956423f
--- /dev/null
+++ b/samples/pbe/openssl/des-ede3-cbc.raw
@@ -0,0 +1,2 @@
+Salted__/��Y/�����FQ�p$o�
+¨
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-ede3-cfb.base64 b/samples/pbe/openssl/des-ede3-cfb.base64
new file mode 100644
index 0000000..bc44959
--- /dev/null
+++ b/samples/pbe/openssl/des-ede3-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19I7oHyglbIqCQDbHBukOaaRPjauw==
diff --git a/samples/pbe/openssl/des-ede3-cfb.raw b/samples/pbe/openssl/des-ede3-cfb.raw
new file mode 100644
index 0000000..9a616ff
--- /dev/null
+++ b/samples/pbe/openssl/des-ede3-cfb.raw
@@ -0,0 +1 @@
+Salted__a'�
7MY�z|N/�с�
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-ede3-ofb.base64 b/samples/pbe/openssl/des-ede3-ofb.base64
new file mode 100644
index 0000000..cb1f162
--- /dev/null
+++ b/samples/pbe/openssl/des-ede3-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19O+uqDgSn48JKfd1ZmT/EW9DSfWQ==
diff --git a/samples/pbe/openssl/des-ede3-ofb.raw b/samples/pbe/openssl/des-ede3-ofb.raw
new file mode 100644
index 0000000..2aaee9e
--- /dev/null
+++ b/samples/pbe/openssl/des-ede3-ofb.raw
@@ -0,0 +1 @@
+Salted__KjTO�7�t��
��_��
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-ede3.base64 b/samples/pbe/openssl/des-ede3.base64
new file mode 100644
index 0000000..3ad36d8
--- /dev/null
+++ b/samples/pbe/openssl/des-ede3.base64
@@ -0,0 +1 @@
+U2FsdGVkX193v6U3qbRyleGYQ+3nf3vgubY8Mt7HzEc=
diff --git a/samples/pbe/openssl/des-ede3.raw b/samples/pbe/openssl/des-ede3.raw
new file mode 100644
index 0000000..3e73552
--- /dev/null
+++ b/samples/pbe/openssl/des-ede3.raw
@@ -0,0 +1 @@
+Salted__�uݡ��q�:u��V݉|�Elaf�
\ No newline at end of file
diff --git a/samples/pbe/openssl/des-ofb.base64 b/samples/pbe/openssl/des-ofb.base64
new file mode 100644
index 0000000..128aec2
--- /dev/null
+++ b/samples/pbe/openssl/des-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX192vJ3lZfCnhYIFA+wrnKArDflCUg==
diff --git a/samples/pbe/openssl/des-ofb.raw b/samples/pbe/openssl/des-ofb.raw
new file mode 100644
index 0000000..07522db
--- /dev/null
+++ b/samples/pbe/openssl/des-ofb.raw
@@ -0,0 +1 @@
+Salted__K(�Px
pm�o�Ki�vJ1�
\ No newline at end of file
diff --git a/samples/pbe/openssl/des.base64 b/samples/pbe/openssl/des.base64
new file mode 100644
index 0000000..0a49602
--- /dev/null
+++ b/samples/pbe/openssl/des.base64
@@ -0,0 +1 @@
+U2FsdGVkX19zPRX+p1hN8OdiT/721hQELF0qPM/BrZQ=
diff --git a/samples/pbe/openssl/des.raw b/samples/pbe/openssl/des.raw
new file mode 100644
index 0000000..e8f603f
--- /dev/null
+++ b/samples/pbe/openssl/des.raw
@@ -0,0 +1 @@
+Salted__�u��
G8����`��M�D*F/$
\ No newline at end of file
diff --git a/samples/pbe/openssl/des3.base64 b/samples/pbe/openssl/des3.base64
new file mode 100644
index 0000000..5c316cc
--- /dev/null
+++ b/samples/pbe/openssl/des3.base64
@@ -0,0 +1 @@
+U2FsdGVkX19YbvQFfBFxGlJc2AuPkALt+lhOkLfiuBA=
diff --git a/samples/pbe/openssl/des3.raw b/samples/pbe/openssl/des3.raw
new file mode 100644
index 0000000..eb1c405
--- /dev/null
+++ b/samples/pbe/openssl/des3.raw
@@ -0,0 +1 @@
+Salted__�A����`�L�&�+=/<2Ǥ���
\ No newline at end of file
diff --git a/samples/pbe/openssl/idea-cbc.base64 b/samples/pbe/openssl/idea-cbc.base64
new file mode 100644
index 0000000..1a02484
--- /dev/null
+++ b/samples/pbe/openssl/idea-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX18anz5GbGQC3cEYSpxQJpP7adc2pierOGk=
diff --git a/samples/pbe/openssl/idea-cbc.raw b/samples/pbe/openssl/idea-cbc.raw
new file mode 100644
index 0000000..ed7621c
--- /dev/null
+++ b/samples/pbe/openssl/idea-cbc.raw
@@ -0,0 +1 @@
+Salted__���CU�/Ud�6J��vzL�
ղd�
\ No newline at end of file
diff --git a/samples/pbe/openssl/idea-cfb.base64 b/samples/pbe/openssl/idea-cfb.base64
new file mode 100644
index 0000000..87b3b73
--- /dev/null
+++ b/samples/pbe/openssl/idea-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19WEa+hCPUXsXw1cQcOxuhFKZsTYA==
diff --git a/samples/pbe/openssl/idea-cfb.raw b/samples/pbe/openssl/idea-cfb.raw
new file mode 100644
index 0000000..9c43fda
--- /dev/null
+++ b/samples/pbe/openssl/idea-cfb.raw
@@ -0,0 +1 @@
+Salted__�L[��ߩ�ߛu���h���9
\ No newline at end of file
diff --git a/samples/pbe/openssl/idea-ecb.base64 b/samples/pbe/openssl/idea-ecb.base64
new file mode 100644
index 0000000..cf252fb
--- /dev/null
+++ b/samples/pbe/openssl/idea-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX192rke++eIbThteXe01uv4EAkShDnmCkfQ=
diff --git a/samples/pbe/openssl/idea-ecb.raw b/samples/pbe/openssl/idea-ecb.raw
new file mode 100644
index 0000000..2e5dec9
--- /dev/null
+++ b/samples/pbe/openssl/idea-ecb.raw
@@ -0,0 +1 @@
+Salted__Qt��Ґ鲥+��٤<�?���\�
\ No newline at end of file
diff --git a/samples/pbe/openssl/idea-ofb.base64 b/samples/pbe/openssl/idea-ofb.base64
new file mode 100644
index 0000000..71f1ae8
--- /dev/null
+++ b/samples/pbe/openssl/idea-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19Oo4w9AlD0tpEySsbAkOjLdswl1A==
diff --git a/samples/pbe/openssl/idea-ofb.raw b/samples/pbe/openssl/idea-ofb.raw
new file mode 100644
index 0000000..80dad7d
--- /dev/null
+++ b/samples/pbe/openssl/idea-ofb.raw
@@ -0,0 +1 @@
+Salted__���S��UKļEذ�
�/�
\ No newline at end of file
diff --git a/samples/pbe/openssl/idea.base64 b/samples/pbe/openssl/idea.base64
new file mode 100644
index 0000000..99f5907
--- /dev/null
+++ b/samples/pbe/openssl/idea.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/NG2JQ8i+waaovzgmxYzKJAw8r9XYnR2Q=
diff --git a/samples/pbe/openssl/idea.raw b/samples/pbe/openssl/idea.raw
new file mode 100644
index 0000000..9e5e848
--- /dev/null
+++ b/samples/pbe/openssl/idea.raw
@@ -0,0 +1 @@
+Salted__���2p��ε�p��R��
u����
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc2-40-cbc.base64 b/samples/pbe/openssl/rc2-40-cbc.base64
new file mode 100644
index 0000000..9415335
--- /dev/null
+++ b/samples/pbe/openssl/rc2-40-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+Dkr+tjgpPtlo+jpfdPAWpTkV88yzXaM4=
diff --git a/samples/pbe/openssl/rc2-40-cbc.raw b/samples/pbe/openssl/rc2-40-cbc.raw
new file mode 100644
index 0000000..c17e87a
--- /dev/null
+++ b/samples/pbe/openssl/rc2-40-cbc.raw
@@ -0,0 +1 @@
+Salted__�q���
�=�:�U㩣�2
�
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc2-64-cbc.base64 b/samples/pbe/openssl/rc2-64-cbc.base64
new file mode 100644
index 0000000..5b5b232
--- /dev/null
+++ b/samples/pbe/openssl/rc2-64-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+3+4JXs1/XiSH2fB9mn1yqU8qdonwvl+o=
diff --git a/samples/pbe/openssl/rc2-64-cbc.raw b/samples/pbe/openssl/rc2-64-cbc.raw
new file mode 100644
index 0000000..b9c08ee
--- /dev/null
+++ b/samples/pbe/openssl/rc2-64-cbc.raw
@@ -0,0 +1 @@
+Salted__��>�f�
x
��<�����L
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc2-cbc.base64 b/samples/pbe/openssl/rc2-cbc.base64
new file mode 100644
index 0000000..fbcde0e
--- /dev/null
+++ b/samples/pbe/openssl/rc2-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX19O/CBHf3CpY8+jvQkw0Tq2czsnICJOv+A=
diff --git a/samples/pbe/openssl/rc2-cbc.raw b/samples/pbe/openssl/rc2-cbc.raw
new file mode 100644
index 0000000..d5200c6
--- /dev/null
+++ b/samples/pbe/openssl/rc2-cbc.raw
@@ -0,0 +1 @@
+Salted__�bZX4��5f���4����s��
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc2-cfb.base64 b/samples/pbe/openssl/rc2-cfb.base64
new file mode 100644
index 0000000..7952786
--- /dev/null
+++ b/samples/pbe/openssl/rc2-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+JuIje5xmEnRsCsmwaWTYgjVVqKw==
diff --git a/samples/pbe/openssl/rc2-cfb.raw b/samples/pbe/openssl/rc2-cfb.raw
new file mode 100644
index 0000000..7aa1960
--- /dev/null
+++ b/samples/pbe/openssl/rc2-cfb.raw
@@ -0,0 +1 @@
+Salted__���*� ֻo����F9
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc2-ecb.base64 b/samples/pbe/openssl/rc2-ecb.base64
new file mode 100644
index 0000000..208b26f
--- /dev/null
+++ b/samples/pbe/openssl/rc2-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX1/uCJVscD2CrMxyEtpyqI7D4mFtNj3hsig=
diff --git a/samples/pbe/openssl/rc2-ecb.raw b/samples/pbe/openssl/rc2-ecb.raw
new file mode 100644
index 0000000..9f9e117
--- /dev/null
+++ b/samples/pbe/openssl/rc2-ecb.raw
@@ -0,0 +1 @@
+Salted__���x]Cb�V���U�g�I��E
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc2-ofb.base64 b/samples/pbe/openssl/rc2-ofb.base64
new file mode 100644
index 0000000..1b575c3
--- /dev/null
+++ b/samples/pbe/openssl/rc2-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19iLfApzAcq690yVAy0D5IZjybZ9Q==
diff --git a/samples/pbe/openssl/rc2-ofb.raw b/samples/pbe/openssl/rc2-ofb.raw
new file mode 100644
index 0000000..28fc695
--- /dev/null
+++ b/samples/pbe/openssl/rc2-ofb.raw
@@ -0,0 +1 @@
+Salted__泷>@Rp2[l������
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc2.base64 b/samples/pbe/openssl/rc2.base64
new file mode 100644
index 0000000..fe79ed1
--- /dev/null
+++ b/samples/pbe/openssl/rc2.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+W2lM2oWECxc+df8bRWRjjQAZWgHyK0TE=
diff --git a/samples/pbe/openssl/rc2.raw b/samples/pbe/openssl/rc2.raw
new file mode 100644
index 0000000..376a092
--- /dev/null
+++ b/samples/pbe/openssl/rc2.raw
@@ -0,0 +1 @@
+Salted__r���阙t1����o9
�x4O
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc4-40.base64 b/samples/pbe/openssl/rc4-40.base64
new file mode 100644
index 0000000..6623b2d
--- /dev/null
+++ b/samples/pbe/openssl/rc4-40.base64
@@ -0,0 +1 @@
+U2FsdGVkX19tJLA4MdMspjkJ9yV98jm4ZEH4LA==
diff --git a/samples/pbe/openssl/rc4-40.raw b/samples/pbe/openssl/rc4-40.raw
new file mode 100644
index 0000000..cc3b9ac
--- /dev/null
+++ b/samples/pbe/openssl/rc4-40.raw
@@ -0,0 +1 @@
+Salted__%�°SⲨ��7�#��"��
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc4.base64 b/samples/pbe/openssl/rc4.base64
new file mode 100644
index 0000000..6653092
--- /dev/null
+++ b/samples/pbe/openssl/rc4.base64
@@ -0,0 +1 @@
+U2FsdGVkX182oCiqgQ41HapT14y1GjgXQW+xTw==
diff --git a/samples/pbe/openssl/rc4.raw b/samples/pbe/openssl/rc4.raw
new file mode 100644
index 0000000..e0774e7
--- /dev/null
+++ b/samples/pbe/openssl/rc4.raw
@@ -0,0 +1 @@
+Salted__�t4Z/�ck�ء�{�"Yp�
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc5-cbc.base64 b/samples/pbe/openssl/rc5-cbc.base64
new file mode 100644
index 0000000..8ede98d
--- /dev/null
+++ b/samples/pbe/openssl/rc5-cbc.base64
@@ -0,0 +1 @@
+U2FsdGVkX1984SHjF+Gnmpg7mzTZcUatW+a4AbICOJ0=
diff --git a/samples/pbe/openssl/rc5-cbc.raw b/samples/pbe/openssl/rc5-cbc.raw
new file mode 100644
index 0000000..fd2070f
--- /dev/null
+++ b/samples/pbe/openssl/rc5-cbc.raw
@@ -0,0 +1 @@
+Salted__Vv�'�C�Dn�J�T��p�O�`c
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc5-cfb.base64 b/samples/pbe/openssl/rc5-cfb.base64
new file mode 100644
index 0000000..3bba7cb
--- /dev/null
+++ b/samples/pbe/openssl/rc5-cfb.base64
@@ -0,0 +1 @@
+U2FsdGVkX19S/C6iCDSQ3z9Tuvs1mLppmLIrKw==
diff --git a/samples/pbe/openssl/rc5-cfb.raw b/samples/pbe/openssl/rc5-cfb.raw
new file mode 100644
index 0000000..12c626e
--- /dev/null
+++ b/samples/pbe/openssl/rc5-cfb.raw
@@ -0,0 +1 @@
+Salted__����>Ƨ��~�+�lz�����
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc5-ecb.base64 b/samples/pbe/openssl/rc5-ecb.base64
new file mode 100644
index 0000000..118973a
--- /dev/null
+++ b/samples/pbe/openssl/rc5-ecb.base64
@@ -0,0 +1 @@
+U2FsdGVkX18bkW6/nLaP0zItEAKqgnmMnJ1oquul/tw=
diff --git a/samples/pbe/openssl/rc5-ecb.raw b/samples/pbe/openssl/rc5-ecb.raw
new file mode 100644
index 0000000..4e7963b
--- /dev/null
+++ b/samples/pbe/openssl/rc5-ecb.raw
@@ -0,0 +1 @@
+Salted__������F�G��@��Pyw
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc5-ofb.base64 b/samples/pbe/openssl/rc5-ofb.base64
new file mode 100644
index 0000000..ddbb752
--- /dev/null
+++ b/samples/pbe/openssl/rc5-ofb.base64
@@ -0,0 +1 @@
+U2FsdGVkX188hLLVFYY9QjWngoLlMX1ziLhd0Q==
diff --git a/samples/pbe/openssl/rc5-ofb.raw b/samples/pbe/openssl/rc5-ofb.raw
new file mode 100644
index 0000000..f547846
--- /dev/null
+++ b/samples/pbe/openssl/rc5-ofb.raw
@@ -0,0 +1 @@
+Salted__�*��@bҫ���K��]e����
\ No newline at end of file
diff --git a/samples/pbe/openssl/rc5.base64 b/samples/pbe/openssl/rc5.base64
new file mode 100644
index 0000000..78dbf97
--- /dev/null
+++ b/samples/pbe/openssl/rc5.base64
@@ -0,0 +1 @@
+U2FsdGVkX1+XyN0T6HGqi3prs1uD91+BIG3RIaqJYxo=
diff --git a/samples/pbe/openssl/rc5.raw b/samples/pbe/openssl/rc5.raw
new file mode 100644
index 0000000..710fae7
--- /dev/null
+++ b/samples/pbe/openssl/rc5.raw
@@ -0,0 +1 @@
+Salted__�yx����HvA���ɗ�W!B�ǣ
\ No newline at end of file
diff --git a/samples/pkcs12/pkcs12_client_cert.p12 b/samples/pkcs12/pkcs12_client_cert.p12
new file mode 100644
index 0000000..206b9cc
Binary files /dev/null and b/samples/pkcs12/pkcs12_client_cert.p12 differ
diff --git a/samples/pkcs12/pkcs12_client_cert.pem b/samples/pkcs12/pkcs12_client_cert.pem
new file mode 100644
index 0000000..f45a4d2
--- /dev/null
+++ b/samples/pkcs12/pkcs12_client_cert.pem
@@ -0,0 +1,94 @@
+Bag Attributes
+ localKeyID: 63 5B 15 F0 27 F2 03 31 C2 A3 21 65 54 08 FB EA 03 B4 C1 D7
+ friendlyName: commons-ssl demo certificate
+subject=/C=CA/ST=BC/L=Vancouver/O=www.cucbc.com/OU=commons_ssl/CN=demo_certificate/emailAddress=juliusdavies at gmail.com
+issuer=/C=CA/ST=BC/L=Vancouver/O=www.cucbc.com/OU=commons_ssl/CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+-----BEGIN CERTIFICATE-----
+MIIEQDCCAyigAwIBAgIJAIz+EYMBU6Z/MA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTEwNTIxNTIzN1oXDTA3MTEwNTIxNTIzN1owgZ4x
+CzAJBgNVBAYTAkNBMQswCQYDVQQIEwJCQzESMBAGA1UEBxMJVmFuY291dmVyMRYw
+FAYDVQQKEw13d3cuY3VjYmMuY29tMRQwEgYDVQQLFAtjb21tb25zX3NzbDEZMBcG
+A1UEAxQQZGVtb19jZXJ0aWZpY2F0ZTElMCMGCSqGSIb3DQEJARYWanVsaXVzZGF2
+aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhj
+r5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2BlYho4O84
+X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRyzerA/Ztr
+lUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY07hNKXAb
+2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8BqnGd87x
+QU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiVJTxpTKqy
+m93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0E
+HxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFJ8Ud78/
+OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNSyoemDT4N
+MA0GCSqGSIb3DQEBBQUAA4IBAQBwLCkX9lU7sPKCU9sGrAGMLEDCWTBYeK8X1zlL
+h/Lf7c+TgNUFyoEThLzWhxUBfkX4J9k+Rgqlkg3OcSW0QGsXFuf91DCMn9+K91NP
+kecN6rcGA/RIi20J6s9YmVWJWAXciiUFVY0ZZYfzvjK1mEIBY4CbJatQiEvhbQl/
+aid8ZgdkrKbB1nPmBTBOMul9Z1FgIBRetzxxxwKFqlcWZlY6M86FrmJYQVxmiK7m
+Pqd7suace7kpLvsM3sRzXEDPqSeB8fBaoqVxCngsdx0MiPueSYw4J0mDtRRTT990
+CxgCFeby0mem9EsZ7CMBBFJbQ44NjjfGoZoh9LXKxiFPMYtU
+-----END CERTIFICATE-----
+Bag Attributes: <No Attributes>
+subject=/C=CA/ST=BC/L=Vancouver/O=www.cucbc.com/OU=commons_ssl/CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+issuer=/C=CA/ST=BC/O=www.cucbc.com/OU=commons_ssl/CN=demo_root_ca/emailAddress=juliusdavies at gmail.com
+-----BEGIN CERTIFICATE-----
+MIIEnDCCA4SgAwIBAgIJAJTNwZ6yNa5cMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxFjAUBgNVBAoTDXd3dy5jdWNiYy5jb20xFDAS
+BgNVBAsUC2NvbW1vbnNfc3NsMRUwEwYDVQQDFAxkZW1vX3Jvb3RfY2ExJTAjBgkq
+hkiG9w0BCQEWFmp1bGl1c2Rhdmllc0BnbWFpbC5jb20wHhcNMDYxMTA1MjE0OTMx
+WhcNMDcxMTA1MjE0OTMxWjCBojELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAkJDMRIw
+EAYDVQQHEwlWYW5jb3V2ZXIxFjAUBgNVBAoTDXd3dy5jdWNiYy5jb20xFDASBgNV
+BAsUC2NvbW1vbnNfc3NsMR0wGwYDVQQDFBRkZW1vX2ludGVybWVkaWF0ZV9jYTEl
+MCMGCSqGSIb3DQEJARYWanVsaXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAL0S4y3vUO0EM6lwqOEfK8fvrUprIbsikXaG
+XzejcZ+T3l2Dc7t8WtBfRf78i4JypMqJQSijrUicj3H6mOMIReKaXm6ls4hA5d8w
+Lhmgiqsz/kW+gA8SeWGWRN683BD/RbQmzOls6ynBvap9jZlthXWBrSIlPCQoBLXY
+KVaxGzbL4ezaq+XFMKMQSm2uKwVmHHQNbfmZlPsuendBVomb/ked53Ab9IH6dwwN
+qJH9WIrvIzIVEXWlpvQ5MCqozM7u1akU+G8cazr8theGPCaYkzoXnigWua4OjdpV
+9z5ZDknhfBzG1AjapdG07FIirwWWgIyZXqZSD96ikmLtwT29qnsCAwEAAaOB7jCB
+6zAdBgNVHQ4EFgQUe5raj5CZTlLSrNuzA1LKh6YNPg0wgbsGA1UdIwSBszCBsIAU
+rN8eFIvMiRFXXgDqKumS0/W2AhOhgYykgYkwgYYxCzAJBgNVBAYTAkNBMQswCQYD
+VQQIEwJCQzEWMBQGA1UEChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9u
+c19zc2wxFTATBgNVBAMUDGRlbW9fcm9vdF9jYTElMCMGCSqGSIb3DQEJARYWanVs
+aXVzZGF2aWVzQGdtYWlsLmNvbYIJAJTNwZ6yNa5bMAwGA1UdEwQFMAMBAf8wDQYJ
+KoZIhvcNAQEFBQADggEBAIB4KMZvHD20pdKajFtMBpL7X4W4soq6EeTtjml3NYa9
+Qc52bsQEGNccKY9afYSBIndaQvFdtmz6HdoN+B8TjYShw2KhyjtKimGLpWYoi1YF
+e4aHdmA/Gp5xk8pZzR18FmooxC9RqBux+NAM2iTFSLgDtGIIj4sg2rbn6Bb6ZlQT
+1rg6VucXCA1629lNfMeNcu7CBNmUKIdaxHR/YJQallE0KfGRiOIWPrPj/VNk0YA6
+XFg0ocjqXJ2/N0N9rWVshMUaXgOh7m4D/5zga5/nuxDU+PoToA6mQ4bV6eCYqZbh
+aa1kQYtR9B4ZiG6pB82qVc2dCqStOH2FAEWos2gAVkQ=
+-----END CERTIFICATE-----
+Bag Attributes
+ localKeyID: 63 5B 15 F0 27 F2 03 31 C2 A3 21 65 54 08 FB EA 03 B4 C1 D7
+ friendlyName: commons-ssl demo certificate
+Key Attributes: <No Attributes>
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,958A07981A0FCEB0
+
+xwOFxogRiAGShZ/VkWz5Nqwdk3j12i5vLLbNhA5OgAwgRUqk5DzuJYaozJ+lVLk/
+sCwKtQ+OmaYeSYtXsTuUcNIgki8GgaPnBCXOyfZIR8ZjSCA+VT41lAvcWQ3EUUvB
+wB0yT2kWhSIwR+0lWw57MiUhyzLmTBlynSVZBRTe45/y0c4ulzodQW7zrE8G0hqq
+pB1moyADgeLh/i1iqvf3LNrZoRA5j5d72jA5sOJTK75BDekFzrPbf6Z94/N/+6nN
+oluxagf2thJ1fFs1vqOmJGb/sTBow5ToZ7lwe3kH/q5rc/0ecJWu5EAezvYB9dFs
+V1QUVOSsdkdRq8QhfS2QjYujkqUg9CQtWbEF90EyV4DWhUSugEOPj4LKPmqHg2+i
+zC39d/jizCeax42taJYYF5moWy/h43UtkLdHCkDjHmOXuMQaXGxJyV686ABuuMgI
+UN/CRKv6TjmmJZwxDYCuGNbcOov/J4Qk/Qf7FM62ZPT0DBnIXGnOHmegvGNbL3hx
+va60Fvga5uLxT4f2a5JXrNOJyxVlkFNqirWvWuS020rVK7SmF6Hx79v83g2oW83b
+Ox7KZ+zlcndqFUDA8iwdhmrqTpRqYxCF+PHFC/wO0LmA25693pLN+2x0Zdk0cH/Q
+hzykSOcydEctrkqPrJzg3m4U0gICssfPrbB8pkP6qk3ucSsFWYRQpo1Fv+yDqssG
+yiDOzmYXCxkjYcYm5MkX4vY/ggNi4ge3TVNMWCtIyr9WoVXT/0qFDN4i4vlJkTOQ
+kyhjfS25Dou2+PyNUe4rfWg7lH/5EhZbn6ZN9E7jKd0OOymLSeh08nt5abcuNBE3
+2QYXqBxBUmh29dyxn0Rl8UQQceFC6zvai2XVYKiw3EdMAeNp0NIKOEtkLZsGrE+t
+IWul0NZyqJmMDAP1GzNMg8HaL0mPh6PgoesNKMRYAqD1uNqzQfHnid1TrxFoJuzH
+GSwmX7QctDt7iXmqG9WETbw+WXg1IbpetxC/Lom54jRo05GcI0eCDCSY88EwSNPT
+SWLHlBw12axu+fzNFmkdV2y5qoi7YHq95S2BzO0Eh5p0BiCl80zCyT+eTt+2aJOK
+i7TTQDSjzwtqj7qgqltJAmdrbMFF0d15eO3+Fj9PULN5cOBor80RWs9gv71I5Ybe
++QA0QijIPuH19nB7L4hOT5vZgp1aCUsLyoCgv1WaIBgYgqQbcgDhbQs/vPBP699y
+/52Dr8G11/9MIEqA9yVLdj/dksGhhjRy3mtT1m35qG05ohKMd3+jESFA6IpHOyNF
+D3v/raj+ioW94KqYZepSvQYfDV4GUKeI40YlH3yDzSbj9npDtWdHX3OnCo9TKNkH
+xhyDt4t9WB7G7nUxq76/ZKSnAA0zvMRRRqFQOn8F3JMnEMYy5Dbn4I1xmmTXl3xN
+Kz7bywFiFb+lcCW9FGHRFVL9skEYLxvEQVbv+IteVqzrbInhfvIxgRr4Cbxoy8sU
+rl9sGr5ab4OTuIr6zOpUxJkWkTFy+LRv2M+lJ5OFbKJYLC3azk9t+dzjST6pE16R
+SQLoi0JXCiE5ohaL+IGXnegKNFIy9L/Wy0sBFUipkhhlDAWGNwgsPTnC1mhwGjKF
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa.html b/samples/rsa.html
new file mode 100644
index 0000000..f03e594
--- /dev/null
+++ b/samples/rsa.html
@@ -0,0 +1,114 @@
+<pre>
+java -showversion -cp <a href="../download.html">build/not-yet-commons-ssl-0.3.7.jar</a> org.apache.commons.ssl.PKCS8Key <a href="rsa/">samples/rsa/*.*</a>
+
+java version "1.6.0"
+Java(TM) SE Runtime Environment (build 1.6.0-b105)
+Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)
+
+ SUCCESS RSA AES/CBC/PKCS5Padding 128 <a href="rsa/openssl_rsa_aes128_cbc.pem">samples/rsa/openssl_rsa_aes128_cbc.pem</a>
+ SUCCESS RSA AES/CFB/NoPadding 128 <a href="rsa/openssl_rsa_aes128_cfb.pem">samples/rsa/openssl_rsa_aes128_cfb.pem</a>
+ SUCCESS RSA AES/ECB/PKCS5Padding 128 <a href="rsa/openssl_rsa_aes128_ecb.pem">samples/rsa/openssl_rsa_aes128_ecb.pem</a>
+ SUCCESS RSA AES/OFB/NoPadding 128 <a href="rsa/openssl_rsa_aes128_ofb.pem">samples/rsa/openssl_rsa_aes128_ofb.pem</a>
+ SUCCESS RSA AES/CBC/PKCS5Padding 192 <a href="rsa/openssl_rsa_aes192_cbc.pem">samples/rsa/openssl_rsa_aes192_cbc.pem</a>
+ SUCCESS RSA AES/CFB/NoPadding 192 <a href="rsa/openssl_rsa_aes192_cfb.pem">samples/rsa/openssl_rsa_aes192_cfb.pem</a>
+ SUCCESS RSA AES/ECB/PKCS5Padding 192 <a href="rsa/openssl_rsa_aes192_ecb.pem">samples/rsa/openssl_rsa_aes192_ecb.pem</a>
+ SUCCESS RSA AES/OFB/NoPadding 192 <a href="rsa/openssl_rsa_aes192_ofb.pem">samples/rsa/openssl_rsa_aes192_ofb.pem</a>
+ SUCCESS RSA AES/CBC/PKCS5Padding 256 <a href="rsa/openssl_rsa_aes256_cbc.pem">samples/rsa/openssl_rsa_aes256_cbc.pem</a>
+ SUCCESS RSA AES/CFB/NoPadding 256 <a href="rsa/openssl_rsa_aes256_cfb.pem">samples/rsa/openssl_rsa_aes256_cfb.pem</a>
+ SUCCESS RSA AES/ECB/PKCS5Padding 256 <a href="rsa/openssl_rsa_aes256_ecb.pem">samples/rsa/openssl_rsa_aes256_ecb.pem</a>
+ SUCCESS RSA AES/OFB/NoPadding 256 <a href="rsa/openssl_rsa_aes256_ofb.pem">samples/rsa/openssl_rsa_aes256_ofb.pem</a>
+ SUCCESS RSA Blowfish/CBC/PKCS5Padding 128 <a href="rsa/openssl_rsa_blowfish_cbc.pem">samples/rsa/openssl_rsa_blowfish_cbc.pem</a>
+ SUCCESS RSA Blowfish/CFB/NoPadding 128 <a href="rsa/openssl_rsa_blowfish_cfb.pem">samples/rsa/openssl_rsa_blowfish_cfb.pem</a>
+ SUCCESS RSA Blowfish/ECB/PKCS5Padding 128 <a href="rsa/openssl_rsa_blowfish_ecb.pem">samples/rsa/openssl_rsa_blowfish_ecb.pem</a>
+ SUCCESS RSA Blowfish/OFB/NoPadding 128 <a href="rsa/openssl_rsa_blowfish_ofb.pem">samples/rsa/openssl_rsa_blowfish_ofb.pem</a>
+ SUCCESS RSA DES/CBC/PKCS5Padding 64 <a href="rsa/openssl_rsa_des1_cbc.pem">samples/rsa/openssl_rsa_des1_cbc.pem</a>
+ SUCCESS RSA DES/CFB/NoPadding 64 <a href="rsa/openssl_rsa_des1_cfb.pem">samples/rsa/openssl_rsa_des1_cfb.pem</a>
+ SUCCESS RSA DES/ECB/PKCS5Padding 64 <a href="rsa/openssl_rsa_des1_ecb.pem">samples/rsa/openssl_rsa_des1_ecb.pem</a>
+ SUCCESS RSA DES/OFB/NoPadding 64 <a href="rsa/openssl_rsa_des1_ofb.pem">samples/rsa/openssl_rsa_des1_ofb.pem</a>
+ SUCCESS RSA DESede/CBC/PKCS5Padding 192 <a href="rsa/openssl_rsa_des2_cbc.pem">samples/rsa/openssl_rsa_des2_cbc.pem</a>
+ SUCCESS RSA DESede/CFB/NoPadding 192 <a href="rsa/openssl_rsa_des2_cfb.pem">samples/rsa/openssl_rsa_des2_cfb.pem</a>
+ SUCCESS RSA DESede/ECB/PKCS5Padding 192 <a href="rsa/openssl_rsa_des2_ecb.pem">samples/rsa/openssl_rsa_des2_ecb.pem</a>
+ SUCCESS RSA DESede/OFB/NoPadding 192 <a href="rsa/openssl_rsa_des2_ofb.pem">samples/rsa/openssl_rsa_des2_ofb.pem</a>
+ SUCCESS RSA DESede/CBC/PKCS5Padding 192 <a href="rsa/openssl_rsa_des3_cbc.pem">samples/rsa/openssl_rsa_des3_cbc.pem</a>
+ SUCCESS RSA DESede/CFB/NoPadding 192 <a href="rsa/openssl_rsa_des3_cfb.pem">samples/rsa/openssl_rsa_des3_cfb.pem</a>
+ SUCCESS RSA DESede/ECB/PKCS5Padding 192 <a href="rsa/openssl_rsa_des3_ecb.pem">samples/rsa/openssl_rsa_des3_ecb.pem</a>
+ SUCCESS RSA DESede/OFB/NoPadding 192 <a href="rsa/openssl_rsa_des3_ofb.pem">samples/rsa/openssl_rsa_des3_ofb.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 128 <a href="rsa/openssl_rsa_rc2_128_cbc.pem">samples/rsa/openssl_rsa_rc2_128_cbc.pem</a>
+ SUCCESS RSA RC2/CFB/NoPadding 128 <a href="rsa/openssl_rsa_rc2_128_cfb.pem">samples/rsa/openssl_rsa_rc2_128_cfb.pem</a>
+ SUCCESS RSA RC2/ECB/PKCS5Padding 128 <a href="rsa/openssl_rsa_rc2_128_ecb.pem">samples/rsa/openssl_rsa_rc2_128_ecb.pem</a>
+ SUCCESS RSA RC2/OFB/NoPadding 128 <a href="rsa/openssl_rsa_rc2_128_ofb.pem">samples/rsa/openssl_rsa_rc2_128_ofb.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 40 <a href="rsa/openssl_rsa_rc2_40.pem">samples/rsa/openssl_rsa_rc2_40.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 64 <a href="rsa/openssl_rsa_rc2_64.pem">samples/rsa/openssl_rsa_rc2_64.pem</a>
+ SUCCESS RSA UNENCRYPTED 0 <a href="rsa/openssl_rsa_unencrypted.der">samples/rsa/openssl_rsa_unencrypted.der</a>
+ SUCCESS RSA UNENCRYPTED 0 <a href="rsa/openssl_rsa_unencrypted.pem">samples/rsa/openssl_rsa_unencrypted.pem</a>
+ SUCCESS RSA UNENCRYPTED 0 <a href="rsa/pkcs8_rsa_unencrypted.der">samples/rsa/pkcs8_rsa_unencrypted.der</a>
+ SUCCESS RSA UNENCRYPTED 0 <a href="rsa/pkcs8_rsa_unencrypted.pem">samples/rsa/pkcs8_rsa_unencrypted.pem</a>
+ SUCCESS RSA DES/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_md2_des1.der">samples/rsa/pkcs8v1_rsa_md2_des1.der</a>
+ SUCCESS RSA DES/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_md2_des1.pem">samples/rsa/pkcs8v1_rsa_md2_des1.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_md2_rc2_64.der">samples/rsa/pkcs8v1_rsa_md2_rc2_64.der</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_md2_rc2_64.pem">samples/rsa/pkcs8v1_rsa_md2_rc2_64.pem</a>
+ SUCCESS RSA DES/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_md5_des1.der">samples/rsa/pkcs8v1_rsa_md5_des1.der</a>
+ SUCCESS RSA DES/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_md5_des1.pem">samples/rsa/pkcs8v1_rsa_md5_des1.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_md5_rc2_64.der">samples/rsa/pkcs8v1_rsa_md5_rc2_64.der</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_md5_rc2_64.pem">samples/rsa/pkcs8v1_rsa_md5_rc2_64.pem</a>
+ SUCCESS RSA DES/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_sha1_des1.der">samples/rsa/pkcs8v1_rsa_sha1_des1.der</a>
+ SUCCESS RSA DES/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_sha1_des1.pem">samples/rsa/pkcs8v1_rsa_sha1_des1.pem</a>
+ SUCCESS RSA DESede/CBC/PKCS5Padding 192 <a href="rsa/pkcs8v1_rsa_sha1_des2.der">samples/rsa/pkcs8v1_rsa_sha1_des2.der</a>
+ SUCCESS RSA DESede/CBC/PKCS5Padding 192 <a href="rsa/pkcs8v1_rsa_sha1_des2.pem">samples/rsa/pkcs8v1_rsa_sha1_des2.pem</a>
+ SUCCESS RSA DESede/CBC/PKCS5Padding 192 <a href="rsa/pkcs8v1_rsa_sha1_des3.der">samples/rsa/pkcs8v1_rsa_sha1_des3.der</a>
+ SUCCESS RSA DESede/CBC/PKCS5Padding 192 <a href="rsa/pkcs8v1_rsa_sha1_des3.pem">samples/rsa/pkcs8v1_rsa_sha1_des3.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 128 <a href="rsa/pkcs8v1_rsa_sha1_rc2_128.der">samples/rsa/pkcs8v1_rsa_sha1_rc2_128.der</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 128 <a href="rsa/pkcs8v1_rsa_sha1_rc2_128.pem">samples/rsa/pkcs8v1_rsa_sha1_rc2_128.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 40 <a href="rsa/pkcs8v1_rsa_sha1_rc2_40.der">samples/rsa/pkcs8v1_rsa_sha1_rc2_40.der</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 40 <a href="rsa/pkcs8v1_rsa_sha1_rc2_40.pem">samples/rsa/pkcs8v1_rsa_sha1_rc2_40.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_sha1_rc2_64.der">samples/rsa/pkcs8v1_rsa_sha1_rc2_64.der</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v1_rsa_sha1_rc2_64.pem">samples/rsa/pkcs8v1_rsa_sha1_rc2_64.pem</a>
+ SUCCESS RSA RC4 128 <a href="rsa/pkcs8v1_rsa_sha1_rc4_128.der">samples/rsa/pkcs8v1_rsa_sha1_rc4_128.der</a>
+ SUCCESS RSA RC4 128 <a href="rsa/pkcs8v1_rsa_sha1_rc4_128.pem">samples/rsa/pkcs8v1_rsa_sha1_rc4_128.pem</a>
+ SUCCESS RSA RC4 40 <a href="rsa/pkcs8v1_rsa_sha1_rc4_40.der">samples/rsa/pkcs8v1_rsa_sha1_rc4_40.der</a>
+ SUCCESS RSA RC4 40 <a href="rsa/pkcs8v1_rsa_sha1_rc4_40.pem">samples/rsa/pkcs8v1_rsa_sha1_rc4_40.pem</a>
+ SUCCESS RSA AES/CBC/PKCS5Padding 128 <a href="rsa/pkcs8v2_rsa_aes128_cbc.der">samples/rsa/pkcs8v2_rsa_aes128_cbc.der</a>
+ SUCCESS RSA AES/CBC/PKCS5Padding 128 <a href="rsa/pkcs8v2_rsa_aes128_cbc.pem">samples/rsa/pkcs8v2_rsa_aes128_cbc.pem</a>
+ SUCCESS RSA AES/CFB/NoPadding 128 <a href="rsa/pkcs8v2_rsa_aes128_cfb.der">samples/rsa/pkcs8v2_rsa_aes128_cfb.der</a>
+ SUCCESS RSA AES/CFB/NoPadding 128 <a href="rsa/pkcs8v2_rsa_aes128_cfb.pem">samples/rsa/pkcs8v2_rsa_aes128_cfb.pem</a>
+ SUCCESS RSA AES/ECB/PKCS5Padding 128 <a href="rsa/pkcs8v2_rsa_aes128_ecb.der">samples/rsa/pkcs8v2_rsa_aes128_ecb.der</a>
+ SUCCESS RSA AES/ECB/PKCS5Padding 128 <a href="rsa/pkcs8v2_rsa_aes128_ecb.pem">samples/rsa/pkcs8v2_rsa_aes128_ecb.pem</a>
+ SUCCESS RSA AES/OFB/NoPadding 128 <a href="rsa/pkcs8v2_rsa_aes128_ofb.der">samples/rsa/pkcs8v2_rsa_aes128_ofb.der</a>
+ SUCCESS RSA AES/OFB/NoPadding 128 <a href="rsa/pkcs8v2_rsa_aes128_ofb.pem">samples/rsa/pkcs8v2_rsa_aes128_ofb.pem</a>
+ SUCCESS RSA AES/CBC/PKCS5Padding 192 <a href="rsa/pkcs8v2_rsa_aes192_cbc.der">samples/rsa/pkcs8v2_rsa_aes192_cbc.der</a>
+ SUCCESS RSA AES/CBC/PKCS5Padding 192 <a href="rsa/pkcs8v2_rsa_aes192_cbc.pem">samples/rsa/pkcs8v2_rsa_aes192_cbc.pem</a>
+ SUCCESS RSA AES/CFB/NoPadding 192 <a href="rsa/pkcs8v2_rsa_aes192_cfb.der">samples/rsa/pkcs8v2_rsa_aes192_cfb.der</a>
+ SUCCESS RSA AES/CFB/NoPadding 192 <a href="rsa/pkcs8v2_rsa_aes192_cfb.pem">samples/rsa/pkcs8v2_rsa_aes192_cfb.pem</a>
+ SUCCESS RSA AES/ECB/PKCS5Padding 192 <a href="rsa/pkcs8v2_rsa_aes192_ecb.der">samples/rsa/pkcs8v2_rsa_aes192_ecb.der</a>
+ SUCCESS RSA AES/ECB/PKCS5Padding 192 <a href="rsa/pkcs8v2_rsa_aes192_ecb.pem">samples/rsa/pkcs8v2_rsa_aes192_ecb.pem</a>
+ SUCCESS RSA AES/OFB/NoPadding 192 <a href="rsa/pkcs8v2_rsa_aes192_ofb.der">samples/rsa/pkcs8v2_rsa_aes192_ofb.der</a>
+ SUCCESS RSA AES/OFB/NoPadding 192 <a href="rsa/pkcs8v2_rsa_aes192_ofb.pem">samples/rsa/pkcs8v2_rsa_aes192_ofb.pem</a>
+ SUCCESS RSA AES/CBC/PKCS5Padding 256 <a href="rsa/pkcs8v2_rsa_aes256_cbc.der">samples/rsa/pkcs8v2_rsa_aes256_cbc.der</a>
+ SUCCESS RSA AES/CBC/PKCS5Padding 256 <a href="rsa/pkcs8v2_rsa_aes256_cbc.pem">samples/rsa/pkcs8v2_rsa_aes256_cbc.pem</a>
+ SUCCESS RSA AES/CFB/NoPadding 256 <a href="rsa/pkcs8v2_rsa_aes256_cfb.der">samples/rsa/pkcs8v2_rsa_aes256_cfb.der</a>
+ SUCCESS RSA AES/CFB/NoPadding 256 <a href="rsa/pkcs8v2_rsa_aes256_cfb.pem">samples/rsa/pkcs8v2_rsa_aes256_cfb.pem</a>
+ SUCCESS RSA AES/ECB/PKCS5Padding 256 <a href="rsa/pkcs8v2_rsa_aes256_ecb.der">samples/rsa/pkcs8v2_rsa_aes256_ecb.der</a>
+ SUCCESS RSA AES/ECB/PKCS5Padding 256 <a href="rsa/pkcs8v2_rsa_aes256_ecb.pem">samples/rsa/pkcs8v2_rsa_aes256_ecb.pem</a>
+ SUCCESS RSA AES/OFB/NoPadding 256 <a href="rsa/pkcs8v2_rsa_aes256_ofb.der">samples/rsa/pkcs8v2_rsa_aes256_ofb.der</a>
+ SUCCESS RSA AES/OFB/NoPadding 256 <a href="rsa/pkcs8v2_rsa_aes256_ofb.pem">samples/rsa/pkcs8v2_rsa_aes256_ofb.pem</a>
+ SUCCESS RSA Blowfish/CBC/PKCS5Padding 128 <a href="rsa/pkcs8v2_rsa_blowfish_cbc.der">samples/rsa/pkcs8v2_rsa_blowfish_cbc.der</a>
+ SUCCESS RSA Blowfish/CBC/PKCS5Padding 128 <a href="rsa/pkcs8v2_rsa_blowfish_cbc.pem">samples/rsa/pkcs8v2_rsa_blowfish_cbc.pem</a>
+ SUCCESS RSA DES/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v2_rsa_des1_cbc.der">samples/rsa/pkcs8v2_rsa_des1_cbc.der</a>
+ SUCCESS RSA DES/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v2_rsa_des1_cbc.pem">samples/rsa/pkcs8v2_rsa_des1_cbc.pem</a>
+ SUCCESS RSA DES/CFB/NoPadding 64 <a href="rsa/pkcs8v2_rsa_des1_cfb.der">samples/rsa/pkcs8v2_rsa_des1_cfb.der</a>
+ SUCCESS RSA DES/CFB/NoPadding 64 <a href="rsa/pkcs8v2_rsa_des1_cfb.pem">samples/rsa/pkcs8v2_rsa_des1_cfb.pem</a>
+ SUCCESS RSA DES/ECB/PKCS5Padding 64 <a href="rsa/pkcs8v2_rsa_des1_ecb.der">samples/rsa/pkcs8v2_rsa_des1_ecb.der</a>
+ SUCCESS RSA DES/ECB/PKCS5Padding 64 <a href="rsa/pkcs8v2_rsa_des1_ecb.pem">samples/rsa/pkcs8v2_rsa_des1_ecb.pem</a>
+ SUCCESS RSA DES/OFB/NoPadding 64 <a href="rsa/pkcs8v2_rsa_des1_ofb.der">samples/rsa/pkcs8v2_rsa_des1_ofb.der</a>
+ SUCCESS RSA DES/OFB/NoPadding 64 <a href="rsa/pkcs8v2_rsa_des1_ofb.pem">samples/rsa/pkcs8v2_rsa_des1_ofb.pem</a>
+ SUCCESS RSA DESede/ECB/PKCS5Padding 192 <a href="rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.der">samples/rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.der</a>
+ SUCCESS RSA DESede/ECB/PKCS5Padding 192 <a href="rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.pem">samples/rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.pem</a>
+ SUCCESS RSA DESede/CBC/PKCS5Padding 192 <a href="rsa/pkcs8v2_rsa_des3.der">samples/rsa/pkcs8v2_rsa_des3.der</a>
+ SUCCESS RSA DESede/CBC/PKCS5Padding 192 <a href="rsa/pkcs8v2_rsa_des3.pem">samples/rsa/pkcs8v2_rsa_des3.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 128 <a href="rsa/pkcs8v2_rsa_rc2_128.der">samples/rsa/pkcs8v2_rsa_rc2_128.der</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 128 <a href="rsa/pkcs8v2_rsa_rc2_128.pem">samples/rsa/pkcs8v2_rsa_rc2_128.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 40 <a href="rsa/pkcs8v2_rsa_rc2_40.der">samples/rsa/pkcs8v2_rsa_rc2_40.der</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 40 <a href="rsa/pkcs8v2_rsa_rc2_40.pem">samples/rsa/pkcs8v2_rsa_rc2_40.pem</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v2_rsa_rc2_64.der">samples/rsa/pkcs8v2_rsa_rc2_64.der</a>
+ SUCCESS RSA RC2/CBC/PKCS5Padding 64 <a href="rsa/pkcs8v2_rsa_rc2_64.pem">samples/rsa/pkcs8v2_rsa_rc2_64.pem</a>
+</pre>
diff --git a/samples/rsa/openssl_rsa_aes128_cbc.pem b/samples/rsa/openssl_rsa_aes128_cbc.pem
new file mode 100644
index 0000000..e315053
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes128_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,8DA91D5A71988E3D4431D9C2C009F249
+
+ZUo4tso7YF0+ayrQpLsgM4TN2H31b5g5ryj//QqqVG/WmvYgl56Vu7fDbYXytgnb
+PQoJLo+8iUI1d51nirw3RrtAx7Z9lrBu6mX+JBE7nwCVsjBVVlAx1B6d6Jwc20wj
+935VaUkwT3n0zZ1dwb9HLjEGUp82TIbiZ3KjWKnfER2AhFXJl3SzswA5Fvwe0AYm
+KTAEYaaxigTTPgltiEQDIvA/Pnh9ZHjh6rbM816Fa2hdk30wjU4U/KkTYbg4hdoV
+vLeQpYnMT2uICCuvNXq0cXXetfbgdMFsLTxvVElUZrjyMTsw1QtjijeM+gj1dbDj
+HGzR0k97Xj3q+84m+SoNW29zPLZzSaFDX4KdKKG2cHs9BTYJmzb0h7qP4pCXjGgF
+8V2iUDMs7BQlgNnOa9gwT7x7DN4HM6J0MIlNIiYQZnupqqYQTDR0rd+fhdIsXHkA
+qNZKI/4ep7voVIufSS8ZyoISES3f7dvs5nnM2C+QAtL+l/yaaqRdfUyn9BL1djaP
+akSRPXmHrmed8s8YamuhLHyf+GPL2uYpd4i1voA2KKYSx4PnfjH/F/8fXPZr3dNh
+sDtcjhgXHTNAEVVek9VOaHtlUNZEY0UcbP5uqBZta+wP2rBTC94DxIbN+k8A2SlP
+cKGkaRltjnPJAXWmwKMRm1J7vXngXYq0r5VUvnGPiUhFlQwAW5TUml4+1SMEUirZ
+y/Oh3AjhOus67uiAXAQoqlr9KykueXobFrhZjLCgRf7iDmP/t1eK40UyV83w85yz
+cORi8FNfqvCARz05qXwfhf2NBMTRbLNzKCGjS4iY0dLNk+QYNgJGoM4nFVkHYgbM
+pTThzpYgtRnxQf1mYTZFtqr8hRJqiRfexzCyk2JC3rDtEO8WUmNdvdKNN0KwCd4+
+dcVS8KzNov9fYMqiiol0dL89WBN1RN+hs7HnOJkNZZgaNVspOLCT4+SN5fLgtbJI
+BzbAgTK1ILrSom5fyzZcRkYwzIqNc97YhRYnxDp7vJFlgsBqySJgtdGUkTPrrzAO
+CCYyi/ukSVphPe+qRsvj9L4syZgpLRgDdZaW+BR0pbTUg2WQvZuKL5iMhfB8cbAC
++FjoKeSlxI68jukrAYHBNcco+qaAYrUaHsJFUsbf7j85DzHxnaA3M+P0i+LWJwOI
+3G751QR2CrjgK+QD7XUtUjBMrsVGlJmfaQsEm7+rtuPynXq+ArJrvgha4lc0GRD6
+yNDCTTMafuBnJ72wop1UEE8zGOsqERsgvOAL10J1s5KCcPHGwrDhjhr3/x1GI6/e
+H80zp/E9mPgzYQMfhl06s9SwyvsxFCIZAfrKIhq7lVqeEDiusYbe15kCLmTVNZ6C
+c/BhDc76vwek05AOLaZLGbdpMRwevbOn4WvUHV0o5Yr1h1IGZKx9BQYwFS65SDCg
+uxfM+dKulE6MWD2hPUP9s47+R812cBnHu5BVV+Cq52YygAiAP1+nfFw7TBKzqczo
+fnIsoL69JthqtkZiwl36uMmcoWwZM621ZqYFJI53WO57uhW0uuoyidQj8HoNG/re
+o3OyAgVO6sTFsw/Dwxo4WX2AKuIt9W2IJMFNC7aS7lH0iPrtiVC3FFXvuY5agipH
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes128_cfb.pem b/samples/rsa/openssl_rsa_aes128_cfb.pem
new file mode 100644
index 0000000..8bd32ac
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes128_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CFB,2F7AF90B0C0A420FFD62214EBEFC4CD5
+
+hciElffC9lqjzOx+aBT3DYY0/oZrI0Q34xfQg7IOTUPUAxrrT/UjHlToX56VIbRm
+PH2M5yoF88Ji7BI2V/Y2QRAjAYRFVjZvPO9ke4IGYI8xfnKRivfxLtW/YfaiKnqc
+7VyyO2UI2tYGm27+JJbGLR+GdaHmcnLmencGdS4Hn3KDQ9IK4eLLXrBPWyzGnxEZ
+qA2OWdzqodjppFCjlx892YJUsq+w3BXu5lkPoooTEoxB5RywZfngUY9Y+raN60S6
+zhjkaaJTEqAfnAsdVMUvzpkYpoH5LCO1vl4+XpKdeUu3wJ5p3D9TVc4kt6/V/MeL
+rHJVN8FKJKYddTlaP7xOmh4bivrJao6LzRUdnyxGL6SkVQ4ipitgWcSwFGgRQc1m
+/MzFmTATtC8tocSqXMY8nblp0/sabGhUSTGG+uBGddDr16D/8J5rb8cMCfR0KLPF
+3uwV89PbbqpS73IUKkolRjxslO74TPDT5ds0i+UV+J+AJM+9CnyY7WI3FgMlVvRn
+KwYJuihDzFjozJfe386XWYs2Joa3Eo0vbaVvp4hbHq5Gh7S2iiBpqy2uN0xxuZA9
+QB1XpLd+rOC0y5l1usuVc9kBlGsTiFVyBoZo/pWVlTU3z8Hzgv8p1TAJN6jgqVH7
+oMVgubXsz1XPHrrjjgZEEpxqzXtKJw3DKchGDfAn4VLTSrOINwMC5sR8l30OZVtD
+IdlmftUBhv2AeVUqkLsSMKGdeagfwoqOlfL4FKvSt4n8Vq+Hn9lY/S7n3cjM17YE
+YAgpBjX4PJqXsp8K5KmBHPQMB08jW+NQFABOprdes5bwflrERogdLZmQH4vxqUvs
+DFhHVJxo1wxeRDOftVgtxnmHzU+SaB9MgdWWhC/4pxx5uzqYi0Q2kSOZ27EXZNdh
+MgVX16W6jLUw9zaR1wJIJZU7SmhJOL1fxvt85RytaD28+JvPTNs2ffDpjPu0sXh9
+n0gYiWztuBNUv1m+LMpi1SPtHvtoZLhc++9g4BXoZevtgNl+FqvHs2Ob9w3yXqkT
+lyJQbqju674MaKXDoQ+3+tnXad8MRGCvIgmIUzmMZj3O7QcrBbDY/pbcxoEDOaKI
+SygvYvKfrBIKq6PuGsN1KHSMrjc2A4+wuTYy75xsai9YtwwT1tyIIeCv5NXbbtJq
+vW+nbSNYW+khIicBc+Ye+GFfUh2MXj+iC1lK+5i+1leKo4zLNFDmnXKgZ4jOOPMa
+FMYPZkwANQ6//tyP/qzLWGyBucIC/Ym9hUvi0HlYjjU3Z+Zv92vM+2+li4mtMy7M
+tdcm72bqsT3+1rtJKKRaYG/FiQizOGTDyhgV+JX9MEVwJPa+61V9jwkIPPR6iBrl
+u7NoFfSp666XbD+LurRh82vlS7KYOB2zimHFxI6nOHBsypJynqtgIzLg5N1+LhVz
+t+cxucW9eFvkEEXmjZwofqlxq9BDso587kKY+EpOkXrlnG/ha9XeZcyUipn+jQ0Q
+64Cb7LfvcU5UEXTcMh6BKkoeNP07O1ecpD1LXMGYFn2HsfYHigwwcZ7sm9oCCC9q
+vF/rjXg/oIMagmc6MZOjRE2eT9tpLRAaMynLiln7XS5u+Q8O3RexEw==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes128_ecb.pem b/samples/rsa/openssl_rsa_aes128_ecb.pem
new file mode 100644
index 0000000..b6def08
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes128_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-ECB,3E3ACDA483AAD613760CC55C7DBFE582
+
+PJupElZP0QC92uiYotAm/CG6i8ypU5SXxc3zmrk7sBdxVU9JQXsIE/oIUK40AlFW
+cGuHWxxYkdYNtTpuwG/CVlsrq20YfpxQrl525f4pz8ETWt/P5+aLQ0TemEKr+LVE
+921o6LNstZpftQJbe3yMz0cFTjSfsxsHbadfUZUQzobr1XcbazPyhr5rrSntgIMy
+rJ5M4G6QrOEAIHfVVZ1oizlFnd4vjGOKk1i6APgEEqJTIyFWoCXEzDtaMcl97GEI
+EWGusd8DJrqpJKnohVoTZdOzLrnerJXEUEJ0cz+UjvljAYg2MBSJk5v6HCp8aWcc
+CCoWUbJp2933n4nLBq7EXTVmJ1pwbB4cjNM1oL2BznW/pdznrSRcw8qut35ikEKW
+mB97+IMVr03orl0uFjHBIch6cPLYkXKi5w7CO4vvJeqqPK+mCtckzgIlzsdTL7Pp
+tp+wrMBtG2Ibh2HeJuvvlFCgoYBY482aPu/4NMei2eqfs0p5g0bf67R/BiG2Sxxr
+4o8hmR14v+dzLsQeoKrr3RnMqfmrbqgdkUfgBomlsunHUu9u7jB70TuYsZk/COPn
+SgMM0T1pxEuHdXfyZPSS9u2SFGEhbW4zIuVz79Lo7h3sKdYJqmwmgOk1P3IL/nra
+YpcacWzmV0g/GK8O+2CSGvEh1+m0ffQac1Pd2Abjzg9jghshsBTVTpkcFI0UfkIm
+gpP/hwLONl5a1KJn7u/ltFPdZkJ5CWPe0ZQ1mqjhDaPnc8j7iuFzUilsWITLRof0
+KHUDsAZSV7gZ5G/Lh6DGZdlwfkD4b+2GOPayQ44mr4p2hdOque6Z/LEXtOv+UvvF
+kR9azOu2RXVTiDLL4c/ntltS6laT/nCg0goMs5NAis+3cxKd7Uk/yXBAulwR6wmy
+MIZuSM4gk2pqbt6TJWIfxl4ZtPwp+jYIpMZc47XQ7w5m7YSquJzjilaj+IDVPkhF
+TWTMf+Ucb4duBD39HZjBWAoLkF487M8KDtcxL60uHuhVJsKyYsb8b20ukA++c6aH
+0VqU3NB8VXH7De3pA08G51P+XLurlLUUr118STaEd4r7GR8FddFmSh5x+PSuVXut
+D2p2W7pfvS8OTuaMF0PZo0KkUq/TbTpvMcTax+G0DgGJqFFhqxNur6WoJyYbQE0M
+nX8USnuJhS+BRNPEXc5i14dWmZEeE8i2KGm8RlL3KZfyrpBk2zwnGs+WM8xAlBSY
+KnGO6bLvRaUl+8IT1nKfY30HLr2tX+F0fEM9Tn443VgsXkYnMoaPDU0aW6+J0lLE
+lTeqJn8MPVRbU0Ss/0Q2PQLpayHrR+ly6yxJPOY6Nc1eLkhXoB1DwiGh5Mp7J6+V
+R5UL4nRr40hZy+35sH1lf/+1mY95Rb1hAYP9r5K9dAvqkdUMSPz8rtzb/4gevLi2
+rxB5XyOHM/qZL9ySpJWjFPBwOtJ/EJioRTvnG+/8jdxXWBiGKdkGLKV8k1z7gOee
+ewq2/8n4HnzMm5YKdTesy6LuaO5TaOAUe89Eo/CxPgdM5YnxSxRsxunrPR8JMLYI
+V6xyNRRHLOy2ffGdJZ3nqbSOxCNiHW+Glh5I2jyrKG5Bs0S1jbt3l0hZKWSU8k5k
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes128_ofb.pem b/samples/rsa/openssl_rsa_aes128_ofb.pem
new file mode 100644
index 0000000..2986eb2
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes128_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-OFB,271025C313E6EFC0403320C73382F15B
+
+/L1xK2Hx7pYQBTuhHX1P/mkXqLAlbSSz58hL1E4oxsDJODiVH+ueTSKajA8+tbxG
+eBK4p0s5j1fp7SJ9m4QXBwvhCnis992H9kQws6U9gGFrofrYAniRFhX6yzvm86ee
+deQ2Pfcv+evGRPigkoeRSQGxSa40fJ+5cBs4G22cfrKabaEKxnLtQpqPG17JQ4/f
+LdrHz64IyJTgvV6LCzJxShO7vxwIXaA82HNR6Qp09WUXxLB1/pfQ8oQfZbTUkvWi
+CBdXWT42VZklPl7StNiAN9U85K/USIYkKG47CpJvWMYbWJ3Dt1EFiEFi/wmYTinv
+b2K0xUrVUKxAMfmVtr1wGSJA9P9AT0/sBO2vTn5ibXVVHibtAET+vGXLtpGqf89/
+RmcqNEFYxvLzoTyR2FONtVluAC2yk10cKHY/pzZwQyVfjcgMlbnrZz9Pp1Y6ntR5
+AfXpVR/qyYOaQ8BeMCXkfR79GPyCPV6txy3KE2mbajwamvL7eR0+0R3Q0lhVcWGp
+g91D1nbgVFkHGOugO+2yb8vLq9k7K84Za+TY9NCqCG6g0S46yAgZD2rqrAAO4UIf
+6+nno8TS41W5wmsdEarbRoIg7iIKaPKzEmRRurSdlj/s7MKHgQFoet/OdZuAQkV6
+FumyDmqekmPAgIIJEO2NdrWo87RWKCzc61Yl52qmWsqrJIHrPORMGdjdlLVxXXIE
+XZQot33Rx7/f0VZktYB5fWk08kjWQ0sKTDiHEp8Xobq/RDyMTm9TFIkeFm4rLkl6
+Zt2bzp7ssoKeYuJgpoRzUmGP83wgl+AaJZpupARdz5MlqXd5knuPTETFPaFIf98d
+r/sl/V4E1nh0x83HNOBrLlpKbeWocVV4zv22q4zemALPCOQKUPWulINQWAYiTPDA
+lBQhFRnJXSZYFUqFWpxjp3yIWCvTZd4wgX5IQpaJvG+ehRn0H4FR0hJukMG7Pn5y
+ye0M0XlvVYWfxhLRDK23iNkRzVIbIxZfxqaInpGvatcTHyb2vnVFateSGlXIk0wU
+GxgytnTGW2fZtCDOqeQxCL66nIkpqKhB2hJKaD5WIG7SUikjBblvVcN+gkj9IWML
+7LB7xjE+4cyt27Rt9QHuLchdgSScPnPTZhdX0iK1LVELlJQFx8WPZpfXwpQR/xz8
+tqAKOfyhOX2XxYYOoaNN+ffQ3mEnsVFx2uQOp7PvNjL06XdYP4p/AruzVnbqsDsG
+BIo+oo7PfepNw1jRxcmeoaMotIZ8Feq8H8QEARqQSnzRWAJZhV5D9ztmUtaeqyy4
+QDbgxBxdV0nLAWG7e54FMn5yJfjqq2pkBl69ZvR3N+F+L5/eWlEpalIoq2l8AffY
+gDxlGgp030MAyFYSLJNYj+UUwq8k5INaC0QKjARbBMblf0HOX4U6RBqrpzn2xyvU
+mlM6pTiO+mOpG9WLgQS9XTUk2te8n0vAVUTk4Camj94Vdl8JWFNsfJIgwE59hprg
+a3Pz4FosIcBbj1pYtlA9Lz3kIGe9U3z9rHeQHNxJ8agW8NKGvlzY/YBdb115UhnM
+WOVp5TkpF2MyE+TGWqXzwNo3GutaNVs5YO5nX3Mtx4ClRrsmQYVTMg==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes192_cbc.pem b/samples/rsa/openssl_rsa_aes192_cbc.pem
new file mode 100644
index 0000000..b80686d
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes192_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CBC,51C73DF9487965B976234C88321E3F30
+
+6yLkX7C2XTX5AE6KqWsB2Lmt+TMGsoHIH5BDl+o7Yjx7aBSzB9X9KPTsVoPmTCOg
++yhhV6am/yBImCdyuY8d9Q0A1kPIJTEkshgk5vc2KpW08blLCHSCjokEVbQ4TJDH
+bMtrEBVMU1g9KBTMuBpbu6MLVaFth2GTsqExX2gu7FB5EAKvEGhkmLudo1jKkgvR
+aiiyMd2CH2MTdatZtw5PrJmkhV/6RMZRKP8r9wkez8NN14ehmk5QDY2s/hj5uaEf
+xK0GXY6OcwoRo85PsOYhmOeFDqHKGRo9a0pPBy5ZaV4udj0QZekE1fziOxiPf6K8
+0BL50UUzQBW+3n0dIZbzlOiJQScQkjoxi0kc088FHXHf74VBoJUo6pckAu4OwpXW
+L4XLIGAr2Kv4OMiFSJOcaihyawE312B2URcAzVCO7skhTYHaC0fMYDJCGTc2D9rR
++V5tVfT1dG4xdB+p/b9TQyAu8PE10jT+tVNJqGsZRI8I3iOtyWsBcn4sQInpYFYU
+R/v2tgG4hDdq1beEY5N/ZaLsoSyFYZmwbzB+BVhPg0W/9s91/nYAQgOL6XrExQjF
+lZxS28ujAq1LDNzg0NDA2KsDGJF2TuST2stnxyvf23h8+KV2nZLOZXjhlVl/Nr5O
+WPm3gCmuPf8F6FPqM+zI4YBBRtvLRkXafUNuvc7PYVNiaPyuMh7I7U1EUUzTpkqi
+OI/YD4xv6DpDand/WEtLHaYfVYU6PAapLV0T28BoFITp/qxHYYnXVfhn4htSgiwW
+R1btcxWyNjsIedjb1LJ2EwEfuXqZmzDz51uDLBq3XQ/dbvDkDzfZR3O1KGaACxAT
+tAeAdnTnAVliWYQiJ7BHn4LTJZ0ERGL/R1xpQs4quki4WHtEBRRzP6BbmUYYhigO
+QwvTK9darP1Ev7miF5BkRnrzWqCQHNTlDB3i/RzIfIDChQbSZtrpZH/V/quPuPlO
+1353Q6D221UiChhw0+8GmIszbLwBkDq+Zr7/poUBAqHmTaA3LeiahACM55ATbg1+
+FKf0nvUL0SaEBAqFxSdQ1mnW83VCMlCE7Luh49BDl4/nufCdF+iv3cYRW2SDHPrU
+HELYYLz+b4QLl+XO2SgUYEkU9s1Z+eCKcVUXGzz6vZUsA8UwvYIy8b/1cz4Y5sZ4
+MLpEXnQRMwAjArh4fvmosAG+diC18H2asLWpUS5HBBrSb8lAqKPLl+n72SlZkFjE
+WP+qq3koz3EyJsjwH2qbpx5BLhTPcEVHl3DZ1eOQmCXcpSm/cqKp2MKQFubCC4rr
+nphTD8uYKCP3mJXB8vqIIO9ho7+GVlCHJdZGu+3bw1L89O6ZG6WClbY56eGz2xUn
+DBmikb9sppeYSs0eX+yQ9kjQRf/BGnRab2dSTGtDT7jp6cL+zWUUOawLHWS72XtN
+3XYSEvvAWPygwbBuAuw17pwPPmTXduRiJosR1lRk28FGsMwzbj4byXm77IO3vD80
+cyrAQ/bmSpvlmYEHvmRn9N7QT7SFANY4a03aBK2iuqZQUz/zeo3eyrJudBXIiwUz
+/ZRteBa6SQagqDsmfeuGCjgTFGVnutCokh9lajm9BZ1pZtCmHEDd7yz4Odx5CmxG
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes192_cfb.pem b/samples/rsa/openssl_rsa_aes192_cfb.pem
new file mode 100644
index 0000000..00cbae5
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes192_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CFB,58F8574921C585278A50F7A2EA529595
+
+RQtPMTKDNttPq1R+DiwHrEK33FOfxK1Cst5x1jrDhXe5MObLhqbz4Ft2idjtG/vC
+pemznnZqQYKsuJl/Th6Ydsthkg7HH1pYLRstc/tWQTESa0RseHDtdw3e/Wxhm6DH
+pSqymOfRq8R7PQKPxboj9fjxeooWlA+RQxGdyRJ6gki6PljOD29C2hxZV4HuL2II
+tUn/cdzaGu6bCvpFDvDuFja3TRtIrHSbCq01uZg6XrFui7BuwJxxR5lERsauJ6RX
++lAvhwXqN4nsEQefvZc/GeTFzklsoJ+c3HJy7pN15nyfwNzmmH5EK7C4CdBJQymv
+MRwe9hY/LGXB5IFEgXvop9bh2qYk9tb/zb8aAHcLS9rwFsGOo+5+Yib3ds4GC5fx
+ILKH234g+hkhutao530kmWXFf7qup8lvTlBZueAWcIFdmBCsWjm8ejxQUZaPCqEY
+sZ1UMDw1HPX7/4TXdVNZWrxHisv0VWnhwJNflEcI/k/GR0/qUgkHnUPycWTtg0W2
+7ivs7D0EkIJy2OyFj5swWs+eqhsSDmd0BgGL0VduLB0voi1eU908Af3PllsTwf4D
+UaLFvOkllIbul+YweImT9TinmkWIFMZuNDR/PHjpbLN/39YkvSub6oS4LOgKEu1Y
+Xr779QOZHMcIP+PXoaxqOWls9hgI6M3PAH+gAjwF77OWIQIh8JZCibR6HWYcr/qo
+iFTzJGNN7P06s3IOek+YoHG1c0GoPsNungPOzthNnaAUcRyvZ1Yg8cy/nhrA8Eeo
+A4G/I241jr/Ex5jooykpeotV1/AMIF7qxFeTARQgObRi/fiR0r9rjaSMbOt4PlRv
+Ln0ZBqedtkkRBPRGO0VViSbUAUOq0oSb98FWqPFpcFl8tXRyqe9m/W2zACczZplz
+OySvRuASdKYpGk4DmMlQtS8wjzMYTesBx68OiZfw9W2nkH+Xapc4cH8hyb3+aXXb
+b53nbp59+mx4UwPOcrdzVHdKhDT3BjYrJTv9kHAY8yA4Nr08ZsO5tOeI7vF+bUKx
+kWu4AIEccB030iu87/xHXUEOBzsV6HzzT1TrZ5GKSh43vhRwoasYON2xlO6RuKCD
+Yv6GbcPd4lv2mv4lAaDXk5IThABHUL8yhqfwru4L43av5AwdslRKIvBM7UWrlXFe
+A/Hipy6jjcusGiOyH7WfWBFV2/f6NtX6lGuna03F/yMZcHI/HEK5RyhqOYOmcxfw
+A1eGKSqOnq9IJ6vXnF8PuRYKB9i8Ha0z5JmWkh/dX5dhTzwH6wOz4+bLgkgXBdhY
+jptSs5zsvrxGiLCbENPTjArsBbT5NISh+VTrrUtmA5BLPWx6d4NNJ5eBXTnpOIJr
+rxA0halZtFYKj0mp1ZgnVylHC45QDiwzDnhXra83RVrcgQjcX4npjKOaYZRQ5cKR
+2F1QdvoLvE9YqhjH0QFQWMWfvmLHGIDIDkSB6EyFsgzWdv6kIaiYsmdir5FzE8c5
+SvHvu28j1X4OL62AquOFKMXQVns1/jLp0KERx1EhrQChHUxpA/cbqNJbhjHoRQK6
+0zXWP9gNlyrSIKY4egyQmjcTDvNXVcSDu2o7EfnprNCYirFgsAbw5A==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes192_ecb.pem b/samples/rsa/openssl_rsa_aes192_ecb.pem
new file mode 100644
index 0000000..106704e
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes192_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-ECB,A3A4C4B92548B906A635B84B3D67591E
+
+E4I7KvCs0qknDw8D9ISQev5oQCNiHskfB/SvuKJ/qJoJP52qk+ajN9pNMp+011R+
+MRaMlK7tANTrQ0L/Yc6QNUZW2aHyiex0aoC4ien4ojgvqHfaP12dMxFhOoLctN+N
+zrAPSuQg2OEBiWxEoDqpgA7FTUbxPiJ3QdtwwOXS5kqAKIEIoNnCPCL+45uKBrP8
+encSI+nrZIXLFqGEukKZuFH9qzdF2leOKSmEW1kmwxMOfQLMVQMJyVzd19cCxU/1
+FZtPRRIzFlx4PlNYLKDpypSUavgo5V/o3UHk6vbP/Wd+Wy1ERwNliV7CTCCpOrBH
+qJezvhkbktiHQQ7+5zU0jsTzTlZcxATdm2ktyfEa5GKrCNfrmUYNwNSi8DC2Dn1x
+4z9r6OfKV3dKcSkgmFS3ZI97ZhrnMqpvo0h1kg8tuiboI9pPWp8OsLIvw5+jz707
+GLsl6hI0EX61YFc7bqeetnObgiaJMJxQJXHi0U+Z01GjZ+qgGb6USmQ1D8r34nuj
+4l88VYW4jBhxa/IFpzUoxIioKG58xQT+OK2Fi7BF/OJLQpj+3RA3YLqry0D+AOT+
+f+nDJepwrQ/CZtoQl53ssct+mDY0D1IU6u7ah9WdIuuptV7+WxutFfDpXsmErKcZ
+eILXaH5zK9iNVnVNQDmnVacjQt0x0Rm28wrjI5N7M8jGWKWi9PMLElx3BTo9EbON
+pJ6x6xshjmdCR3gOLo86CZGkoUM1eNGhJuihrl6HelcZxeFnuiNYnLb5hIaqDd1v
+NpFUQBRC6Q3jz85zIvVsiN2vIyak2OGDRs7r5dqb1x9QVz5tMjxuKe3t+rfX1FN1
+vCusACQQzOl6NdTgmm5Of+pMniOL/kRF78e7zva8vM1Qf31/z8wtq3gemt+pZstW
+WV/kRhIvY/p2Nm41TtltlctThbYquFTEy8gxhB/Cot2k7Z494+8UBVIn7SjsdDpU
+X+N24itXM9/sd1LHrXBSbBT5PzSBJFC5MS4Nt6qpvSKIRbyWINjUoTvbbUwoCo6g
+soYBPJR9KeAcQ8YdBOEXtFScq7c5ZPOGCj/+3p++Pk7yMmlxNPvs6HLjdHchjAYz
+jycK/uWYNLOwKS/AMxwi4R3i45pPgIRuwGdRyi17Z8kOKATdyQwScbPOShW9/066
+OA0rEORx3C9gMoKa9QYo3O9YLjA7NS1ERSY9c3X9anSgR7eSs+DLRwFiB3EHoCba
+ULqd3n7qBKgkQpVF60p34yKb3K8o5s0cIE7oAm3VdoI/O/RSs87rDmUbpuYzAA24
+mXRwBvPpwEhke5PoPeFIYmcWa4wUZOJWuF78U/tZw047vcLKgr60Z1s+DlQJvFXI
+tXkV3qS45f9UDaWQ15YNev9fq+x/1JDO1LjQ9AHANBjRQSzE9K6YpyIw/SZlbo1O
+xuFrE077EL3hrRNh00O2rtcrK53mAOKMX9D5xifIcN4/uD9AdwU24YvC44gij47m
+hSg5wz0RokMNGLKTXaJxJGs4+ZK8JWQs/Kf/V9j6j/i4iDWuy5Ra7+/dIU/Qy1ZW
+cc8Uo2ji4i2z+QyzbpbR/jBqO++lcV2byEVDy8Xp/0X2G9mY0ymIbm7ATTlzE2/b
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes192_ofb.pem b/samples/rsa/openssl_rsa_aes192_ofb.pem
new file mode 100644
index 0000000..88dd91a
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes192_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-OFB,9797077D8AC3052C37DE4D719CA8FC00
+
+SU3g1XmkcVhlJpQSWXdeHcHI8IQCQBg0oenT/35NKgWnFBlysqwGwl/pwgdDBmm4
+jLsPaE5Vanm4aqWv9DNhItOQokIbIkxF6qKeV3wNSNbTsSaG2LNphwMiLs9rw4G9
+3aFV+0THPLAy3BDTsB3NPuRqlOSVcwVrfaeMXQGhCOPGmsGDeczai1xH7eq1C1no
+KUqNMGdf8g1NuCmQnvswuTF9BCi6rIO0JRqLPTxoz/1emKfHhJFefpSj88zg3ucm
+cz6ZOAlsmWm1MQrktXd+odzpmjHtd1vNsgr4GSYUeVxxWQX4o8pVFqWqiQXii+HS
+ubtMARXAuFIGoM1RCMN8o7sJG00RbG7zNxfhHqe4wSkKgx3qEuusUDewXkDeYhHJ
+HGQCD1epByGHCZkLwBntccOqbCQoSNB0/PcFU6vJrtgVFl8N4VsNMRuLj2ZJ7uuL
+/EZ3qkLTk/Ek68++m2dtAdyj2KF1O4z2SFROSh7MCqWl2rYh4zZcBtGEfmQe5Pwz
++kPycc76ayzHO8Bjg6rl/16Ua5Wx7d6vy4Hg7JYb5eDmj2UGJ8p/z83KBdQnb1ku
+84ZjpYgmtjZ1vY8Z5iZqfZro9JBjWM4wFZIKNXcBniC7kBV9fRC5nzpjs6qWTPRb
+bd7PLMuyRZz9PO6cRuhqYlP5tYSGYYVhAMVutIqSrQVRDV8AnmblfPiOtT5lHC48
+GR/xPTIFxxVqsDmeyBzyXn9gzAJKgjTVCXNksXojM/ZMfDDvAF6m/Ntz/izp2CbI
+f2lcHgsm7SwVn2fvHikAugA9B6ixMCXygO0L5OEUDJW1e1fB7FMasjrwRorDsxsj
+JUNDW0KhUXWt/U8lNyfRm3oNUjQQU3x1iEymjQZV10ZO9DTn28fZOF70moUWnl0y
+ffELY1vLtLNP7Y5tcGNtJARSGnMUW99P7OKpLNXkhL8zE3DGEL1N+gDS1n81kzTH
+7hPjM6yR6gJQVsQrQmXrEpIlHQeGA99LYchzyVog14qMhvQItDlCsr5UIPwVwhMP
+LTA2LITZOYieRAqrv3vn+yFHYG4k9/C/xHwKHE/4pDw8bLn1o8thGv5ZW4yDsHGx
+n6F6vqJrkPW6vXkmwcgO5jK8JBbEpyzAPc6aSsibH3JF0ufsfs2hQ4bwb96OmU6v
+mukMLjQoi3BJC70Op1bpe7wtCELJw1oFvbZDoXLYsa3c06HK1M4rmzJQTIEBjqxd
+vs3g4L4CQ4RHAzlkjLrCF+wcBHt33586bDrt03qBEA7GSyAUu1NSM3UKjjM0OydG
+u8echgFIz6XetqDICHdN0r3ZWyICM/FgnVQhs39fCgafVJsy9C4p5jByUuDPvebP
++gvvVqkb+DGwfkKT3RUFAcYiNHdtIob3kmp8OJKTFk/nwdUwqUTEu3VFCmWog9ps
+oe/0KOL7j1Kn1xEFkOt5MdSFCcpbsYjQNi7F1gWAr1vMXDDPsSizsniGSvXZIYBt
+Pk5AH4MflqbHFofWClhGczSLi0FRiVPqWyudoU7LOesQhhN74Dn5IzkeAGtDL8r6
+4vC+G61PZdFXhLXQfOEL99hgJ2mjQP4rVqwdz143YE4/CUHmpq6d8g==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes256_cbc.pem b/samples/rsa/openssl_rsa_aes256_cbc.pem
new file mode 100644
index 0000000..7b03203
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes256_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,1876F5A50C9046D504D47B2BF8951875
+
+BAPOppBjFxMrMU+NI00PbmXXutKdPAiP+If8JqX5xGQDB9bSt5Q9R2QkaMx8Z94f
+trVbp82iERyPYnwcnA1Av+pcZhKi/mYFgDBPP+dDLp8qKRFAWil0zc0U2jkfo0U7
+v8cpO5+oipkJ9RtjaTg3/XmrwCUFZH4KA6G+SUFc4Oxj8/dzQ5YUDtJ5iyArRlnr
+v4nsvP4OvsI5UFYwp/T97ks0KSmo6YLMpJwUBwcleX2vOhX8fd3thk9I+EbVVt/f
++JztCTwr4EsLxWe4XVmit9AKfLU0AhmcA20j2YXE1VFvRJdyr+gOGPD2SDoRgiZH
+rRBhfi7cou3QmZ5d43jFYoYCBc98blEV07umH0DXMTL8XSrfWNIjZf8uQR3+ZbHt
+W60jVdhOCEb40KoRTHQAMBQdgVVkrbXCFyc9NeVzzhPqyKXElGxLBjRB9u0h15DV
+WCJUdc9UGuHzFpVFzpEaehdm/7vl+SZXUzAOgAQDtL+ATsvZglyMx5y2UA+5L1eZ
+grA6e3tQFdBcv8w+WgYW37oAY2VkHKjoHs1TnR8z1t+OpVovnpcklawybh9Avv5J
+kXyZGc+lbbb2gvUw33VeYR8yIE4zBoePuhTFM3K4NfkBbKavBBXMjQlsdRzlt48r
+RqdFnpYc1XB4ZLP2VparhG+Q1UueVML8uBcd5F6X/0u9n78LfIITwRUpVoaLXRzs
+94Us0pbzWFDxqxtqKPZHLAVJOYvEOwZD5Haw/bwho73EHEx38MY7mk9T5PonsBko
+7Op6aEmKK1qfpJ1aPvy74UmIlVDHu5WEMkYx7nQL67gnFXHY0yKjmP6dc2y3+nfR
+qNK95RTaS9VbACRS+re+P9+Z3aAsQGvj3MA+4Q+qlscUmb8uk+M7tg9ADk0VSe1u
+Ts2x7UZroI61c+WzgsQzMAwm2QLPoKQcvv2b+iGD82enAtleTTHL9rkoS+KmNNU6
+hWL+AJ7HP9s/5+FJ7/4CD84pcLECXQ+f185vvE42TfdZmoq6NgSKrGVZPLxYnyjO
+qa2sTRzImZrXPtsnFEL9OBflWA+ZHaAGo4HJNxZW4Z90HJlAZN3isSZnE3jPToKP
+YFdHsPv5m/KpNa5luh4L3K41QWzLmPlRR0aygWM7/0fYkgxI8PnBeCp4OjoK6qHx
+VYTWMKJQTLyji3YwMr4CufFAVty3InUZzm+ALMFHqEORB6JqPTR9mtnR145FHtxE
+1z0LnEoDFEdGuLjtC57yR+lYS/vgMbtj4EqQ2zK93JaXvI2HxxOiZCZEDww262Bx
+QZo0vBoAd5vkMKmz5eAMpRVkguF1wN1RPvao7I2auJIHp/3zoaUowpZgtbmDHZFA
+Kddfc927GQRxtUH3QQVe1R6FFAa7JBHNeJsBvZu3bj3l/7BATzcne5OPhjZ/t8Sl
+hMqEBZuo0svrEc0w+e8dpbPEjuj8UwBmHYZWlALby5N+YJ1NEtLYmyHe2PFNXwK0
+2fo45CCSyl7YJrHD1ONJ0M804ML4nMwmYq6fOAaV9ufQBFqQQj/hyyE93blB8f2E
+I8LMN/SUKN06YU0nErN0PRdm7CkrS+kutn/Pz2H4oSbUZ67z4Ee1tpnVQjoDYdQU
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes256_cfb.pem b/samples/rsa/openssl_rsa_aes256_cfb.pem
new file mode 100644
index 0000000..a616b68
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes256_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CFB,37639E4753C0E4CD43EEDEEA18AA66D7
+
+HKuYoKfUqTRf4sW12EzTuIFK5J1FkeJAD+ajYnKeKYneNiDbmDlQv0kIk12qBv6l
+LA0oBH62QKjUDKi/sg8NAO5CqYkN2ZB0gQurTgGT/jrvMkkkkwE0x1n69bGNScCN
+mkqMnAnjQqbo1xERzwqX5OWNTTb4iDLiPyjiUlQDONl14pe4x6zGpVziCVCQh8Q6
+rAPDryZBg/wQtPXNhNpk8MiTiSwe03wq10QP6W5TmUIKp3kD4OVfBxpW1N4znyIu
+unJDVcRdBf6XA+aL7plAsETL6F9Tx3Mxm5GaeaJcSOWWzKMvqYhAcEYwM01lx0w8
+LMMRUogny67ZqaLywXZWH6FCJGCnJK5oaJE+jlnKZ6xhbwAxMyxWRCZC9pF22ocI
+3IY602+shDOWZQDoihhddwPJejh+o3mVFEglco3YEByL7Cy6GvqxhctEEH7uKvlQ
+gXGb7srmOpeHHfP76N9afF2hn0mqyToakdZqgnlgT2jm4UDHJ1vQ+onIksV56I07
+tVMEmPhXQCIHhfKdzEgI/v8CiLL3W/g8r+20/5qyKCL5vPBLAxmRudYKbGkhm5pq
+GkzaSp1cKe4ipUfVc5OEUikOMCuadal0TUQZ+h658aBCxLWHNPdZCzNdY/bZLN9z
+XPhAzml/H6VOZyIxb9hm+FNESvqNKdlU2NaE7HW0ILKaDif7gsZhvogP4qNDp2P9
+xPANQh9UxpA16AUTUNOqk78t9aQVpbjZfAeGmcw6AxJ77uK649JgkEnKqcuxcDSi
+zn/8NGeaKow/bTW6jJJj7b4cMys32uxRjeeeClC0moQiy28OIJpRRCRJIs7Muka+
+dMBoNyftBnCONH+oqj+F5au3QPMwKH4v/4VpO3hcByXcqxegH+BPEZzzYJ1OnI3u
+dh9VlpTdC/CD+Gn3ZRqYbguSaqow1ZF+nlpD0xcs0IQjNEe2BVR7CULUFVXIgF44
+pTv96/LvbG1J9b0VuBr+iIp30FG9azd2xyn4O3lW2xk1uzvo/Wf1vDGvT6AYyXNG
+DQS1dGtIm3+sy975sNTlba5gWgh0YNHjeiQq19I6ZzLFhkvLKfh7zpx+R53YcqSY
+lXj62N0u2s4KUygqg14oiIUoEnNr+n7Pq0es/gYs34mY/KvlqA8Prax91BaoqqLW
+qHN5bEv90KdKaJlvdWsCUjA3wReeaQa+U737GMXaON9/oOJ02bWC8/OIzUPgfGRH
+v/8YL7kMnTd+Col0f+XxnebWSfJsAzT7mjfly+An9EjccTeiOon8submd+L8WySK
+lVvWzBD3l4HKjQkr/3/YtmpuymVZyeTzngVuSdw+iXWPmOOuXHyjyD2Htn5iNWch
+Zlw37a5sHhiFtpNZtOnhpmDbX9sgt68KJMB/E9Mh3JuWCaKZZ3Cv/22KA4KQRlNB
+FSvDDKJBrM1m599A6GPJisR+iC7g7asJQ8hI1OqaY69v8nP0Fo+Qk8+Ac1L/n/Vm
+RjksignkKjvqgWENNn5Bf9A9+zZrLLu9wJJLae7wIiw4UgsNob68sGjWdLyg+tab
+QTxd15H5VUIuD6pkeAI2qC+0sSw9V6LKm6pmEIIbp188CzApcsGBXA==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes256_ecb.pem b/samples/rsa/openssl_rsa_aes256_ecb.pem
new file mode 100644
index 0000000..f679d6d
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes256_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-ECB,C5DF56EE3F83A1F8C1AC805EA73D4D24
+
+ac22chm8+bxXpppAKfsrFJwCY0S4VPnXmFRqlAPZRuqBH9ylFcG+F8TuHdIsLeof
+q6s8yxkXa8y+/3hyqIZeMwN5Ai1Cas4P1iMwEtMUCMeaip5t0nf+yeCyx433hDSW
+dVnsdeuiFCiBUPUXfp6dCGO9kOLUEwu4wM4lIJkJ4QVyauO0/DwObQ6s6xEMFvQH
+GF1AFFTfW39CpZuS1rguG4hTxW6aNxjEaSKHJnzWu+kduMLJEaLUiL5+i/tUw937
+V8DhGdWU//1Q6KKLMr+5w0k9i/FhVxAGJZoZ5j79ToYORGr4jpkDPOvHaCydM6Iv
+JH0epC0wfG8L/dArNGLEftTpVVlvqHMpAlc0Rgvn+LtqstfyWFXqbQ90NBxC5Fs5
+xiGxKFGpkX4stoKIaOvFVw/hoCI/oxs8Eihz8u4QjBsl/3TdYQ6AUyfBGEWImy/y
+hh+QKCVOfzAmVGcffXYf7fvZETVgpo6tynxKVlSRXO9ZuzANJCC8jkUEOjc7jSKl
+jyMKQMNnQxyplgaFxnWIfs/snvlLQW8DlpMPH8xSkHkUgLKMWrSLB9Cisv0N7V5t
+Zl7Xxm3tOteLG73JxJKJkSZ9djlhkPvlvS///mvLQc6jse8EzY8peQMI1pYQu87U
+CvHVDOYn56SFVJmo2koER8FG8a1910NqdCKpNkzjqTl1Qbz7Z2VwghTslM7sUA2L
+AJP6PgdCkiGbi3oU8moPy3Nyg908j/17Bj9VyCXiegMAOxI6Kefim5Nn/sq+2/7Z
+MHIucQX6ka8KjEp9jvf7jvNC5WYxJkKIl+yzwAzqRQ395Lp1sun6jPfngnPQmkXY
+toeOeFvKlxaQu3QgNY7Hq9wwGbK/uo+rLK+Jbnt/75w7x5aGHQF3kf36epr3O/0l
+MyZPPx6sLblYcNQhBV8rnSey1WeO6105h61xTXdKV6To/m+RDZYvt+qs4z5SNQlj
+oKTezoQUh4J4QMg0EPhghyCS+/+cPMdnVnwX6Ds6nD2feX2CpN27xieGEp5ZhioG
+qWi6/59B38kBW2e60eQyL5f53bhWvywBg3HeUsXCD0ujtXBqPMuNnO6FU+/5Ohg5
+BAJ/bXaWiOkobmppBeaViidGv3NytL48ZIuQ1PZsYQajFb/k1SkyLebmeC2NYdO8
+VBWxAz5glgIKP11K9DJMD3n6PVl+ZyvlYZUGXjfUhOxHKVmNDHv2o5Pv8jf3WEhs
+yuWEoRECvfNlkDrmda0MxMhEYjeTysbxeX6fvwD2InzuFKhfzwh49p5LdZLurEm8
+DI8KBIXUx8g3svArJRvbVLyW0deMlXBY7h8Yc/2y7c5qBwfYrYhgazxVBfRqS3lt
+EsO2sa0V0GaGhPh7LUt+n1qDDYmaOfxOdpZoSLm/surciEQIQVNXt264YuFJS+ot
+vHWWVHzS1AZIgizu7NHRVeUmu4XEgT8vRsJYeogyG9o3U27L/lF1L5ysvYQjtvkd
+q5idZxCnY5RctE2wa5gjxPjmgbt1sUN23KOiPyz2cmXGBh/dwqEhIV6j7+WeS4/r
+SFBZBeGRHi8tACblT/6G9UB6FcycyD3hf317Zb3jXZLve17ozwRZRQ8aBkz07+iy
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_aes256_ofb.pem b/samples/rsa/openssl_rsa_aes256_ofb.pem
new file mode 100644
index 0000000..34ed53b
--- /dev/null
+++ b/samples/rsa/openssl_rsa_aes256_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-OFB,E6AB8D4FECB44185E26505049A97B0D6
+
+Fg8Nq9CxyVZmBNEiN9vBI+gsZL4lvWqCPaR5E+Po7acLxYGos4zIcmLCBa2X8lvM
+UInn087k98OAClm+0PvhZ64/AdDE952UclD/xiNvQCH25HGQy7wk/BxuOM5/FT0S
+rlV6RGMibelHpnv+yploYoHD8CSo77N4RHdEuepPwod2fGTKu5Cbbt1FBGU5LXWJ
+BrDMOlSN8P/rD5ePADhDsYnh86g4cBVHTb3MkrteLa0m1Szt47E6d3s+Ued8Cg5S
+7tiJOTFnXkmG87LsLZ0HDp6yML3g2gpTL/1Zhn9zS9lZc3cnkBfRJmttLBPjVCiB
+mStjlXnuJTDBdgQhJPJ4+2xJiR/ucFbCnUF/VICsl0hdz2Hd0PCOdhzj6U3jbRk4
+uI2sv5TV/E+e/Ppvdh2W8LISSBdIwp9CJf3se8RFz1dUXwTMGM50LKr/dpvy3T4m
+NMO/Cf/LyA7HBFJxjqf++wi5LPDXzROm1QHncvXNUjypNPND3RhP53pMeQ/Ffd04
+dw29zrmbyQKQOOac5Ss9Lj33Q/WzBgw5UxxxMxwRVDyfFpdz6JRfMrnj2c97auLI
+RI3euI9A9yRNxneBKTobS0EjYyqAiU6b5MbNwrybqvavbA/+ZMEg9Ylg7vtBOXpW
+YLLYFYPhWNEambOfNJi4tHcX8znGACxO/W7v3Ir+QFhw2IzSvntcMODKGaNKMGys
+HJ6mqKbmYidjhtKen1qHB5u2bukaGWUj2kjkv7jjuDK3ExsvB2PjEV5d0foPEwW7
+9QQeKc5pY4tOxFVA4qCq1tTzUhWr0mBkPhnFjc7XOLbu0sHYdr6ArZ3SadaNT12w
+LG2yg5r8BgmaUVTTQAzIiHhAQYZoCHAq+ohNocIikIh7lPE58DL2GPpEdXZsgzTi
+T+EUSkSw4VtIMmnWw5GNE3zCOxvx5qzhKiXVcnB+2+IF3nlHkQqFXcYNGhezZjnJ
+4FlR4FPzumRmMj1x0zmdbp7eTFpipUpKqJtC8iuea29pEl8opXDNhvmpmrT4/429
+7x8eJOjZhm8WL1dVpV2/Ikc9boEsYzHcBkY7kuaTqT8I9tdQ08ODo8UE5aReaFuZ
+vlBY4J+A4lltQ7qQ+sAk6gUMvlY8h/9L9gZiGbLe438Ndizskuwy+jAZAEx0f0cK
+YnTsZxBHPkWQXgBHMhe3BAAA+CZaXPps0SjD0yMQs7lkAgag6zBXW2vqttoJLU9R
+f6uP+BLwZCFDF1NtkROLV1oROnaGvMbHWcar2tw5qNe3BAsPQqGk8XnqwILz4IwX
+MN6QrjzbBC2jcL5jsxPZ/Tis9+wfI3t1Ke0EljYqA9RVWuC2KtRK+X3xOK6tWEK+
+QlagHRDI0Z0u0slCLjpB/ev9Ajqwlr0h25T5ucdsLd3FFEKZbzspdfsJuOXPM5la
+Uv9gpYIcuFrKcVbvuBPzt6NX/rp9gozZv7ZOnujjor6RDorHsfbgbEfcerydvJGu
+PRk788TkAB0LOE2wD2J2UO8+Ufp1qK9GWmtr0WFCazqFfeiorTh71iS7pwUt08so
+0BRkqfrfP6pXEcnh4p+LKh+dnbgIBD+KH0qHsyc0ci43byoOSDDHnQ==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_blowfish_cbc.pem b/samples/rsa/openssl_rsa_blowfish_cbc.pem
new file mode 100644
index 0000000..e3f6e24
--- /dev/null
+++ b/samples/rsa/openssl_rsa_blowfish_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CBC,E59962EBB3DD3C74
+
+1FpslA4+P9E8HcUUGpkIMWeZYV2XxCgOiSgCe2NAUiutcRkVAg9nPbzwnsQTbckx
+d5uOE/w53BURpxPkz3nNcike0sr3fa/MzaoRUDo0P4MU5bmAihjnZqhRllqvw4Zt
+BsyxjHVn54RaqZC4RNQUqwIHYZwJmHUi7Zk3+Sw7fivMZBr/AWqa66I2hk20+obB
+y5ubRjtjw6uaciPLIoMZksxoEwi5xv4KnQHAQnaihQ558RPpUwweqHXyOZPEC1Kx
+gNQPrTGc4Zm+CKqR4CceACSYzcYtechZpSQqn61emmtyhowDqXpqqjG2nimNihcI
+hbp5O+O3fKZFkJllB20xuaj0rK1NFF4aLiS3BK6aWeCZ6aXFawSvbQb6vGx+pQmP
+eQemfllRXXkT43CHUmMTaf6gKnz5DaxDBqdVP73dBa6UoWnxTrZcUNKiPUCvB3g1
+ciJePjBnsijb2Bh6jIwr7yghIbS65AYE/0V+5Duw360Fa1OqJkMuz5pKeJIUcYEZ
+3yuI22CZeorkvymKhrt1hUn5xLIKRZkWg7UbXG1WXCrGtPdJ+CxnwupHMdL8iMLi
+1haNeJ3E/PeMjehQRzSEEFwDljn/b1JtoWsEwnQPTPKY3505OWIhYRwRXLEo5n1y
+QEfktZ9UtIsJcIpfi7hMvbpp/7Njlu2MJKZ/1ZtvwVLoaXFTSivqcAkDdP7u5enb
+OJ4EaDWrRXS3Zj31fpYTV5p0fRaejFPevRNnYvMLRiSoFobd5MUrKjxpxPRCLiW7
+24BF9QY7C2Nso9yR7gNkzLw5x/725lGxa2ZD16nJmiECOaEB8ORVlilmjX2OQi66
+hpGVtjHMaoGr5IvBrtc7Q9aM0bdoFZD5I2mOm0hniNHG9es2IMByHWRAQFzOOLGH
+IFoIyW3OIuzK3cz8lMLsh/Hlbzo/3bpX0rbrn1XZULWAJ1oNzRJRi6a3Sw2YoIMh
+656IJB/fGRbG9CMVMl0T7onDUhZYLA/mV+xy2CjkQdPBjFpQUTn5YHu6zMU7gejo
+YSV/4esuUfhogLiqw7sPuCDqLL2UftN29xloQDTY6MlrkFb9jCciAwn02DAmsN4h
+7Utus3Z2N7gJnxt1dRecqr2o/agIINm3tMh0LK3/CydmlthZQNpsxMD7IqaWFfQR
+Uq7zQUfYZi0l2J6iy6FUHUokskqwgiNhMP2Z+uZ1xHUnoP7E0IZMHnVWEKBIQZ0d
+ddDucux1jOBlMwLqom3jYPjPkxoeSU2E0ozVNSOqsPnoKkz2qKnEHhea2sAPg4eX
+lsZ9ENQyQMZVapjic41BU/32pbrE/+JkK2Cc+dcLlrnHo+JpFeTdbleJhZ2JgXHW
+8r04vZHA7tQOc0KNR522Niu7dvOW302lwmfp7D5xfon62/AxVhos1DSZuNpVClm3
+V59lqeCBDm1yJwdM/946Eq45YJiTNTzYsPPFl25KNv+3+GKkhZ20GuLiaqprel3S
+MC5XbMJg4nc0LiAfDT/q1jO/EKZ5LzRRtkVvx1D8To6DAptyFoJSMKyFu79tQdfN
+371+sXEX1VjpEGxO2t/DUmuERIBdc9X7rPNOXSl31QxsXy4s73zcAhI94X8xrqYZ
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_blowfish_cfb.pem b/samples/rsa/openssl_rsa_blowfish_cfb.pem
new file mode 100644
index 0000000..b3581da
--- /dev/null
+++ b/samples/rsa/openssl_rsa_blowfish_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-CFB,A6C793D28C38F56A
+
+sjmmZGwl3qF65MFuXEtiTkltbaXuionUsMtzc/XzyPPaIxcdl/03iR5Fix0hTY2Y
+/W9BntQGcycH7uNcoYwOUScTRr2BJncyoDXZaUx/WOQ6cDHuhRWWwpLpmitfsn1B
+SRvLdKddL1GE2nfG2xhCdN4N7pVPUwIahHye1AkaSJ4gur8tU0++mJQTjDo63xKB
+oTh3mZB0OCnelXtoYFKGFXNh5ouAPZgcE84breDJBoGReH6f4elkigtSx/J2QhgN
+vXERboYz/HHhHSRCtMSp0qLEQo+uLcFxZcSMQE12eglOOucht877V5n5RMLFT/3c
+DeZdg6D1b52UzaSjTvLm/jJCdkYqZf4SFuBgLHF/rEALQ1vBqDiKQ7QxuWz5ApPm
+P0ntscETngWuJ2g2M1EoxGehwNiJJEslYE/CB0Aky1XeUmUAUm++Q3QVfUA3G3C7
+pP7whQSr1Y7gL44EmttFCX+dX8GWXuZDXa399wijphVw+6bl0gp/hWRWriTern1D
++/4S78ddrci4slA+/Kkq423wjLNGZtOoy9cXRmFdbQlMfVaeu5U7LmrTQRrgGVM6
+GQjgNanXYhkCNubQ+v2Q6FflAdri8Ac8ZvFXxSIGZ3JG14cm072vOdp0/rCNkzSb
+fmtyzXUGgNgKzfp/GFvIXD04lLfeipzlUhNvDK8AKUNIctrMHZegpbfSm6HD6BiV
+rUFNLvr58WDK0eLeRxg4pFTCf9QXr9Q1v4MWehkn+LOTconhJtRictdlj+G2ymOQ
+LYgSRPPdXVNxlBI6u5WRtMxzZM6G3N8jkEvFfFsyeMtE+R0OsXiIwvGzdksnI/1F
+deQJzav9uMBj4A0bJuMQ3Ls8ydZNFU2RDofSU84bP/g6TzU8MpT7QXQXPD2jKdLp
+JouxtbRw+YY+9p0sk5PFYxti+T17jZN//pqiBrZUzvspwr5sWoa8BbA3bWE2gnXT
+cmx98wREJ3wWRx+t0k44084kD5/cvVH7MsAQ75XxGa0ofVj3crMCL29c+/QaUnhR
+GrdJ0sVJeIthiOQZZ5zBqG+IhJfG/jkKpweA9fkQ5gm+FoasTfDnAdSJjah7WfoO
+C6LKzNBB1FaOHqy4X6LUN5wraEOP+0OI3hKPdOB47yUzPF6FGneGk4BajDHG4RyT
+F2ZnG1aa+FRfakQ6l7ok4j+VPtDlCPY2jnT7muj2F78G69abNOS7ASXg5+PJzso0
+liaWo1d8TDfEazlDQvglDAKpzYw2mSbpJVmmbPSaVZxUARcIIaBqxu6xWepfdN8v
+qZGrOp7vTOuGu8f2YmWKd3+lcNm2CwwGYIPpuTFjtUuF7guKEdTffyj5tpOdo942
+RAy/F3tCy5zfZrI8SkSkx+wfZAnkUnI3xQNdKKVLCXcpBtQWht2UGO1G9W84OmFy
+eg21zeITIwPJZfUif9WHihdINSlfm0CiS+gDRzXukS4HgniPfS3NPo6HAepc2Gzr
+QUGF/ENern3v85DCEE/AebRaQN7liM+6Z55UZ4GOT3Tj64+Nth7MNQXqBYEmCS8P
+ndWvlalOs+vlj2Rl13IcSUOK8OOr6S7jeZhoutej1b4lbw8RwYBXGg==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_blowfish_ecb.pem b/samples/rsa/openssl_rsa_blowfish_ecb.pem
new file mode 100644
index 0000000..bc3353e
--- /dev/null
+++ b/samples/rsa/openssl_rsa_blowfish_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-ECB,1E15270A7DD42BA2
+
+zz3p7Ml80hSdlJsI5RyvOScQlsGC1GLg3AK0dC/Hh0IKPTDF7a2OITL6H/y/3txz
+LJ6jAcobjRfVMWGAJUwFaSlE5QF5W1+RauV+M8oMmv+Mf2K/Urha6m63EauLEVWu
+IDtxj74qfQgyd//qWHU+XmWhhNEGk5MrH163VITZqpG3Qe9dYHdalh4TB/ILJqfN
+URKLjdz8L4YbL48dwK6UxargixQ3tfrvIdTr4mkMiquNlayTk9g5qXWnEXy+I1DB
+HweXveJeSUHhYRXdx37y2I8Bz8HcuZF5wODEDJJuYXy7a8Q+Ar0Ll/uQ4NXE3iI0
+NA8RA0caAlc+Du/xfzKdUgIPQaLt/sjhM4gPBDLlASUmO+PJfb1VYgDIbNbXiR9x
+92ePzennPnbhKsPcuZzXoc/jH2BiQwwRT2gLscZ86n9O1FNoaPAnYERlyNIVrQoC
+0Ll6NnGBM9Ls5k1royQQtZU2x5Yu5Q7DGcNqX2yI14AZrI4e9/Y0nEa+17WRD6eO
+fdaIC5dVrv8HZxlfzwFs33FpufovP2vlINWM3IqDjMf4FIQsoLdnmTsgoLRYm4JK
+zfcyiImXPt2iUrcybZHKa0EXYjrcoIVBS8YP1UTcG8WHnj3ploMxXOw0AmpXcznf
+sbLsaehbs4ugM5G358PMeWFXTv8K2YXRtArXHtkIYzA45zqWzpta5E7LiTQJfBRL
+VNtLja40a0gaajvROCekEzWhezZc7bu6RQ/XZXxBYHx9m7nhzKRkDlBrrJVpWSW7
+QmS0ptXblyt2tbaUtNLsi2SP7gP9ggTlc5hCpwygT+lxrcr6j18CiPgMYOgDmFY7
+gZ3jZ+HHd2+8GnimOai+r8wh1aW06/tLfIZxpIn4T9yGh/EMW/R1RTJjN0xe6oqw
+wC+TPUM2bMvDtAvdn8bYh3pVVLXnFa6LjhhgNvnx6wBoiBCJ4E9R1Ec0QA4jF/97
+B4e8TEv7PAFB+VGhIPnQqfsAqRfM88FwgZqSfZrBXKMVWA7I4fBeVD0cJQq8TwCz
+TY9Fi1YnomqTfacH1hf9KiX3j8OkfrhIM3+w26nE553/wOcO42YJ55NgnNXlQL2e
+e1s4uJ9lroATY2WqvgLy5Th8n5y6kVkjuODb/8hk3KXqiLqbUOmZCYLuT4ZHZ+Rk
+xtWuFpmFiuWgbg6Nr2t2KYXwD39pjGBRmmwMX1mBxmUD9NK28yO4HEgiPVzfn7sU
+1PWC7HpgPf797M2/N1gyUfrBbfw4OXWpycvmtJLXHEJi/p/H1bz0MuMJvPtNhzUO
+CP4jq0xbu9nT5eW9rD7kgvv10W+aUf314RcWKaLkOxkk2dTENjbviASce5X3ZU4l
+eGG2wtoHvCvHnNVj2ImKf0jbAL7dymVJlA1XwsLANAmk+9RGyVJgHn7ZkOfRVJmW
+VMfZ6AVeFY5BeJ0LCq1uE6QMClVx8fLN2iBEqamBNekcZ62Qz3b1R7ZbN2tlPKee
+JnLSouju6Mu8U9twVI2tr63OTh/a0XAjtlO0OAXuVcOmYOHT9fSjPdAAt3Rp50Sj
+PDvgN8s+qSkQKpx7C2OA9Wisrr71UrBrCfBhCOmN5gyWFg24PwwRKUnc1a8mT5Zx
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_blowfish_ofb.pem b/samples/rsa/openssl_rsa_blowfish_ofb.pem
new file mode 100644
index 0000000..acbd8da
--- /dev/null
+++ b/samples/rsa/openssl_rsa_blowfish_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: BF-OFB,B9F95E282FEAA06D
+
+StEkcUPp3txNaJlYBP+eVabWYcEzAkX64aj8vaDX64i7bVl4ospAs2stac7uXtXG
+IZLTqNNACoqC0jWWTDJca9vTEoqjDRKjN9yjXYfrovj5oKi79wfsSU29oH1dcKG8
+G4y8qNsA9TexRQDWTBxYO6EiQFVie9O3oXzjhO1hYwxldSWOV5ZRWoVmg16vAOxX
+Gx2W1twtjQXG/hp0HxosPkZteUDdhMZLWonYuqEw1oBC4iDG1Tjp0p5uSnb1gaIr
+pzZScikP0Z4/8CxiKV9/C1VNE70EHdAUYKjUx2PAbPaMFyO/sAXOy1INI7Wis7jh
+U2wKeXgCMRxmca4OMITcjDp6OGmKf41uWyTFwjO1scMvjSJsOZxNjAjcrZW1PPRA
+tvnhRpU9h1G9BOH2rM7VUI6zJ2FSNKG9R6M0WOQqxRegJzvK+YNLhw5lUzrbWOR0
+RdkKL15gfnuXqLTDTMuLX+aCDS1Mu/ZRmDqLWkJH4W1HJ4l2rBojX5fcbamueMyf
+Sbd1S7QtmF/B9LaGDEPMT12kOQHZkRBUYpyolK6BoMuRPYnGS0RkUwvIuPZA8uJU
+vHHuYRZsOA45YFEipyB/sek61bvqYy+8TaPxzpfj0fkh7AUSQmbk3qQRkQbltzqq
+/MkFShIzS7SUkyiowOet8fVjXDJPsw2bS3uOHC4zy2QQmhVKzCYWd4yCFl+WtJnZ
+eEkrZH2BpoCDEzKlex/NQlH9KBLOor221nJEVd5tkdWWZt71eGld20eFL3ewtDqV
+GJX8jFmR51vQL6NZ2Ehp/5zhearuBJ8VKJfFxIKSrbPjyCbEwUgYOyVHHyvYyMR/
+6hcflrUu1IFFwFhryg2bucAkdX9AhsO1dimxSgZKEFlZbihPBysCdUw3WRea57iS
+n/zqLrOm786KiWh0ndBgJ973g1x+OeuUvbNl/0yiO4Vjny6PkXcBOORu+ILEflzf
+UiEKyG8+cYzoYZjeiCFBxsA2+gZMdgjxVYF/lKzTqFkfpwYV+tF2K5N8W51cL8Is
+yhz5OHiENobjx3QeFCZ4LWDEXg1H8cA34i9oELbXtyG7W+hkZp0B9tRDrXcDwVWk
+4oYqWLNCQXqr1lL6cCuctKLdXbc1ibLt1nYGpJrPkPCbOshsI+iCMmulT23s+jqW
+TMW0RNb3wFjR5z9A1YTWfiqMKEcyzRhP6bEM/+WNmHE5LRefx+dnvZrVJzGZA/3k
+JAOpsxEPKv7YNR8N9yoAopRfFEOH4HYtLbsAA2sZfD6iVAXAAeiZ2Ehn+Bvek5lV
+5zIOtsXswRgzXvxXCPy0V5GWqMglbkUS2HGsWaHpxDSMbvBJuaSi2blZ16p3IICM
+7YcCLolKUaWqpXjhb3UypoYRwJs+40EiXid7aJ8rKoeId1SeETOwVWkz95NMiVK9
+5K37/OMvxOAdjAUxtmz/+v+twKfrUhYqP3Qkapy6FgA+qxnzpCFZZXrMKjpr99Pc
+QVNcvM/SKWB34jZGTo+Styc7d+iXDC1BUS/43Pvbka/Aa2IV/LPQA2pD44aP5l3V
+/tOfQFQWI0wCqpBPV8aXqGuqZU2ES0yc9DJ974a8NvS1cNWfsMcvNg==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des1_cbc.pem b/samples/rsa/openssl_rsa_des1_cbc.pem
new file mode 100644
index 0000000..2d2233e
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des1_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CBC,4629ADA1FF55BE00
+
+2093wYtiVZThSK/Ecf2pxfukmymwYi+yaWhMDfxz/O001tbrlC/emwfU7iprUPeD
+NJyyAV4GLjUBA51tfDqia3ATKaBfUtMQoC48+q/Lkr5KhLZEU0LLVuGrfvmDXmPb
+Ne9Ud8XZGnrDmvAFkguzK7cF4PFWUX3l5oYKinm8he7pA+t9RJ6QX7+BHKQHlWcR
+cT9e1iN7MykRD2Hh7YjSxg1uRlJ+1H5zIJBDjQ/WIUMj4EdNJriurt7eYY2XrP9M
+fyvTOBgYRHn6uQU0tdV0619j5yjEBpPTRf2M4RGOeNYGfvmk4RcyZPdnccDq5bWT
+w2XhhBPZMdCHmDPTCOwgfSvqBBX6OtH2EKd1aJQmtudMATPjA49Q2v9ZrgIQQxmA
+ZXIXuYH8wNPlzpm+abolucwIQhWJqr5TP5q7IKfYLD7FIjyrPBJecGoDuPB/Qp8x
+D9G73DKYgu3aYEFxcjs7tWwWe93pn7glEPmuybK2HP0iD5/YhXy9OUElAUZVBHXb
+WNyFdcdmyP/hcex5nI3Q27yM1auTS4Wpmvg9I5Psr1NN5ilWFNiJ0fr/YcOMpVsz
+NqQPuSLqxX5sg7X6m7MkE0/k8PfFO+tpy1cC/K18nnka8WgH4SJ+R1I8WXLKFznU
+X+mWcOaci2YBUHT7TWRzJ9/5bL0CEWlheabTjqbaV/4kiE5L0Wcbh/am56c2YAzi
+6MzassP58vp4hHXTyda94+Kj4ymYFbRBLqh9CVspolwDhy6e7ydcspGz/RRbuWrN
+Xc+lsExkvnLkYvkfmaAU/C5ME5PNjgM0kH0qXLyXPPtdKmwWrkGjElzaY2iajzpP
+XEmnYu4E8AsNdNg3HVcQfoUU7jFq1NeB4uibFrq8vh6VLmqGvK6XCul0gxJsfsh+
+j/38B1+5I97I0oplDZrAQMgek3BXegw6HZVqADC2KH4Jir50rYNCFrN1un9aohHG
+BdTzB1wGkjW2fJ/yrU5nkkTYcNhl9zU0D09XvFvXyeRdLzJL5eFqqZluwsPPw/TM
+CSwjTZbbeS2LvvstAsoYGfQTUr/E+BOXVpFmNg+94DBxwM7lCy57nG2Y6oIy8Qcb
+IfmF+wKMZEVJxy8O2uaCYUwU7qpucq1tz8l4bTo8wUctxw80Iflq7WYg/8V2ilro
+F1nSJ7gF0bn33KwlLxLy7akXiol8Rg6aOg+cAiMi2Apfg+5DXWrKf9YOwebDLOX3
+LWvDuMYRVccwVWsA+X4zUezGjVNuxjnjtsDfeiScf9QyliK8kjlMP/r+chrhFFzc
+LXARzcVfYCQhF6heOOY9YTHvcySV4NmgRKC/dlzvN4NMGh8VxWiEFDo7Vu8XTXpN
+7OiSd/BvmOism6emrC8zRMD8c1ZgCxuY1MOMVXRir/Qy1IWZXiYmI71mmJmRhE79
+Gn5JJ3aZ9xZmr34l296CWOBY/suTRvkrfyMRoSTC8Z9K5nbd+cm0MLzWMgiT5PAg
+cy6PHN9zVWInz/2z00qf+3lx45ZmMeVj2+2h1PFapXaCwvek3VgsXL2HUV/mKNcU
+ZH7mV8imvIopRSS4YQXB0Ophiv6i7lJWdKrSYd/Ac+Bt2E4z7q7y4wFNlZBvsBoO
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des1_cfb.pem b/samples/rsa/openssl_rsa_des1_cfb.pem
new file mode 100644
index 0000000..814ff89
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des1_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CFB,07BD7DC7BB2EAC98
+
+yH7T+ZIRWmzcMociF5wV3YjHWCUMs9C/GUrnBP37vvJrBDBB3x0u6aQMaOs0U1Ih
+xbGOweaw7cMag1HhafjVK9ZFZlYsCfXRZk6JdOvzPchDctQrnjkDxnwpOllmp0w4
+Mg9mYLuEvN968Tx2TS26va/rPAu3xxA8mrcCuSfyt6O9HteT1axwDpZzOktmnbYy
+xHQDRcpDXaXspP2sVTaZJ3oq/AMGfrFXCu2m9jFHcyZKmEm/DW2aLmfOI5I7gCLP
+1KMekkauODnQZEE2Iyi1SVbTBKH5DPp7yXAXWOtugBcWNHbMF9QHqKlMs5Hd2MYg
+doXtBSRRBc9pLdF1FMwHHjPFI+GZL3hurqcD+YyZJqYvzEgnI9dls2K8MzQKYKDn
+6VpDCNbEf8aC0QmvCLIjqei5fH2RVYeV2M4Db1GDmpRAIRJEq0fXf5ojAD0Mhv6p
+DZYsz+f/MLTGwce+HCWxZyAyfptdK2ScfvaH8mUr1OHd5IdvRudh5+9sCtch5xQL
+DFIp1eBRd+2gvLBMja7gBE/xHXoFZtTR8xORCwgYXVrLLf4wG27XLdKQVQiS8dpi
+E+xCtiZmZfxb/1Ly9yHP/ehWD9DmxRRr/n1QeGMjSlLSzffuLgt/0tftK5yOSZri
+Xc1T83n5rLqhBglNEvwR1ewsTgeIxkgZo7q/LFajrnGh4L62cIoLkLX3lG0jaEC5
+VTa06i0b7U1nJ6kiqjHuXzkZWjTim4V7p7r/SQtAGuK3s8AmqJH53EMmiK0zFq9Q
+ao1ewixzD4NplA2HY4kAAVRQMR7WWIRrV2wXRTqoKwITMbZ8Yio8PwgSjsYhuzwv
+Mct1CmTc2FcCH/+AZOqc2HNS4qwQVmwLnOLmsr7L9kgf9aPIl1hkn9KzC6GAU+fZ
+F+N0Ti7d+ZkNAtAUg8fi2Bf/rtPvxmyJp6QICI4Tj4MFpGIRWP5rLwU6XXNch0l1
+nAcIYFvzLNL1v0TDnDz/CFW7XSp4IaDl0OLyAt+JxnPuFOAo1wJOhUWHheGynEBP
+U3K4u+761XMdqHb1n14OSgfyynIuLM6WtnBDoevKX8v0dYjO6PnvcuZoRqs1sYKr
+D93XsV8uMv79Oo84xQPHpJrUIJVLDeE5GLFimD7rUPvMURg1IrFnGyfcMGTvsv9O
+us/B1dNmOHjG7eZwJ/8MDNsYcpwm7CQsTOJUZkQDN7MZOKJZJr2gQK659eULJwaZ
+lEkR2p6A51etvlSPZ2pjy2Mgxk/T0mX/mVprEvCkxFWGlAxys1UFWKHDOOP4rUZs
+iE7nxBMyW+4zHAcco4Nly5gryqWiW0gn99/I7+qQHkb5X6ydP+GKOHmUdcb8RPIH
+Ec3bV7mBtfYxDC/ouStuQdVC7jWGwU7PeQqoz4d3mhK8dfeOvpudiTD1BLw30LKE
+Dt8/tob6zIHMEA5NTu6g5cbfa0lhRH1tD+O/7RejWPwOTc1LbY2igvHoh5uWTo8G
+ufvYO41PElmJoujef4njSZHcMvHArinYdlWlvMIg52d7Y3lQTTztY2UeO6DKRHx8
+Qjda5g8SDiqgFktkl5r9FYfqMQFqheSgKnHaJ2oPPbwuJyuNdy2Rug==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des1_ecb.pem b/samples/rsa/openssl_rsa_des1_ecb.pem
new file mode 100644
index 0000000..91a3f49
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des1_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-ECB,451BC59702897B57
+
+lYkflQyHR1brYuUKx2oj0+L9fRwOhpKR6NMeH2nlLEMz1yntUt9DGuBRwP4RJs8o
+AHo7amQ1YzGpQCEZx3p+tMmk/hHRcRmU3ZeuP3SlGwpUmbMe3NI8I2dvh/qDL3Rb
+QParp+YK2vH/u/N2VPB11NvgwoUQpfS35vOhoLk3GUcupSKfbsbl/gn398DsgfoI
+d0qD5VSxNutst5I05pl4JFnL5+DBv1s9w68TdvAvBqWmsfhb4ei/mSp81e6ndxOR
+VLF5hgXauJjEHvI+c/ITF0roIyyxiMMjFd8IuIHbeznIjOWn4P5YcNcSswSG2wOz
+1wB0e8dlskukcUGqFS6W6mJzqb2TK1Eo+l0w2B2rNGX/MlGV9f6r7e0DQQFH0nCI
+nLS76C+WB5G6RA/7OMOWtsMnYSLldvXBxxZktcD1CNjyvuCOI5NK1KmG/Kajho6S
+/+A1mTs274pI6sIsCNl4ay2pfgwjZSWh95l8+YNt7o0C5lHudZ4hZHCDT8U2uCoe
+7dhj+KTuIS3VPI7lzruMZBGAj+haZ/cAEdqYGXizOle4MwKM5+lS8E5gEviTABua
+7jqhqbBE7CkN05Y3QmyE48yzi58hzSmiTOuAJ6jhB47A6Vsp/FpKFzfsK4BoD0Zh
+0ujT2BeJhtsFmPY6+RLtGITnl1498j9FTfy8ZNdrXEMxvp8SnEzlIKytLQyNoz7a
+tPCe1od1w+MUz0PHqDO/Av3YMULGLCUgnuZc0YjZv3P54FdC6si6KFEEqotIGD0j
+C24TXqlBpn8Qqkht/0TmzVHq6U7jynOjD1VUeB/gudPlHGLs468c7HzEzbpE5h0G
+1e5o6D5u9Nh1ItMObNrjt8NUxbi2/FX/Nkm3J1Ogno0ngzh15jZUfWFPAGkI1nho
+12F8Sf7YTBizPW+sd5hDbVejJURyoj/jt6UfiVKUg9iUgOW+ZzgkbD8RvC207xis
+QoF+2Lr8mPsNabUaFbsXmQ+6F0Pn05BzyBN2fyTxRt6u0CKmLE1fqkIuQywk83UD
+hBJfeewGoOGvoXDSy0ggIkjaRCsk//Xvntt5HEmKwc/wy/1Nzuu9H3C6n7qLqyNJ
+mPhrOGXt6C4LG1JscqS87z4VmhV7mol/Umdg00HRHs7l9qKRTePdlq52JL7oUws2
+CJs/UTaBHdbV2vh06qmymtEyNmQ+PrweEL5U/neyeYyrx6DsyUDdY1h1n+aKSEyR
+eittKv/pouPSLlIiMeY/DzQwN1ifoGsfYgJRst9Ry4MdlahpCTX+K7X6ryEOoJ/H
+1IEOm2aSlC3qEABUGo50IqiNF/PWugS7Qf/JzXAyjtcgQdW3cskNDCR7JVJDtATu
+0817ST0QXBL8qT1C3z843LcY1HpnQ1MiQvM3maDHCxuoEoUrRILWc59mc14gmowq
+g5XLMOLC/y5mX5LDqkxoKhoED9eM9/9EGSSy83dWWVZlGNLzu/JHBiWa3tVhas0U
+LytNa+kN8UfTC8KPe6i8euhauunLIKkq+MUBWy6agFR+jflE0zd0Av7Ox8HPbGe5
+0fraChwokeFM44fy5cOH7zENfng0jVUUreTpDtcfp390QW5Ca59J5/5P2aUBLZHi
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des1_ofb.pem b/samples/rsa/openssl_rsa_des1_ofb.pem
new file mode 100644
index 0000000..93766e7
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des1_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-OFB,62D0879F9BE636D0
+
++iyQyk6TcPldmHOJyjJjsJ4BgdDqqdQYRzQWC/WfDLJyw3CXLquWDciAw5aCof3k
+b6R4PvJHzvG6j9jdlcv+yD5M3j9ZVHYkLL0fTZA/LEODUOTX74gNZfoz3FGarYIV
+TabFLgwQh4YJ0+Nb5N/oISaNszC+wxf20D4N445kvuHKbak7o2j+5ZzGId9zYIPU
+Jat1HygggKh9PtE4NildizyVVK5h8ws8qPWbe2/m00Hf5R2oP2YC3Afn6kqMuueJ
+RrvP9l26WboAKFED91xY3gJy8r3KkkLOJq9856BlndtgkA3USqRM31W6RvLqHUDy
+3l4ZY3wSTCdZIX+iHV6Qm3xYaIHNzYjHRcPQKdOVmEYiUSmAZmcavcsPC7sEfD7d
+OMEbrYrztF8iO90Myey/lJxo9RaL5PfWbtXqnXKUZtbcudEQd1fXM6gzdMm8AT4F
+eUSayg1/3AGEEHq2PH8kKtxnWAb7xBOgLbjTuC68f38dFw2P8iWZerG5lbLsFuwD
+YZ5eItuDhL8+dbFxisBX6H0lzcm0pwK1HCHOvSCcYfpWC4QrU08WbtI7NCqIuRWv
+4QOHU6SoNGW99BSnUlsqgLdIcsWsyTwiotZqusZV9AusdsGqU5ixwal4YX/8JRg+
+93EwnFnl1Y0Bj/yoAwNfvPlZhtjevsMnPEbrXbFEm0Xw1kdhOYokrx0hQWUmdt7m
+cFdmFBYQGsiKucvRpmInylrS41VQNbNySqQ5iGa+vDaPBMKZusvgPgwWSchotkzT
+qTQ7HNjszwR4eIjBOiBSvY5YXoa9H3irdmLn76mOyDMjaQyC9o/0tbAagLKADuF1
+Ui4Z/3WV67SuUoawqDJsYEWbOaNFX04wFby0k7oACoNxqoGFM3ITRzmxnz3ZyiPE
+DV/grOZICMLfTQ81VvE8/w+w697F6EJ8rY1yOznglP4GXrtIiXAaJbxEOhosyuN7
+HikpDQ3GRnPzXeg/Yngzpp8JMVdxKdEItcXnWd9uhB2Ok1vXH8LjhVkhrL76bJe7
+bhagz+LphPaLnkE5BPHKLUwL8bQQguz7ITfxsEFpWIHG5zCtpaQwdMEj2ePVubN8
+sfZ3qhDRNG8DdwXgCbCot16SKGuOawMMC5tsoeg3DFQ4MBDrKUv3C9nF8izTs1Zr
+3J7kWYrZg6+hVcJDgLS3t/lbFIhaNAULmep6wl4Vcp6nBqr395r8/uDroOpoBxoa
+BNjvFaztkRy3XmNHp3TOYLg5HZPWsK3KXOs0FvdTMEEsnoj3PXz6+hw0gMV6huYp
+o24r34gKiwdbrkbwLRnyh0oF6d3bPOZ9WnPgA2y2MB+slulA47+hOMcP9+WiQxE/
+eGd6TTRjMPopQXJw7/tZEf6qyVYLWfKJmI0tljsea48NocZdsek+e4ZsTW/iP0oZ
+wPDYNt95V64APcDZfNtfzydp0516KY7p624TanOXsxNNiBV6Nuqmd0dGhbmcRC8Q
+KNgGNvgjF3rhqrXZyFpnZNQewE7a87bgmO1O772QU6GmPUZr3nzPRwE/8+TNA9AP
+hHL9HtItZ3arx7eJ42obFrxj3uzpQ8WQo/cGLgQT0lz6u91xJyWi2A==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des2_cbc.pem b/samples/rsa/openssl_rsa_des2_cbc.pem
new file mode 100644
index 0000000..9dbe30d
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des2_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CBC,A48C2683D96452DF
+
+dRu5UKxN6kr8aSBwZnynPwIA2y8Dgu6Xf2vCf0JswuFMJAwFGjiHoZTmIHuAjArK
+GWhiMl6ak552D/Nugz2SNgC3eJo/LOP/g2NIJnG09GuWOGXkiagjDKNbPCiIBPww
+STIBg5ilKV07lryS0FxQSUWsjI/2c0yxk/6MGSzQ6rrAWB4Cf843u482w6Hidr/E
+euPsqXJDtlQrKQ1gaMTJiOY9Y2H81b485MBN9BnKfDH4WHp49b/akcditst59fty
+FtzwyUTee9SGY6u7oKaUUe6sRzFOeeRR2TgWG5Bs5sne1AFFen2/q59Va/7/iXRd
+TOKKUGR4yj9gA+9EIpDF3n8Vn3G9LnTDFK0Xh1m61C1mQmXgEOqJGLVreFq4u1xq
+0J1yEZKoXreZJH95+gYAW5lmG+jNCMy0RO5PsTClx7G4XcIGFZAXi8sXfk3FYLT8
+nboMgQ8IXFjqO85FIVMt+xCpov+S8yOfPMOU63zxrynaXD2eGv7y2dTpeF3Mf4Ek
+be0YrQEWpCtYUdZ9AwA4N0/vkdp84/WZ3Aw/i+KUqYKtK2agkJYtarqj6iUweUvW
+GgWvZqNiTAd3sGcxffSbcdSRpuNttnBG77qAFgFiPXtvJu4wRkGlaxhwVTyUWK2E
+HvCEsssbzX4tZ6GUXScXv4zg3YaDP6HXsnBENl5SGXK8Uelett6PJhwH7bfpWysG
+Z1TD75uk6twThhtPURGG4GUaQ6cZ1RUsL9/y06v3ZmfUBxeVGLKwyMzlr2FTYenU
++LcvzriycweTLMO6llLVQH8XwlbAZ7JgndCjZodtFXhjhrS5Iu0sO6J2D7xFvL3q
+/Ym8PhhRStcVjijX+5+9aiA8AkXK3khP14T3yhPLu7iayl836Lh1+O1BHiYgr9Z6
+DdhCmO2Esa822yxyOdiwVlF+mYQylEZQy3D3kqqJytO9pn87cSvR3WbPtFOStlcs
+Htms8SdqLAamuWLGZiycPr87mSH2By2JED//80fNHdR1D7cvPU7oL/ClFMX/F3EW
+UJAwSXswmUxqccBR2hOJ6K3OvSIULoUn3awM/qPNTQL7rg++dSzUDbIiUywxuU9N
+nXkqfBVjoJTjafgWd39G3RdoK0ohf9QFj1nqYfaQGKy90cPVw/FdjRyszJWDUBTq
+jlKXnap6ZS9PGztjEoLqmFaFT75RUR49NnNtmcKmH0i6anjwFWEYBM61jox7gH+g
+W0r+0R2yijAspXHVpuibx9vdgkq/WR4A36t6DEMajOHM3SVzbPzkHTV5HyYQKnaw
+SZLSdUk8VwYkGSylm3f64PJLxBl7TNtrQhFLgR/9QXkhN7U2Qc7WxRQzhLQsLbtL
+qcBLGH34SGQarQZ5dfo3t+B6IIW2HvHNOiT9HQsIJTz4Er1SbLNH6bco7hud6aOA
+eSifKkWLp3SXXS6wjQZzsSGZ7Mws1DRcL9gEhb4tgIvopQK773AbQ1SJDEcmBpD1
+NmxrTbb1TngaW6u/79Nng84YEUiWNDKu3ovoe/HLVZoDr3tGmy5ch0jfA6NOxEn3
+KXZCiu/PjU005SLyLql5dcGzagjnnURDi7TLue/97xtpI/ac0vL868Cqfm0+e26H
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des2_cfb.pem b/samples/rsa/openssl_rsa_des2_cfb.pem
new file mode 100644
index 0000000..451670c
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des2_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-CFB,36E0C8A965F07E25
+
+L0GHzT9XVnA03q7rlchpiD4JCgzISj+B9GxKCrKSJJBC8bRTgjgrwySMQyhdX1nw
+DiCtb9q7UCxQ/j0VvHuoA3OS1/Q95mwCsnjUXYAPiXeR0NMJkLgv1hFU8EjAJHY8
+ZenlgfC1RNoUONucq7v3F7jpsqBWrxjyDXFnWwe3edSfUzkfkG27NK6LPScjqdY6
+kJWAkHGpoGog7cYVBJ78LbYYHSBR+xfeFzhVMqB78mH8/Y/CGlKvXnPFpiJCY7Af
+zpd4/PJRVubXVyANc42k+0/E2oPOSKiwiKV79BxFw8g+NxkhRzXeCDuzvExKL457
+cuPNB0CQLSVNmOWKr6mA1bIBiJXgASzijsjkyoH62D/QoBo+kBT8W3hiHooSzJ89
+flhyknT+rVuAbFdPGqriS8siN/r4Qq/gbQIFhNe9jsSQesfr7lM3oK2EPGpDxstf
+eKc+EhHBlT4S9X+AilnjK5il2X5szyhOFZQ7RdAiqZ7X2KPNNqbeS2L530ZvlL+W
+Yw4qco88cilN276QQWCcrp3YcWv+MzawlNvfOOAb4GfUlR+njPxRAxM3rGVXiMn+
+6UL3X1SqZfADJOn57S4cDoP/A0i3FUfoPTwQW77LOAIzLSeMi7brQkZi5J9s5Izm
+OMcEi+GwBrkbPl67fKMnt3cHeFGJmOftrLZCt8HpGEdiQzP5iiC828XvLLxby5Ue
+BGoBILGIHL3OqkTVjBbSODKFZTIOQdVkqrWKyXlrfoI1meATptP7/GhdQP2DTW8B
+ppmNgtwIbGLg/AwNmGPdpL2mP5SZLIDJHd81BL00xPJFCR9wxXLk3hgm6auzAsZV
+FYjaIQ0Qza5kBCKNqu8ad8edqgp5Rj1/ZzfCWEkPRHD/lZ7nj9vuC/dMnPphohKz
+q8/L1+gbp8dwER7sEVBiWDE5u3lpSbx+1qkk2CwOjE9eBh2Mr6qLL2WIFb4YUvYI
+OAWIU1ftenOEjgjvYZcdeEOYT0UF6/avfHDPvkTIwl52UUhunbnqCjQM3qr18rbV
+8vB1bC64DxetUPhDymLqJCe4QVQajdO5BxQ2wwRjHlBi94nlAS/uOFV+WwqtFKZD
+TakruYhw3VjGxtnjukruMzNjDSqxd8Jabp1oTHY57C+aYQcBo34XAr+j+PQTPXEj
+GNL19MUMHJo/yk05NZfkyf3/+YtAV+/Gle7TlWWCV1nvEwrHPE4yCGi8j6qtCzBC
+TgpXl/lxJendZgVzIGGzMDemJgyrLNV6ar8TbOz6d5GDV3S84g2S7cToMVHX4Z8M
+bR53pt/KfH27Wdn68z3Zd7sT8R0g7yCVIc0BJgRrZ1aLnyKLSUk7iJULg3+B5NwK
+JNucRiU6mT5SUiyS5WjD6vZVDjggAx7H74DP04rzgzcHvTB2gzx1hFzw6WW9wcCk
+7+RiY0j13M/nD8UjW+pp/Ugk4Oc/bvxsA2tWQ1BeyF+KSNj/zjHMwN/sp1/of43X
+D+lcWS1hCwMiy79KQudrkc2DiYKWSIiXEFlblSJGiQz7SxybtO+D0PpVmlEYWiDF
+AAMz3hM+CrWcXIFNw86mHSsJHvYsSjbCB3ydG8L9OdATYsS3tZo38g==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des2_ecb.pem b/samples/rsa/openssl_rsa_des2_ecb.pem
new file mode 100644
index 0000000..c3f285f
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des2_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE,8B0E5396F9D19442
+
+Ym7x4lqzxkC0K7f3nTtR7/ZVi0Vj36NLORWiJig0qvSmH1rhkkmMjssQqc17kWRT
+ttLj4D4s1ueQBlDFaumMrXloVp8c4zQS5jbHNmf+bUsom+HXGFHbjPC0usHm9TAl
+pPBWMCON5uUxoqJhw2mvrGSlkQhkkh3+Oiag6fxNxnN8Te/yTPC1XXCqIh7zRjCN
+q3wjkh8+0QP8ui2jK/2zrlbwvCyggs4q1YhVzWYiecFro1llb+CDCz0mzKEXj1MM
+MLyMdcooxXTb4t5PhkW87N8PSWXeJEJTxcWYbZ7bf+Bf68iHm6JChc/HTXZRLUfo
+3lACV21KTTI/614rLl44l/Ftg4HDSE4UV/J2JoenbRecljKXneeVj48Lmurc3zZa
+rj46e/pXEGfeEGmkuVnriWhRBcK8Mq33XfY870RsP+4bfxd2ykJYyxFZyoTT0sAU
+LJ4KIVZVc3/jB58CRBZDV4s6/cA0uHPhprtzEHSxp7vI9N4dQAWaUBMnDtPVC999
+QjVGYKRUUNp2S4XVLtMH3+jZ5ntvCTTabjuie/4TAxoUY45CwKjEFpWtDBEWBbXe
+zmIQYCE+o8hSVtt8DFWdz8+PGqF9QgWZ5iQtnp5hUKA4rVeaxF7+ktumTrwguZcZ
+6ZK+K3t4lcHyPZMQBoiWijmBLoRsoQ7NIFEE3sn9muV0XUz3hMCRapWsqS4fd3N0
+LRXrBmZuizqzaNBcDku7lBbembdW7EI9flzY/0Q0xRl7WjOdK6Nj4V2A2MblQoh1
+J+pvV9Tc4PANApNLcFZSPawOJVyUtmpX8QZYTe7QlXQrVIQE4HX4od1S3/ZlydfT
+DL8Atfec1sabrRFs1M86lJGnYxsvismLVH0VmkigWe+4sClAl5QrtCfGQepYmsYi
+jyVruF3FzbOCjcv04x4a4HyKRHeCVlsRlSq/njqCh0WSc7OMacpQJZVvsUYRCaS1
+7WhmzeiVNjgKXg5lPwta78Kh+XbQUtUGryQQrwOnbj0SDsho2hBTt/gbWDpxoQjL
+LGPHVxwqm0GZ4bw+4IXwltfei7MG/ceWxLZYk8ZTkc6r+w0+5HQFKZ3JuSKB3OLm
+rK0m87IybLY/Zfap/WLAmreRMUz/FbsY9Vjh3gt6NqrDhqLFYCyyUKZyKrWnVlIj
+j5vohFGbq968UYVavCZ2eqmtwWywsBXLOabypgrIUQhmCxOUBM7Mi2NVrTqn8uIO
+G5+mwzsy8imChv3Zk2/LafxPpajlu1MuC6CtMdZjV+zrGxJBEUxADaTJU7tTAWef
+lUjlZ4l/XO3vxSvv/F3yONmgKp1t3naS0ZxxYalcMRi6xTznW24r5voOAsVqIz5y
+Nl5FtPMSCBE4FONoUI4Gq1GAen2h2/Dz1Q3CMYAvJz/QfpZFu4DZ+jAUISU7URfL
+7P/lXQhg3onHVy5tgXhiXDhCCxY4pUPSy57eE32F+sIGeltoXU2Okx5/ey8ijr+i
+5URStFLeFp90ke/EhdOuhDoE++7G826ky3twqtSBTt4jU9IemH0agFU3PWIJffm3
++Ezce6LusooS8Bqs9rYXHHGe2q0oUNY3ipggOzx4Th4mwg1HzBQnD6FU33M/WyCw
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des2_ofb.pem b/samples/rsa/openssl_rsa_des2_ofb.pem
new file mode 100644
index 0000000..c34872d
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des2_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE-OFB,0A4E382F6060AA1B
+
+hIbY73AFUCWIkdT7MEKMhr7+uSoSMO9wihHjhiHn01cq6kTe66Vy/z9dmTcgbK2q
+edRngIRyiTqyul1dhQ2ezVDisowHAtdiD7O2/Z+YiXc1hsuC/uELnYV1hTUg73Qb
+v760pWyH5AXNpqGsx2LLw+hstiiWVO+/Hs+CqtM/RgONfvUCzbyOQknDfSTDoVXB
+W4gEDKSDj+ydXm0ZmMS17DLCXgk4HBsJxyiK666l2TzB9pnzj6EDA6hDsiHfy3z4
++MxfcnLxWw9TJPxdLYVdw8WNWsXQd1JHQz/BQ/Hum4eNoYxLGgsV/hWQmkFil1XO
+GkPjF2z44fxN4FJjvQskrQox+5/gvnG+KamfvQt62qN16Z6ROZu5buPijxmXoecq
+gW6SyeFbnYFn27hglllax9awEEUtcJwi6OxKAkWD3REjqCfNAwcqoFqwkxlPN3IH
+00Rksn3P7cN5IqePVjSdwIhZtCfeBW2267oNxb870CDon7OlrUdK8KIjp/x5jKUs
+Pjehw1Ovtvn2YUQnTPvIYQsgdq3BMb9ETcnPDneCVweSxHxpb8ao2hyBMyYtQG8f
+LNqvLnjh7FUyRenf3XRbqka2w8B1CFTTErkMm9E0OPD8tMtDyakI+8fMJDkGhGI5
+jMwY2q98Z+Ef4wDifOi6qNklBlJwjvvybeqhqWOoXKbQMhnQPqFnLGjp5GQMczII
+m9a0anYSvmNKjRtD1LBL0KDMUgIx35U+7GKQfjrRTURYtAK8EITKUqYoWJWXUevR
+t9cikdwQ2yDuDH/C+a2eaEHJITerdW7ba/Rxzh50VdPq03uUNkN21VZEMjcU+GPB
+sLQ50j+gSFRMMzMfDx0G3wHoEJNAul8x2+umCUSpzPfC5D6kjbyREm/fWEuQkvL6
+AUCheoD7ouRR66R8syjIbeCKhjZEXUOvxxNYHSySrxHyiCGE5xCSVDlTzAutvcOn
+kivQqRlO1C6ZoEWbGr1SPoIoi0iMoh+TKZDgMy6/pRWVbELW5P9JnH8K+IreOIXd
+IgnCsqKZBVN4qRPrW8HtEwiWW7MsoXGjhpVl8wer8cNmcfPTo3x2l2+mjV2r0xEZ
+Xmv2LEtjDfIUP6yXuID4OrV6kpqSDax+wmujr8jlETKf0uEi4PZAXqhrgh/fgH2p
+VE+Ey0vnDaXcEhS0ketOGmBIYaKzWbMH9iX46YSkA++5/PavhlbCqZZN+906jwEW
+6MS7Nq1UBoUiql1Xa8AL0p/7QKZH2mgxpFcBeCHF4q6HhebbQbCpveJgBSR7/12H
+fJOIubovV6AOx2kBRAf27bii5iwMjfzC9IBE+GLCX3CXR+BLfOWutTcqbaBRdmQv
+K4yJqB/WHYcjlLKf/Q8+B6elmMc59NVUfStMszkIGlTzMFIkObLHH1NYPSC700rH
+ZkrdbRGfcncT2OcyFbWZ/tIvUER/aHjh/BvZ9s8UyEVEZzsFJI8HA66sJzZ3fKaM
+8P7nXXagyarILIzO90JIwkX+ip//QtpSDPkrUtii6Wj7n7RO0REe5N5+NA3A7WUs
+Aret+KXgmsOi2fnTmCFjVN2QgmQvOg8PGx0yYx8gxWog/NAmLCVMjw==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des3_cbc.pem b/samples/rsa/openssl_rsa_des3_cbc.pem
new file mode 100644
index 0000000..6a632f2
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des3_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,6D7B3D8B829964B1
+
+mw05Vw0Y4gDohoiqd0xLN6ZKCalPCK2F0QFSyAVeoPY39y1RyKdsg8xt/qDx73jZ
+rgZb/fQLKs/W6SqCAAk/7EIBNTCWf+yD5TTdG9n8viNDSNXWdyq172rEnRV1CWGe
+beo+YjNDh6UlZ1FcXLj82TpZ9EokUKLabzNkY/coVPLlytqTSO5oZmbdreuUxOyJ
+ktQJUmGBmBY0aHJmV2wCkOFAXbzoSfo+SNPntEUNTa8i0cSIgmZd4/QS2Xfa8qRZ
+c2R2hNyVZygru5t8eckKj6uvj/Yszg6XqQby4ktK/cYfveS85CNlu03WfjfI5V78
+vY5efs3+NVJi2+ush4p4TfgT0PAKTWjXwpMEiGVlmxBoPoFGtTXY3Xp+64QICgTa
+MdrxPDDBw2yxmWAOpm58eeRqAN7Jd42qBxerJFiOUZxYPyRrQvro6fkldUlbPNon
+53Hzb+zHXv9xM5aUqfEjMO4HyprhKT/8aZgQiDE8fHgJhI/S2Ho6Fzqz2/uOHzBB
+gx0m8fM8puQ11eRxO+oSE4OSKbEQG0Uj66cHXY6FbJUhsLkGo9HdjLSGW67vx7RY
+Q3PQApOCFcXLecfkXrUaAEeRPNqZXjCkF6s8bfCOXD1cr9BulaGpiGxdspu5Tk9Q
+bLtoX5VHnW9VoIoFsIWs1G0h3WILs7ynCE2ttDSnIjYZhE6pRBiDHRs3J6dH/oOh
+c4dFaapkisk0BANJduvB7vLvvbJ0Xs42q+sRUCWzHNnJ3BqQZtL5f0dqu1AXafji
+qwxcbrEqJc1kOQ+iRAZ83nVlVkI/UgWzTceYPR24Q0PnAux1LkoIO/FWbhm62j3u
+xS669GX+GS9urX8oC3JUYT2n9dnPL8ouB77KfP6c0GVxR2hhiLYmyP2600C5q5DU
+6rdNm6fb75nrAmD0cgPxbdOB8zbgVvQuPXG8QnTO5Vvhp5ETgifIXPCIWwNHg5xL
+o2zrAdrNaio8FZUVPHOvMKE6Wl9QDMqnnShH+8VhLk7+LQpVDewBnWaMd8pK8qGn
+robl+i4HWtn20uZIDFyI4ioSa0S3Kanvd9TkchEbDjKAVi1QXdcD+q9O0AYt/X6n
+ygx2DGhkNYMrQmc+AIt7dAPa6RdZv50AAc0R3S0DBaxtd36pWugT4WIEexmuYj8S
+NbRNLuyjQMYCeFs/Ff4df0gmfeyH88YSlafnLyFhvv041LAbU52e/yExCEUvKr5J
+Oj2qVHJVe3eVW+FX8hsoUAte/a5foVe067dThfZDVp0TirozHAycgfKI600VF3Rh
+rvQiHzmXRoMptt5g/yLsTVYiKAF1n2hU9556sJPARFrG1xXoFFwhpzCS5t8ywniN
+6wwV+V0s4LSJFQJBFjLrreu9ZkYMdEOrekzqBohF5wG/BJILkN8hBmnD5gckbLIM
+QUzGTGxu+BIUi8JNkso0hwZDAKnYit+FVAs+5yU0NVQU6e3fW/+m48YI5gqFI+k0
+gIGmAyU6zaUJBJJQ4wc3+dOsy8sokqRhVmA59Tv20IKHh54zWq4ouFAg4Yc0bwK0
+1ua9GJMGTXN0+Trb7MKZQVKokyNA0RVCDN9AIfwCA5hDhJTahsO8Lp4Eolz2TFaQ
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des3_cfb.pem b/samples/rsa/openssl_rsa_des3_cfb.pem
new file mode 100644
index 0000000..129e02e
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des3_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CFB,B99E3DD88C3A9D7B
+
+4Dsk+pNUGsgEqelOveMyrkoDb+khouKf83Yt4/qxX8CHs5q6i70NLViQWwqvIqQP
+g3h8Gs8cYKZfkEAFKP6BRFPy8EttnBCzhAdvLKrKFCZoDmhxC5ia+FxPLtNaDEb5
+6bgSoZ07KUMvfMZdnG5Kogex4DedqENVHBi2Rl3Dck1pAgxwzMntgHsluT4ht3id
+SgyUT/xAaMSwIklsjclR998N6V8Nilu8TDDf5X12RHOq/MSqGZ7yJC3Wb/dsirNs
+7jsEQwg9tIg5B/5hxjN12E4Ov7orIuO/WHNVtLznx1w1t/umPjLFn100Kln8GvfN
+jiGSB5TUz4t8r3deN7oDrGjoyr5OMnKWSsIwKcMsNSh9aTdkjIJBUUhIB2PStdX7
+WbeNXicNMQeteIrY+ZDDPpMbjsH1Kqcz5y9OWnvaXso5lSHLBp1IamCv/XbQcAPR
+zbnbN8DCOYAMcUiwcRAt0U+BNc1edX8VmCB0d4RQq5BTFbjGKqzo6yFVUOVLhiFg
+E8G3v8sTqUhJyH4Dmjn0oDMtfdplk30Ywg2wZAahnI9w+cZFvzqXshL3mGdu+rbb
+h7PkiJE5vS6/4VKA7pngsVanCRQa3btL43ekShth+DXwsziQixGD9HhTb2iYeF+u
+9niDPI5gzi9IfxIpb3QjR1xDJYAzKDDBA4gHhbEBSObByMsVzjS0+dwP9N6DV60v
+3x7RfO094FXxlVWSh2SMvz/sB9fsD9dCp/gadqHxhk2aJf7lfSU1C7EmM9hxGZku
+vR3J1QcSu2FMrvHyRzFZGKozSHq3QunOLno/KmY0ja1754NEkntGvPuB7LhGBNB6
+14NvQsl7qFw5wJxmEdY5rhVdz4PxLfjnMyvCiWlku83QIC51I5DbhRP7eG9rJSMw
+b7KFSQwmp2yzDeX+Ipd0JAgd14GvtmICKJVushO352O7mVnx3Jy1ZtJsonhzySz6
+1fGIvJI8jxZOdO7q1OD0bfrXS/kwdXnxoxn4pkjw3ZN3hdFTfAerVQ+qYJ7zIez5
+0lUihHNw1C/KRsggraOl9rTUNppcNtMYwKXCJOGXI2UEn8p3JIxEHLwXyOjTDfg/
+5oK2nPAmBdGsLb5ivJLPivmaqDXf7fdn0XBQQmtYUQRotlGmfpztujt/b2pL5YSE
+Uqginw65zyedjL6Aff3crvP8/CUR0JARx9vF12R+v2iAnDqVk/yqYpRqOp5elm1t
+yGB/PtpoRFsNU1hDnPZDu7kZV9oSeXaBDFOnHmX09qE2r869Aye1xOVmxiG5tm/u
+KGA+zlJVVpQSwnPc/qk17S0dvNAlgt6MH+vYlhKw8zk1nDCuavUK3hTFT+9w31cQ
+yjPdV4/K8seK4zIqpH4LZrC306/1/7BT5JXL6ZChATHaI68xwEY2GsEl/Ze0JrQv
+WpWSN/I269rUfaBDE6eFaiSDzq1xY+qyApHSTNPSPDHbFeCXz+puqv9lw0bJFnRJ
+nLsK2fUAKNvyCF18IydyhiGz42LYbwwjlEWuVsfWtgvftDebZRIfQFlj7DJwXfZU
+zcEOI5YyuQs+wFK/8b/bknF4xRpaXwt9Il7tcV07h96TDJV05illig==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des3_ecb.pem b/samples/rsa/openssl_rsa_des3_ecb.pem
new file mode 100644
index 0000000..bcdc5d3
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des3_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3,9675E5342C359F94
+
+aqJHsie4Ls1x3Tk73mbL7VyTembpkhx/a8Mc345TuZOZEkU9XYrkFMvhEB+jcVoo
+9ydosCL2d8xjDusry+vn5yF3iwE9HFHQ52M0/a5IH3sTtJ18BzAOi72ykGb2r6ly
+FzTq7xdXNihN19wHHnI98GKdxdQmNR9uITx8VRBbZdbRNGdJopS8zT96+AV1QAE6
+lyKKLA7qbATHR7JWQN2OYz05vGt48Vmq+da+qs5liEtx+GtNUxS5x8lAC6Llmq2s
+/Xv8X6kjYmxHSYWM2JyxsznGfdXKXe9f4Xxwyhedei6JgrTHa/JN/+tvgh5NWODK
+er1tLBRRA7atlSoB2AAegJC7gJRVOxRF4hiKX/19cfEpq8hF9+6EHGYm/IQRSI/J
+F0RGcnSdiddYbEb667qTkbLZi/d3Ih3KwKGww6ZzkHe/qPi230/cDR8tac26jmG8
+qoCwj+XCNOe9IUJsCN6RmLcFp4Tr4UVSsswxReN+xs5Ui+S3AY8IKscLSo+bB8gq
+DVBvVFUBTiF5/zO8q8H8Xv2c0aA3S9UQla+l3yoZygiUym+Q204Li+tDXiM602kr
+GGDA5/cGpQuit/7O51KF2OSwnnvLdu96qz0f9X+rq4QVNAy5PXcr2pj/y88UfSXN
+GAbogEXqpQzn0rmV1OWM8hsnOpN2DLcuZICCJFJc/BHO4elt65OfBjAvbxjhFU6s
+nJLUcR5EopLex46WwuucR6W6wjAuO8ET3cDV5L9wQI6DT+XItotk+yJyYawNPda7
+wfmxZ0o3qdcpRp7aw0ohfshRGJMuLnGVgLczU4hwO2/1LgRMnCywldacAfo8Ot8s
+WnC7d0jVOre2K67Omh4gLQTzikvFoxg5kjmFFxF+QOFakT/B3RMa9mgjtOlX0boK
+HepTxOtCaS+cZnL/fUCbWdnPxqooKid2DnVTNIXXBg3S97ReediwpSn6v6gU8QXI
+O0X/+syPkCRAOKLjCdgxFXRB1UA13v6iqeja9aXgzbUnk/MrT6G4ivAMsNS1cEdA
+KVKVpbiKchEpiiSiPyo7buZN6t3m4JnupU+UvcJAEFgdbPvP/kFvxywpPBcAycAM
+HgujJ9bE3OR1lfyHHTGF/f5lXGDzB0/ND8h7Pm+Bd0AFde79rCswhnR4oJsPLuij
+Uy499ouKhoxFTn3WMF6at2QLf36rfLHl41uSN0tky8trT9SE1PjX6yQUjl48bJh3
+MWUFPYBDfDPGTddENYo7hDmwoSLbE5WFxbAeJa86wgV/P4/QcDF0IPVa/wsDTPKR
+RIy7eNqxXBYhFeOBCkTKHMJ0XCawi4q2CAwo7RNuAmTrHOBN2hZOwYd6yoEQ4ALq
+70cflG8+rITJHOdAjXYAlcuuB1FjDWJjO1E3P9MwMfiFZBnJBsYkDT6ablfwgpaQ
+z9ngnzRqxIjqAxrRY9GdR3BEWgRIiKXljUgkk8qFSRIS1i3w+nHAipreOwizTVUw
+otTU++EjpQBracFsuGP6w9vcyhHOp3K+RzGYEQoh2vJm25lzUWBHvmVpCw5BBTms
+RgurNRdm1IlN+qSzriotjPuHr9Ucit7VFV/gXtmyJiNNPjTLpLQEZOUpz15eaFs+
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_des3_ofb.pem b/samples/rsa/openssl_rsa_des3_ofb.pem
new file mode 100644
index 0000000..dad36ea
--- /dev/null
+++ b/samples/rsa/openssl_rsa_des3_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-OFB,C8F1482CB09D61BF
+
+0GfYpcSxvnnRri3s5PutcESsHTuupx6UcprKRS+B1neyPR7Ga0Z3mZ2/X0trJVpM
+cxJW4g/cU4TknCZLjIJlClYQenpPRH69yw6BTi6/pgUhKeGmQK9Oob6G1RMjS9lO
+MTb8DKz8P9GmDR4/3SvJwPU0aEM1EAmwGJV2beB2QWRhaPkAZBzeijYf+uYn0mgm
+hZwjU8tdwnNnCdUXdaHeRkeqFcL6OjJHV+U5SZaMbaky1U9lyIJL+GUQZkRfZzJD
+41Qt6yVtetTgzljtCtd4ix+RX6EYsWfZ3OVtwHGYpg28IdfJ3LVE//O9EkLZoBeg
+DyU9c0gDnQ8Dxl9VHGFwQvgdSEyJLvWDv+6RXvCX4Kb2Spy847yxqcfqDpjUhzgv
+C7FoBwswS0pkQzGXKgdM+WlBe9/GYOrzW08IYwrX88aihf50jXi472th6ILIkFHD
+6m419YsrmOeEMXGW/VIKxk8H8MGHwdvK82xewu8Ftgfx0WihfA70EyI28VLMQTAE
+MMHxxCWtdWWnmd1xiHQSX6vedPLXQKKt2AYxYmHQYfqNFMcvDc5uM5uM+mNkX0qt
+VL5PeYRYtdDtT5Xj4/acZD7X7DhqcOwvNll3J7PRdadNXKfjHR7iRP62YkIiESE5
+sCHhYXmtQqK2JUJr8a9M1QPhmAIF3FYr8wSFu/eWw8ooBaTxVoGCw70lT8LNHVql
+TYdW9sOnvUjz36oz6H+z55CNldor0tS/Bu5jNPOZ8F6j5r4xpTWi3d/UWLW7uBbw
+VTAG25EiFvQBXpJFqgRCBdD1Gcfoc+ZefLXQ1l0RJpRf1jJMkfSWvUWDRNm87PSs
+qTeDBzuLNx4A1wYcJ1H+R7ds5QK4moNlvv0hJrsqbOESpLv/XPcYrFgzms0b+Q1d
+uJEWjz38AgIJQxBxmoglzDSRx9OBh9D8HQ+aJLSVcz0dBmEOEtPjZn2AmxxccwCc
+NkMnAxXyNPEJhecTp2/lOOupQqMYTGe8aoiee3m01QPzfgL6m5p6IJdKzOKi0TGJ
+xNW6fD486B7i8d+VOnst6vnd4xiQ03gNNA654mrXIM881X5elqmoFWyup+Ct9lw5
+lxllAJGh7w+hf8P6mIsezOkZGieGhzrFnuLVM2srRDEId+shTV/0lZi4LhfDYroN
+VAbZ6bySn9fmP4Pn42zu4XjoZJffF74u8gFPo8oSFYg88tzjbPN9KAPInNxD6lBA
+cwp3vc1n71CEepmfeZFR6pm1wKRSupkOZNL/PV9rqsyP1pmPE3AEU7WYjNbf2ah0
+GE9f6dtLWcDP/3SssoSnZGy5SdqcNPymG9vOR+QD12YNxn7yA87HM3+swparlSYy
+Mhg1BuDXb5Q5XFVFdajFwAnXJblAIbuJAeHQ/mNCAnR3HNv/Qic2GF7X757MA+dP
+z86gFzJJtb7dtZ0WDQzzEVHgnfVHP5buXnHdepFLsETw9fp4ZjqPfHjLXIOvp9/9
+G9pmSzB1JL8kK8sexWgsMRnl2j2hUDYiVJ/LQjMzk2YLF5I0D5msNTAJvb/gFBdv
+ynVKUpIoJEfRaY7pxR3tufbzADNiqa8OUCGxZ8jo26j7XWDkunfGAw==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_rc2_128_cbc.pem b/samples/rsa/openssl_rsa_rc2_128_cbc.pem
new file mode 100644
index 0000000..1763340
--- /dev/null
+++ b/samples/rsa/openssl_rsa_rc2_128_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CBC,C9CEE2FFE7D795D6
+
+hcUF0vilpOxap0mbziQfS/5kPdXsFb59D6myNYdLDAvBWUVAuu5g8iDDJIS8KPb2
+xvmWdXRhbsnfeQGcGWM1rMc7brutqefFp/OAJVymI0TpILMgef0abf49PEqNUa/N
+rYs2dd39fsyrJ0rcEWT2lBA/+GTLATB+16/9aCwjHjQ4L7d4Soh1laMo2K2Us6Eq
+pB8f6an5Y/vSIlnljl4upKOlcLItd//2ehQnkuEhI2Vafz+kX08Z3+OCLZfdNEq0
++8b5GbOvygEZbG+amZDB/tXnR1HB+AI7lR94PmM+h24COWAelatj2uPOGov54gXc
+iO7NDGoouysqfkfcMpuy5SkLVW4FoCAxfOl+LOU9p4x8+iaJt7Np+TO16dvX8MOL
+4WcIz4huaT125V38Q4UiB+WbsvQXrHRM4WCyJBGBhakr+FpNFdH1UPb9Unb+8UQL
+BeddEGT0l9AiSebT/JMKgFUOInQdKxOjg4NBp3asVEUeTGLeTN3o06zUoopzT0S3
+CHrpgvpZLf+4NATrFMw0HkcUK4GHZl/Q68C67qNGTc4B37eGcxzGo8QOyjXzKxL8
+Lh+Ry3eJpEXae5xDUn9yt8eqYI2vdwjA/3+XE6mRhu1sbPNJCcWo2kLZ0ibYgqdB
+FLsXBT8aoeKrW2p82OpehslbmswOKZgrPRYmNh1GAPz2jwBFfCEOLQYXAjCFViiL
+ipFLKLGt2dhjk5RbCraN6eYRn2XcIai/7dnaYxXkjOsNH4mmPzlzjhvRh/2E/r2Z
+hbTOoa2uFUtZHWtDXUz7ZzCJErJaA00ont37BksfHDdDw1HIt4z6Ut8Jm1cR5zPO
+pC7s7ohOS5j8Vr8j947bEXITC2ozcvVVZOCcHwF/PnUE1zx48HBp2m9NAZ8Bz3LS
+Zn799/RrNtJLnkheG0wIrizk72M5L9PZQ4FXlupfJ9c9XniaQ23GQFszagceDN8j
+z/MR4tTfdWRy/889lqZ6ccNmPAXdwwijC6Tw6V9HooN9m3++ZlbPfHpboQUp6+V0
+Wwq8gdnlYW/i++9n251xBsR7mQtFNXaYwFmLUTt9C8OobyWSsX/OaeQGbWiVnmAv
+vPkr7mh6g0ha/x+1vKgEOjqItJsGdspf8ePHQ3FaTkfFwhQ4eN9w4QR3uzM/7fnj
+ql3yA+G8ftpaU9omFbs+VqIVNej5tvjODQ02BbjSuRklAGxnReCS14vLwjg9BV6t
+Ow74oIttwlZof21BWsCISgybkPmMhkIhUNAAkHexzY3AiqjAtEGnpmvfZAX9zN8+
++Kg58DxudjHQwUO4cwP9p50NndrilBShkotdYIqekXn6h0frYuhspJVWwIVswNjX
+BuEZE5B+Otswbt/caj9C5tfsyKmnGToG4fpDdk0ItxRq2126crKQd49zZybyR3zR
+phLeduyS5h0oYNwTjq+Fg2Z+f6d/iyCAE8ynfqcAPK1WpM/02DBoLsOmve5BCSPB
+YYKdrKfkGbj4J2klrptGmqgctyW5jKGddE6NO4XFYV174rsdPoErNWWcfptHEMLR
+BWfopqdN/HMrpRLTkjx9rIeBJ0F+wQEEH1JehnWExSSSAhm/gzQc1kU/wihOStU4
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_rc2_128_cfb.pem b/samples/rsa/openssl_rsa_rc2_128_cfb.pem
new file mode 100644
index 0000000..4284fff
--- /dev/null
+++ b/samples/rsa/openssl_rsa_rc2_128_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-CFB,AEA62B1564D645C9
+
+NX4iex15O1Dwp6ADN+uFIycPB1ELvBDVRGh+OZnisNU9h+8dPO1cb3j2tkwLFK4i
+Pml4zz797d4I4GqdF2Y23dz2AoBrl2Lj0N0W01AlOGagh92pZ9dKjjU+S5N85OBw
+buDbADh16fSPW6Y88guWFXYBlGJ6HZFK/9D4CZmEfI2Pt9AwEIZ/JvWrs/zW5eGP
+YMFsLslsNu9TOIKF8iDnfcWM9MFpgwcFCIqTwyQ/+dka0hw33WsBREhFcNleLxhW
+NKBIMC6jNjpW916IClH5sBu7T8ps/7JVw4DUfpl8NAOaqJSicPGpZrGIZ9N9cfLp
+KD1XEy+yWc9ahV0mfiyOuzNnP2x9IEBdrk5uqJwIT9RuiFZixIH9MRuqAtrA5BIP
+dc2kw50AbXRghE0JdUEFfUm9zcRKdG366SgADnteNk/77gqI0OZJDD0XL9R/N3Tn
+uh3EI9joJciWDbEX0/751MfcLaa/EkI7quKMEyFGWvox9sKLLEKRUV6SfO/YX8ZM
+RV7ebJdW+Mxya/beG3Yb9TAYkrG2TT2+uhRqZlZllJQFnX7k5MxyfN5I+WJP7SEs
+Uy5PAkNv3h7DTV7dBFMy/gPYAooY4JzBnbq33af+w/VbhyhVid/hn9UAONahw7H/
+1Ao24IlYMza2fJ9yOn+ejLhjvwYIP5992cmElneqMdBfV+oaQTHtWUuVF6g4gJBw
+9QucqxH4JbYccwA1UiKIqkmOlePm5I57RbBw1OG/Un3SiPcAwiAW/UpI5yv8kNwq
+kZeWnD79kMBEW2pU1CTvf5f8aBmcgQykC0M8H25Jj2kVvj0EsRGx1LuQx3ZCSM9y
+sZejgZouYA1WuZaIsz+3t4fgYFiOHDxmSvPt6VtZAMJGmLB/Xa/PVI4rsyNv99wB
+UinlINhzeGKpYYHnUgN0PrRQl0LBR0TdrJ0eG1djEvflXsuAQVP7+gP+oCckkT2c
+pIVm2IzplT2wzsza6+o1SA5BF7RKI3A6IxySFEBJTeaiZnYeeJHxE2DJvU1Fe29G
+ML/lM02waLJNbIs0Vk/i+hyE1wtMwZetptG+En5TDzTkWlVSLSqW6LXVJ53J2E+q
+wypuz4akL8CaYRm4XTmIH3Tom3qSf7rdbL9gk8llZacFNqAl7x1C9zDUzKU0DAOg
+qPKAtD1s7Rtg+4p+5cIEAWD0TKX6DlXKC/EdYO1w0vmavGSvQrr+KENE4+/gIRst
+qlTCiEW2U+PPyOgpZAFF0g5y5Xw0Fea/0HwBBLfCiPKRmDHQIzWIEW7RkkNfQlHC
+iCTBoMRFDbwXJEI9XUu2N4RdmlP+84i6fSRWuzZGUACvzEnRJEc6H0FaaN+fX0wM
+Op5O2hcdA0YTGGmTLUAeajiQnqGRobC8jQL/WQRVwOiFU9rgy1K4Cu2T6eBubvVh
+gk/R12LezvD/KwLgQz1+vXa5Vgjp0xhpnLnJVzPqLG0Fmj3V4uRDc1Lvvl4uLJiR
+VFjFYlqxP6w+ToRqnrfbmUCuiq6pS9FQi2Tghd02P5TnZcyS2xF2X7o45gegMplS
+skPzTCON8140xpx6Flep3bHwzEI0CEwO8goVMc6x4a2Ggekjn/Nz2A==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_rc2_128_ecb.pem b/samples/rsa/openssl_rsa_rc2_128_ecb.pem
new file mode 100644
index 0000000..d9609d7
--- /dev/null
+++ b/samples/rsa/openssl_rsa_rc2_128_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-ECB,270AFD04879E8434
+
+u8jYUJhoDMDNI5cHXhnJJ7Pm0lF+MrOl84maQOwfwZ5hBbjpx9s+z5SMYpWfz0yQ
+WlgBuGkaY1UNBDrwH6baA9/eqUzem9ZK+mYmjKC30OaumjKVJIB7cJfJf6Itcaom
+SH1W0kJYeDn7ANdmstOGxbr2TDCr0BXa+7j8cTo2TZX1rfsXcdmjQ+8Qa8zfQ3Q5
+FbrO+VNmAQwO7HeFjms38+ukJRW30EPibmbzx/YTCZ7XtCsXt6t6ggYja9Kvk/eI
+khwvFFk4g6Dv9YU+x2pyrkquIiTUo+jm3Vqhz2m0cGcqfynVEYn4fNPc27Ekw3uj
+CrprMgnfaX8QVx/EkpDYp7gpjcLYJObpUTcBo5iA7R3lpQ8itY1Ky7u6MMwQ2VHd
+XZcsS6b06mp2EW1CO951ZaPyma4AqoLl2gZ3zH4qPygp7uxrGdFdFSqrapVkDee/
+lLtj8Z+/g1IyVSIW2FP/SCoustCHcqeDDq70GKY9qiahNFybWn49vZAPB3HPM22f
+mCcw4ALiKr0S9oofxrb8PKxmDQMZAJqjc8qRMLktYh9rJLMoUG2bmQqpKmLLpx5q
+3CaKi3wofc005VcILyRgjumscAcpbTEz4vcR4jTwMPNP+WI8+AHtg0OcF+7hE8qc
+a9KTSsx3eJNbqq5UYxVjV/DcttNx9ENllnG+jEdttkaf+T9rJiayc0WPd+Eg0XlN
+ByBG0RCPQVJ9YH1Yke9HGE0FXv7FV6x4c22ePePcyE6VUNBoxdmXw+KRhRlvtXtM
+1fFMwUrY//jEpfbf193avTVVctDTLxDSmwY6eAMBm81uDTlpUm0q7l2rRuKzdgFd
+bG/MTOd/j7wtKJbQpbUfUNFtF6zjssPdGhJ3l+8Rg4xZyHWHgU5FYGodp9RsxUhm
+8AzoPDcVbbvu5YlPP+XvyEO1860fX6iSZKuOV+owjh2i51CPzsgX6OrOEb6/1rc3
+M5AkLVl4insmetdTqb9PHCgfD6bLYcDBj7Qnf4HEDQUGcRFe+jogOoSH40C5UgPq
+F83nXv6WYBb2Y97lhb44x7d1MzE1kkzQXlyf3QuZ0ZjOvm+LuOWkbQWmLj5JhFJv
+9CqY2MBL39EFamKjmmBmjrRsI9XMLHvB7VvT1hJPzxbF3UwDZ5BsA8IXSps0EjXR
+rZXSwo+vqTa3NlvysgvuJJUjwyf6mN2SVrNaKnZZ1OGFY1oQ3bmOgdI+SW9cpGzY
+Y8eFpaG2RAiOfBZ0JIyBUoHUH1MMMPw+Mh7KzIknP7O9htwiAWEvkcjWr7X6jpG8
+sBdBmszX3TMDTToQ6DvyjVRP7mJ39dV83bLI3EA+N8bJcTOcHijCvbzQM50WzMu1
+2UA9e6rG+ouQAgwaAHdR6bwm+Zr3e7MswZ0Q8/Snd1UdpyMyJ9nb031NSRSvkEyB
+ipu85/738J/g7tAIOJwwHeVWjL4lnrLC3CwbtvWAQ9Ox8Sjv848608GzQxFwHBHJ
+0NWgt/AfLYsq4bmmFWtqvqTjWeAeUsM+67UY8m6/kxhfRNNN3zZcckq2zlF7TRNU
+5AL/3KbVVLQl/7fD36m8AK5eImR+Gvom8ryzNacbNCL55ks0sycbICulXbdb0Jgm
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_rc2_128_ofb.pem b/samples/rsa/openssl_rsa_rc2_128_ofb.pem
new file mode 100644
index 0000000..cafccf9
--- /dev/null
+++ b/samples/rsa/openssl_rsa_rc2_128_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-OFB,E5989634C878E65D
+
+6o45POmHfE72UAdMBQrRIm2+oZCd8GmkmrFZMXYnVWP8ciNiGVQqUxVJS9j5Rx17
+8qxpNrzvcWEGWcgs9AOqog7YXHkxo/s/RIOKjUu0WhY59UrYcbkN7Rjyn3wSSD8X
+kN4Z2tz3iR8LnfljD2ApbR3yEYz2NvmifZzsac58R3LvuFg3Tsl0QetPSC7PfMUh
+B7dezaycDcx8QJy+nRPcqpGzeL/VVk3F4Hppc15gfdWtVellGcYsT0Z2Iu42I5nx
+HYFajRliBukH98M1d905lk1aNLDj54BBcq08JsDJN/V6DY+mUpJCFOK4DfP5WLJb
+/HCQg0wqsUmRHK3dVo09ilZa4OfrrRD5qTWr5boDngAqyD1r1fiHxcv7uU/HOSvt
+PU53frz38BA+w1pHtlE0TSG0oBe/+741kJtpvj/1Ts7nUeYJ/DGR4vmLpg4rnbZJ
+Yky5TaDV2LVLFR4syqombb3eiK5xbnjePCQFLwxYLQKZFINiS5zDr5mdjhWbIhpA
+7wg9BKNpUeXRDtntWXvEH9FmyIicbk670riEYEo/EniwrxW9f7MFhPUpOb9ktE56
+RnaU0EK9zUx1sIvcu7LVq1G2EVG8IrOKGcj4LHysBtg6PQW5mvN4AA5PZlc2Sux4
+L5Z6mJfwgBbBB4OuRXAYxHZbnfMTs75vL3d/HIcvSPcvb+7nfvNLiwlaBxaUfBFh
+fyDurHkMG6tBgE6OORgWraNEINJeOYcG2WK60qC4E8YfYCmc9V+28A//bsyRWyku
+xIDup68r+Os5RMRAaZrkIqaH+h4Oyd5RqcjLnAFF/wLGnNwSttYT8o7WwCf9ZCCy
+NFvHDWyWMUxonaWgvuSm9YPfh9/9CEsHkKh2RqBffFcZ1ktEiYaI+dGyty12QW2Y
+909pnCZkKsm1Lt3ts/xie20/gcwfsnvUC8OveKPaiCnJxDv3r9pMCNFPdcXo0GuR
+oadhn9r2CqNCDo+l6JWVRka2t8+yCAskZC7bKJnSeKlEDyn7A/2SLb196G2k9cve
+V2qQenhzuHmG5PEVfhLWQ7fL1BmJcRDuQlSmMGrdmOD4Zb0Truq0zpFL2qaMBQvb
+58hG5YkYehE25j8PpJYovOQA2hih6v9RytR2VKlTeYNFbREf1sdLfeIphB9tlHlp
+qZ7eOFAjjVzLsC4LmoCzWMaQuwNO1f3WiNdGVvulHkWqFnGS9bBBTahUUWI5SYiQ
+90vhSmJ7R7461rqWwn34Om5jlgRV4+2LhUbp+XdOyklujQYviHsOs8/wlg3lKr76
+SwrU5oYqlJ7FJoDq4IPpOnJaxsRjkr9foecgdqrU4SJKyJJDbkHNfoYq9r/aZJ21
+ruPFv5t021gJmWa87199GlhBZD8dxeXo0PT298Y3pmaaSdQIWLPeDAtc1R9EJLwD
+6+ydhg3ZVtSgXU0zQ2SRVMGhqoEXHDUrMtjKzuaZsYL57tqH6At6vWS+xA0CJBCw
+7GkDpM/lLGjyisFEQL73F0YmJPpb5s4izzCLUMxZQZ3u4T3f9OPRvAIUf8MiFJxh
+RJq2Is1gD7M8+dySkFeAbQ1STvLy29uIxKTE6BgNng5NrY03GuK/5A==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_rc2_40.pem b/samples/rsa/openssl_rsa_rc2_40.pem
new file mode 100644
index 0000000..5a9eecf
--- /dev/null
+++ b/samples/rsa/openssl_rsa_rc2_40.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-40-CBC,BA10EF99A1862AB2
+
+/CfoFtIX0zgNckXzuODWoCYVY6NoXOvu1jt7J5/BfSZUydRWKa2lpR3SWAUAesQX
+H/IK9Wkz4um0QgrHy2fmVaAS1G3ifwgQ9dhW1EMiCEAmuNwPsT2YBatSyxnzWjHa
+dv4eZ0Snk4DsS/Ajwn+Oc9uZ3u5gKnfYk3tXoZ9BDPQbgIz01UI/AyGHttB43brl
+e1C+zKgCSa5WB8wfxCJsKHDSEHx+qlipVvDk/pntc9m4AM0sp5wsHRw3i1iirQOw
+AG6qRs3Ro3jwajlEWPmJolhbRQWyA2rUfSIajElYFlFgxPLI10m0tO5M55VYXpWe
+cprQNe/TxK+YJTcBvyhFmP4Ha9NeC0Vq6aHiECpZ1uObH1brZ1bdYUsSGodRzGMC
+ucOkFDpsp9We48TAHqEGArCsKexxe1dDe8b+cxdvyv33ZI7dyr7DfHek3X7B2rHv
+tZYjgx0cKn8SNl9qdRync9wLqjL2R99sHgphkXUA7qLP7ZdvZEeAGs5NEuq5oyDj
+4aybPFJu/xvByOEZBwEtrixVJ/2h4KYF6g2vK5CgmnYrq8SUNGobt+oLv3FywKhQ
+AK/YvDt97wXNdPNqPciqCP9LIeo0B0cgxFIbOOE3mvYgPaUoTtZ48B/hpkY4flKR
+U7opVqbNl/pnh1OCI1ce/K5KPw0rvYgsEQ8Q04+dipPdmvONYGhcgHflS52xju6s
+RbosS+iET3a6BB8ydRS8V4oezbr7AgzoSv7Od6geru87fYpVW3WbGag4w+Xgil7u
+C22epy/AX8naBOsMa2QMCZ97avi/qhMFIERzhQJcxULff0lHQBq+HMGsSI8jMEiH
+d2OIERTWasAEPdoBnELO3l4oywb4NmSp09m9imihdgocDAQEXyLkjmRqkm5H3Tdm
+ALFIaSwU5SE/dk3T+BTmnfl+Anx7QNWTdg+ykfH8VHbs10A/K2zt6RyJGLdStfKq
+VWORUG7gYcVGIQrcJllxt3Jt4sG3t3rSKA5dukM7+D1d54ExiJN5DrnaQ4kX/v7O
+nENonLRtV1KqrH32R+tIuBVA8rbmyseVequTBQpkHbG/IczTG1k6p0Qye17XlnPl
+kEPE3CG8+1RMLvflA1rTimSh1WafHsDwvwmTAgdkG5btLlfTpPnoKDy2hPS4Pd0P
+mF7OPVfA0Hl/oEqP7bqyUxuwFrz7pZXQrKDS02nXaqVAP02nKsiEUZNo2kprAO2v
+9ceOhXP3M+ItlWeNcX5jKRaaLddQvj1ntOKqDMfRk4yWm9ro8/E56Fkrq7GpKrXL
+FCJJTdrWk6EcSfI6grVjPbZGBJiA+21G4IPQWskPkr9gLuE0E9I1UAdliYKXOrPK
+F1lZ1ZBpG1ZBe9H8Gr2sK42pzJoFJsOvGRjCxlHpf/gBoOADH/hcxvQqBGizEr0F
+kKraZWJnlL8qhDzfJ7YLMqzFsOu7uYQRqfOcv+66FqT/by9rD7dR/M03YJReupoL
+lynJfffGCG6aeM8hLZ8iizjIc/RzCY0QS4lLPkRVSRNt3Z8RNX/nFuYhYgOx38pu
+6dflN059kTC5iyjsI5Ka/Xzq69kR21qCcHOoq6IQqZ7q5RM4Cj0SCXw8/4jeT2xY
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_rc2_64.pem b/samples/rsa/openssl_rsa_rc2_64.pem
new file mode 100644
index 0000000..7d09608
--- /dev/null
+++ b/samples/rsa/openssl_rsa_rc2_64.pem
@@ -0,0 +1,30 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: RC2-64-CBC,DA39EAD05DD48A5B
+
+mil5OpL9dVqnEoKF7dNjIRYLgDjCBmTDZ//Bmkd4aqkPszHaCoQqgyGYOuqWXdT2
+FAluu/fHMLDTizyr2Jh00ekcR3nmnGM3B0oDiEtq84YMHPWYopWkpId1ZaoqluUe
+6NP6Zew4DZ8mEQvOxIxBEZqk0ye6srtLszByw/dTy4i9S7l4oR8hx1i6Jj9lLXS1
+y24lC68igFNeIecggG8uwZBVmnHCldZGn6DBBqcC0b415+59vwGuvc+POy0Hog/4
+ADPuZcXEO2whVGyOjCF7CjhEFfo0CO2niwS9PiUIYNsUluwfS+y1qhw4VJ61sQ/q
+7cNHrD4NfZHGwpIRXk4c27YHS+JsxH8Kh61e/dQPoeTf5NBQs3PthFcx+hzlTBAq
+VK/4TtRRlnqTVFKRydpKo3cNGp8qm9Kvz6fr/yLb7CJvdoGDyHVO7JvT8nYL5gC0
+dvN2RySKXMrgmPS7uMAWjpnDCdNoOX4pRTRPEdBw8WsdXqnBqXM8tvrkolF9n3//
+lldN3sSGLiYM1cwD4dXlYJEJNaarelHk6vpJIU4A6gYyN9MQnv061jd7sibrTAjZ
+Rx06R0FrYFbfkp4yAmUbrPO5gdwZPBGS9XzkZmZr+S4u1fH7tTFxIlWNgxwSzsZJ
+P9LXM8Iy408gDn1AJlbT7WbdWfcFzqIsmauRIXE66TloS+485ro9zX7O27MumF8S
+hjD+cRMieUEREuAAlpNxZj5kcT3SpxfSdaAZtJv8OKeRHz796LRxlLmx3ZDAjgN5
+0H37gSCXJDP2a4YnsiI7th5fNba84t1Qt4Q36v6EZT2kscv0TB04ov1+4UX9jCQI
+zn2zxzJk42kkxRSEBP3BnZf/qV5t6/+BKmg1QGCmS5AkIIlCDjTPpAom3n7YH9LV
+ykAQ6Wcdo/7dGtghgaHbPGl3cXR1u7BI97GCU4vzRbW58ULh7KSC1xptDJrP7tPE
+6OwwYk5YZ6lmg54cLbQcxeFwYQg1dc4pYAgBppUFUB/uWeQrbJP8/FN/GlW0HTOU
+kUIz5pbI7nstb2hHrRMTtG4c0oGO1ACD2LigQo5Cl7jR0sBC3I2MB/JcBBwAHPVP
+tePpIdSAZjAYI+x7LFxxXvT7eXe+BU4ZLGLcTISGJjtsbJG1oJ/e7dPP5bLL+zjJ
+MrwoE6awH5GKOOxB0iUGce8jg8566qY4e2vbmVL4a2qRiKyLowr7Lcz01VzzE/RX
+0Ec1I8noUmsystH/57UMBuhZNFjW3LtTaw6vuTrrmFtdmJcGwars9tBtH0LPip9X
+xQbwIiTJZCyDjql7Ecgu2ncw7zHZzbHrmoEF7VEdPT4z21utXgzJ3HubvB7Agvyz
+sB+EXeUqwZHnyN0GdGd6sqlHkW7TP1XxMrjewUHjXuY4SvsosJ/GqMY7uKJXK/Lt
+0kqYrV/YDIVsJ2JqyxwXYYIqmZfQ2xXTLuESuesT7omKFh4cgwbYHd33YWRCsZJB
+7Og8d3ciguWDutd1LOgx7da2ZA+3UVz8X601GRpFD8YoZTo8QOayXFvv7L1F3oeK
+b0w11lT0npxstmeMQUkbxAyCnKrwpQagiwBzKlr9ymJvh/ot6sJ5bAFDvZBBKkQU
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/openssl_rsa_unencrypted.der b/samples/rsa/openssl_rsa_unencrypted.der
new file mode 100644
index 0000000..3bba408
Binary files /dev/null and b/samples/rsa/openssl_rsa_unencrypted.der differ
diff --git a/samples/rsa/openssl_rsa_unencrypted.pem b/samples/rsa/openssl_rsa_unencrypted.pem
new file mode 100644
index 0000000..f540dcc
--- /dev/null
+++ b/samples/rsa/openssl_rsa_unencrypted.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7Plp
+gpjUg4pNjYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc
+8BQcwHf0ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTj
+HE5t7iu1JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindx
+OSAnAxK6q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfD
+HArDqUYxqJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABAoIBAFd6vTKVVT0O/U04
+wTtiptA/p7fkDM5PHVBxh32Wxno5pj8PerIaiduKyuRVh7PvJRMJpw903BrAK95o
+847WWOVOaF7TcKGMBURJUS6maiJS7TboK1ZbUVnsg/I99ArhiVUKGDhlsl/Xd4np
+YPDYztzXLzLXpm7bS6CiuvP762x9dfVu8K+afP8cjH8pfXLq55ghZOUKidRQaYz1
+mNOTQyAQlCQdLRgKlYgqcRHlj0pb28XBJaln3W7Z7GFMWFPojkxx6LaCp8+Jyx2C
+tv54zIZQhMjF37tQyTnfK4Ocl3sCRb+jYV4FkrUnsQE9W2dey0Tms1XB31gfUJlx
+dRZu7zkCgYEA/nWcTwzot2OIAhXoJ2fnqTcpdmj05LHhGcayKjyix7BsVH2I0KpF
+9kXX066tr3+LxZTergl4UpWSl3yx/4kPBQM6np4VVRytn7+cQdEhOczZnBw6x7IZ
+fv81DSNruQDBRAlTtklW4KBY74JKLhaJSvF1F3x32+H+99i1MmCNJRMCgYEAyZpF
+h4c3pM9z+YlmgLdUh/G2abdoamugcQOFbzHbZowsRAxEzdEW9wj2McN6mt8Rn1tc
+tY/+PcYuIK+vcmk9k23GuzxRlJlkaDicHwlAebgVIulFcrStfTlSkXjpuOuusfD9
+2DuHMcUiPx3qElNB0dZJF/axpq7BjTIFENefhZ8CgYACn+vw1M1BtwEcJGW0olm9
+YRhIZGTCRyNvRKFp1h5HuQYlCPZ0UI1QMQA86rxX5xTmANcbLHXVRD2y2lJrtFo3
+TwU3xaGqsxUHZM6TzzhshDRqa9AfZzLkIHXHoOnnip5zuTTn2HHQ91ZzggCJ4Smh
+YEQ47cu+tOIQZGfaESzjiQKBgQCCfnZlDJRq/NFwA40y4fg4arANa+eNgw7+OC5F
+1HrUvQTmIx7iLmZ0Dvv1KDgTSTLJ+MRgzczexYoUJEQnhZGS/Wq2xYt06XlBsOr1
+d/KhFxOvXllSrzrhJJqaiS6YQQ36JijZr2aKQ7UwL7fUlsmy/safWVKStumX8Hmw
+9jFOtwKBgQDmtirdNQ8aKolokD/3bDHPcDsNcybEpiCu8BIltxZAs/LsN1IIxfcp
+mGP2AFt3mbblKbsRM8hDW/X9taeG9s2KGe5wlKOE5lV8YAo4hFoJYN2/0d8Y0K9X
+QAAYU3iPG1zL+a/7TFLJ0u/biqsBg9hnNbMnN/tOeSuKnH2Rx9F1rg==
+-----END RSA PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8_rsa_unencrypted.der b/samples/rsa/pkcs8_rsa_unencrypted.der
new file mode 100644
index 0000000..b092957
Binary files /dev/null and b/samples/rsa/pkcs8_rsa_unencrypted.der differ
diff --git a/samples/rsa/pkcs8_rsa_unencrypted.pem b/samples/rsa/pkcs8_rsa_unencrypted.pem
new file mode 100644
index 0000000..8111b0d
--- /dev/null
+++ b/samples/rsa/pkcs8_rsa_unencrypted.pem
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDIY6+Wgj6MqdEd
+Yq6FgH5xMgTBmFqAonR/eshjxY2C6MHs+WmCmNSDik2NgZWIaODvOF9uOEK2U0Zf
+JEG2LcZxoeIEgg/mfII2f4DLy1JYajm/llzwFBzAd/Rkcs3qwP2ba5VKn/pSqNLl
+nKHMXkXO+9SjfHDx95x2dK1dB8eGQGculOMcTm3uK7UlWNO4TSlwG9qHZ1aoM3GI
+g5C1fIpbxJqDVjFq6fFAapE3KRIWIQmKd3E5ICcDErqr/AapxnfO8UFNxVWSOLW7
+ZAfis4w/c8/EAgyQHw42R0dNyjUOZsToF8McCsOpRjGolSU8aUyqspvd8IWJPd5d
+6HBHueXNAgMBAAECggEAV3q9MpVVPQ79TTjBO2Km0D+nt+QMzk8dUHGHfZbGejmm
+Pw96shqJ24rK5FWHs+8lEwmnD3TcGsAr3mjzjtZY5U5oXtNwoYwFRElRLqZqIlLt
+NugrVltRWeyD8j30CuGJVQoYOGWyX9d3ielg8NjO3NcvMtembttLoKK68/vrbH11
+9W7wr5p8/xyMfyl9curnmCFk5QqJ1FBpjPWY05NDIBCUJB0tGAqViCpxEeWPSlvb
+xcElqWfdbtnsYUxYU+iOTHHotoKnz4nLHYK2/njMhlCEyMXfu1DJOd8rg5yXewJF
+v6NhXgWStSexAT1bZ17LROazVcHfWB9QmXF1Fm7vOQKBgQD+dZxPDOi3Y4gCFegn
+Z+epNyl2aPTkseEZxrIqPKLHsGxUfYjQqkX2RdfTrq2vf4vFlN6uCXhSlZKXfLH/
+iQ8FAzqenhVVHK2fv5xB0SE5zNmcHDrHshl+/zUNI2u5AMFECVO2SVbgoFjvgkou
+FolK8XUXfHfb4f732LUyYI0lEwKBgQDJmkWHhzekz3P5iWaAt1SH8bZpt2hqa6Bx
+A4VvMdtmjCxEDETN0Rb3CPYxw3qa3xGfW1y1j/49xi4gr69yaT2Tbca7PFGUmWRo
+OJwfCUB5uBUi6UVytK19OVKReOm4666x8P3YO4cxxSI/HeoSU0HR1kkX9rGmrsGN
+MgUQ15+FnwKBgAKf6/DUzUG3ARwkZbSiWb1hGEhkZMJHI29EoWnWHke5BiUI9nRQ
+jVAxADzqvFfnFOYA1xssddVEPbLaUmu0WjdPBTfFoaqzFQdkzpPPOGyENGpr0B9n
+MuQgdceg6eeKnnO5NOfYcdD3VnOCAInhKaFgRDjty7604hBkZ9oRLOOJAoGBAIJ+
+dmUMlGr80XADjTLh+DhqsA1r542DDv44LkXUetS9BOYjHuIuZnQO+/UoOBNJMsn4
+xGDNzN7FihQkRCeFkZL9arbFi3TpeUGw6vV38qEXE69eWVKvOuEkmpqJLphBDfom
+KNmvZopDtTAvt9SWybL+xp9ZUpK26ZfwebD2MU63AoGBAOa2Kt01DxoqiWiQP/ds
+Mc9wOw1zJsSmIK7wEiW3FkCz8uw3UgjF9ymYY/YAW3eZtuUpuxEzyENb9f21p4b2
+zYoZ7nCUo4TmVXxgCjiEWglg3b/R3xjQr1dAABhTeI8bXMv5r/tMUsnS79uKqwGD
+2Gc1syc3+055K4qcfZHH0XWu
+-----END PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_md2_des1.der b/samples/rsa/pkcs8v1_rsa_md2_des1.der
new file mode 100644
index 0000000..f60e902
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_md2_des1.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_md2_des1.pem b/samples/rsa/pkcs8v1_rsa_md2_des1.pem
new file mode 100644
index 0000000..acc262e
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_md2_des1.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6TAbBgkqhkiG9w0BBQEwDgQIDKNx1mLdfnwCAggABIIEyMSJNGKOaf0rxVG7
+3es69KrcjE7RyU1RRy235ByFV3zmqxtv0QhPvIMxJwiaoRr9SE6wlzKYU0hiCkB9
+ggYeDQ7kQ1a79Gs7EPEVcevN1DpHMII4LW1XOMSfWLwffc/oETiLbkgPQxG0eEsA
+8z4/fS0k8tEQ6AOF4qa51UdORkfExRF5Yyv46fsUs57oCKtqYx/IIVPcSg8Ec3mz
+M+Zz+f820bB/vN8ge5KWdOalIZohYR56nPouPnCtc30CfHfFqTfJajFYLHCPKq4a
+yE7h/u46zi/T6Wqwrua35MLmD9ne+sPN8+Hxr3hlCh8HhYXroqr7PyZXcDbshpEM
+ZgVkrYIq4C2XXByQqXyYX0lO4TzhJHj0fhG1O0epTDuyyvQniEbD8lZFTc1xUnh3
+WNNB18WbX4Ra8neZDCNiJsIWCdQ+TMA80YPyIbP97Jo4zIi7DJciwHotSFyWYa8/
+2ROdcV65IrzKuF3w1ssJnuKtQ13Ku+UywaFCqf+0z2P0U/6noOLBx6xtDhW3KCgg
+FykZnG39jWAuwjfdh+EFgKl/m2FWVZ8AR0JZBlaboHDhbnUtcqUPLsHmlq05ozfr
+GwduBxVeMb0/v9WOQIvzqDykhd2CW7DzrnrOQwoH2NV64qWi8qyF7mQZPpzCiMNc
+Oe0/nwHPTp3C3dR4YOlLEAJTWqMGnD8byYG8JoMq1fQZcOnWZN4pZiL97hGRUFKQ
+bl9U6oWUJ37dLJFpIUqSqg3rEHpDOuJhFDRvkPIihnDV45PrvH5sbKTF482c+JUA
++aW5bDIpRIhB0Uhj+i8wDCsd/TD4X/0bDcuewFOZ7RpnJ+DkKfBiIONwAUVgWO4G
+ot2sxR5+ZGLfLgyES3nrpIRjhHDzGZT3lNtUvj7ceXEOv9LJWYGfezAAhu/LDcHH
+YX79AoI7qCITBOS+nIZMywAACOTjTRJML2RRWF3xzckhNV90vkT1vzdzeGPCXnZu
+iSb5PbLJAkWKaIcq6WaFumk6XK2cgVP231/K5+gDNN0YxwddmRHzoFZJFyOuXSFC
+Genw5ImW8V5M9SxJ6Hs2h9RoDssyn05XALMCx4n6Vj2q8PAMQoxFwwRAWql0hjvL
+ArzGt6IuPO/wE4xCL+6fCggixlAbHuu057XeMDmshQwc+nSyuQ+xujiVesI1RE/Y
+BT6ML6tLRTOWNKlNilJy2Ql1M6RoiZ66/IvMHarUeOe4IZpH8OlJARgjtViXKyCY
+k3TLPjOgRXaUkXvCmbpDBk7lCXWeDHeOMvigwrZD327G3GZ3gA9gNkS9fIx8eivY
+cVXL869yfceiZQ2DRFbfEh+bX4DI1JGDcTy+TgdFmpxLqKuBbC49AqbgQM78vY3C
+HuKPHLmnV9e2obPneMrHQXVs2PEhDOKwLJojq1W8YHJotrKQn+4z8NqJgcjNKgrs
+KOHywXzfHbzZryih8PkVtDeS/ycKOzl2D2lVTl6ZR1c/064zCJsQG5QZBuMDbaKF
+PhITFoHcmuUioS+F/HTh0tSJvwk/xI1W92WTJeM6pK97mxOxwWCuog3JmlwmCaKI
+HNhQjBxPe6R3IVjo9CU1RjqdujiRSH7iGkTR6Y48ELnqKwwJfJsARFDkXWOVy6gG
+IC14P4HAnNgLQ5ATVg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_md2_rc2_64.der b/samples/rsa/pkcs8v1_rsa_md2_rc2_64.der
new file mode 100644
index 0000000..9ee07a6
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_md2_rc2_64.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_md2_rc2_64.pem b/samples/rsa/pkcs8v1_rsa_md2_rc2_64.pem
new file mode 100644
index 0000000..0e9d9a7
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_md2_rc2_64.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6TAbBgkqhkiG9w0BBQQwDgQIuhO2PlAopLUCAggABIIEyMnfUQr0i9ShsBuW
+/9RKaa9xR0WHNp6xj6A5ZjsMgZ/V2IlVJJ546zxSA3r4Bo2vEDY5GdJQ2AVlCDfA
+SWLcPWvHGhouqIvOehu7teThJp/QeYGbb25TUlwfz9Zrr7U5uDiICzbcM8jc+YeE
+5oyMQ3uzxTPJFxMoilQnr8v0pHUo3SuNj9Cur++sy0F0LCmMyjX8HNrUEctPzBdX
+QOCYrxGQ0H3yx64FaL8Kp1ZL4JI7zw1oDGvyRkJCD173uuwE/QvG/m4ym/fnVUzp
+xAXACHokmQgWsuFFSG9VbNdJ6XWMTdVMvQhBeJ8vMjNNlpvFVoAKJIldzDwROiKB
+XTPHSuNYpmwqN1Kx8QKstIUW+31Js0ZJ7WH4nC8lVu1mnhVG7TEIG3szd223IzBm
+fTbqOwOM/ZivWchr38dOYU7/tEizbyGPjP8EWUC9nxGkmJGdTaluvZ5kdeOH9r2Z
+YudYhH5N2FSKI/0em1rq/Jj9oA5zunbX3ZwdUM/poNCiSC24wq9trBjOc/CWP/EH
+9zLdO7TtCk+nBtoa8bAXwJWlK1LLQrA5lsM45fYqBhf26C07M5yNPsjTA4cFVF9o
+PFp3CO1B6BEdnl9ETaO1vyc0jB0QJE/z1ySglsBtN1HI9irsS/IqGHAQq9mt9tcv
+knAWpjO4vDu9GRh1TwFzliU/FH9UFG9yInQTzQVWMcbVgOPN5uxGfrFy2qiJNkAT
+iMOFQb1xE3MzYM4bj9p4uoKh04UdMusiIodBc0xmoXRqkNH2G+oFP2xsWtg4HCKY
+Exyxc7Py49h3yYet+IY9FUWC5Gdp8hBVFP23ENMeWVOnTIjby1MbkjFukQJrf3W3
+SqftK0nwYmXkdn3hwFX5CxAYqVb5XakrhxDJw63kFevfm5Mblpj9QhVcjGsWJ0f9
+pzrkUunLdyOIT18YzZkdVaeTTEbVbQWqNUsIFQ8n7HfaOnQ0iWUX523fcDnY1Sc+
+0vFe2NZvpnl9EtvYEQmcI2tjGpDVrCljvayKbn/xnC0ixxkI/P0PrfcqfyqxWRS8
+p/e99gBwJ620iFhWd2v/KmQ20RJzEofKI3Ze0fIvnbG/z6mPj5yj/E9EsWCXT4Tg
+svU91hsSa6xoOyeAOlzhFy/r9fdwNNzhsOSYU3fwqXZOzd/8gXi8qX2+bpBxv2S4
+3KB8fIVopHYUafXVerhsVwMEX9S0mlrFvUXn2+ZqWOR8PI0jpuvYuQ53ZFq7LU5H
+U8CSwG6LZIFiYDT+t7I2B+iH6E4refjr9UWGwWEYGvViFbNW/dEW4tMiwsCEoYUR
+iEcMN0SX/OqOqz3I++7tuxaP47NRWew6RhttnijaEAnWmtiThMO4BRKfltAXcCo2
+OLhCaik8119YAinRGgPoZtLBQ8ZvfVV69Zwmdc6xgF4ML13l4/04fy72nZndn6T3
+TPm2+t0ndyCyiI8QWA9b+JyAw6+L6RNnCHC7CknXmvczbnJYUwsz6x8oQimy05Ak
+N6QDVOJpoCUngw+gn74T1Cta5ZaxSJfGW8FK6qb0hO5wD7gZwtMzkDoo9xNbW6bw
+1l6lt//wyOqkhhXeHkJp37Eaf+XSCrmCij1GRqTyRPZL+jRySjXRrLLsIZYyVway
+81DyAMtYfjtpDDyzfQ==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_md5_des1.der b/samples/rsa/pkcs8v1_rsa_md5_des1.der
new file mode 100644
index 0000000..81cc168
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_md5_des1.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_md5_des1.pem b/samples/rsa/pkcs8v1_rsa_md5_des1.pem
new file mode 100644
index 0000000..f0ec276
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_md5_des1.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6TAbBgkqhkiG9w0BBQMwDgQIxizKMy0aK/8CAggABIIEyAnnix29lspsrzEJ
+CN6s0zzdZvcbiGqUHTQCUKdhCmYBEns5IuocYmc6i/oONG9Gy/S7VcksLZPrWFAI
+DWuEpMKcnM/Sv7RtMq1kpAFlTlScRzxOEflaymUhr8P7fdAhjRi4DxZ5O32eHzhg
+G+yo5PhCkQSl+sClUh6owOl4zm7l3aVdqOK51fFE0EZ5RkZ9pRQ95Om5h6++c+IS
+T4Z2jF4mS2ALNg3vFABF3HQYO+KuGqrGRd7+gKr2QU6I1Zs6xcFVu6pF7T7jRKh4
+d31yJ1ac52+oWbw6P7Lwz9ZMzjlfxDhStXhl1FQ+iIeKq07J2urgXdxxzvoHfwOV
+wZakQejSWnyOvCvGZwJZJh5OZrad8Y9mAZgicYjDxWfxcLZQkZW+vUDJBWD37Sln
+8BwvYBATLdBPTqdXGgv4IyDwnPXdXxflRhHGTVi94oY3gEbhoH2yPvCD0IVtA1lI
+cG229JsbNQvH5DqTS32/mz0LJPlbPmP4tj7EZ4nqehM9wrF5dV+bigGqH6g4hfWg
+jCS+wRw//Qa/Z553XZq0WIJWg6JthiuiLlme1axOceLIO092+9HRjXQ1j4SlLPgs
+bgCiKn7uISvhxuAtir2d9jxqZ+KPDaSsLTMP5JycNwYCbtb4DYDGonwEfK+20tZ4
+3ZykwRKIyD5c25HBZ7maWbe86rc5c1a2fcvIjbXzwOXNXgNn4wn471oKchbXUq8p
+4RFw10omqTvzmKISucI3ymUkmuknRtVwc4bGAprvzpszBlSqPUi8E43+MVzc5pGu
+T0b6vGqhwYNVEYFJ2VplJZkgIDnT47PBPR7RmBak16kZhQPO8yUpVtEmhn6nCtvo
+It7wEktt0OxPcjLKm2Pus8oxWM/L38V3gADAqLny3A5c+at4VxkfMbNNNki/dh6M
+LBaLIgdKZoT6ZIwP5GIPjOn/y1FGOAB2NAHm+RwiPxCBshr6ztbMbcPJ+VhQpcy+
+z5FCoB3xIGE47KazVCUozy3JRjwY3aYqgQoIqbhvJfvxo3IfoY359x1lSAnQMGcQ
+AqsqRnjb+/PrwuPQW/vCR5SDfAxBJGsnnI0WR6nwmfDXrR0BQKjd+//M6y+GA9cF
+tm9b0gacTQDynK2tkcfbBwsHfQZJpAxWHpW6fgSRBxaMnFHq/sOqMtz28at8M0wX
+qOQLYPQw7pLTXMRuhSMI1UMs+fcTZ479El+inWZwzF3CjNnKr0LCV5ZhwLhPqOu3
+CjXeY4KOto1hGu5tufEIqNR506fehqnklq2qAwpFbJxzYyVzTADx/eTTNd/4EHk2
+B5u0lpY/xIgvSMAkkb1Y4v8MgBI6klgBAsKWhf0ojfn1fUuiY24/NzGTE5g5MZ7X
+ZyyFkqYrc+T7hXRSe+qXltLxD/4StXOTOBuf5TLsKbkBbKVHtnnrEwzhejQMGZrG
+BNk66KQRIL4LQlTBS5/rcumNgZys8cxYVw6swmvKw8ACSnihOBEvMlOqFBmXnjwv
+fn3sCuOoRmCRHNrk0wi6CNESBkJqlvstCNCuIIZZr7cXkihREK/uU/GirxAfmpCd
+jiHB/jD+FyOAoaSKaDfmjTjF1uLjyiEoBC82yfvYZBETm+ERp+6DWOR/mX9e36mT
+HQn56M8rvTeoNeqccg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_md5_rc2_64.der b/samples/rsa/pkcs8v1_rsa_md5_rc2_64.der
new file mode 100644
index 0000000..d060e47
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_md5_rc2_64.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_md5_rc2_64.pem b/samples/rsa/pkcs8v1_rsa_md5_rc2_64.pem
new file mode 100644
index 0000000..ba3a9c2
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_md5_rc2_64.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6TAbBgkqhkiG9w0BBQYwDgQI6ZMXmLzh0BYCAggABIIEyOU42e6vlc8GacmK
+NOf8IXA7FZsgmrHQKimv0HLfkxXa4MfIceL4GcHpKMPlAsXtbVkucaasIkGadBoC
+7tQP4ZvvsGS8H490QHzs5Q8WMpF9dG9rDfnf+/cKTEnRJ6BDqI7RN48p4VXtOiFq
++vxZ3j9EVW4+MLY+5qjJMyqtxUy5cOENM4HI4v+V76W1xZhOinCffEUMPwrxKtMD
+x26bDOWSTvhzNDcFjgmcbq1YQRoi++F/vDkiIsl675eosdYaGfTK5NJeiIBQ5J4U
+wtX44OQhtM7vxQzkPUZoxnul6s0Z0Sr5J2P0mureb4As+lyqPVoBMwJp4g9bJTgf
+zFDM+OiIiuRA2tgfakJ9xp7Nkg4HffEJobR4/7QG7TyXG78mlKi95g+ytUYAyB0x
+YEfiuKOxHkMlBALTMnJgyhDLtqrmTofcaBslNLBSMxKvCdJcZL3lncrRtx0u4YuG
+VXa1etHSfjNs9XS1jsrCCW5kGhHoWoaq3GS+XcdNm0U/hl/txIOhs8jFp4rEwAX4
+fc3uqhrK5yjTthWQL230jaoEfHhLyNJUDCGUZ77dc/t41o3FhwBseEqvPTOK3g5U
+bhI0DD3Rjp/wfcSPZDJdb5l23EWhBsFh37U6k64QtwJkXPpewMCYCli1isCVUA6W
+OpL3+nQZsQEs/sAkKF4x+eaIvrHypW+fI/7JLP61O7twBaoACapVNNlt1JMok8XZ
+4gQdvf6BLjE50M4onV649jc524ThC5nA74cKeEYX7UPFBWYc6EyIwbCIp9yLCWyH
+QZUpgpUXxAfk4AvMxO1XEtNDCs3eMGlzcXaHhb99mdKFQ6DB8dLNoWjCYsjjRWbP
+N0f/egQZUeUGXY6e4lcxFsb1ItVvSfMgkYJfrTLysVMiCpcjvwAZTKIMhM2iHf3f
+fUZD0SeN/XuY6GUBgEIKlNpeyNS19gkE27Ykj13MUpwzLQwH+DQGAlPGEnaZcAio
+M82BLlr85Q8LxypOZrmvIqJXqBbhH+lOfPRKUrhOOPt+Pye9BNUbJDpN2oktdqAP
+mJdCp5m4Vj9MgAF9VrgN4++uOkn1QO22xQyzdCOQnWeSPpI1wqlrU/AyxxGw/ex2
+mxZ+Y13CS6OHfgsZKawrov56qmog4Bfmxra+9y+C/FzFXhXgFhJu9M70dAYk8zqT
+U3EvL9eY+I+dxKR/ne+S0siCVgZ9/ZizYLrHyRaO1AkevlsBwaqc0ST5bT8+AWlK
+ZhPQVEH7uIbSSR2rUMF2olTZNDpRzCqn1ZxATZq84aMzgTjlxxHCrFP2zQOiV3No
+BrAfHYDXXe5uSqBDTDifbAJhDmDJinl7QOd7nHcFQloAySr53g3KMQ2WNRRkUMxe
+TLNhuN6Sm1ymvi7VYlNwVl0nqUltuV91lE0RzfO/fFVhRjUQ/HTvTwvQsFUy4DRl
+Q+Gx1p5lrM4zdYcsqgD19Pw+3AiFqQrGMPknz7WU7H+I9L+ZPlufokLVMbChSuga
+2jfSzE3ozkpD4jDBhUg5CHQC16AQ0JwwVGBOHiuOkNZ3ztLjik2rqU8BR8UqN+gc
+JGZWC+U5gOIzNzA89ovrO9ozPT1ig8icW4VP8rdx2pxN5qB9ZNgI/96T4R9MTgTz
+hhk2LVnA5n3xs6ku1g==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_des1.der b/samples/rsa/pkcs8v1_rsa_sha1_des1.der
new file mode 100644
index 0000000..421497e
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_sha1_des1.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_des1.pem b/samples/rsa/pkcs8v1_rsa_sha1_des1.pem
new file mode 100644
index 0000000..d2a00d8
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_sha1_des1.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6TAbBgkqhkiG9w0BBQowDgQIuvb3MliqZbQCAggABIIEyHVgem5Ez9BZJsRK
+Y35R50+mIs7AY/S9hVcbnXmfikN4VrM/PfP3vTUfyRe4tJnaA/5lEsUmTLpZxl1C
+EZNuPYWbGyqwjeDYTe6d62dLsdt3hLp+lpEF7NSFnNUCWF+ZuBujArrg8PVYGWsV
+eYvTDXXrdCUjZ3oXWSUQp7u7gVSKG/w/B8OXuKXHNwMMgdba2eAdGG5gOEN2Sfca
+loUPFEoZNtNoEw8Z1i6FM70cMSQ+Q6UL1OTshNKICFHx/RW9+VA5driUKbASzBEi
+T3egbUH6Rmv6MDANFDP5ql7FaNSaitah1O2yGbdjJlhYcGjLk5U7UnRrphvcPuXW
+t1izrQ2OtwV/6dTck7XJbrY2FKvq62N8wyNHqdidgh4zGGR8PiDUSEW9faUuW9Ux
+VS0495vOyZoophrNTX7iD9J1a3c8FJJzJAsGmk2mMAOcFLYWJKgXDRKZjMcYWfbj
+fxNz+TYlSb1+GGzZEyeiyr218tpxH46uwGe6dk0zuyEmCsK52S7g/pkJpL3paRT/
+xh+ds/Y3QHYGeCYkO8LNb3PWwhg6aO5Zcq/nSGE7l1EEvRbIiMombBYEsyvlO+/h
+0qgktSqpW8ukhyOGTXCFpy7vrLDK0qJibgaKhZ6HZim4vSXFl43kOSvHPNhip2jY
+fu1G8/nRPUf3JqxI/cCUiNj5FG8/Tm41RfXupGZeaMofCi9rKIRdWsk9w5mJ4l+W
+4Y8qrR3Tmemv0oqSm5NzuwFDqyl3tRQ/0DZ+lAEY2fZd+ntOY1vXUTQCQ1KQcdBW
+70FuB5mG8UK+ahBQNiEPxnuXkdqR7ELOazgK4VgVFvBf6biHTt+f81sR84yMOHsR
+kAM48CUZ7FULQ3VfIOfNpUthRMDo/bq/t7x/XWTaV+Oy/N84+icaqqpobJtLk0tJ
+0hHp9RXiwF/iL+u+MrEUFIyAdaQcqi7oxPIe8d3wL/q1jyftATVsRQyTClH2zFN8
+wxcQPs6xxOI8yGSCbHF4LTjCVtL/wzm7sCfzi3HezkhMtiHIKvFQjKjXXJRRAU6+
+JXztTyMokEF5e9PDuLoBin1gpJIDXQHgd8NZ76IOi0S9LeSvRFK6ESk1o3bg+PzS
+kZQ7bM+Rqt4jIsnuLwXe7dU9xprFiUAv0TxgFQI5QqX83tKllthAmBoE2t3KANR9
+tbOnC3Z+xiri2Z44kQgt789rqb60QpUMJm1eI3WSGzJN9Az3yxKL3wMB8tkd/G2B
+/6rMoC0RHGKh9LDP7IzTXT55JdmJGl0mY9ZSC9oDg/iUiFKwzlB8kjG8cU5/0ckQ
+Osz4b/Xn+2h7P1zvLyIcpH82FCRjxa6wLbOFqB1PUJ0ZtX9Dng4eEtxkxTSNoXgz
+O8TZrCC7EVY89y+vHsBD4XiJt7HCIymtwN3fLuDkqsHezcs2Y5ljJlwIcaUvzLg5
+e3kfVM4l1U+5XfdYvBHu5x1E2z0gcW2shhUFMGVzuy8xbvVENXsVYxyP0RHeqZgv
+Fj4NUPMicJ2KoC5Yej6IQlhTmFNsMy/TJLV2d3HwEFOTsG0saZHVLTCNLMpSPym4
+u5YaBOlwBsNuTlWtUMG/gBT+wKRNUaLIBJwmplSkKTWScxMILElv6FKZXpophiBs
+5AdrjrjM0jE7I8I+7w==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_des2.der b/samples/rsa/pkcs8v1_rsa_sha1_des2.der
new file mode 100644
index 0000000..c4ea356
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_sha1_des2.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_des2.pem b/samples/rsa/pkcs8v1_rsa_sha1_des2.pem
new file mode 100644
index 0000000..626dae3
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_sha1_des2.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6jAcBgoqhkiG9w0BDAEEMA4ECJmiRQv0ipIPAgIIAASCBMgYV8qimgmy3BFc
+RIPjRdYgrBHAs3IelCotDmny4mx0IjmHRqu4XNeye9dMhVnxpntxoNKc4B+Hfoa2
+QKvNj2uqOTJw08c2uu6BSmlr0UHJj9qyAergV0hh9vzIBD5tCr+hGwWIRyR3l+Y2
+D0ZaNPP+Axei6eLBV3QvRJt0AdiNPY6u7+SqdzKAwWj4iotbwVlcYsKEdMZQB69x
+x5fz2PZBHKMcg9EzU5coEOGacoKc3ex85v4V6ZA0gjSsmj4ldSvb9t4QfeFJWPsr
+waKPvFa+y4TSgg1mIrW0/+rH9QzrKAUVucLsM8SzyOXayWPQUmieNiTcMZJ8MOvj
+eJVyXOZ51BRLW1/hyGbJhgZEgqDlfNNecFXAFehFA8HEsAwm/KjiRaTM2znqv/jT
+ZA/rEeovoyjTQ5BjbLmcHIJL548EBHg6ea7Gs6QMoZU/0iouYKhHAgIrk7oIK+D+
+Y1kTQ+WbvQ6KpEmgySvznKzT2THrI5hny19dvcbZrk/rUsnrxicAbSbPmdaH2Rlr
+3xRi3h+LjPbuxTIIovToA3jvHprheeGiRODnoFzjQoUG+hROdOXyGz4/QQvIK1Ry
+AWGdaeKehzWye+eWB2p1p4oJWFDVgXwMIt+CXJJrsFVNp3n1f8jw0g+OrI/iHpOD
+roh6uaNCiBkqUSG0fCrOpKpoQKg6EcqV92l74YeXKcOwuLmSse3bxz9igof2jq+h
+NGoozV2qc5y4UqOjSGQsI12FMDV9t1np3GR413AjsXKbOHl83eTHLB/GYlpPkdNr
+obu7Xj5GVYLX7A54yof2gwBXH3dbI/1WGu9QU1JdUdnKL07FFs9BgtRqsU3MSHtJ
+EU38J+Ezlz8wW2eMyIXSTQBYshluIko7fzAkEVWT/OCL3RSJsB0xKB9OpgKD+p5z
+Q+AxibHxUBjxddwjEgcsX7KC9lEyMb1vH5XQxOO1vdup5eJZx6XL4+V3GoiZt8Im
+3VSOciynMLAkz/AgzcG8b4XdIzf7dpjN7dvJPpz8KKDG3hztnD0SWkZEpLcODeGP
+RJcki3WW70vy9/DDqbE749511N+jiLDTxFc25Jbd01XuPZSsONCB32zjgJZuxwax
+n4/+EWN7+H95G1a2IHJ6VlteSRXxRKrZ65yNju5eAIVIJk7REXA8FYx2mvNNuTeW
+FBbBT4hn7f2015PX4zJPe8ot0SPvC8GyxpLANCfbXCp6f5LAj/bsn9CeYh8yGiQ9
+WrMCz3RFt2itpvIEeO2W/MGs862GUMjdk8qrZyeRCnFjE7wja6CdcJidPKwp8dTd
+h+fdBJtLbB7BfOXn8OGaafCwFdGHvpogtv/GSyEsaT8Vp4D0QCWlJoABHchp8tvq
+8LjIfcA0kTP3UKTkvsRd3BJSZH7AOCinHF4IiC8kkvj0CxSseCsKjjBcXdb5ZnU1
+YUQirDYCwrKvZQn24cn/kp402JQpvParUDXl6gqoiIgrrjnsgcr75cf3AZkpLZe+
+f6zMPwg/M4Dg9l30F1OExUWNgfs78QaxByCKuXP92y1gZ5cDAYZoi+ioJ0pMTG3t
+egIdfMfc/kO36Pej3s86sJumMdWI7FTU96AZf5CM99Cl483oN2PpUXpj09K2et7G
+lwXMU9H/9aJxUqvZ+jo=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_des3.der b/samples/rsa/pkcs8v1_rsa_sha1_des3.der
new file mode 100644
index 0000000..df01c84
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_sha1_des3.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_des3.pem b/samples/rsa/pkcs8v1_rsa_sha1_des3.pem
new file mode 100644
index 0000000..6dad536
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_sha1_des3.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6jAcBgoqhkiG9w0BDAEDMA4ECDFK+hyHRPJSAgIIAASCBMjG2lWovCpivpZ7
+eXZjRQdhN/SrZCajGzwAQNtykElbBlRpObRlMpJUEed6kMI3V310hQDg/0imf+PE
+ff3ihc300LTMb5woiqadncRU96+WnheFLO26V65R7/ax2q4Thuci/1hD6bqNIzVb
+rBxyRr8XX8AwOIIkfCDFnNBppvvc8CT9vNJ7ezx4q87ALkuHu8DAo4NmWJZrOXzI
+VKv8TvyE6eNYRp5tiWwOloj19vRMCqU5tEjNWi7PT0FXSogMidpejhZrMb2N7oKg
+XHaaFlqofZz6CX586B9dRgg7EPoAE2d1R25o/jen8xL/mQsWa1WkM8hRsjIQ0Cip
+ng7gV1r7AwNQgrNoQoPBPHSAhFXGnXM9viTt1kHHjdE81A/JAsnw6OaI1TEAkHMV
+Lcu6ZDhKPBa798PDWEcGkYPa25NEJmV7cxFwZXH6b7C8h1S/FCLPuzYvhae2YSeW
+RgMb4MMweQHf9q9zb1Y7LyOiw1kO/vPiIFgS2KRxMwg3/L+FCK+D0NJaETB2ycM2
+gvn8U0hDY7lfTtog7jiInU7uZ0eXRF7mOyp5WdIQpmeqUNMBUteRvHscGm2jOdNI
+RUTUhLjKzfXGLRTqAScU9IB/tcin7X8tOg7rJkRQ3Vs6JcHd0U8Hm/tci9wXc7CZ
+MZBKEwPZ/+KwyzdbGbBp0Y+mzSshmOTyc2oe0uUhDhMKHw242uyaEj+1Wp3y8NmI
+dEx7c+A/KmeynNfwYabZTQW94IWkl8v4lr14hh++gyu6bBCeSVLe7ui9L8xxWYii
+g4n/SRFXnicU9Mt9m3yC1Dybd5ArctsLE/GnKIRyVJSwoUt9D6MB9m/3xosKG3YC
+525u05bpxOXEP7Ed9P3AnuoQpBgJQupy0CzZ81dy4CYPItJT9EgiPjF/e8+7YiKw
+y6ySR0LgvCb7yOOh64+xKo34dSs4C9l3QnBQ0hNfeT4nqr7eA8VLLjd0K1MKVjZz
+GBI9gsv9Uhj3G6wtVXITkMyHMIT0KPeUwyjSrFNaBhlN9Gr5rU1R4gHZpIBPeOt3
+7JfaDikpAphUx/wrywS7KFvVhb8RXCDAgg8xvtLO1vLTEUg4g4+XgKysuPqq+DrA
+AnUl48GNbZh+O/mJfpuAP9Y9x1a7ZT19iXXYdzrLOqfaoAsT8eGIbDVFo3GlB8B5
+mf0WJ+ovnzQBbGPxSYEVn3M/CLzpA85q8R+FD8ZtQIYBhGETODDGguUKnHQ6MI1V
+9pxH5unjulZWlhYo4VJGd0gmmFXMuLyBPh5w2xvQ8ZJLrJzAxMc/KCVxtTmTWJjy
+nkh2N906ZiChdecwvqgwq68WkDxcAbkqkNNTK7U4fDmeJNAVDrNTOHyL3mYryw4z
+pCjreLjxSOv997TappTy9gN5mJnbzDoLIq+vzFRHQGY0At6gcC5JE4QtwDWm4Wc6
+w3lMHYYqXceZjsCuIKu5To2racKl3AoxySnE1JQaZOKCt/xsSaRzS5TSmWyJp0Mx
+1YZwPpTGAaX0xcQVGihktpIHwLoxngqkzjXmQ5LMYhodfW8BYVcIX034D14RbM76
+ec9xRAoXQkDaIp/aUi1hMxyr9aEo7x4fVPrgHO8bV/2U0/qu7EZ2Vyg4/zSPb3Bx
+XC7kbX4PMsWZby737HA=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_rc2_128.der b/samples/rsa/pkcs8v1_rsa_sha1_rc2_128.der
new file mode 100644
index 0000000..979f216
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_sha1_rc2_128.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_rc2_128.pem b/samples/rsa/pkcs8v1_rsa_sha1_rc2_128.pem
new file mode 100644
index 0000000..989cda8
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_sha1_rc2_128.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6jAcBgoqhkiG9w0BDAEFMA4ECOkayjIA+6pcAgIIAASCBMjjgTgBAlc/31JE
+i/jvM6IuCtTToO92d9Ut+tgT+b4u5VD+8KM4ayz9L+KIp3mvowk8pUKtsIWJPqFo
+Kf+crAWSPnYg8Of+ZFHu5s6SYu9wOQ9VOyP3LwHt1/5jnqhuBW92Buog7GvauqK1
+sdEsR3zuT7cpbq0MYrB6Bp/HI7fGYMUPwy1+T90lejrmTSVAyK7dyk6U96bkWVCx
+p5h0Pc+xF+IbtSqctCaw+FV8KdZgxV2e8GzGVlJpDa+J8xqjZNk1X88JuzrrIayi
+J92szEBhWIXwJdTj8mXBFjVb8w4khEv8i30ABxHxfo7eWpt33R1riizwt7NbbYbK
+2gUXqHmaS4MVKbsxb/NMiC2KbJ6Is7/tPYXvIiCqeKz1IcvrwbVbPJZBon1Ybyse
+JSDmcf9wwHt0zlZ7598OCtxCCy1JrUWooAmzGJZq4hkg+3+ell3i0boj8/2s5auY
+rD0ProInuCEsJG7JbzwUSsIAF7wmIxSLUJZBLbTKDs1XRIYtLVQfvT+ZQOge/d78
+sJh9BRzAlSpOVyEtGYYW4WZLJyJaN5Pt9+zmfSo4yf01VELmC40PipstDUiNQ6bX
+lGJbJLY5hEWPcd61lfVw3KdbtkzrUmnY+qZy8W3R+8zP4UV+IXWCW0anxrNiVUqJ
+QQkucC3/b6/AOjZGz+wx5RbpxzsSXx1P2pDdbxAXXy2KAUql+fM5ukeh3Rj7ih5w
+gS19Fx1XW9jikJg4GZEOs9LkERHcvhBHhfsSYUlgyzA7pcliFsYLSqe9KcfpvogI
+xJjkRVqc6hKYejU8HxW20MTdh7yDT3PEYBrkqmG2QSHVze73w40uyEoaTWCiWfdV
+VlLW9ddq6rypW13QK0zMcXizP6rrsM0PbDHvc+cyPGk2eWaBNWX59W6ewvQWVyp1
+hS5B5PzA5JUhUyW1/qbmNgO/se8jNT97E446bprQ+SGV1h6bd37SCplEBSsv8Gm2
+sYWAVT4IY64pFP0LO3SttKAi7QGxdcNXSkqzdhdu6A9+ZnAl3ssiGU+mj7rIl9ND
+aAhyIZpqdBYIOj4nJ+jwlNNxLrvhBTCocpIZE66uTGv8c5AGbyX43USzMTyx+fVl
+GC6SVPIoFLm+YNu5wSpLS9YSxfNr5AIcM8fkfBpNJ+v0gKi7Ky+n3Tu+CQyzxVXd
+k5Dy6Xs1Mw5fh9tOO9gJFXwIcAXZkEtbY4bjiA3fvEdLrKhzWaNOZKA9pKo7Zhdq
+gR3WA1A5iSDWTeyWkjJKSVxN+K7AkE5hQTI/6q+Su1JK6OOfui7BQvGKpgNiJGc8
+swHlwprbbNDqqeHLwp1+XTIFt9p3PhRuS4ooqWhhJTRTUxERI7g7J2oCl1kYv8HQ
+YfROPqOV/2d1TK7k0BSym4qCd1uQg6OewQ+C6w/QhkGf4Xm/FAfCkv7/cw51c4oq
+VJDJIX6O6u7rg9F00jb5e7DTw52x+afcMv10svlORM+LR/70gTwV7jV6DnXFUp9/
+ZDEq4qOqy/lCIgFTlziN3zjapfLYkcUppa2QHVgkNOEiRfwKQDXVwgX/kRkW9d6G
+WKgoxjeRT3A9VDcTrL4E+OtB2c4ykHsNzqsWunGGLR4KY3NyAHs3Qn2Egq/klpKp
+M/3VvFPU7quGOcbHYvs=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_rc2_40.der b/samples/rsa/pkcs8v1_rsa_sha1_rc2_40.der
new file mode 100644
index 0000000..f3bb093
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_sha1_rc2_40.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_rc2_40.pem b/samples/rsa/pkcs8v1_rsa_sha1_rc2_40.pem
new file mode 100644
index 0000000..7537522
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_sha1_rc2_40.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6jAcBgoqhkiG9w0BDAEGMA4ECEmBQOdpNXpwAgIIAASCBMiuvX4e3RsNqkgh
+TxtXZRqXCQN1CB2fxUhDKMW96szcVTZKBr1Doli85mdP7kPPbGHyouoFZZF+z76a
+2axtCvgx7X65MVB8G0MH6tMC+FPRcy8vLnGuibmy03vBfuw8aVrvF2EjDwG0zncl
+FdPUWutO4LiQbWT6zzfYbHOX3pw/ccIAgHyr7BBv0lPiyZu0+Xv8wfhvc1aAtg6V
+yM8Fw22hSMz9KnbWvdu9NcKJuHRoh2eLC4lXha+DN7PSA/DXxyEocx93pgia2mj1
+mb8oVkX1uHWtcLEPWBS3CtTAgskO6XH0IAL1M4FZOXqpf4IPAiWEanCjdVC8cO7T
+jEphF7E1aYgrCuZIoWiE6bkceA6rxPpGTtEafrUAJBSIeu0ek5bl6EiRBZdGCY+c
+DT5Oet3c80xk0+rz7L4IBUv92aHITSRs8E7CStMRWAIM7BuqesfOwz6uDt/SGW3I
+wNVBbrEGNemeHvT5QdML1mXXRZu4iMaNE3eoqT5Jcdq6keRZqihR/ZdBs6OEOQNO
+Olxcn3QgyCwmxajD2/sF8zwFHE0tBPwbgiMVBhTJooGzJ75LzpbvT0j/ly7JpIoz
+6EYWLKwBmJ48xQRWTGksb0/n6Pevq0OkFiCtkSn+S/U2V59RBMSWhIY2hiKrFsh5
+sss7GIDPLj6eneAnhjNFt7aAiZrX4bg/Hhofl65BxO8O/HFww5h/qRRslbwLIkjw
+xy+QPM3mkem5GaFyDT4pBeT536RH+NIXewyeMub/Va6MJNAT0JLAq6kRPr6RF0uj
+gqSVetDMHVXuKzBc+tkk3mEH2zt/tdOAOEtp/uh5kRyS8lzYCYbdMVwXG2b4tmKW
+c9pIPCpgqKqzYtLq5ohp4qbs+UKFnMfef4qxXA5qdjeSjLA5IfwiQ/2sjm94pYsp
+rBBv+zULfr1iQlsrPDpvFkV7frH7lRV/72iwUbXnMFkY8yZYCX7pPeMz8Mn/RKEI
+MXFXb5zYExs8oFySwOAIMA+f06Zuzi/uPB+DAek2foZ5EPTruizi9GSR0q16mtrg
+6iGU0fYiOws9RRfE0q5y7Hs0JAbG9ivsnKs30FFtHmK5icdQWfraIGVCR2QiPPfs
+N2lA/PkeuF+j5ADoYI5zQSgZjo5TawJcjtXzp79yLAsvoRk7MDpmrHudLHQucKz7
+vvOk0w9pQ36E1Ytkd8OLm5AX71/YZ1k74nh2gqVu5NIPLaOLUr35mD24+YwX606I
+OIaQ9auYDgZN517MD0knbFS0f8hCCg6yTOj489RXszjRglDZbKnrXRMUmFKBA3al
+g8RNupq/VUfXvxPIAcselPt2br2CCoJaLskZ8VKJEyqi8bnZvAxuEthnZDjX0uAn
+JQHDIUqdnIrTSxIihyNBzcs3O2WGh4YEsP3Y85o9KdYa9JT71w1gT9SVBXVHKqve
+e+HkohUkcs/qQMRwWFhWX3XoZklvum1czDxmVbzt2S9NZ2QUg52ga1MGfHTCyRXu
+IM9SnveJyXWjEJgSfGj2phnfw5oVy097FlrGS8WF+i6bRWVdJrV/0tnZ5FdB7qWL
+uDObQTopFbkXBbnwlJ68UYdkEDbkAvy7QOtyFEYOTYQOwsYglxd6iWI/M/a4ciKS
+TMOCQzxIRUPAeJENBTU=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_rc2_64.der b/samples/rsa/pkcs8v1_rsa_sha1_rc2_64.der
new file mode 100644
index 0000000..c6356a7
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_sha1_rc2_64.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_rc2_64.pem b/samples/rsa/pkcs8v1_rsa_sha1_rc2_64.pem
new file mode 100644
index 0000000..974828a
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_sha1_rc2_64.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE6TAbBgkqhkiG9w0BBQswDgQIJu/CJ8iPmbcCAggABIIEyIFkDgXMUnmd21JV
+Jf5mVH17/NAPEUob1P1nijVJkuZlSx0Vv2ukPcotDLv5FQltgRMx3TS7xGI91Z5y
+vzCVrOsC8xB9OyulD6MdACAavDhy4e0mXu+6OiiXFIp8EeEap+dHszzl+G3vz7mf
+LCZMf8BkaXrl9RdDNDD10ich+vtuzllY5uAZzQIt/0gHVz048qNywoscYV7xniuH
+4AOpOFHo0F+zo5oxfK3ouWzhfvOhIvqxgK7PFqSMixmkIGgKkrhEYWDp5hrLpEyr
+qfXCRtpe5auOwt6pOQ7MvCNY78zF0WgHrmrmXiWcl0eBWAVzBZGefBl9DsRTeW7a
+83rno6bWfdTYZMP32XvDXsBlFaQu5xtC3wdvI5aX1Cj081KcRUdyVTkWe7Uz8DYZ
++3NZCbw/2AQ4KeGB52VVWy7R2ZGaHyRObVvT0MheEZN7iucMDlrxIRJLLUdKkyN7
+VXY5sLcN8JfSfKqLaxQp356IxJqdG2jdBbb6LqmCdNwtc0WrFErCGSS2PQEwTfVO
+s9u1WsReM+FEWW8/byoovbQvP9BVFsP9MZ67cM6fPMErLwmAaryB8gzajTHW6kh1
+i5RvoDl7XaUDVUVVAujsVA8cvwl5GU95XXQUTmPQGyObDz3fuwZKRPTYrOm4Mjvb
+tI0Fuc2HZ8/2a4OeB1CnnxfkXZW192tgriLUZLwfeE4nHV8Ik5C/iXC9f5oKB7Oe
+CVSJy9ZSszgw7Z69YzRhRbmxCbG+M1nUUUdIkEQbXKw4VtMx1HFRpZNk4ygvWd+j
+O/8h5QuOu3QBDXzGKUVMRhkOprKXqPRyO2EnqgV19FN7XSbiCwUhhXTfYfUxHwgS
+cvWeF78nb+eYGLTp1rDo+fbttc3hYgy3fH+9lHMV3uibdnVXXMbGvYkTaX5nwl04
+H5fz6EyYbVH+tg7C9lTED6cVAg1EesqdoUTtq77uVT61inlCfdPRr8iXa19KMTA0
+ICszvPEp1uISnA5DBSoLZeQFShzgbn+WtgfNqrE1o3oqsIi91wwpPMCirYhtBCoT
+sg3qPhGyr7ov0rDQRcDqTL0pkpfhF1xRzP1vDF5PwZhqujYnFTkcMfjRmUdu3Pjy
+VtMbrX1yb0Pyxi3Tdr51k17rqm6PM2QHmamy+8Mhz4Rg40VzwrwJd96orBmoYq0C
+IajfA4tnQ8eV82N1HnMa8WAcoKmjDwjvzoZ6IwNov1ddOj4+stcjQlkArp3mUIn+
+k2G+wxHkRdcqjrsht+ntBsDRE9MmMhbuDGbyZn5XrcIeUjSNt/Vv+2jHNXSV3Say
+rkFAGMgOpk2gUZEwYVZFPuY+crEgxu7ZhmmUXr4duTaEi0l4Dqod8EmGhrBun3UO
+690lnV/6dOTGmvDo9Afa4EVvpC8BFmFrGjEmtIz6cCx2RDSTg8KJI4XBw2YTCo0V
+/E41iA4lWVfGAxvfCu1Cm7JDfvVrFEuqEbH/FbDPYOBXYrQLawGWc5jd68eRToE2
+znCtxSHRwnKBnHpsZ6zIugpjxM4I2QinAts3bqUhLdU/h8YUC6xzco+XBc+GVj1D
+PiQsopJT2Cut/uY9jRHsZrm3HvTPRaFssjqEhrUjgcQgLijGDx5p+y1bvfFMI+q/
+18+pWzqjHQKpi4VIpA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_rc4_128.der b/samples/rsa/pkcs8v1_rsa_sha1_rc4_128.der
new file mode 100644
index 0000000..43592e6
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_sha1_rc4_128.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_rc4_128.pem b/samples/rsa/pkcs8v1_rsa_sha1_rc4_128.pem
new file mode 100644
index 0000000..399da95
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_sha1_rc4_128.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE5DAcBgoqhkiG9w0BDAEBMA4ECOEwJ5V2GWbOAgIIAASCBMLjTg01txxBp1BY
+92SMQKEA5tENp6zTFZwB4L7ObAZsJJ0p7sE/vII982EsrVytM2V8gTjnRpk1rlG0
+Kow44HtQX4bI8DIlgnWdedP+Vmw8DwpiVBDC2TFZULlEXp/54pKEEcfWxK4PCTgM
+Ve5PDCPVJU4Qt+xPopzL7/sg76XI5a3OWhk50/TlkmC+IFPSqdZ5bOBQfiU0ofLv
+Ty4oHzBUdZ8X5U7B/FihGAzn+RExxgeKXQrLqUSr/ruMIIdon0s2hGGrxasQPJWA
+s7Qh+hnJuKQJPNqdXIECiZR0iBx1MfDCBlH4kd38H8SKr+J82DtP1AxJGwbTLl0u
+WQgQiP52KCw4jMLe62pKW/Pf/F84YSIvMDEcMLtn9CoSfOBvjtaNRggc8XWKtFnp
+fu9VAYgOVQWUglTIQTtWtX+xzpErCEkM2ceHKxIFdS3oYnrVf0lluiBWC9N+jDbE
+ciSor3Us2hM9O5IW5A7EKtjX45jUEexqq+66hLngK7BmzO2jXIDQ9DhkzurbC2GD
+SaUmqtWFRSOEXrXXhTK3BrPRPXCri7C5wWlQZhQi1Oj+glHg9YWp2dkcPdhUDsiC
+Bg+NL0zx/oZY3VXglHtQDP9wI7si0rVssCFDefO0xzJClssa6SEkFW6iYMkAYS1p
+ptxzrCXOVfeUWBvOttRKXhc4BYrktCfKhQYVec93LFHIIM9giS+mGXu3PAhrIuQm
+8dbXZK2VjsKP1WqS1Ao25+VP/aQZKZCcNA8meMEw9TYGfAd2VnzPOfDVEiU5+/ZJ
+9DRn1JH0M1z/iWkbH4cSipkK18BVcdOqzqL+BuxM6d48RESPof2155qOWWfHLYvq
+wAkF32MbTrkObKlmzr4ikEq07vhXAUH+y2I0vaLObOtvjL5WVMNyr29Z5DE/F5WK
+SX/BuXwQrsdqXMdunFxm3gYKgaZqvS0iDMAXBFi4JYPX08LVuLNG9KZurn/peTZ1
+TWDlVEmk/PME22Clkl7ya1H73o7u10jNCqPgVh5M+4JWmKSjuRB5F3NmyISdjxYy
+2e/YACDvole45B+SNgwKqS42akK9OFYJlak8Uu9Swycwt/+OIk8TLw7C9Jyt7TsL
+QSLBpG+mDMimwT/skpNbEn5IBFM42Ldde7oqc0ng2Y/xWePwFW27F6aisYoh7T/X
+nujylZipH8vUkeT41XfAWid4G909sirR2/KYo8IO8qbzfdKKkr2MSp3Wa9k5lYcR
+o5VQrzxcgy/x7zl/JOwOC40RGA5iojGMS+Y0dy+W6p1lN/XdJlZmGrUc9/yy/d6r
+cJ3nQzzqkrT/Vct+XAM2ZdBT+I30jXvTLw/959dyqOhejkDYuPG5TpsEJkCLr786
+k3j74NXTBRns8LT2NUQwSLQnuW5B2cKVIMWYtmhVEOVRkP4Btxs4d7KYvQTUsfU4
+eKGijUHAiPaKRJvgfCHxi84hFc6i8eGZyCS4J7Oac0Zpc5kni9VC8f2AURa5+7CE
+b16j/4oT1QvGRzjrbnwpRXckTNJJtyfg0LoIWHe03kB3YxHvbMJLx85bKo5x8tjn
+STARLMlqqgyN6KmvGHO+YIJRVAy/VIzvkyhOLkngWT9JoHw76mDSMvFlDKVa13D6
+Z6QnJfmE9gY=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_rc4_40.der b/samples/rsa/pkcs8v1_rsa_sha1_rc4_40.der
new file mode 100644
index 0000000..e88e6aa
Binary files /dev/null and b/samples/rsa/pkcs8v1_rsa_sha1_rc4_40.der differ
diff --git a/samples/rsa/pkcs8v1_rsa_sha1_rc4_40.pem b/samples/rsa/pkcs8v1_rsa_sha1_rc4_40.pem
new file mode 100644
index 0000000..dfc3a7d
--- /dev/null
+++ b/samples/rsa/pkcs8v1_rsa_sha1_rc4_40.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIE5DAcBgoqhkiG9w0BDAECMA4ECNcyq4Se/97zAgIIAASCBMLQXerEc8Amz1LQ
+HVVV57nwrBN+wGK9b0rlWZf/Mj6L1zFTAJFgoswzEP6zogWyrMciX2WIF2XopbL8
+GYy3VdUyIS4/rIHVjXZsVM3BqDwhPyPfzCPi0pxVVLJtJBH0rD04U/fHMTOv1Gox
+yWoLK3eyv3u6akZyTZNOA1wudOaIVokeQbXbpgYtN9JY/TYLUe7snv5OQSNYZlvk
+GfAJA4JIaZx2CpWt/kp4GaAamrAImUgvNLrMqvUE3YHh9P2JyVCR1iOCxMsMNJo8
+ckO4MsL3a5urh+X34HHDRAs7Jur7VCZJmnt5Ehh/mArLRdJKrpwuPVDeRXE6jU2s
+LJunc2t1hO/nHedzBE9ZfUUTzNLCLIPtmstMdelgt1A2OF6ZbOXMhJYwt80T5HpW
+PYiMa34qWzynTzSBiDT/F9foAT65xTleftIh/IqK9rkvJH4OjLiDQEtv8ffXfyj3
+mZLBOTJgIMX4x4hihXGT/W6aF2AAzgawlThpCE/o7BGJxNRuk3vEQ9K22PKMbMrM
+lQje8khpKSK9nJp/BTRIc5HDM1tVlgmcW/5RUywyzQtb35IOjtY+RAGII0U4q5YO
+lJNLjfy/ewftx3TxhdBNWWc6ODHhmqZwgX5QW7A62MiFbjs4zqfr0UZvK3ydOeMk
+ALk4OwmZxAENS398Vpx1mNdvuxi/wWjJ3Li+4lz3p80Mkisccfv8AezcaSPigUw8
+DEfF1DfLBBVFozRCeNIEV/qm0x3wuSIO/+0ZcriiJmNNm4s4oB/qDDRDAQ9ynCaL
+ek+xvP77CjXNCvx7RyYGE5ZjrGDHiRc8t0SeUCb9KslbQ87/SyaqaKWS4Y8RnSOq
+LHzAk5xIc6YwJXMjE4xH3SyUpw7lmSwv30a+c5mFfI6Ddu6R1GhU4K4t7CgXOMXV
+1TP+e8AEMpdrp/KCETMQDYwgFc8bGUOTojmkBdouLwphfB3as0ndikvsESZWJp2m
+rPRjzKhjFO9IGOcDKQgMH6lbov0trzN5qbEORuz3MAMmBkb/+64yqrSwaFh+a6Mn
+LroS1t3ng8+rilEp630TmPIu1XVkkLP1PCKxqZxX3nG06RCvMh7dGLGxS9U4O5fF
+7qCqr3eOCkg3nQIOgCohP/fIILrKRiu3ronb9oEMN1lh6bPcLaMhh58iE0nVNZeH
++3VoZA6p7qbAREgOpimMNH22yyyyx4naFlK1ajM+jLooRf3dYqQIhcTWw9HNMI08
+bHxYPLS1CMLadpxlfRJZOcDgwwZpVju08RVIuF+Pk6+knAe04OVhx+pPS6rLfDyF
+Tozrz+p5k22EffLauK8C/8PKbQfhSRY7o24t/mfTqjWXmQlC62b/HWvsHqWv3z48
+cmcB0tRBEGIr9mWuCLVCKB/2crJ9uCRCdz1y9egc1Yrplcl4epvjtPy3dYBl7ZGP
+7O20jZ1XAdePAE6DiPS9els9BUIgOXPPhKuUOI9KtnPZ+PuoEYR3kOUCFBIJuTnc
+1GkFixrlP6HrkLnM8eGBBlGzcCb9y33G/JoVe0l+fj7HIFE4WLr7Xvfl1GH85SAe
+66O+3K3ZpUoIXMN/tAaTHMj94e0iZua2+9v38HDHrVQ21EZvraonDe9P139lMvnz
+bpNCuk6sT28=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes128_cbc.der b/samples/rsa/pkcs8v2_rsa_aes128_cbc.der
new file mode 100644
index 0000000..df1f7df
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes128_cbc.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes128_cbc.pem b/samples/rsa/pkcs8v2_rsa_aes128_cbc.pem
new file mode 100644
index 0000000..651de51
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes128_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQImXjLGxzpmkwCAggA
+MB0GCWCGSAFlAwQBAgQQf6Bn85WfZh3mHP1w0yubaQSCBNCS2Rvfoebwb7/sIbN4
+uBS2v30Q/fOtUsqbo0JGjJEZ2Qe0kRDoXlDdf+tk2dQaI7tdjhxCcIeJOuiV0qJ6
+g7y7tmcUhyFHJqm7L4ODpdH4jIGhKFod2szydrQ0lDQI7ZYjucRGd5zxb+wMphqV
+dDcjEw1HPsVnG30WTjMSJ6lKs+PXLv+jHsf56p+QAxmiy+5eD7fF/C6vxCk0E0wf
+63ZkSiprIYsmbM1kDBGnJwsH0fmTGi5XD3mXb6zpm3dc47VootC3jL6dG4259B/q
+gqXZ810mBDPaupS7zc1D7MQvqHwSAhSDFylfVxpwbKx9Lke8e81AyfZsmuUe1QnM
+fqqY0Ciu9LjxkE8CkitV9/2XwNkusyvQmTFALi735kO/l6bieShFl7m6DTK3R3E8
+iSx+ZB4dO8tH+/9DbXI8un0DptXFKER2goXBDzv1MElmdBdAQ94j14yT5aTX0oTU
+C7gaLgfzly70sEJAmrlbxFhgyrcdOZorFgga9qnri2w/0KoDjQGian+tH452pWZe
+0XadQcrAaNviFJHw6/EmjDgHX970rWj2ZXrbWI4cm8scc3BcPaCwTDP8PZrxVhLG
+0SJeAjEaME4n+Y7CT3cSdOJh6MiAzyqqTJxFMEovhDOTnyUKkJ56VONG12P9JLiT
+eIpQlV1ywkH3hTXPMe4Dpbmvn6dhy5dRdOAtRFHOdno4Ri+0+Kne1VGhX1t3i8nP
+HzRSLUg/tq3/hAwaMfHPtnE+3MXFteQgGd2eVzHiwMwcLYAoy9ewWW7+wvXjbDaS
+gQ+Oz+gDCm/U1dOMRFp33lSN/eAKluVr9ZNewJ6r8WHg530CeSMG1rp4gq5LX2vk
+SDQ0RPPAf++6G2tw79GWsCGNFIW/6xHIrBx37NT/zn/0P5/NMD4qZOrzRPdy2tBx
+ggszbUK20sXAikibVJp4YWHAZMpdexKLWcktPE41FylFc/4XI7+ddRyvcW6re/FT
+OCZFm0JZOmiopz9rOSGOgYklrUNWqAXWrkAiBo0mco6UdvBjGVFvk2Sw2b17S4Sr
+9glXPFBNMHLy1daN5mvWq1uBob2us27MiSc4+4Biz3S9FMO02HhMKxC9cnFw5ZZc
+aQHo1+USBQ1qJuvA0+od7JwCC5XEm+qunlnUDqDt8bC5WLXADDsVptV3IFIZ9ZB3
+xM5y2K2TBpXzjR+fVg0M2qnbQYv6SVszuLlPArZL1mrmMUj1mmddPBJQk9Sl3lsx
+ER2R5bDdLA9ct4mVLFjx2u7NNyYQqyvNOKGt1RD0PAlaP1nynVzuLEpnDAKrjCQI
+IDivXTsjc3UyVx5C2sc+L7HuUibi8726sBYIrlG6eU0rf4wfgstGp9l0A4yBlbRB
+cJRSBPdKN780IpEFx+SfzVeBvYUeVH0DFthaJfDOWAwD1XdQoxaPUhSel2iaaSCJ
+WK0eaYETMc1z1P2Yzr2BCHTSxOrL7YJEMDYb1Ii6MvT/xaNSk/yuqhz+rS8zqH0E
+qalCGoIi38YJy41a1Vau7MCjkxldexn62ZbI4J4dO0W2mX0Fe8aYxxGtL2EpCqnz
+9c7BBsGqGC2agru0qTkvwCKtk8duMg5RWOXnW29tBYuAyT2bmwmco20XOdTgXIUJ
+qsiX6xrG5S0T7vFExbxBIX2Jhg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes128_cfb.der b/samples/rsa/pkcs8v2_rsa_aes128_cfb.der
new file mode 100644
index 0000000..73b52f8
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes128_cfb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes128_cfb.pem b/samples/rsa/pkcs8v2_rsa_aes128_cfb.pem
new file mode 100644
index 0000000..1e87d53
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes128_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFETBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQId8Qhy+607E8CAggA
+MB0GCWCGSAFlAwQBBAQQac2kffj8EBtimaC+HXnM2wSCBMKaK+sjj94S1ZJ0El82
+Wt+oFB7t0Wi1oE4fCWofX4T04VGR+6NYzj0qZ+LiXS/4rw9AQjbCfkYm+WFhMs23
+b37+/jfwZ1N8WYMxfQ94Q4YiN6EknPouqBpKwUqUgXL+WJbmAzMfH877ok3Pc9YR
+5LKwShKJLAQkHlxkDMq6ZWRZuCSVhRzDOvR4bmrwxViE5nmyWJJZmdwz8uI2eEbz
+WA/hCON4N023fqAQrhFMrWtklPVvG78HtCTo9r9x8kNjdOF2rue7eE3TH7ysdr5J
+/xlWVDXjSOVuPzUOdeCmUusjpgC2vSqq+oKF+MsYDN04sUZ6MksZcJnt/aOESc09
+lOHmxoEo0fZ210HCKaCU8yDGvQNyUdAmfmoZ+yDoT7x0AD2WkNGPab6jsCOSaDxN
+RtMoQG7Py7OUElVj0wkidKd7oPOzxZx1WdNG1V/PoGfP/ITAxeBZhM6rq44pLvtL
+nfdkrasQ7zDHwbDO4f1K0KcgDrl3p3Gbj09Vh9Go6ENfImLoF7N4a/Vmh0vtfPJ/
+PsPXUv+fLP/lKJgd9fFPdBbaR2LWcl7sdDSxuFlgFkN0Z0EKT/9S4hWA2IETKGRc
+7lmq+PU2yljkISz6LgJOLO9LC71HavEbDB9VsBmfnj2RkvfXs94HpBQVATG3BF/o
+maTznQel8aMjglxhTZPwB/bGvxf3BYd2zGtDdbrBB4huhgKygyTaHAQMbb9UaIGx
+GtrUyD0mJ7Zj97z+WIbbTcCkqINeDtbatI00SQXCaldN4luSj9cF0+mHIaQJcEQK
+5/mQnDVYD06INUR7kOVI7/4EsBQ8TXkjwwjTAyRM9fcC2DKCt5RJuS++6G2eXm8s
+Iep9neO0YKF0NXARnLw+3qsY7PLUfUeWtTTpUfOBW+i44kW+mw3MqwxlgICgZfp6
+OmkArD0ZpdaMrIJi/EcAN/hqB+DEAkO6qd46cDK3PJkNGDBNCEM48bwNeRwzl5IG
+Dqq3gFyek0DaPpdiGBnP8W9VdG/mfzYCZkaMptRKQg01iN3KHujSZpTrJ+MPfwFc
+eDCIet7L2z8tI4p+Xm+XHBU4+7V4aiplXAqY3Bt3QgnyGe5L+r73nl21/2tpDNGM
+JdYvLecji7KK/uoSE7icYKXuZNM8F8vdEUE3UvSkv3UVStVijZdchV+0nHeTBo1k
+fD3LVWLTUw8SrrOUWpkFAUbNSmuoQxZti9vl+0cBaCipG1cc28opKuIEt1U/HYl+
+GTxOO2W+9vJy7nzm7cw7Tf+HC0ROAbrG0tPOFdePGAp1sWZyq+ox85PMcjqmeMPJ
+6SuMUXzZ/zeRa3MjifY9QywEJY8TsvtMadPAK+jm6otDxOneXcZwzuwHnd5Sygxo
+A1WwlcmrV9eq6748wopD330EZj1oSqz++6givL9nGxuk6IDi+HMmJCGgX0IXnB1q
+pqt2skUTVX5oWTrGnsbGb/JDBqmMl6q0NRGQInTr23GwRftIsBWPHIgpplqpBWPs
+lUXhdZWukX+RJX5oPL6esik5XJvN8d7souKmxWQjgPwzocn2FL1d9l+SfQeVjJVL
+zpyPCACnXFCygpwT6hqfYWz+yXSLQwOFc6CgHV6SAm8Sgz0CIfBVev8PYSgeuNFm
+momSCys=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes128_ecb.der b/samples/rsa/pkcs8v2_rsa_aes128_ecb.der
new file mode 100644
index 0000000..466e861
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes128_ecb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes128_ecb.pem b/samples/rsa/pkcs8v2_rsa_aes128_ecb.pem
new file mode 100644
index 0000000..8f1b2fe
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes128_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIJ8UOV80biOECAggA
+MB0GCWCGSAFlAwQBAQQQAAAAAAAAAAAAAAAAAAAAAASCBNCnRcJxfi5+Xp/DG1nc
+jvQbvUTu4nlM1pD/5wg4D0rCuCLbCWv5/o+KZB5ASdJ0SjaOPx7TFM4xR7Dj0EzV
+/FePoNNqCiaGy8SVFz+nCWnG4B++IOKZgTRi/zMSNccenl1HkAFdUqEfwFcg6kMx
+TlWzYUR0X4DgNZzTjm/BhQpJFduh4wXkShzYQMV/LrZUaY9JZNWIWpiaSodQc9X7
+1rjftKvPljW5kSkeOgQCHeL5F/6aTHOdrjTGlzgL4ql9JbZccCs2E41yJ1cjqUNY
+zdh9fd76i/vfFuqZrFWI/IYM/NOmD9QXO5wKIe2dHDdXBaL4DrhPqV3w8qWoVEfX
+xBjQ0uNXwfTb48s7G9RRKoWf0Q/ehVlNVxwSJ2JAmyci68C9gyG5lZ4PLsUSwLAF
+HRjozR/LPhSOZoEB/z9nY8fEFQH3q1j5he4v4j80IPFv3xdd9b0v24g2SeAoEBgh
+9IHSVEcsx1S4cvICX7bOWXIGKNhq3TiSVD5X6VmKG83bNdUivbrmSWKOt8u3sKXz
+FmE7CSHFrsJI0I1sCfNEbNS38GZBYkQ1X6RJ2p3umR4syTSxfl19S2tWPE0HEpJi
+uD8WFm39lj03o27ujnp9yVPUPGTAP2qzIivG1voTUFJ32z+0rWRDqxP5AZfrTQfE
+DgI+uzsEBwCKLmnWaMAuHovf++7n6qhWkM4oXzb9uv0xUSfZdk8/1pR4zxjNazz1
+JgNd640tgqAoDrKLtW/4hP/N3yY1C8Hjwqt0GnqIK6UdGnju0n9zXiNfBLv9Um6L
+O0b+N3nUZ//RAkFTT5ZRPZ147EtrFIbLhvu3II3P76cJaJrpZ06/sYUmTjHn6JCo
+XXV8u+EXr7+Mt+Ml5GqewAOxs0yQw79bszmTS4U+aGQObSxMKFQKe2N0biTo8Xit
+EoqggCtSU9S5sukI/VAEoPEhojsu5kwXkdN98GibNKCg1A1e+wVWari1R8XWQtB4
+swe1jO9iUTWc7zc5EedzVyhIv3Yockxc2smNGmco3gF3PImi1kWtgMPKuu0YTdvE
+R+Elawccm3w9wmeCHDL8/jTU7vwGNKAN/MJ2RePGLXg7sPSruCwuzNz4TzRrHuqn
+jZGslqClmz5ASjNihun16ObAtP2q9nfnvhJh7I5smiSoAPbt74Fg8uAZfj7pJONd
+Z4QVs+zVlF1gi7VQqNrVB0zKnA2xDeobqZG8PonrwdfwcTlpwPA/olct8EHP9XAq
+kMRv22iKPIpfs2cTMDNj/1w4r6RkzWe5pfRe1hAwjLHlDKTiOJgAAOX5b+NbVwdG
+iwbd8ajh7sfn7q4PMxB9O4E9t3zXphafaTNqELAGndsmsOFuJGwmFvw/mFkbhxYg
+fbBIFsaxV1IlBEuxSKYymUnJqR4VVrhSEemB9HfAW0sgdPEJ6Lsh/c01WzqyzVbG
+9ElaC/YQpLsAqmpg0JrSN+4vbMSdPpVjWn5CYuBeTmJdZBLgYHitg3VSqMTHwUfJ
++P4oQMWHQegL5nuOsRZ1oeOlLqQhIYVyGn/Kgas4UWGvv8NbtoUXJhhIEo0EfzRy
+YUCB0b3yCWdJ3ZyqLvaCMmM60fBC7FHPA72oRL4OonUwRdbz9hY/k7XNxcQcIaGV
+fCkBBoVYSzzr7CdssamJDBLLUw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes128_ofb.der b/samples/rsa/pkcs8v2_rsa_aes128_ofb.der
new file mode 100644
index 0000000..7bb364b
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes128_ofb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes128_ofb.pem b/samples/rsa/pkcs8v2_rsa_aes128_ofb.pem
new file mode 100644
index 0000000..4b57254
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes128_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFETBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIYBTitmleS5QCAggA
+MB0GCWCGSAFlAwQBAwQQfpTMeedMDwo4LcSfu3UjJgSCBMKtj63O160n7dTs3+YV
+ds1bZFbJ/8TvSMOVbJn6VZMy6l1Hh92CcGuGzLulWLz/XYYgIvsk44Rmi/gaf/Rl
+5Sv6EmfGmxzwb0RqbyL8DTfQie7wu417qwPOqomkFzlJ9/Ku3hfgFDykMEkjr4bV
+EHrTHB/PzHxhY5dfFoH5rGR6yoCbbOpg8p5TguKxAU3PdPd2xGHI3AdtsdrWFEES
+HahIa5TkHCjHQ3M7QvuVY9RI00gmf/N9OXccUCUXusoV381W8U2WBPuatQ2Az3aW
+iQF8XrY6QpOrvIDdiM84AabbWYk83JcMDL4JGjEyYHbNZA85fw8mD/OTeH/fPMmt
+4VKuA6mRjZuAyOpBh++4pWk+GF3/AiwbPFZCM1Hyg+Q4ozHgNOW8RmwExHfEFsQV
+cAgZBJS3j6ot6wxoc5R6n7cNJPTSSRceP7Nodd5nNyj4bB37nPZNgJm9FprsilEm
+LCM7IfsV+gi8DzrtbEi/e89ZMkm4ENTD+9lRjLdT1g36Qf3Kz6gUI81lAEoqEKSb
+yDTV3jkA/KOFdqzuqwXGIi6mD80X5cLOmVvjWmtQh76odSyIAesagWwksoTuMJsa
+/MmKsSszUy8/m2xYKTjQKADmMnRrrC5ZLpnRdpwKPXgEXVlKkPQz/Vw4lzGq4S8b
+m4qvVrtTYZnQwqyU/8TC9UMqwxLjRlKR63oQuqfEw/3QAQXPPtGo3P5Lz+bvtZ7h
+PEZr8Nzp7Z09lqEXFWww9cTQH8AS/Aq1jr3pFIf9yh/Jdqj0ZlEm382PNC8avUbc
+pS07LlgOeGLrTWZQhZVJSFm5X+y1ws4Row7wfgoscp94KczkvkToTQd7ckz0n3gp
+N1JuSCloxLzgnE6iJnELc7r3FHRqW9PZy+QhXTKkgG12sRpXeL2KTmyJke62vwTs
+MIvdXV5qJUM8LoqStkDFksqQT8q8Tmp3/wk9XHuI7b4omK+LEZT2MrK+Ot8FLpbx
+x8nDbXlnDt0sW3MjaEcfWKj6azitn7RIqAvIdgptj+JACwFHlDG+02v9wP/Scsfw
+s1NQgpPnBD6vYU537J/faWn37kp7ai3+8l3+9E+cF3s17QI/MBiRF2ZIW5Ps1aP9
+ZeqJF+irwEOs37DdkWpfZowXkW+YuFUTXUtRUqVBaAe7ZCbaS8e7jlS3+tKZ+yHp
+30JlArAtBgUymY4D5hqIs1EXGyrb7l75nxCuKcfnEz8l9BPHB+CelhWN7DJNE17t
+ncqT8wRF7/d+vSXxC40BQo4b4n+33MJ14RvTIamhZcKUv58lvFhoaltxazNFDx+8
+SxlCpuP6vK03t0ZufNpNJzppj2g6qSxRARkQTamQkg2SuAjbt7mNXIwg+VW3U6El
+WEyHJ+mewX91T4Bwidamw1Oe4uhWSx87vHJqcrvhpPjFACrZXxzBvyPoyDk1Bmln
+SH1p8awSS6s/8Agrng45ZBaWolez459R6xscXDqUAFwqe9In75Ojlj8ow/HJJu9Z
+kxLf3nWrrey+lug9E4p+Zx3CgpAVPxm9iJtCwBDFcOvu9VgOUleZO1CvKjDDFOE7
+z38j5mSmQcW2+1Tx36JK9uHoD6+p8i00wpBzeZiY6JMwx5G1vUYEwaNd00fL66ih
+TzcIMpE=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes192_cbc.der b/samples/rsa/pkcs8v2_rsa_aes192_cbc.der
new file mode 100644
index 0000000..92b4c02
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes192_cbc.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes192_cbc.pem b/samples/rsa/pkcs8v2_rsa_aes192_cbc.pem
new file mode 100644
index 0000000..16ce386
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes192_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIFf5BlNNsxVkCAggA
+MB0GCWCGSAFlAwQBFgQQ6s1KV3GWRHthTWZh1wm0DwSCBNDNscsywNkbLh2xD/5h
+vn/IgPbkjZG1en4QEiX4bS0T06F7JVHNtV2nu7zkbDg7Moh3UyteIyTeGyTdqw1g
+y7GV4U/RwDU3QDY3k0OJJAYIosUxJSyc8g8aUSY/Q9CCo2XPAZ4wdAP6yDcZtYRq
+PaXcQIAKIKayKFvBTr/ekV5BY1V4xpAoVjKNDE5rICPY2M1M8qLgQJzvTdRqyevg
+uF98REPA7rSiO+Uj5bfHkNhK5RQx7pu+dM6GhOiItKgWpLBEfQN9Z6Oa6MihUtbb
+eSbNdkdx5PdztRPRRMeTxICG3fDReYdvaNAh1T3x/qfYutHlkToI+A2jYMd/NoVO
+eaHlpXIB4o4d4TKsIbhR0YrDqK2xJxr7dVbEkc1rY7TmByL+Y8fHw4KXAV1etmvU
+/9SGCEIajdyeVN+v3RiOJPyJvfZSSxiv1fRfmoUTpCyLkdZVq15yPO7bIwN9xDPX
+pg985onYKXxG6xy2Ck9ErVsX5iLb1wU8f+k5E2DAxF+oAZyIpItnH65/FEkGdAYu
+orYilxbOvtB+lVOZVgYuE1OIsOy1wc6GEtoZ4UKo8qkGHTrqtBypJRhUQanmKPOG
+DHMptPj1cyrLaAh58ZwebGaSi0gSVtbfmSppZOpc5O0tnEFr2+uAvKnP/tSyh1my
+SbTjkDH549C8Peu5T74TDjM+1ogjrecLWOyij5ZBVdFWp/s+lpX2Q7MQLsXrptd0
+nLrnIsMjphSXXCFLZHm/hSTI5fcZKVjEwNCbVj4UMOd16oO5s66KuIX3Wg2MG/8U
+isSfVsga5E+kIyChlag686on7p9mwnYVBNI2oGu6zXhSqjiGdwRmUvoayloGDR76
+vtIVB3vPQCJTMMdbDxJ45E4Avr43hngWCp3X4MvzXgvFnvbEmiautqnxCVwRXfFS
+dDWlGYKvb6dKKBrJ99muxYUik3iJ/riQpp+BiHbj+/Ox0pIJKpGhL41vkvuUCaUV
+zri5SdrPL4OPBPZwShrIglRSAgd6Ot0X7ZbeLV4hmkqE37hPECWS4lYt1wRyC7pz
+cB5DbKoE0GRCox7pOemWRgi8TPFtvMcMdUmx+bCZ+KNSfzYzLziAyBm3LC5iuH8C
+9O35aOihXyZ2pvQuQCQ37pSuVzm3ySQYO4YTSgY6o8J4ypi+ax8g9/StEJWP8MxN
+DwKMxHzW9rD8YKxgi38yW5gNQ38lqEyxgwG1PGmkfqRtk/2XOTJj6Xu1h14edYK+
+vXxeESy8iwBFoHUqBQDv/tPMXTvxRYnItODQY9efVLVAQ6jPOgvoiTubeQTdX3JR
+J7MBVHEqWDY1ZWi4RIJew1h4txFDC85UPHhiRrjff/EMyrQNzFoyF9ixM4Q+Wwof
+MlTrGI4839GtECTRdvonzOSNfyUGQS6B6v1Q49ogBqk+m+FNjfx5hYYL7rqtvuG8
+VVbQiV6ImkDRFme6gbmiNKrGMrd6Ntpah9tAD9v+RQJu4Y8TyNBeG5Jvta7GAk1Z
+PdUNF1Or53aeVIZ64pS1fruTiXB+Z1CnSHo8EareYFjnBIvTjU2Z/OJcnp9/vL7X
+GJXRJWcrnRcBaiwmKPqQ905mATsr/TCR57yWHhH26VWd5bvb3fNbtmbf68m+godP
+PtPPRfTKSh55tmrSvpQ0WsIUow==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes192_cfb.der b/samples/rsa/pkcs8v2_rsa_aes192_cfb.der
new file mode 100644
index 0000000..29becdf
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes192_cfb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes192_cfb.pem b/samples/rsa/pkcs8v2_rsa_aes192_cfb.pem
new file mode 100644
index 0000000..942fd9c
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes192_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFETBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIwocEWtwMl2YCAggA
+MB0GCWCGSAFlAwQBGAQQEQR9w2BnPQ+TOMmn5o8SpASCBMLJgyqgJCp58K5DdDod
+wKj+IZVKl8KTgtYyYvhfFcYSYbpNamV1hipz/answ/ECJCi59iHlo9m5p7bYGcMh
+rs1QT757PUMVGHwGv6GUC1QDr4k/DTHJTcJ3Lk/vo6HkOUvr09XEiGL4L567t405
+Z8iZgvoCoCQLWmGvTAtsYaR+hk3foTii32fyn0O1uK8VKrI0Uf5X6mw6yGj+NUD2
+4+hSTU4ixsPWxEa3El/CPuBZ0JAxGr7IYMMLmLulQKW0hlkbGtUZlJlVyoopUuMK
+PoUN2GdzOnupyH4ekLSgnUdq6oFSH+jitmpIZeiFjLRP6SRrhhtVPVkquTUzV8Xe
+Czo03yGr6IY+HU4oc6EU13KrtQNL0oOzM+AnO4Wdl2QXi53U0z3Fz6kKDaZUGuQM
+rHs+/aE1AV2j4B64vQs9pvQWBLx4PyprYi0Grki5gaiDKBA+B7Qa6X27hB5+5y2N
+wZKQml+P0h8sOMOwovlh2atBSzEkiVbNWmTPW+vqiaGD4TPIMH5RZlpjOwkTd8mp
+IxHu+Kdf+wdsy1+rjBVUKuz5pCI8yLHqVqST6q41lHYsEZCpL0otz8AVxTNEQfio
+I56+208nZkzk6862uu/n1IfZvuKKkcNls04Bydj+Mh80Suk3ETDHCqzHI0J3towu
+HnS9DhjEB0yEkpIJJ10xxbQ2yj9i0eC2rmc0KlWhiWU/HHYfaEHoYJRCfs/cQmTv
+w+Jjxi9e0HYWqQ2givReDhkqVOSKW1jQiOFh6iTdq792NWCGPr6+sBNYxE6jCjU5
+4etyxD68NUuAWdPss6emTJzClnaNvhIt0oKidZME3fycan/Lu1BiRkQhw2wN3Xq3
+PhMFgiO6OL6VUqa6gnwed2s4kUXfvKDfmLau7VIYFMVDXVTL0PAC0+KM+n5M/2Ou
+t7ftFmbxrjZF4Yrj8pe0hgAad27ZjvnB6dr3Hvcf6s3/urQxF01SlKAyEgUsvG7m
+DJfRj0IU8lXkVO5kmUaW9nsjqF3mUiuqJ84/8su+/pQj2/3zya+8f1DXa97gStiz
+mH7vgbUir1Tea5c20Z7htQt+8sTVNWvoW6/9fJmFD655pmk4vJ4DK1LV2w7sJ37J
+L3gk5CjcPsrtswDiCg8s8gUh6NZvaKW6TmPjrK0Zttoam3dl2ypEkqnmsoSFCvnG
+Vbz6tfvKXwDCeqRrxEEmvI0Pr6UfedBcFBtlI+o0OORaWFstwS0UFx0mLCyusPzq
+zEBHdJyMKomPr30o82RQQdlFgo3O5ODaB/tXH+LzNC3qHaGSnqmJh5WLHV+n+Vne
+kkov6IamjmwBmYZkOgmHRkx/0ljpnpb3GGBnGOtJrrp+O6Nlm0C1iVgtTI6RC7Sx
+DC0n1E7vEeofQWamzPutmMrKluqHpei2kDBdcgk34KIbyQEwopjXosO/bRag/ekN
+akhogLBfYs3LR2R7PWgR1L19w1SdNqfaqJwRmq2svBHQaAZmsGvL/cDk01KDj8nR
+eic0pYG1SwPMFN4R4Iv4uYLH2Sm3oP7EpCkNFZv2j7UkRUXXA/BhdQMsn0f6ZBEC
+FpVcw9rwqv24nZrC8WLqSDuAdT1QcpxSBHeL0JCMVD2gNGn3n6JbAjJCGZ4+BzQF
+mXJqiis=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes192_ecb.der b/samples/rsa/pkcs8v2_rsa_aes192_ecb.der
new file mode 100644
index 0000000..fd32604
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes192_ecb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes192_ecb.pem b/samples/rsa/pkcs8v2_rsa_aes192_ecb.pem
new file mode 100644
index 0000000..412f57b
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes192_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIpbFYsS5145wCAggA
+MB0GCWCGSAFlAwQBFQQQAAAAAAAAAAAAAAAAAAAAAASCBNBLAAueXBK5nlOxXmUj
+VM4UZJn2bfiK+3iLmqlip29aHS2eCHgieVZoSJ8wGSzERzNyTYefKGlVhSQ1az7L
+88sUC+NeT1jb6MdpLPiFprRuh/nWIBt8PzmrJnhwWVLiaSR6cNPdiHw0bkML2uzK
+zQNru45h2nz8PqaxDsyOAdpc7Jpn39aGXep8nZ2qpuJ/UV7zxsKWGvl6WBudrH43
+4lyM1ZPQJiM94UOX0YyvtGQkwWKdnJRq1xC3DLzW05NW1nhHhZaQZgAmtk83RH9s
+g1o4eRbjdnoTQyP9ybmzJT+LqXwIYuGXihL5dmrvUqA1LKthVrDyKrXKBOYNNPUq
+v6HFWYc+Qux3oQETeDVs0kjDbWbIwItFY9LAaKGINCJxnqJ8KaUbHapETj06pvSa
+gY/dEvICQp0NB/qS8KZRnbHsLMsosFdF7vFmtkRXCyIB4GZf5NYfndBufXT0i0GR
+Pha4lulIefrOlLCi5PhIN/rVoQplk6MVpk+wz+/zGEffvFD6g3uQSIgSEZOyr19a
+weZNIKf74ccUVqLVb93BL7nwOebBB/kiiHvLa/ubHpprFUtuxJij5g7odNQsDNEG
+MrFtOZqAaL1xDQHavIUcvyHPMfkskvToqdNNNXvwSnOBs5CtN2ErUxo6X7ZPoWGx
+O/1lBARNCEzjer8/zXYrU0WyzGdTm3hP2oO4aHEayIjDcbrnPmf6YMeQ9Z/uJgOz
+xiy9wL4DyFy+oVrBEA675jjXRAMEOpVabtG+DPW0aPnZImbc6kIM6hEKMIOseUAE
+t2zHLTyHS3zv3VseGsJOk3JMzrT1LHc21x9UUWLGiXWCYDde6FiCAgT4upvDyBDN
+Bv9Yjt2ymEjWkl126xDF5Eq0ew945iU9xD2caYXqpvlk+sOCn6jFyi4IigWluaui
+AGrFdeT7TJI+G8C0MRSG0eq4GwNg+2VxhaepYdKl52b4nVZBYcVCCL2ijBjWQdET
+APvb88WgAfCaOPdvRQ0qj6ZdV7HwhQxPgrc3GM4lgTlu66PtrYfZt0tLYp8lSFoY
+e/EMy16ZkJ5uIqzby76lPF6JSOaqAh4lrIjOISXYwvyEjfJMAib6IzgCnHrXHykq
+21pmZrrLaFHSILizQrohjPRnXFkUYWcpM5kl8NytQwpBpXBcxGV45TLJ9ykdsXhF
+UMyHQoyv7CM1xhYpu0huEKkm4ee1CYMDXU8j5xV3l44NwXc1UjACrL7TfAX6sJuM
+jJOG3gJLBnSCn3G1356nD/wXRkrn41DlbJentlGRh269+cqzwOOoKQYRgc7ClRVP
+L7g7XmfXm9BCn7IlMKVXfr9zkjQgkE9vi7Ann7EQeP8XL0IiW5zYD73tgFjt7Mzp
+B/O48zbBtT7vC/JyW2fM8fWhafShuML4pXFCUcwyhqP7Zri1X8cyNYfQZMImECD4
+HJzfszKGVSQAlBwMdma8BdKUKTKm83WnQqDT8ZxItxeHprYvK3ZxxKRNpHB44Wkn
+nUabNOeviSYf7LljVP5X8fGL1GM/HHcUs0FSniL0Z2g3lCS60ntEL4NpNej2EusZ
+Svfb27XJh11W2jLHsI0JaCnpWH3tFNgdcfohgtSLLDxAaT+/7dWO4WE7ZwQgEL3U
+6GiW9hdkhEsHoaYgEALVs2bsKA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes192_ofb.der b/samples/rsa/pkcs8v2_rsa_aes192_ofb.der
new file mode 100644
index 0000000..0f958d4
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes192_ofb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes192_ofb.pem b/samples/rsa/pkcs8v2_rsa_aes192_ofb.pem
new file mode 100644
index 0000000..2b0b2ff
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes192_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFETBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIAFIDSmTxSqcCAggA
+MB0GCWCGSAFlAwQBFwQQB/dDK9L/TLCwZUmXSzErFQSCBMIVw25Vc1S5+aa2nzx1
+33rZJL7h7UwaJJifFw1hCXLeOodR9iNSdTK0INnRwl/SQGB45nxTQ201o9FTNACX
+UowUCQP3AFr8/etdkZgBvv+Sc21o6VgP0nxQ2xE7tYmt6I4vWgsCdfZX0OjuXJTn
+X3xRFvmHwjb40iZCnxuptVB/kCPKQ4LqNBveKRAsV4MtODLtns2TWZaFy1u0zEG7
+6XNaTHzT6KjOlJCbEcYuKOrn6eUZLb4W4IBM/Chq+Q83yi3G5vKxc/MGw7yF80do
+7eEE/wnJyFt2EgAsutxDwOyJLN/cx2W827hIGPQY3N7Sp95vbpOBWGvBj/qw8hca
+Iy5quIBbkC86MUebqq/5eFYa6Fw+ArUpCkt5kmwGiVBBkPppxsqtW0SsNSFAyuEu
+BmA+/cjPqGx9rsqJhXCve6/tUOk8eTji3zyHPH8hGe2tkSfsN545yKOUPuZML56b
+deZCi5PjzUEGX2cLf+8KE63/Z+vqyVzBd2yGlxmwLoY3A77r4zefTwdu/ogoVZH0
+l4sPh5pRLfx3334hcglZ7ezh1M+633d0V6dhlzEFXTit+jaDXTIndSBwdLDgYHgX
+SEZOgqBtTowFTLMb5YPu/RObiDXucm1H/DKQZXOPM1th950Se/XQQq1gkQpqxvGv
+/FO202PD7PuZFE0yYkjb542YodXzuVKM04CjliSWjNlgNu36vE7yXyz1JX4B63OR
+kC/QbP9GKIwA0FLyusDs65wO7bJtW1IAnfm+HhjRgH1xh8lMb2Q05UhS458raJxb
+DstoQbgpW8FS1vTWPkJmRzkIDC5wuowgKnvrrWq0c0EtHH9kFmRmcJlTI0/di7Uo
+7rCdvf6Oi+lDM3/oTpiOKCN7Bt0TWz/HqWj4qo/OCaYOy01J1kaL/VDlbTkW6Qlo
+CpRtFqAVw+BpSaChKRAwaICvoPpSgHpc9kcot2Vb88Ar2PtWdWrrMylg7vMwlBXN
+Gp0RArOLybu7SLTF4fkONm1lK73f4ff5AB619FZFyytHKhj45QWQXIPAiuYHf7eN
+cpmBjQG6behKgMs2UbzS3pttrB0QVuF8wsE9K/3nC4WOclTrO9niwg9iQxRoaVAS
+0hR6fG7wN/Sskv9E0wHUIv1cZWouDxj3gxkav+/4efwi95h3XhStSVa824XmEsTB
+IG2bqislVvZlRl8kYdxcjSH/cV9iLnQoHU5Ng28VKFjIr2P1HhzFjtZYT9Vxecii
+urKS/8renQA86ONnJUkCIcx+aJtR/81+aNViX7ZBO1++l9I7ujU3PxkbGWaYFWjN
+papweOFGxUBDUF1KE5f0b3u9NfBx7vpzPsz1iKhkYrKaWUaXF83uB23zeWktnF9J
+xKeObzzTbLLg/xiFMDrJiqG/DLRLjXDOhqTSyWCUanXtsqlHOQ+nLKx3bGz0/z/N
+F+0PVBzPe/r6tU5l9ZAqjAbmpOZ5/rv9lumq+4BNSVvx6+h2HCoFWkDjrn1JPZ/B
+LQDMNwabOZ6i/Tj9IhMRYMRdN8wqRWUysX6s5auuNcp3ujZXVVZ0ot3zkhX8sXYo
+MD9XnXHzu/obCd68rl1UpuNTuXSplC5a4R2U3vuoQ+6eFGBKh4YTZN5xZppX4R6D
+J2IDxik=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes256_cbc.der b/samples/rsa/pkcs8v2_rsa_aes256_cbc.der
new file mode 100644
index 0000000..0e810ad
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes256_cbc.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes256_cbc.pem b/samples/rsa/pkcs8v2_rsa_aes256_cbc.pem
new file mode 100644
index 0000000..8ccc57a
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes256_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIacMv5EvHgDoCAggA
+MB0GCWCGSAFlAwQBKgQQCp2dvaZRkvo+B1rVXRkYBASCBNCcbb+6XB7kPjKT0wp5
+RsbuqnQZP8X5pdlCjCvDoIIpXtGFFgVu58tSO/VbUhvsJxm/R3AB/rQNb4IyKnnE
+Uhgo3DoqYyQQba+BoyOPz0JP9fEvyBGFxLSPxDfDKk/PNO/CRCHra8eX6+eKjKgx
+yAwQOg0PRgkugAy/fKwC8XqTlgpiKrWDmpPK1JtwfYFQmDXv//67CEyS5dqFEOVi
+S98BkbH+8doI7SWsF3sdpzI0ikv0mkpJwRpBjwLtMaiuY2ErYJOPzqkR6BVhd+FE
+OvRcAVmLjU2Nic5qYg6gNERowUTPMjOFjlOeUBJZe0cImQN2A1gTsJIokohootwL
+lZe5IJajBXCDA7Ps3LagWK6+WDZ6i+hieM6kH6UMzxiRyTqmE1HSVkOajUYJ57RY
+hicAp9lV6lmc3gTdvHWTPhidphzy7pdaCxLilygvBRPaIWlDY2lY3Wxfo/qy1QlN
+y42IzLKSsiSzynwiFVSWtCSEvxNWYCjuFYMeYpqZcauGA+tWOXPI51ys6oxYxemb
+8IDP9dwgjdbHrHavE2PwjoM8LQRBtb5+21UY4ygm5GFerTeGnlao2FUXULm9cnqW
+y5oKk0ghpGRt8lbVUUTriGWN88skf1fBjfUAbCBVcK9g3OiwiHLfQkaItkSP3Qq4
+qC2bQevt2iDDkoW2ilJC7eQzrkpuuA2n1WTmB7J563z8A3vatMp93tZvtCr0/tTh
+i8oXuavrmZTNcG998RpRGTydCP9A+YuxvEKg6hU89uzEEGABt0+ykmQ/6COydics
+UVvFfSph+aRu/QxFNCkrmuajCbDtFUzZRew4kYzS+ADrMhOpHqdd4qYWM/9KrCcx
++tz25jWLdtKUKLP/U0p4QuedBO2ncDeJVnhVYEh8NyOvDS4K6Q0GuFqMDLQzTWMj
+MM7YSyCcKe7VRbWrlzBasUTOqoGfz0qB9Cu2iy0FqMnJo7X96iRXRNvATFL5hxm1
+1+LHsYmaO6iAnA/SNOmieXJ8Ywad4xrAd81B8iN7K9+d/pHxGDQ/NknPRyTAUPBP
+lSzeqkcKdBbHKeo3dWGgJfWceTeVGGDt3gxgjVkGALoogxmHlpF+D61tkzrphVK8
+MqIuCAyHB6kJfOfOern/GuRYiiU9N8zNF6zQ/aIMAOfGA/CpXW0t/jaUUiL8syXu
+IfEWpfyb+slFPmkIg5aEGHj3t+tFbHQ2zlGbjqXx/XQMIf2Tqfc1U9eP8FnNfonD
+furVawdSy5UsSSDbl+hqrs2DrpfA4l8LaP+/FQctXxZc4s+cS7GZjpZObahG14ep
+RvT8Dza+Wfv0WfGxlN75Cg6NNCpKBpMaSmwygFM2JlFBxsE8HEkHxE172pw4cKg6
+y9DievnbsAKqU7lceljTYerqFQcQnC0SVVxpH23ailDPHTZjE/85VWX3PLbOejSU
+f+HiL8J4q5JiC7cWUS8FrEvGS8I4P3SrdS39rvgU+SrVrxAuAoK86TH9A9Xf0iU8
+ySLJKzAWbI6ioQm3RnRxh5mp0RHBzDZGLT0ViVXRS8r8BdnMlkAFJ9QdEmHmNvNL
+rkZpxMghheKkRcB7sh/UgWb6bd/SUwO3Me4V2Mj78uE6H3Ces4dfbyNntc4xYQ3P
+sVXaslDS3SXOoyMv9ifuQs+zmA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes256_cfb.der b/samples/rsa/pkcs8v2_rsa_aes256_cfb.der
new file mode 100644
index 0000000..3ccaa66
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes256_cfb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes256_cfb.pem b/samples/rsa/pkcs8v2_rsa_aes256_cfb.pem
new file mode 100644
index 0000000..19cda1a
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes256_cfb.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFETBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQItWMJ9qt32P4CAggA
+MB0GCWCGSAFlAwQBLAQQrOcV8g02pInohv6kLjyZqQSCBMLVaid7VH8IMQ7h4QNR
+jRP4LLjcZcoYvBWmlyMMa7ihajhaLJf2T4q9kaONfYpPDHgehR6zT85LlvwSuRWt
+88p4cajWyJuPxZ6eEr6OCS5WTpssfVHAz8tBA4qnKJVtcNkVFIsFJz759aAxf1/c
+zh/4lHQNdLwZoOoYLRf8zDifQybJUqkFFD32cHezRyjOhI4qWQxgKmGG5gKyv0BG
+zBRjUCsj/0/e0Eo0vmGVeaGQwrIuJMESvfjysRGq1YfMNXBY2gHy3W1Hm6t22DwC
+Jncadc+cnsufYa38ATcyUbWkxa2pqPQZIASqqMGIGav/KHZoNyT/E/P+E2Cs7vhd
+FZUMeTR4/Fi+UKMt+V3KS+kFMnj8SP5L9c8TE0N/gBhtwQicvdNgmojQXD/3a7GM
+wckQ/eWz0VrbKNHQY03u5Ymrvf701CgfXjM0R1PVtbUHvI2A+2/2pDcrwxnZ1mdc
+xhMHSGN6WMoRVsjh1FWFeIA5MFG84AAk/G8x6XHZXEzaqpuB6ySk/rLlK3GLNfAi
+gMb8D42q5jF70crLD1wLBYQMMNtRovQ25rk0nlZG+gkpqie7HESngH6phRldM0KC
+OnlkBZT9Nnfnm8aLM/4vYIzF8qsLZ3UgEdPu/B8Z7hrUeETsHTr2g27E3DeJxmqe
+ysnVLVKsAqY0LF+IpnrO3v6asU0Og68DXq93Mo/U7kfSPeXol3QBmMKs1OSyT1vP
++3BfWN52TBIutLDKZN6QbCd17cJaUjQ6k0C4xoGJJz+BoP9rSMLlbDCatqo0tHBJ
+go1RFfkpooy+ZFVgBxMpEgiD68Gk2N/1zvqtwxMNPPJituY6x97DZwf8zYmEgKey
+t5RWS/cwIO4WwwCdy1riZey8DrgRqxZO5GKExnOkmFhH+k3TvskjYzwX2xrJbLGF
++xasm2AohpSTHd1BSCVo2lhVCDhRqrS36I3NNwI7qEOaWHSjzuS8f90CpV2fsf5l
+VTTzRc7c8296E0k1thpn4vq4bNH+4RmwHiPE2R40r1zPhaPH4uwmHRb6R1gbptM7
+aA3rTZwvRfmMtrBZ9uFgwJARn/k3tme9jjUOPg0BmVvSS02uM4B3mF1X8ON492j3
+Ibg1fwtZX7uER+JaHx+2ydteRdveL5bfx6xv62l/JifUIhlhkxmw44/SOX22rl45
+/v5PxTwQquVJq0OIHQLiegvb+SGROIulEsGSs9xpVRZsJT4MypkYDbuKXIcBnKvh
+0zefCiUM2r/UFLgDryRrQShaBPp4I4zc8iWw7OBOcZlR8spNd4pXce04Vs897aSw
+4dky+wizj++eOvPVyJhapFEqUbJDSbhM2dyffB4BI05GTpPuIWMgLeP84MjX8ba4
+OCI5IiFoyRyCt1weOxxXPHNiirUvNcXe7BCKbHcfkj5l3NI/5ncFVR8RoVReqgfF
+ewro+RJrhiewFRvC8qdA4r+RiNv1ZDn3btSwvH2oVvRVk1zzrJod4Y5rI0GcRldn
+NGvhzs+PULdS/V0COsWjyIACRR8dbPKd1GEM/veFVFb9zgs3yhSjLrQKig5ePFVn
+7u0Uz8URs0GLx0sRBtsS4f6SI2n531RULzOt37gfIYTf0aiEsJ2boHPajRoE6XKE
+px6YSso=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes256_ecb.der b/samples/rsa/pkcs8v2_rsa_aes256_ecb.der
new file mode 100644
index 0000000..ea4553a
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes256_ecb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes256_ecb.pem b/samples/rsa/pkcs8v2_rsa_aes256_ecb.pem
new file mode 100644
index 0000000..0e2281f
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes256_ecb.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFHzBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQI8u+Z7SFPcE4CAggA
+MB0GCWCGSAFlAwQBKQQQAAAAAAAAAAAAAAAAAAAAAASCBNAw9xUq40IIV2tSyK+K
+gJp13md8srHqWafHfw1BAJv8aa7Gy3FIq7r5WFjxfaQwrdUSLbesT75o/tdahn13
+DDha0QORRk89Sm0CN1iId4DCicZliys5G0kieWJjemA7xBrgr3Zv2yakG6JUmM3K
+Kjt9bpp2yC0uC3YfkJ1uWD3dWUS8uesXeSJoXmgtR/GJSV30irVarR9lDERcaAaL
+YaL2qEtG3OQhTyKUj6nMyRxGU3RhPtLQ2OhHyLhGhvvq5FT0JIBT4uuSNRL7pMj7
+G5uZCCg84q21oN5xPvqeB6RUkxHAqOI++UiOKqq3nm268medqBmph6wmKmMvKFgH
+jGgihkPlwtfTWba1/P5Pk0HkVeAhKXUCRaU8uCSfXbc3o4PFez0Edh0dA6bSpMQ6
+okcBg4BfkhDsbzkZX6LpnBdm7ItfJYgeUL9JI8qAC1bVVnPrIVTODFxVQj1B3fTy
+QSDrB4WYkPAdUJXZOEYRcJNCzKM19T98nCpIz0Rrmx4IpSC7X1nCHyL/VMLuZNrA
+Q/rgcipfjbX3up8OsDm2WR9vkqeRHuCWNBdsdIvIB50Om8tFVx9q2ZqXLzpYEgBv
+8mwXGlunGi4nkQIo0GkMkPeVCXN/rtseQvAtcPRnXA8mr22L1icmIC9EeDP6sJK3
+p9k1ptex9WhvslHMJhJQe8wz5Vf9vVIoPH7qaaTVOf2CnQardQf/wrtRilPqDrii
+d7+8iA2loYxnuzbRHVrFg+utls2DWVT6Ox9fdUVHNsCFxvGkeD7vZ6wOTwZQSPFt
+oNLDjp0sjmtwy4cjYRhZrmMutAxC9/LaqzpbUe1MT+4k3jl4UbZ6PyijS1FFYvgb
+oREAyn1MXY+Whir2ldRn4JF0+4t31WvwfAnDKp461i64PEmvCm1wy43MRldqI7YG
+vZs5X0H4wqFkcIU5/CtTSNfHJ8mf+Kvr957ni6nQ50tRhlxZs7wpBq8dDPWynZEv
+a6+ftAiHWK7xajEp98hKsf7/oNuiz9frDHQYYNa2wKQa5F2rQ7nJqVy+46Qo8IRp
+e6H76WqeiXMfBfsuLs9dm2elGRZlAWiKlmYYpDxxUoEknDYcuKGCKFaoQ4MTna8u
+50HR4aegbaAoDX1CYQR1s8jbAOrCtf0kwCrz9pGTVLRo4CRSnYAmS4IZxUPpYuQk
+V+5433SptoRK05kB2eUkkULnS4614v2lqaVmPceCdSAfkMdc6YGJvyiohHZf6eAI
+lXuYVSRdCuo1B8+Wo4uxL2JTovjLg43pxxJnInwE3IEbGU9lGNn0xm45UHHuXoFh
+LN9htP/30O/Ls8chi5RhGGDKc/n/9nx1G6LkOpX3adXgEwib1KKZkdHrOGtl85Jh
+HxEDcCnOLZQV+WnRu4zsoFEs78E0lJDkaXoh8l3tV41uAZCwXZYnjwWCrgqdGk+o
+4QKeXaJGuaofopeB4RdJ9yEVz0X89MXsLxjeWgsFZhP5ZrhJpPw6D7PC2lxaLRHi
+RRgqZRPv9iGnooBibuSSVE7lxDpQwYQvu3Rh80plmd6FW733SWNWk8o2OJdDKOJi
+Uerpx2JtqJfYDfwQJS4TCvaLk655qfh9xzw81MO0uLKhQGA920/UPpgR+eD1Khop
+qUEOHQYtCQXw2DzL+/o99XsHeA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_aes256_ofb.der b/samples/rsa/pkcs8v2_rsa_aes256_ofb.der
new file mode 100644
index 0000000..c08d5b7
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_aes256_ofb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_aes256_ofb.pem b/samples/rsa/pkcs8v2_rsa_aes256_ofb.pem
new file mode 100644
index 0000000..ad67413
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_aes256_ofb.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFETBJBgkqhkiG9w0BBQ0wPDAbBgkqhkiG9w0BBQwwDgQIk9vmCD/4P6YCAggA
+MB0GCWCGSAFlAwQBKwQQDFaVAHk33vRfvl1jtNDfIASCBMJIyQ9pJV2GgNzenpFl
+6g+yCbi8b5siIo1qAKHX1sV0nkOVCPwgXdEfXvZISYitOx0AtnjTdXqRHG7dhQhV
+O1GRknfn/frhW2RQ6Q4X1zJ4a1U4oqVesrFHroWHdVh6BHbASCRZPnVEi2j3gC/f
+Aad5QtJx/HRSE2BH7fK5lxb4+xVQzhCpHlPcSE4VKL31V8qsrFav2pPPHroNZu3e
+qVVZPDgcd11rHBilCJK+F1iCuzc/JWU8qrleTXdkJQkmBOvYBkswbUnAV+sk/Lnr
+u0uBtgmdRfFauaTOgtMel8GjliMj73ZJbAX3eZE24sF67q8irdjZZ7vKLJWkmM/c
+dIu8rQ23rl7OvS8jASSojxl59wXdF4QmfkC87NGssARyY+Ii0xf7q9uQNJxPFsBg
+gtpC8xNnbB2A64Xs3KMYEJIt5w/6UeYccoffhchlc5GDqHldd0NGVw6cUMlzTo2i
+RSvllRvWXBQ4ffu+ApBVoWlhcHVUm+CzdiLlLeSh5IPO2NRpQ/pLKLfHTQAli2Mk
+eJuff+mRClcZTTMP8/zbCH+wugb16Q2DEVcwn3rXF7tcV3NaO+EBfcoQgmyR193S
+MAz9MMaWBCipGNC0ElTayESUgDXF87L43VzL6XM26MJrhVrTBkbOKhGcXjrvrIzu
+BkohTfPOnIgFR605Mbld03a/vtruP//3A4K9e7oB6xNs0jkV5LzoqP083mB2JTAg
+zhy7Qck6LinI9ewUNd/KrrU4hrAEpzRJ6O1fyyIRppDnL3ID5BdHSdcwbyLlUDaj
+dhKXCkLzWxnbpKHnsiH0DTcoabC7jx5s02eOZ56L5cEleGumhYDhCD70AUo6f9Vq
+mfv5TWIJGwQLO/YGtxQiDyfRq3wk25IBM2UID8aS1+rifukaaAficP8KmrQWKPyP
+ecC+Bf5035gYakUPhNgh0FNjFp8MQVTtYrWz92VQuPHnY2aBoSVNIybZa3/vf0cy
+V9jgsT50R6i0lN3mHu7vtYOZ6JjaWX7rcASLf8JFXJad0g9IQ2RTjYn+TG+cdFix
+i+19O87Vq8AUCajpCZ6nPr7NlyS/QyvdK3YEL3KbLNBx6AjMF2Z5qCLfsTXogKtl
+73JMmD5DzIsg6cmnkojKo3pruVOwVyZ663Ao3h/FZ7S0nQ2m4rM/4OZoNpPpmtJi
++8stPTy1Je0CNhQf64/jwA7ghVp2lSC67EkTSJ4Ds7B04aKnIoP44DqpY4gHxdJ/
+OFXLiecjZGAKOQlDJfHmcFiN01g3FRiB+DsdAACdWnaTqAlBwpJdw2op0IwCF9Yu
+65Y6lVCQZbp/EYwNNv0xPFInOknO84qmNI6ilNgVaBemfG4H5+SkruHrT9t9GvOu
+rqyoDMN03/LGaDehbLJrDvw4OK5blj+36yQA5QIY9hnWOw3jZpVhTw8w4+EJqvQL
+tKUkchaNyJT/6K7MxqH3yG1hiXviloLF5p/3hb3rrt+yYRbNrotl3GtP2AL3AFeN
+/q1M1ZGtgemtzrT+bX5JJDUr+6VdMgMoLYR2iPyo4OM8V5Cx3PdFpMCJQp1rf5DM
+1GhM8xspnLbukm+ING/4+RdQWZNrpbQB8p9G2+it4IHrlO5aSXmQGh/bTQ3Zxh6/
+u00h5/0=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_blowfish_cbc.der b/samples/rsa/pkcs8v2_rsa_blowfish_cbc.der
new file mode 100644
index 0000000..9d3222e
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_blowfish_cbc.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_blowfish_cbc.pem b/samples/rsa/pkcs8v2_rsa_blowfish_cbc.pem
new file mode 100644
index 0000000..f22fd48
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_blowfish_cbc.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDzBBBgkqhkiG9w0BBQ0wNDAbBgkqhkiG9w0BBQwwDgQI+SHyL0TmEd4CAggA
+MBUGCSsGAQQBl1UBAgQIe5OfjWHHpAMEggTIr/Ma8RAEsq65a1K/AooVkDgwtqRD
+Q6A5Wx5LOvXRvQ4RLd11ham+GCWxHKWHeMTnLLrW2gQyDdEvMPtM0TRoGmm31npu
+soEDFLIruE5XUmpzsKZkqztVhNl0pamzsqD6g7vSMlckFORsRInuWq3THVIDoHVi
+m54JE5RCa/tZMVjmvvYOt1KHJhAqUeyb+CQYZsO6c+mjNBZrvdNFDz4bgutVKreL
+FQMYJWr4sClAqnvHCvra2SV/mwIBZ1lYj920Qq885+HoSSQfgLOwar5XYCyEb7z1
+Q+NYMjaDqhEIWvlXsXu7B2YIYoSC6vse4bfXvi93fJtb1CXVjWnDKC8xJs9pqVCx
+t1P9JsztRHZ5g1daHwu6WQwD/7YRubi0y9pYjHB6H4M7KSWX3CEz/hDccUWoZHKH
+D/R6cNe12RqVqRr0a5tteUCvFwbXCcwKbTG8n5zd3MS+2FF29S8jvhqNXJOPuykS
+Sxq1wi73puQWCXAmw5aYy8RBlv9y3TlcaTDO37AkDdhJkWQLWbNy5MzLmh7dhNCQ
+R2Qy4wz9Mw/1GZYhOYM0kSovMSHcN1jIvw94YPAfflmL+k6VtI2C1iyD4BG8li1h
+ChCqL02fiLYjBsZquOdE5Fkg6tT6IucB0x35Qfjm8lTwcbVnjVRHnaQyPIMZeN9N
+UdZqzyb7nf0zI3rbrCHFMPsGX5741VGt2Mz9t/rQEXjezgkEuxn54Z/Q39Rm0vmX
+LfcKznYCVdMkomC0tIaYHBjVQWZerBRIHPGUhozdKwwASYco+FuJNNc9SZZnJ5AU
+ux2yD3NTec6c/fgseJXi3UT/qDDmUQxX9hjwnUw8CPHUjXWGTmJ/ihfQVGo1ypwg
+oRZWtF0AnxB7ZfdtnW3yq5/xCFzsIrKyFy4s/kdsylC8eGw4snGA19PN23eEyTZD
+bSuW5KLjgScbR+ro+e3Y1F3OTI6+VF2oMLY31XVyt8S1N2Zz1lpoN0JfKaWTrTTJ
+9Ic0oe2qtgqC42g11WHQizYAe83cZYNZgzU9mRa1FIqQD4kMQh+Vv9Cca6FpdPUv
+D4GS7/fA5Ez5jFV7VghOCFfK2+1Q95b+2RnQEpmHk60+U7tZG4dACXLL7i1hbJH6
+YuokBuw0Wjm5dicOSG2DptwzyqFfy7C2DYgB3Gi34fSNFxKis7CeKQLNMqppmBof
+q379AD8hY9Bc8gUWAwMONs9AreDiRCGyR+IokQPTgKRuVzR7ISoxWkKvfW5XIdNf
+Pd5kGLhX0HfGhikQCVP2XQMkOqsJw4ShV+FAcMfzaq54/PzXoemkRCOMsCzsDUde
+C6XGF1wviq52P+DnAr1tDmYGOP+jP+O0shzyXF/res1CZ0PjiLIyUb1JM8m5eMRH
+dEwzX/btO/A/OwNwy5FzS7VdFwaGUjFBXK3F/xyu8jl6ov02/ooddkpqNm5Cxko2
+ZlJG4LXdDbO1y3rbdwSgukYS2SeUmGqLpONlGi6u8kGRrgetcCAzkyT+XQkV3ZWg
+TFfGxr3q3NV0C35hIKBxLXr/+ZZHDP4Yx6/Ok6xYnUyJ7RoM6QE7Ppyo0hFPv0Q3
+VknhyfXk/85k81dxWLWV3DiXZbW/9gGa8TGRuZxliqTr1YjTRGiUwn+fCVx7YLyw
+PiNp
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_des1_cbc.der b/samples/rsa/pkcs8v2_rsa_des1_cbc.der
new file mode 100644
index 0000000..497e226
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_des1_cbc.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_des1_cbc.pem b/samples/rsa/pkcs8v2_rsa_des1_cbc.pem
new file mode 100644
index 0000000..e8c430c
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_des1_cbc.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFCzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIGBflqeZFz8sCAggA
+MBEGBSsOAwIHBAgLbTq8mvQ7QASCBMhUPEBJHO0Uvu4bW2bfb0NIvczMuPbFQDQC
+GnmzPGsa6vLcE+z61rBmPLOT45ZWcbTf867wh0e0KKFERkDh70lgenwYACRcefoE
+ktuvdjRBpMiSAqr+ucD3ZwyIVp1+I5xUJqLhqxV1Wd5pkwFaZsqxUCRd6DQmZvH4
+kVw2ulaE1HfT0XTPGO/ewBQ72wZ/XiegYsP7yp4dNIfmwMk03A+V0K8PjQTY6Sui
+IHeoe9YT0b2J3ocsf38pHAiTmsgnl0ZtedcjlOYJ8yVxXu6h8FO+Xu0MXYGN387J
+m4OUqLFudtWt8oVTVQuevNO+EzP061gsZnTEUJNvQNwLajdQnmER5ht28snby3tM
+f4pzwu6asM5RHDD2FBSp5sBD5G/ev0hM6R5MkTBAEcz0CB/TYSMKq1IfWCqHkY1z
+bvd7Bm19vwoyszXBGEBmhaVC34kYXo3IoTw3ezvXPgSaNk6IUvFavZRvAuJLleWs
+cpN13G7pbi6WeCYQzml3L2hLP62DP+VLwkYyxUW3CvwLhVP1h2w12tb+cKC+4uih
+4Of7cjt0R99vNvyTuPJ4HDjcn22KT+NJwPDNviLcBrNs1XxCXFa211nZWDGDC2cf
+6lCd1JVQczewMfQuFX8lUMuZOfLoAN+wq+ZWLIEtIMC+4bciZWYxzKFijOWKqnd8
+JhnOTKZ3Ua1txrAYE4Z0jLYI4xXImnGoW42h882aEiWSzsGARD065zXiQr//b5ot
+TtFXfJ3IiJMMTyss93mirPPzcua8uoGvwvjw3GoxLbNIttX0hmR1NBGyM3MUnghy
+7lrQssx2FcENuI/zAq/6l3ZT2jGtixch+Eu8mrCBTthWRBap8KIcO428c38C/IJ3
+bdWmWJw0r401gqbZS2ZoSi0ia+RFM/DByrQl1Cww8Z81v6S4tedxMbmSiI5/vpXt
+TcM4xQctZr/shYU9CDpxLUznmaRXbnFb77S7ykrJdPgnk+Oq5GYIhrcrxXXwF7+S
+wg+72F5MVkFhqhzsZ8VGbgpgSw+BFDJd9wHiLM87ywQW4eHYqJfQtO1lPfzAkXfz
+oPDyGX/Q6Nisy7dVErZ4dTXlUKxXEXAfvZABA08/L+3w+p3HEWm1HJFpZitEKHas
+dheCNwnwmmyzItSjXBE2kBg9ZtH6Zx9mQpU2ra75dl+X2SvV8096lh7Xt0uHgjgq
+vtYl2Bc9yBnxcwf6ppI8+VzBTxT/Q3BBBTL5e8RuYlSB+9BTlsp/bgP2prMFL+Lr
+DJUisjPHJn3gPeG09lcWnAzTdw07/JN83WV3HHRjJ/ot8TdoVix/qlrtK7IPkTH3
+hyLhPA4V49aOz7f42Jg3Xb0/C3WUEaP3aJ6UEoCVd0856RN9CTOlG95SPH+IoDLP
+33oFlrRMlqQ0K8Y/j40h/3VbBxaHeWCNiZr3sN5ybxNkT8TaXOr2kWfePsYdGf7c
+Pbz3IEwUeOD3z/GzDdiYvOfEo4quECEEQj9dWedOVVxD2wtc5jbaaB+HEaxlPNg5
+5Sqd3F7IPtpoBGl9OOgigBJIP6JQWctjYJYjLGnVn4GpXt8pWclmkQ+SsCSCeYnX
+Hax2rVBqD3yMRpVw225Dzxb84R1hleqx/N6VJpjmk2agYCTwXKsMyd2tMROOJxo=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_des1_cfb.der b/samples/rsa/pkcs8v2_rsa_des1_cfb.der
new file mode 100644
index 0000000..3c9c35f
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_des1_cfb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_des1_cfb.pem b/samples/rsa/pkcs8v2_rsa_des1_cfb.pem
new file mode 100644
index 0000000..5c96b17
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_des1_cfb.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFBTA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIyrtLg/hL/L8CAggA
+MBEGBSsOAwIJBAitq97jfB2j+wSCBMLwmaT2ht4i5Kj6RAKRBOJJsF8sRCeDO/mO
+Q07e8OwmjgyAl9a2ZrBM6WLsxi9jm85+OOf4yhyqDa1nCcXKoGt1mb/SiAkZdYd9
+7tQrxF94+AZUJ0g/z8pnBKpx/1/99P0du8wxBDBoQhqfY/a/jXmmZsfvO1TeJgEb
+fnwiTHBk+8iUQcc257OaxUyYDbKBbzckAsleiep8Lco+8Mpl7MaPAc3phQDwHfVL
+9tNmcS97m6g+n5KkV7UR6f2ukxRAczmh6x7wjf2rqEI5KwSm2IPkCxPDGQKmeCNg
+F7ezrokU0lIx+DJQtxW02KCWgHLI4I55TdzhSyAwCsCFfl9zDalW64oqFKgJYG2b
+ZACYYGRIENsh/+qfZ5nJt+xhynQxX7eZZ8bcwXRDdPtPpCMmDq2K/cPVkSUcFPjP
+41a6yZk/dd+NQZ0pC8nPTbpCFmbugLS7Z06GmD+aRdDMxTLP9QY1BMu51+vlxsTs
+WhDkrH5BJb9z89FzcXuzR/qp4zQ6oEn49P/IhztUV2V75GvzCiw9ip+5+Sh8v5Q2
+GGyFgFx6qSE6h7Z6iu3BGeGsoFhbLLwgcM9YXdP3MuNdSJsZbzz/iRIHeHif2duQ
+vgEJpielRb80Anq18SsORqamYQCWCLLTyWgSluJfYxt6eGCuPGEJnK8njwjYmOU/
+hukosJDYE25jrSHNC7fySIFJIzxbu7ofXnOB8PaguS/d7CbLbhyKHLNWnsKDrFtV
+4sGbgcLp4CNDBhGruPUihtf3yNwZ/Kqknsy1wvJxKwateXtlqQpcCGoUTn034GAP
+BIA8GJOMiHUMjaSUrq1DxdUki8HAJRfM+CqERaVYNIDsH2AL2chVXkPWHlC/x8E+
+qKMHczBYjDhURrjWj1iGHN8aMw4nEKqT2Qs7J9Mbgz9Ibdycc4uXeSgOuOmOdgZt
+K135ThyHCUTUCjYxwiz+3+cG6bju1A/7dbS3o2W2bg5ESUlIXXf+shOCTHWVnW2N
+JGGYMA8u9Rib9GCchX4D+LqoocZFxO0g563/ADAU+Hg5ZS25lQmrLKuBKUNiyrf6
+W/WzyXH+8pNlWqKCOb692G1NRrBKpZwRv0NDo46dgYWwmSErahMC3dnmm+H19auu
+L9B6gsE+hQjv5NCpUrqNT4O9yVlocOLzL3jINGc1EaB/zCsb19Ksk9XQB0O0EoUS
+T4VFLoeGCxJ9/DrDqtuWiYwfJinJk/kED9zavFe5ETkmjglaw+WgUec6QORQY36/
+cGz5blwsiqf2TSksgLREdGBFQ2ATJh5cKmCp6yp/EEyiuhNyY0LXbhaG0UP0FJY+
+LJ2ihIzcnusp+QfclKOKEOajrI1BjAyFJkMQS0jcPgpQ3SAI8fTqNxpiQ5SuoceF
+FV7MCNnVtlc8j2rSLj0tXXes2Y0N5YfnQkkPuZSJpk+6Unv2RwlXUpda3YpIMkxw
+9rDF7j67tIlnogd4cDma7JbEdgPjvqDNKm1VEXgNhRZ167VyDGP8nTly8O+UGCqd
+tsAail/REaO3m2yNEdE0+7GPnW2v/znHcvqVWyq0R4NgyzugKb4Dxtzh2SWPosTt
+CbcdJKNKWrsNOX1pKp8+NuYS0JScGrUQQaAZmFJ7aAl+3mbYvZ5AGt8=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_des1_ecb.der b/samples/rsa/pkcs8v2_rsa_des1_ecb.der
new file mode 100644
index 0000000..112a8e3
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_des1_ecb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_des1_ecb.pem b/samples/rsa/pkcs8v2_rsa_des1_ecb.pem
new file mode 100644
index 0000000..acb9765
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_des1_ecb.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFCzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIP260cva5DI4CAggA
+MBEGBSsOAwIGBAgAAAAAAAAAAASCBMhzhJsbVbG5HLxDzjiJunh1991nhCQOicEZ
+BHDgTKSGVu9upjcDVnD/wSdG8reMAM9NU/EoHH5dO5nzS9fHq5dqfIAzsXic46UK
+Puh65gxMFpGTfphkdoTjZRQ5mlqzrxYZsdaI0iIxgzshzTVDP5wobEoap/yskoip
+0845BDvdH3vQ8WeyGBIkCIimlDNBgCGwzsruQOREhMOpxiP3KC9qKi+pkcNgKcsL
+t/oU8B7i0pPphi/bTWJeF4TghS7yozwd910/KufBgpAm0BR17NIrldazXscrzykw
+epw3HEejdTI7QZHZ7NARz0mXW2r5+XAhNSLLYwYnn1HimrZYNAb6rTDuYAv5i3Wi
+itmMdNbzeGxSTTvaPPwVQMOSMtyJu0phDt0n4op1C/eK1m0AUfqX86HmLiB1GYbS
+PbZHZ5kj3tfcenTNzCnl7zAwc/BeRNe4ifTPc/glYlUJmvq3vPl9H02uuXxJVNDa
+Yq+B1d5DH8f/MbUXsbpzWDGSWVRauMnGp4ROGcYa7fwl10zgt9LPV9CX9OasO+IF
+/jQN9vjmYNIrjzPcHpeVmJzSw6vbaiJIViyfhXq58JVpJ+tqhkKN/QOxpmDgmDJU
+pPfg/eXpI5miDoHA0EoyTtIsN22fI5ux1WSO0+PezechJ+TFs1aLwfnniWFYhAJ9
+gxci9SFlnBUqUC1nRrmSLzr7R2KXWNNXi2ZSbuk4C8tVbBE5ibyFcpMwqIDBcBfD
+WMw//qS7R27EUcKdX/jHW6ZdIQGJhlXRF3/KovIRd6g8wqjCZ7hPZkJs7SoA+DbX
+lz3KxMTZi1SoD/YQxEqMWEuSffLsRFgNSW6+DyTxi0hBAdwRxJE/13ULZbkr+fd2
+d77i63g3Go4RpydTkIwTnfvg337bTFKASqYpV498ZE9gaGe1epk0TplAE/C0qcZn
+m3NkUIo8CPl4zid+Tn+2gqrRo4Byjl9f5+bqg7CdPB/dRu6bAksvjAgA1c+LM3Y2
+cOBhwe8GzQdNv9xOKufHq4JwwHrkn+tgUZRPgf4qof26jtRQKiPMRPGz7UM6ZOIk
+/b0BZUtBnYTowFOfOCqspkOQoKN3UCvBFjQNhyVqYIGsMxbBC5wABzHJY66pxX2u
+Ortb6MvTHEij3kyrTfrDaUFdoGxEiBT1kP+kbG1A3+p31JMOs3PAaosrEBTqWfdN
+VKI9shrmNIOJz7uxU8eajVi80DDRwovMp37kOCri8Ul0/yfqF1jWXUaDv5MQI5Ic
+PlUDd8LaxGtc8uJNXC+g7P4fRhU97EjMaaFRIBWIRlqbv1ct2+eFApY3RYm6BrIh
+u4cjV7x/9d6rAxBiJdtSq9UNSV6t2OIt86rwKS398HudbBbH4zIhGIbbzjn9GzSS
+6qEbyPYzO55Feo6KZRsQBvitgmQ7wpNotI7s7uKV5yHMdVCnIpMTHB1u1xIA2uiJ
+jbg8+F0EIggQoiXTTLGjj8M5ZXZ3CnqT34U7cMDeg257F40Tl9CZ/eQXyXmqvV4L
+GdlxKIOyYKcsMeJ0FlcxFJ2pTJRFtLvetPNaN5JHaOTRC8+zoqL964ubxikiH+LZ
+EfpWDUGkouqCGoc/6fNjtabJjwmBK2MG3fOhTpNH/4n2AUUulm4SPtBkp4uZj+8=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_des1_ofb.der b/samples/rsa/pkcs8v2_rsa_des1_ofb.der
new file mode 100644
index 0000000..8cb2506
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_des1_ofb.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_des1_ofb.pem b/samples/rsa/pkcs8v2_rsa_des1_ofb.pem
new file mode 100644
index 0000000..6a91ef1
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_des1_ofb.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFBTA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIbdCq00ZNZVcCAggA
+MBEGBSsOAwIIBAhCvoMFuBlNXwSCBMIvzvagl88RWujl4nG2RsaXP1eyr28SnH0j
+VEoKRp3XUKxfchwBmJFmgOZlDX8RRSb0Sr13RPGXij3RJTvyretkTkhmxGuISEtp
+XdTE0AMccTlJhdchhN8wCR2wPpIkf1zKHEwxwYzcw7/kd30MhbZ9FF7kZv9u85GM
+nBgyg9qApy7N9OcdeE0b3kltwnFBv4zlD/6YWZJSE4HdnLsyXqxZDNH6jGEXbJOP
+hQxvCB7v8LWT+97DW0wZCkq+IAmNUsdOWbz1PXUNbhDLimqfKv40jKn2vcr9PIAe
+3hVIAfYAUNBaR+AWl29DxlN5IwuEZI5Wzy5KImGY3UeIrncx2QPyE9C0oT5ec+tm
+XeHbM5qfDXZvIs7pv4GESGQxSdey8fh83tGiLg6jMPSGT4X9qh2AEM58dAGDudtG
+DCznUP90indqcSdFcij+UEafV46g6JfYPUXGWN/loaALD5aCednCddJPwUflw9lc
+CYFCFBWxkr/P+0MVcYuNKYIe7wiKulzG48ltQGvXXU7Q7Cqb1C7rIOHTP1ie45ll
+XJUjcAq049rfgwDtiICQYLvhfQri5VDfq3mEpRk3+nJV0OsS+NIWPVEzuwq4LGNi
+sn45h7rGlcix1NpNL273ZYgL6eO25XBz1UJ3Y04lV1KP1BEXq+vzKP6SuuJcU9rj
+Ny6T4krH5UT5T9et52TaHqy0P7wTYma0UeIbasdbQI/pgT3P53VI/pyHfumK1iTO
+GX8BLPWvMx6Ldfe4fA7eAogIWub0sk/eD5lKi55ZNLbh2WO7tNztscWxhbwET0HI
++sqoMHZDxMUOSZHkS7Wo2UpDx4Qxt3atSq1XPIi8ZGV5+MsIfR0P38V+1gzRA3GG
+8BSdbDaeMKBjIUdXvs3RwfkrCxIhbf0yZTqtd+JNoIDjQdCR6x5lxTc6V25E3qBN
+eAd5J+XsDkwfjZ9ASVvUVU8J/Y3ogd3JIjgwWFmQg9GT7lkb+JM531rCOiR9FdOj
+bMKYdoYN8sbPQjHJL4Dv1A21o9uuojZifx4sQH1CCw/NLWeqjwk6tFu7zBhK/1TQ
+/5ZLgMH2ZGk7B3LIoeDeh2pi746NJRE4rpmqLKrDdjHCfMEhdfa33Ql6ARZgq41x
+NEORrnB5eHpAJF94PErH/gwyk4TdTARAC9LcYV45I1qqqcfp5CZ7EzMVe2qwSJFP
+qfQsmBsKoFTx9ugwArl/jqeUl6bhZx1X/t5maHZGQPTjXr80OMsZvXLk7cQGg4sg
+6YmNeTEIpFsF/rLro3ipXjqThT08F+PgHcO60GtzomtkUI3nZfIosfrvGZ8iz9t4
+850/o/hmo0Vlk2m2+2fW7VSHmJTocus3R2B9OqHZHOpQpHMaUvL3zMdxaaWmD0RC
+L7AppW0y2fx3d2lHwC+rUpusJVl1nId/mrUI1YytQQs/Fy6kVx2WlQdb6BnGev/1
+IURmYDkwlie1oeLipL6e32DOQkpG9GWWW866MMuZpKsaL0q1v0N7SFIxm8Qv6lYv
+YQ8sKh83Kzoe0VN0g4mY5fAtmxJasFnT4f/dn1Aj2hsiQH0UiSJwEpAXSX/YlYSH
+R1zx2oD+uT+EYVc+OmBBw01bf2wmKx+e3zLjR/Q7zxckwOY/fgB3GQU=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.der b/samples/rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.der
new file mode 100644
index 0000000..5d3f1db
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.pem b/samples/rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.pem
new file mode 100644
index 0000000..05553fd
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_des2_ecb_SEEMS_WRONG.pem
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFCzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQInUCIat7eaGcCAggA
+MBEGBSsOAwIRBAgAAAAAAAAAAASCBMiKwGB+zBHFfHfmqr6jxf8CWeEuvoR3G6bs
+6BC5Rr+2yFtkt4/duBBgldL0oEBohVSd0NeoqCGAbVKjmaY7XyDeejuMsGBJ9fIc
+ki/fWc6H/eqOb1C8kbbb+mVivdrx6tpFxQ+8tKNW+A3rOWwjIrNPTWmsnU2/jRmq
+q/CwXeEZFAUBf1/pbxSe3FmLvIbukHJGIAuoG1CZoa1l1jr9Hukt+M3grDozOFlV
+QjRbvwLyT5k33R9S9PbPogeQiLuMFVXfvmt3u7tSsEnwlS7JZqXKGvNq7WEWH3FP
+BdyI1ZC/x1YqUsC9+ia9LObwseqYkWoETCWfPAwHyzYQ8VNBEWTvZuO7kIIoUPkM
+m0+BBljpc5IdLE/KIOhCI5IBn0tR8Qjvlmpr3oiEd6CsbNXCcW36wMnHKtnt4t2C
+yyEngoSuS1VZTFWr9ZhOOoiKzdQVTw7/MV1zsd4k9uX6B1I6wySlJ11LOi/Rnnqu
+ccqJTu5+IJAVf5AHCczbtUDqvzwckoTt5rDHb74QR8hcC0UW4cXXSgaGqeoJ9vie
+wH/8Z6pnZmJv1zAAHEqiUPJOOCYRE689kCTUmwI6x9nXeqk0oFFIP0AcVoPjagJc
+mhnoECLM++B5b9aLG5pUtotA5ig+FcsR4bdiNv0m/imP7Ip15WWQc/PT44VXAQQq
+os/Qm4IOEbe0N/DFgldoMXb4gEodumgsUg/3SiXIOW4CAZOcVT1ySfzUhGCB32l5
+Nsi7Gqet/rHeYeHAXGjS88QE0nKU/RsAi4YHHmvrTyirA5T5yEtL9ELPZwm7z/9j
+5F/odiIPh6E/d4vHBNQLFK56rKi9MEaNxvCaR+h8ThH+n44CaFW6A4nERR5ehsaY
+RAk4dtJGTR+b0T/DpbhxufqIc4f5hup9do+VIZwGLOqOGzACG23N2Ts7biiwH14E
+ZHGv5/bCw/onis8VIhyH0AUeYGswcvhs7XeBkWLNAfov4Uge0VT4age8jnM27Pv3
+9WRrbVi5YhYl9blNA1NAi73ABe9N1x29hWLRBMMgrqL8+KVxsdraQipBqshIO+SU
+i2rsRF9/vx8pm79qfInIGKxxl60ZSqebmNsTnCElFUUS/dyOwCZ3yGZ76Fsb8eXI
+6N+YCwXaMcJ5lYewTIdIrBZ2i6zF+gwKEESdIU8HdgsaUbu4aAIwGC2ChhO8gcpd
+xoKDZ9HXR1+5IH8/c0APIfKPbJkafzcpFpAEsYHGEbSYrThuqqxrzMSababkQSU3
+GIt1aYORWmd9bUHStqgs8py8kf8uPpyaudE9Iyzj77cCWoEmOW0GZURaKNBASV7U
+6HxNO1n2w/Bpe9zk/+eIpIWDYo7dgSC9fW2nZ/o/ULsyLhEUpmPTa8UAcIgn2rTP
+CSVnxBq06pkM4JgX25dmgJbOGkJ5Tian+X4D5BBTCDtrcJL5saXcWKnB15ScGhKM
+8++3TfRMkl54Xlc3ni9JZ3gXwg4hs2lsdj0FKvhUzvnLUhnbuBpR803RlgcyZsHd
+o27xL0Xyi7ZFbJlHEwZdrrqdBTe+TLcswpghjl6hsdE3ol65HiaCYkdkVzMW24RX
+dvaDFvVjCny6gQoJk7oXxfBVpRMAgIic4w3jBPP1mokDbXKkDqGcrRqi9VQantg=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_des3.der b/samples/rsa/pkcs8v2_rsa_des3.der
new file mode 100644
index 0000000..7736282
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_des3.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_des3.pem b/samples/rsa/pkcs8v2_rsa_des3.pem
new file mode 100644
index 0000000..97921d7
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_des3.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIqpcsbmHTx+gCAggA
+MBQGCCqGSIb3DQMHBAiEYtVFOafp9ASCBMhnk03sYcXPAU1eYthAr8vueotiNFFr
+xpbIbhB2cjC/bXd39GxyH/8X36KjVMuBJxFknY630SOBsdTn/H7lN/G8c+fEYTcq
+porajF/pxr7asdFl94xjnx/DGaQmUJooqqUp8p80On1Otj7xEZtTivlEISY5Pr6y
+6ou+fKIFKK5QzDzD9C+vLzYJMqhk4YamjxvDOwzYUoDFl+enMHXcuZYpA1yEvqze
+5lFk+9AxdTbHgOsPECqS3bkq64VGanrfFtqywqLLLhsakcnByjddcHdsFFvhu/dH
+raFdV3vsHppedqxTHbfFpvVl2+9XTpeBzwvb9XcJ2WUi4JUMtcR1gZwOo8S6q8LL
+UWzTbGjsZVG3ew4FZ5avAjUCGgiUR47LFleSJ34eWrllUptHzfVTpV5f787gfN1g
+BRhAJ1YJTWqcalIhd9YEKFxI3sjfWAOLdUW4at4z4yuRZh/uUck4V3ken8/M4JCG
+/Vy7B9Juf9uHRKFWtl3hYDY32UJoQt0cH7V76y/rjpbhvhVtKaAbcK4ccZ+4JuDb
+9qbs81Joe8jW4OZtYL/L+g4WboW/FSGlJXxJIP674lnglXXB5C8HT/I/7CzrEEgv
+wcKKAwZ25+aR7pCYqWdDLUaENQQ/Z1mARGDw9JGszonXJMdMWnQN89DXsmkp6qe/
+YkmZ3Sm4rrvz9LKc7mW+v+d+WnPTeJ4FBHmnUhGkuZroDl6SrCPjm3qFqj3zvyyV
+8Lk8xNMm6AEN8IOs7qeUAb811bdpfUzLebZkuNXDMl8KCoyt+nNF8UN7vpCXU3/c
+PEJahN+XxmRftOR0KKBIKCMKgnR90JenNmSyW2BJbT9D++7ujYoDlL0gTfbYa34a
+P4H3ChnU0s5KMA2h48UBkDUlwCOn4L860h4sZIDfRkWcptB3HFipeKP0npGAfWfb
+sQhueC7Ue8XpZIq5QBDOa+Zle3l8KZdmC4+sZYTsDoYm6jKX+LPgUAvvwyCBEUS7
+0zVrBgXTwFDFuGt5LYROcngfRggekAMa7gWTPbwb0mQgCIvKaVxlu3FO5cNi4ExX
+tlUUJyNualG+8qsbihqhHQBPs6QYhQ95y4ZndDqMtoyPWLhcOMo/Z/CLMQNhpXRl
+okJndM7TjzFW05Fqy+cQwl8LTdGVZKUOGW/RwYMD2TPxXEp/XGEDlnREHVjppToT
++SlUlc7Dh31PCz5PoRSTvpJrsV2LZAUO9hoGoDYjfBqfUbrd5mFIii/52eJva7o1
+RcrsHEkLTvu4BOk3Ztp3Zi26atBraADZ2T6UqwrfzZZrD1gI4sORuKN4/jmqt0KQ
+H4FMJkKZgvJ0Rfjpt6ZqRj99wSnwNfDvr7641WTpB07Ati2LI3Tr6Fx7f2Phfkg1
+SbzEC+qt3bixORhzFp0PbcULwamSsNVODf/EQic56bKZjOFEC+DFw3LKpvvBG1Fj
+kGWbfZhSA2GZFUghvhFbFOsuwKh/GDoetFwKXWcM8DM0+aHSPwL61Y5FQ0Kn4DnB
+ci3lJnSctD0fN3ckDIcTU/Nnza/RMJn1jRwBZc2Ql7/lA98jCM8uKTMVJy76ABf9
+8lQrLGp6tSMD6jo31DMLVmKA9qed7Mk4QeZiDTm0/6d2GZ6hO8xwvzFRQ6Qy1ETG
+W5c=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_rc2_128.der b/samples/rsa/pkcs8v2_rsa_rc2_128.der
new file mode 100644
index 0000000..f7b19c9
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_rc2_128.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_rc2_128.pem b/samples/rsa/pkcs8v2_rsa_rc2_128.pem
new file mode 100644
index 0000000..d68b22b
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_rc2_128.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFFjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQI4aRQrNlj6ZECAggA
+AgEQMBkGCCqGSIb3DQMCMA0CAToECG8qyWz/E/DoBIIEyFBBZXtbGNaIuDvM/J1u
+l8gKw+zfurof6G7BSxefE8zuVFVhRXc7MnLQml97awOeEzvnGC7y61JELsZ7ROqa
+1JWjdfURTsxxE4DGyUe+jOu2A1YSsnADCWq2bmvAkbFbV9N3Z1LqIkJNPtfS9KJQ
+ukDscB51M3m0Y8PaQDrGFBdsRK/lAErOxdLkfRYQItqUnzawF1FuysiYlcQiCC0e
+JrwiN9B/wW4bvnhQXABlQeI02MsfMPX8GLrlRfoNojLKTMCL1d+WK6dKuIA0QVRq
+bXzAkqWe2VjIaOHXcbzk9OcLmJAHkGX0pwkYpgSDyD2yqXB4thhkvCc9hlRQObMn
+Qvj2k5wyc3FzExWRwflTDZqpW9dFGCzjyzvOzfyJ+MWgS4e4a76vPEa79CMTWZcn
+UgNuSK65g7wRLFm6Ko15jxKAEP9zEGV+mKNBMmkRvL4aWWwbJOK48GYar9RaqC8u
+qbMTeQB/nfk//2JdxDR5W51dCSk5z64v/1ZEiLz96Y8GV8cc7PwVVjotW/yJEQv1
+mhWBqeiGLRQdymhU8AKwiNxhw2m1b/CW+pjOUpB21A7P8q3j2h5EqhD1VXneB6pH
++RTvFOUzYWp4mz21Ul8qXzc0CLsDm+Lywiqv9hDKMtaCe3cNrR/PFNoFuRYO6fZ7
+OOK3R7DQ/Us8cMpUJBCuYmBBwQB81fDxiHJdvtq8BmToJ6EYh4KzyTg4SGC1CPlh
+KjWkzIf0w7eZZj+hP4tKsrkeFsJ3/QSQW53bH7sNxp7uiSEwFpi3Sa/n3ABbOLit
+HR+O3GSfQIQMeLdZ5kcG2ww1SFEpaYBryBJZPfF7xF4rl5fWkrLasAPgUpTxsZ52
+UdD6bZb/8Ij3ZkjNJIRaGzCMlfWbUYpM4xBZ4bSQL2OGDYxC37T8TU4s6PIwGpB2
+zux3razpSBMFM6cT6ROw0zTzQpbDNF3U/wjOoyZmqRNpyr9AfXlsnxjXYzevmBUU
+IHEXUjEwhoGrVAv0U67YFgxLay9bWU76q6StODcz4flrcgf6Z1SK1J9WnX1FMYGK
+5HK0krzesjdFSqsx7T4VNv1paf5ql8mvMrIMTT2envm2vwMVG6EkOhGLjVeF/wPA
+0URcR8Fw9Wh9enObpocFnkqKiQfpyTOLBRIcYdJ07s/ER3HmqcnOPO4am5EqHeUu
++3YPVrNuV9E+BMNGKcMFzda5MIJi0rbYlF59Bz5xy8+nxiUqN2SvJYIMh/6egBue
+MEq/6O6ex5ypPFMlXItmubd3cqW6WMMOGuAxj0ciFLzZTxOwGDqh4G8GvPTZ6OtL
+fq2mitjPkLOKHplJ+Mjzd6qQIXxv5S7utPvpVnJPimD3jdwfWFXI5sO8pIjTVgbJ
+ZzkDw8ilLa5dR4e72+KHSlygjy0w2cvDX8kDfZyiRE30gIGQiHH7l/0Sv1GtOxpd
+2tmDTdA3zaI7W/gukmsMrpfBbGgHVC/YKlRVnfWFEh+a/4LLhc5gywqxyZzC59Dc
+nDRVPwSIPwWsx74ViClmviq4j0QV+n94JaQ2exgVvddBjluR7+9F+6+BSbfrgCeT
+nTAowzDF15LOg+/wXaAnSerzIwB1s9xfYyssGuKd31Rc6FBH+iZTZorVGS+8UARa
+yLHeQoz3pbRtiA==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_rc2_40.der b/samples/rsa/pkcs8v2_rsa_rc2_40.der
new file mode 100644
index 0000000..6ae9150
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_rc2_40.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_rc2_40.pem b/samples/rsa/pkcs8v2_rsa_rc2_40.pem
new file mode 100644
index 0000000..8a582f8
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_rc2_40.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFFzBJBgkqhkiG9w0BBQ0wPDAeBgkqhkiG9w0BBQwwEQQIEE4B6fCGV+ECAggA
+AgEFMBoGCCqGSIb3DQMCMA4CAgCgBAgEbKm9AhH8KgSCBMhfarJG3ur5WGGeeRIn
+M31j4IfUqpBGofJzVT0HPSX0qMUCvfIGA9YLdKZKdM3r8KfF5uSSe9vdQwOZwTtg
+AsCgJu76cC/iRCbAZX0gJcVE29KjLfXKl92Jumuysjmd+Le38Pc38/T+gwTeNyyg
+aW/ABB75yqxQUbrBv1kE389jNctQqDfga/oW2LQu05EAxup5aRD1B4KNP+7vCok+
++kzDGRMkZmjalhnvPZUytX0W7MWNigVsg86krQUSGWrb6xPYUmSsYG40RCpPJtie
+0hWTuSHecI7ZP3H3UtUw6jOYvOXzJAmImp5HhGpUNhIyMNi1xJRd5KoKKWLcsChC
+OkLkf7nxPVBFShhwq7jRoPKnv3r0qDutB29iDZmD1V13pQ08gNsEX9sNwgEWMVQZ
+RGQSE3Ff1LmXcpaC0TcxRmoAvEZFsNfmsIC8E+InNfY2QcgGytes8t5FzHdR4ZdG
+G+fWMwSKzC07XestYJq1ung2hG+j4VmH4+yD3KY1iNg8veWmYC45yCp/IU/nBwf+
+AIE0UtitgeWG7GIzVZNasnb2gc/FAOb/6QeSt2l3gS1pzgHXO6iUIOylGLM/eWAa
+/jIaDI//bBOIhEaNNI3xAa04Jk/Lo0slTIUiXJpv2qefWbO2LtHlTel0FQlRWH5k
+rYFohxXeQ0TnZqNsVPdresFbxqsvGvp57gGpAFkUPfdyzhDMwEArTB5QuvuHSq0W
+lYYhAVIMBa/HgI93YuEqsLEM5wp+7NapZGJDUn0y93qn2med4a5xRUeBOVPelJUj
+aexagd9OF5YvT4+ZU2fDA1qaDUtH9ECDqqpaSRQlN6RBnsWCkd/rxOx4aV7w7kep
+8Ie5NtO6ANPkIFFA6q/RuH73MeAnQzABmSHYLYzDe56eGLPwutKeJqx4mp/7lvCZ
+IZQf2qOl8+onLmscESKwzzDN0O4zL6vgNyG+h6quP17LLTBzWijR03JPcC1uhl0q
+Bt8QZYTaD7hEJYB1LNiTG4x4N24/fvch19BiGXnMRomHHgQ4V5Exe3OKsV2UfRYw
+ZbG6ncMUTiWAEhbvpPgVWmvjkZdcyK1EhhED0j6NcOLhDc/BJRLPoczNWY+JYiol
+LbML/dj5MXkNBNOAAF5F9SL72XN+25Ylkxc64axoaOC8HjKIJqd0Kw1LKJ/YPxWJ
+ZxKV7J3jBDqlaGdtnrcWOhkEUw5mLewlOiabDBzYq+2A0PjdC54wzql5dhJ/vJFL
+FM4BxF7y9t811D35A/A8tVsviE27zfz/Re6wKteSaoadWmU5xBFHSO/I6b15GKw/
+/qQg2EdFJ0zx4C/+ZOJJzLpMyZAdOVdV8ZKXx6i0QaiAspdpK+xyuLt0YQiqlmp5
+VCVlmxEQEyoIGM3ec1f4Wrvg0dmaaahyRwxwWpojbe6HqO+QDmfdjX6tNhCL62xO
+J/f2N2suY4PnQAr2o1fKH/n9Tx7OYJp7tXr29/oQRGFcFb1SC+8ucrHROB1rdoMm
+5VQZU7Pzx6ixp/eoRGF4o/sXPrJ2MHzQ7Pr0X4Tz/vYxtA3NITPn+ARZMNxkBnkn
+c0rRtxepYJeNDWAP1dvpWDn3PfMKGDKNLAp69T3QVaI8xIPzx5xgQRT+HMtfqGjP
+km5ELjRjyzzarVI=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa/pkcs8v2_rsa_rc2_64.der b/samples/rsa/pkcs8v2_rsa_rc2_64.der
new file mode 100644
index 0000000..14de077
Binary files /dev/null and b/samples/rsa/pkcs8v2_rsa_rc2_64.der differ
diff --git a/samples/rsa/pkcs8v2_rsa_rc2_64.pem b/samples/rsa/pkcs8v2_rsa_rc2_64.pem
new file mode 100644
index 0000000..5c43ce2
--- /dev/null
+++ b/samples/rsa/pkcs8v2_rsa_rc2_64.pem
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFFjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIEK45YkGUmvECAggA
+AgEIMBkGCCqGSIb3DQMCMA0CAXgECPuUIT3jxRz3BIIEyNfj2MRyn+4lRb4k+M/h
+IAEefhbiYMZ3P2vRDX1zFe6zHqBpRxTD+vskLXG1YScwt6TQMpXxMqlgarwk9wXE
+L/RrpxJrXJ9X4UJoVM47Q/D0an8xkEF7L6YzFKgfngzqI36A8EqSO3MT4+UIHcCr
+LGoUev14l9FXhVar2sW2eeK/LSd2MgqbeMK8iLeWvSWRZYL95ji6PWnWO10Ggojp
+f2ttHty9FsvNigzE2qZutYG3zPL94i/Xz/v6qH278fCX0PHnGWCAsOqg2h648vhd
+tbUcBB+tC4dKiYVwcmprrzJVPEWQuXIPmWMZa+s0RgM7jqI0vkrkLHbgGxLxRvFM
+n4xxQRs+rNcw57sm/LeoNyosqbWEic8RqLV2sDp+e/A+Te/n7JwOuhYHhmeSVyds
+yF1V8k1ObAg4hsYyhwcZL+7X6af4miG3DVVPC8eR2UWOYLvML0LbvWegp/WyNwkh
+rOd+IXR0qWKGmmEpJQPrsTLH8x6ueNgtqKP1jQvRLVS91Y80nmnzHNyOx6z1pR9v
+GZ8dRAPUd+/fygLv8zpBUOt0yf6ZT0TKWg5C3wP81mfe311QkPm2+3AMF9v/QCYk
+hLvAgFFvuzIqzrIVXofBgzABFssUIeG1OmPdn13NFGFeW7QXIktt8hqt++dyBMV3
+ZkOZhVkK85c/sxPYOh+Q6N20xq22DZ/O5/UAVsBMY0NtUgUsJ7qjaSsy5gnhO5mu
+oEl9IgSOMnl+I+wLmgXn84nMmsjJBOX+VOBviArCEEPlY6Vf/vppFE6Fx4wlmNl2
+nuDf+Oe9drcw9JO97Axiu4JzLhTaGITWcuBQnIvmDi22P35DIqUvi20iif3el8eb
+AwtmNz4pyU8W7EiSn5kQPuP36PxnPSLuCvAZAcYrkxu6aCQIMpD4m/CH8UbCLHGZ
+0o2zX/eyYcLJLgNn+u41B0TFBDZ+Q4XovykjGdjl9vMP5i0tW8q5zAC2zdlusRQD
+s7nA9KNCOwOeZBpYrEOtZ0ALTudnKwNEfwr/h2oYdFv16H5RvefyEhn06nBZfxuT
+6xQO/+ayaGZLMcmwhfDkap/ubc8NNlolG8Hgy2QqRlooBM8cxq2KTQd1wgl6KLOR
+Ahj7ebU2+7Q3sqIvCwc7Y5SxclevRiAUbYuvxbKCAjW+iKml3G5rbTBuk4ocEVsM
+Kp6c+M1iCeyaKRja5y6QGYJpw/hB4K//rAvWmnLGYSsJEl2eKo33CvqwEAM70pg6
+o77K6Y6uMoJu5erR7siuybTGXa9tMGfhyQLQ4zQgsi0+YaAh//snDv8YtOOZHP5+
+wrVmfiVoMTj4eE3GeQsnQnYzkpIl4SGDnVRvxTFuMCgzJVLxWC9Yf/5U82bZUhjn
+MXwV16QDuHv9mYK33aDe5bjSwOTGSrLw9WisZLxokjcm/D6ippwADodlXEFb9mKo
+aOoqpeWJpOinMIyUGa89KH8gtdQ4YWvkiZdlugWFirE5/cTT9lR6KMTZxqILGgGC
+EI/jDj6p9pMY1FVUcU34CT//JxUdt7O9Fcy602RlfIxlB4jXMTOPAuwEWhrixk7s
+gwKnR09vcj+Jil0VPJ+Td5PPFnbCC+gKpFKyNIvHCMBKPaXV9hxRrZ9o5dZkRk2J
+iEMh5e/7Lh8dUg==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/samples/rsa_result.html b/samples/rsa_result.html
new file mode 100644
index 0000000..f5ceb97
--- /dev/null
+++ b/samples/rsa_result.html
@@ -0,0 +1,38 @@
+<html>
+<head>
+<title>Not-Yet-Commons-SSL - Decrypting RSA Private Keys in Java</title>
+<style type="text/css">
+h1, h2, h3 { margin: 0; border: 0; padding: 0; font-size: 100%; }
+h1 { float: left; color: red; }
+b.n { font-family: arial; font-weight: bold; }
+span.hl { color: white; background-color: green; }
+div.nav { float: left; margin-left: 20px; font-weight: bold; }
+.nav a, .nav span { padding: 0 5px; }
+.nav a { color: blue; }
+.nav span.hl a { color: white; }
+li.top { margin-top: 10px; }
+ul.openssl { float: left; width: 100px; margin-top: 8px; }
+ul.pkcs8 { float: left; width: 200px; margin-top: 8px; }
+</style>
+</head>
+<body>
+<h1>not-yet-commons-ssl</h1>
+<div class="nav">
+<a href="../index.html">main</a> |
+<a href="../ssl.html">ssl</a> |
+<span class="hl"><a href="../pkcs8.html">pkcs8</a></span> |
+<a href="../pbe.html">pbe</a> |
+<a href="../rmi.html">rmi</a> |
+<a href="../utilities.html">utilities</a> |
+<a href="../source.html">source</a> |
+<a href="../javadocs/">javadocs</a> |
+<a href="../download.html">download</a>
+</div>
+<br clear="all"/>
+<hr/>
+<h2>Decrypting RSA Private Keys in Java</h2>
+<p>Don't forget to install your JVM's <a href="http://java.sun.com/javase/downloads/">Unlimited Strength Jurisdiction Policy Files</a>
+if you want the AES-192 and AES-256 tests to pass.</p>
+<!--#include virtual="rsa.html" -->
+</body>
+</html>
diff --git a/samples/x509/certificate.der b/samples/x509/certificate.der
new file mode 100644
index 0000000..8fc0b96
Binary files /dev/null and b/samples/x509/certificate.der differ
diff --git a/samples/x509/certificate.pem b/samples/x509/certificate.pem
new file mode 100644
index 0000000..0d710cd
--- /dev/null
+++ b/samples/x509/certificate.pem
@@ -0,0 +1,85 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8c:fe:11:83:01:53:a6:7f
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Nov 5 21:52:37 2006 GMT
+ Not After : Nov 5 21:52:37 2007 GMT
+ Subject: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_certificate/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c8:63:af:96:82:3e:8c:a9:d1:1d:62:ae:85:80:
+ 7e:71:32:04:c1:98:5a:80:a2:74:7f:7a:c8:63:c5:
+ 8d:82:e8:c1:ec:f9:69:82:98:d4:83:8a:4d:8d:81:
+ 95:88:68:e0:ef:38:5f:6e:38:42:b6:53:46:5f:24:
+ 41:b6:2d:c6:71:a1:e2:04:82:0f:e6:7c:82:36:7f:
+ 80:cb:cb:52:58:6a:39:bf:96:5c:f0:14:1c:c0:77:
+ f4:64:72:cd:ea:c0:fd:9b:6b:95:4a:9f:fa:52:a8:
+ d2:e5:9c:a1:cc:5e:45:ce:fb:d4:a3:7c:70:f1:f7:
+ 9c:76:74:ad:5d:07:c7:86:40:67:2e:94:e3:1c:4e:
+ 6d:ee:2b:b5:25:58:d3:b8:4d:29:70:1b:da:87:67:
+ 56:a8:33:71:88:83:90:b5:7c:8a:5b:c4:9a:83:56:
+ 31:6a:e9:f1:40:6a:91:37:29:12:16:21:09:8a:77:
+ 71:39:20:27:03:12:ba:ab:fc:06:a9:c6:77:ce:f1:
+ 41:4d:c5:55:92:38:b5:bb:64:07:e2:b3:8c:3f:73:
+ cf:c4:02:0c:90:1f:0e:36:47:47:4d:ca:35:0e:66:
+ c4:e8:17:c3:1c:0a:c3:a9:46:31:a8:95:25:3c:69:
+ 4c:aa:b2:9b:dd:f0:85:89:3d:de:5d:e8:70:47:b9:
+ e5:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 9F:14:77:BF:3F:3A:B6:CA:38:82:42:48:16:2C:DA:D0:CB:5E:87:D8
+ X509v3 Authority Key Identifier:
+ keyid:7B:9A:DA:8F:90:99:4E:52:D2:AC:DB:B3:03:52:CA:87:A6:0D:3E:0D
+
+ Signature Algorithm: sha1WithRSAEncryption
+ 70:2c:29:17:f6:55:3b:b0:f2:82:53:db:06:ac:01:8c:2c:40:
+ c2:59:30:58:78:af:17:d7:39:4b:87:f2:df:ed:cf:93:80:d5:
+ 05:ca:81:13:84:bc:d6:87:15:01:7e:45:f8:27:d9:3e:46:0a:
+ a5:92:0d:ce:71:25:b4:40:6b:17:16:e7:fd:d4:30:8c:9f:df:
+ 8a:f7:53:4f:91:e7:0d:ea:b7:06:03:f4:48:8b:6d:09:ea:cf:
+ 58:99:55:89:58:05:dc:8a:25:05:55:8d:19:65:87:f3:be:32:
+ b5:98:42:01:63:80:9b:25:ab:50:88:4b:e1:6d:09:7f:6a:27:
+ 7c:66:07:64:ac:a6:c1:d6:73:e6:05:30:4e:32:e9:7d:67:51:
+ 60:20:14:5e:b7:3c:71:c7:02:85:aa:57:16:66:56:3a:33:ce:
+ 85:ae:62:58:41:5c:66:88:ae:e6:3e:a7:7b:b2:e6:9c:7b:b9:
+ 29:2e:fb:0c:de:c4:73:5c:40:cf:a9:27:81:f1:f0:5a:a2:a5:
+ 71:0a:78:2c:77:1d:0c:88:fb:9e:49:8c:38:27:49:83:b5:14:
+ 53:4f:df:74:0b:18:02:15:e6:f2:d2:67:a6:f4:4b:19:ec:23:
+ 01:04:52:5b:43:8e:0d:8e:37:c6:a1:9a:21:f4:b5:ca:c6:21:
+ 4f:31:8b:54
+-----BEGIN CERTIFICATE-----
+MIIEQDCCAyigAwIBAgIJAIz+EYMBU6Z/MA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTEwNTIxNTIzN1oXDTA3MTEwNTIxNTIzN1owgZ4x
+CzAJBgNVBAYTAkNBMQswCQYDVQQIEwJCQzESMBAGA1UEBxMJVmFuY291dmVyMRYw
+FAYDVQQKEw13d3cuY3VjYmMuY29tMRQwEgYDVQQLFAtjb21tb25zX3NzbDEZMBcG
+A1UEAxQQZGVtb19jZXJ0aWZpY2F0ZTElMCMGCSqGSIb3DQEJARYWanVsaXVzZGF2
+aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhj
+r5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2BlYho4O84
+X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRyzerA/Ztr
+lUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY07hNKXAb
+2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8BqnGd87x
+QU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiVJTxpTKqy
+m93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0E
+HxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFJ8Ud78/
+OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNSyoemDT4N
+MA0GCSqGSIb3DQEBBQUAA4IBAQBwLCkX9lU7sPKCU9sGrAGMLEDCWTBYeK8X1zlL
+h/Lf7c+TgNUFyoEThLzWhxUBfkX4J9k+Rgqlkg3OcSW0QGsXFuf91DCMn9+K91NP
+kecN6rcGA/RIi20J6s9YmVWJWAXciiUFVY0ZZYfzvjK1mEIBY4CbJatQiEvhbQl/
+aid8ZgdkrKbB1nPmBTBOMul9Z1FgIBRetzxxxwKFqlcWZlY6M86FrmJYQVxmiK7m
+Pqd7suace7kpLvsM3sRzXEDPqSeB8fBaoqVxCngsdx0MiPueSYw4J0mDtRRTT990
+CxgCFeby0mem9EsZ7CMBBFJbQ44NjjfGoZoh9LXKxiFPMYtU
+-----END CERTIFICATE-----
diff --git a/samples/x509/certificate_chain.pem b/samples/x509/certificate_chain.pem
new file mode 100644
index 0000000..cb52090
--- /dev/null
+++ b/samples/x509/certificate_chain.pem
@@ -0,0 +1,79 @@
+-----BEGIN CERTIFICATE-----
+MIIEQDCCAyigAwIBAgIJAIz+EYMBU6Z/MA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTEwNTIxNTIzN1oXDTA3MTEwNTIxNTIzN1owgZ4x
+CzAJBgNVBAYTAkNBMQswCQYDVQQIEwJCQzESMBAGA1UEBxMJVmFuY291dmVyMRYw
+FAYDVQQKEw13d3cuY3VjYmMuY29tMRQwEgYDVQQLFAtjb21tb25zX3NzbDEZMBcG
+A1UEAxQQZGVtb19jZXJ0aWZpY2F0ZTElMCMGCSqGSIb3DQEJARYWanVsaXVzZGF2
+aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhj
+r5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2BlYho4O84
+X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRyzerA/Ztr
+lUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY07hNKXAb
+2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8BqnGd87x
+QU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiVJTxpTKqy
+m93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgBhvhCAQ0E
+HxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFJ8Ud78/
+OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNSyoemDT4N
+MA0GCSqGSIb3DQEBBQUAA4IBAQBwLCkX9lU7sPKCU9sGrAGMLEDCWTBYeK8X1zlL
+h/Lf7c+TgNUFyoEThLzWhxUBfkX4J9k+Rgqlkg3OcSW0QGsXFuf91DCMn9+K91NP
+kecN6rcGA/RIi20J6s9YmVWJWAXciiUFVY0ZZYfzvjK1mEIBY4CbJatQiEvhbQl/
+aid8ZgdkrKbB1nPmBTBOMul9Z1FgIBRetzxxxwKFqlcWZlY6M86FrmJYQVxmiK7m
+Pqd7suace7kpLvsM3sRzXEDPqSeB8fBaoqVxCngsdx0MiPueSYw4J0mDtRRTT990
+CxgCFeby0mem9EsZ7CMBBFJbQ44NjjfGoZoh9LXKxiFPMYtU
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEnDCCA4SgAwIBAgIJAJTNwZ6yNa5cMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxFjAUBgNVBAoTDXd3dy5jdWNiYy5jb20xFDAS
+BgNVBAsUC2NvbW1vbnNfc3NsMRUwEwYDVQQDFAxkZW1vX3Jvb3RfY2ExJTAjBgkq
+hkiG9w0BCQEWFmp1bGl1c2Rhdmllc0BnbWFpbC5jb20wHhcNMDYxMTA1MjE0OTMx
+WhcNMDcxMTA1MjE0OTMxWjCBojELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAkJDMRIw
+EAYDVQQHEwlWYW5jb3V2ZXIxFjAUBgNVBAoTDXd3dy5jdWNiYy5jb20xFDASBgNV
+BAsUC2NvbW1vbnNfc3NsMR0wGwYDVQQDFBRkZW1vX2ludGVybWVkaWF0ZV9jYTEl
+MCMGCSqGSIb3DQEJARYWanVsaXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAL0S4y3vUO0EM6lwqOEfK8fvrUprIbsikXaG
+XzejcZ+T3l2Dc7t8WtBfRf78i4JypMqJQSijrUicj3H6mOMIReKaXm6ls4hA5d8w
+Lhmgiqsz/kW+gA8SeWGWRN683BD/RbQmzOls6ynBvap9jZlthXWBrSIlPCQoBLXY
+KVaxGzbL4ezaq+XFMKMQSm2uKwVmHHQNbfmZlPsuendBVomb/ked53Ab9IH6dwwN
+qJH9WIrvIzIVEXWlpvQ5MCqozM7u1akU+G8cazr8theGPCaYkzoXnigWua4OjdpV
+9z5ZDknhfBzG1AjapdG07FIirwWWgIyZXqZSD96ikmLtwT29qnsCAwEAAaOB7jCB
+6zAdBgNVHQ4EFgQUe5raj5CZTlLSrNuzA1LKh6YNPg0wgbsGA1UdIwSBszCBsIAU
+rN8eFIvMiRFXXgDqKumS0/W2AhOhgYykgYkwgYYxCzAJBgNVBAYTAkNBMQswCQYD
+VQQIEwJCQzEWMBQGA1UEChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9u
+c19zc2wxFTATBgNVBAMUDGRlbW9fcm9vdF9jYTElMCMGCSqGSIb3DQEJARYWanVs
+aXVzZGF2aWVzQGdtYWlsLmNvbYIJAJTNwZ6yNa5bMAwGA1UdEwQFMAMBAf8wDQYJ
+KoZIhvcNAQEFBQADggEBAIB4KMZvHD20pdKajFtMBpL7X4W4soq6EeTtjml3NYa9
+Qc52bsQEGNccKY9afYSBIndaQvFdtmz6HdoN+B8TjYShw2KhyjtKimGLpWYoi1YF
+e4aHdmA/Gp5xk8pZzR18FmooxC9RqBux+NAM2iTFSLgDtGIIj4sg2rbn6Bb6ZlQT
+1rg6VucXCA1629lNfMeNcu7CBNmUKIdaxHR/YJQallE0KfGRiOIWPrPj/VNk0YA6
+XFg0ocjqXJ2/N0N9rWVshMUaXgOh7m4D/5zga5/nuxDU+PoToA6mQ4bV6eCYqZbh
+aa1kQYtR9B4ZiG6pB82qVc2dCqStOH2FAEWos2gAVkQ=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEgDCCA2igAwIBAgIJAJTNwZ6yNa5bMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxFjAUBgNVBAoTDXd3dy5jdWNiYy5jb20xFDAS
+BgNVBAsUC2NvbW1vbnNfc3NsMRUwEwYDVQQDFAxkZW1vX3Jvb3RfY2ExJTAjBgkq
+hkiG9w0BCQEWFmp1bGl1c2Rhdmllc0BnbWFpbC5jb20wHhcNMDYxMTA1MjEzNjQz
+WhcNMjYxMTA1MjEzNjQzWjCBhjELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAkJDMRYw
+FAYDVQQKEw13d3cuY3VjYmMuY29tMRQwEgYDVQQLFAtjb21tb25zX3NzbDEVMBMG
+A1UEAxQMZGVtb19yb290X2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZpZXNA
+Z21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+OnocmJ
+79UeO2hlCwK+Cle5uZWnU6uwJl+08z5cvebb5tT64WL9+psDbfgUH/Gm9JsuxKTg
+w1tZO/4duIgnaLNSx4HoqaTjwigd/hR3TsoGEPXTCkz1ikgTCOEDvl+iMid6aOrd
+mViE8HhscxKZ+h5FE7oHZyuT6gFoiaIXhFq+xK2w4ZwDz9L+paiwqywyUJJMnh9U
+jKorY+nua81N0oxpIhHPspCanDU4neMzCzYOZyLR/LqV5xORvHcFY84GWMz5hI25
+JbgaWJsYKuCAvNsnQwVoqKPGa7x1fn7x6oGsXJaCVt8weUwIj2xwg1lxMhrNaisH
+EvKpEAEnGGwWKQIDAQABo4HuMIHrMB0GA1UdDgQWBBSs3x4Ui8yJEVdeAOoq6ZLT
+9bYCEzCBuwYDVR0jBIGzMIGwgBSs3x4Ui8yJEVdeAOoq6ZLT9bYCE6GBjKSBiTCB
+hjELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAkJDMRYwFAYDVQQKEw13d3cuY3VjYmMu
+Y29tMRQwEgYDVQQLFAtjb21tb25zX3NzbDEVMBMGA1UEAxQMZGVtb19yb290X2Nh
+MSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZpZXNAZ21haWwuY29tggkAlM3BnrI1
+rlswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAlPl3/8h1LttR1svC
+S8RXbHpAWIT2BEDhGHUNjSmgDQNkE/itf/FCEXh0tlU4bYdtBSOHzflbnzOyIPId
+VZeSWs33V38xDFy6KoVg1gT8JxkLmE5S1vWkpsHIlpw/U6r7KD0Kx9FYx5AiXjw0
+lzz/zlVNuO2U09KIDwDPVG1mBzQiMiSWj1U1pM4KxINkWQwDy/fvu/I983s8lW5z
+hf2WuFNzQN3fcMK5dpBE9NVIu27oYuGYh2sak34v+7T700W2ooBB71qFXtm9P5rl
+Yp9RCEsg3KEEPNTtCBs8fROeXvLDrP0cmBIqwGYDuRNCxFDTOdjv6YGdA8nLOjaH
+2dDk0g==
+-----END CERTIFICATE-----
diff --git a/samples/x509/certificate_root_ca.der b/samples/x509/certificate_root_ca.der
new file mode 100644
index 0000000..02f710c
Binary files /dev/null and b/samples/x509/certificate_root_ca.der differ
diff --git a/samples/x509/certificate_root_ca.pem b/samples/x509/certificate_root_ca.pem
new file mode 100644
index 0000000..5811d8e
--- /dev/null
+++ b/samples/x509/certificate_root_ca.pem
@@ -0,0 +1,87 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 94:cd:c1:9e:b2:35:ae:5b
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, O=www.cucbc.com, OU=commons_ssl, CN=demo_root_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Nov 5 21:36:43 2006 GMT
+ Not After : Nov 5 21:36:43 2026 GMT
+ Subject: C=CA, ST=BC, O=www.cucbc.com, OU=commons_ssl, CN=demo_root_ca/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:bf:e3:a7:a1:c9:89:ef:d5:1e:3b:68:65:0b:02:
+ be:0a:57:b9:b9:95:a7:53:ab:b0:26:5f:b4:f3:3e:
+ 5c:bd:e6:db:e6:d4:fa:e1:62:fd:fa:9b:03:6d:f8:
+ 14:1f:f1:a6:f4:9b:2e:c4:a4:e0:c3:5b:59:3b:fe:
+ 1d:b8:88:27:68:b3:52:c7:81:e8:a9:a4:e3:c2:28:
+ 1d:fe:14:77:4e:ca:06:10:f5:d3:0a:4c:f5:8a:48:
+ 13:08:e1:03:be:5f:a2:32:27:7a:68:ea:dd:99:58:
+ 84:f0:78:6c:73:12:99:fa:1e:45:13:ba:07:67:2b:
+ 93:ea:01:68:89:a2:17:84:5a:be:c4:ad:b0:e1:9c:
+ 03:cf:d2:fe:a5:a8:b0:ab:2c:32:50:92:4c:9e:1f:
+ 54:8c:aa:2b:63:e9:ee:6b:cd:4d:d2:8c:69:22:11:
+ cf:b2:90:9a:9c:35:38:9d:e3:33:0b:36:0e:67:22:
+ d1:fc:ba:95:e7:13:91:bc:77:05:63:ce:06:58:cc:
+ f9:84:8d:b9:25:b8:1a:58:9b:18:2a:e0:80:bc:db:
+ 27:43:05:68:a8:a3:c6:6b:bc:75:7e:7e:f1:ea:81:
+ ac:5c:96:82:56:df:30:79:4c:08:8f:6c:70:83:59:
+ 71:32:1a:cd:6a:2b:07:12:f2:a9:10:01:27:18:6c:
+ 16:29
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ AC:DF:1E:14:8B:CC:89:11:57:5E:00:EA:2A:E9:92:D3:F5:B6:02:13
+ X509v3 Authority Key Identifier:
+ keyid:AC:DF:1E:14:8B:CC:89:11:57:5E:00:EA:2A:E9:92:D3:F5:B6:02:13
+ DirName:/C=CA/ST=BC/O=www.cucbc.com/OU=commons_ssl/CN=demo_root_ca/emailAddress=juliusdavies at gmail.com
+ serial:94:CD:C1:9E:B2:35:AE:5B
+
+ X509v3 Basic Constraints:
+ CA:TRUE
+ Signature Algorithm: sha1WithRSAEncryption
+ 94:f9:77:ff:c8:75:2e:db:51:d6:cb:c2:4b:c4:57:6c:7a:40:
+ 58:84:f6:04:40:e1:18:75:0d:8d:29:a0:0d:03:64:13:f8:ad:
+ 7f:f1:42:11:78:74:b6:55:38:6d:87:6d:05:23:87:cd:f9:5b:
+ 9f:33:b2:20:f2:1d:55:97:92:5a:cd:f7:57:7f:31:0c:5c:ba:
+ 2a:85:60:d6:04:fc:27:19:0b:98:4e:52:d6:f5:a4:a6:c1:c8:
+ 96:9c:3f:53:aa:fb:28:3d:0a:c7:d1:58:c7:90:22:5e:3c:34:
+ 97:3c:ff:ce:55:4d:b8:ed:94:d3:d2:88:0f:00:cf:54:6d:66:
+ 07:34:22:32:24:96:8f:55:35:a4:ce:0a:c4:83:64:59:0c:03:
+ cb:f7:ef:bb:f2:3d:f3:7b:3c:95:6e:73:85:fd:96:b8:53:73:
+ 40:dd:df:70:c2:b9:76:90:44:f4:d5:48:bb:6e:e8:62:e1:98:
+ 87:6b:1a:93:7e:2f:fb:b4:fb:d3:45:b6:a2:80:41:ef:5a:85:
+ 5e:d9:bd:3f:9a:e5:62:9f:51:08:4b:20:dc:a1:04:3c:d4:ed:
+ 08:1b:3c:7d:13:9e:5e:f2:c3:ac:fd:1c:98:12:2a:c0:66:03:
+ b9:13:42:c4:50:d3:39:d8:ef:e9:81:9d:03:c9:cb:3a:36:87:
+ d9:d0:e4:d2
+-----BEGIN CERTIFICATE-----
+MIIEgDCCA2igAwIBAgIJAJTNwZ6yNa5bMA0GCSqGSIb3DQEBBQUAMIGGMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxFjAUBgNVBAoTDXd3dy5jdWNiYy5jb20xFDAS
+BgNVBAsUC2NvbW1vbnNfc3NsMRUwEwYDVQQDFAxkZW1vX3Jvb3RfY2ExJTAjBgkq
+hkiG9w0BCQEWFmp1bGl1c2Rhdmllc0BnbWFpbC5jb20wHhcNMDYxMTA1MjEzNjQz
+WhcNMjYxMTA1MjEzNjQzWjCBhjELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAkJDMRYw
+FAYDVQQKEw13d3cuY3VjYmMuY29tMRQwEgYDVQQLFAtjb21tb25zX3NzbDEVMBMG
+A1UEAxQMZGVtb19yb290X2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZpZXNA
+Z21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv+OnocmJ
+79UeO2hlCwK+Cle5uZWnU6uwJl+08z5cvebb5tT64WL9+psDbfgUH/Gm9JsuxKTg
+w1tZO/4duIgnaLNSx4HoqaTjwigd/hR3TsoGEPXTCkz1ikgTCOEDvl+iMid6aOrd
+mViE8HhscxKZ+h5FE7oHZyuT6gFoiaIXhFq+xK2w4ZwDz9L+paiwqywyUJJMnh9U
+jKorY+nua81N0oxpIhHPspCanDU4neMzCzYOZyLR/LqV5xORvHcFY84GWMz5hI25
+JbgaWJsYKuCAvNsnQwVoqKPGa7x1fn7x6oGsXJaCVt8weUwIj2xwg1lxMhrNaisH
+EvKpEAEnGGwWKQIDAQABo4HuMIHrMB0GA1UdDgQWBBSs3x4Ui8yJEVdeAOoq6ZLT
+9bYCEzCBuwYDVR0jBIGzMIGwgBSs3x4Ui8yJEVdeAOoq6ZLT9bYCE6GBjKSBiTCB
+hjELMAkGA1UEBhMCQ0ExCzAJBgNVBAgTAkJDMRYwFAYDVQQKEw13d3cuY3VjYmMu
+Y29tMRQwEgYDVQQLFAtjb21tb25zX3NzbDEVMBMGA1UEAxQMZGVtb19yb290X2Nh
+MSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZpZXNAZ21haWwuY29tggkAlM3BnrI1
+rlswDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAlPl3/8h1LttR1svC
+S8RXbHpAWIT2BEDhGHUNjSmgDQNkE/itf/FCEXh0tlU4bYdtBSOHzflbnzOyIPId
+VZeSWs33V38xDFy6KoVg1gT8JxkLmE5S1vWkpsHIlpw/U6r7KD0Kx9FYx5AiXjw0
+lzz/zlVNuO2U09KIDwDPVG1mBzQiMiSWj1U1pM4KxINkWQwDy/fvu/I983s8lW5z
+hf2WuFNzQN3fcMK5dpBE9NVIu27oYuGYh2sak34v+7T700W2ooBB71qFXtm9P5rl
+Yp9RCEsg3KEEPNTtCBs8fROeXvLDrP0cmBIqwGYDuRNCxFDTOdjv6YGdA8nLOjaH
+2dDk0g==
+-----END CERTIFICATE-----
diff --git a/samples/x509/oscp.pem b/samples/x509/oscp.pem
new file mode 100644
index 0000000..2f5177a
--- /dev/null
+++ b/samples/x509/oscp.pem
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDnTCCAwagAwIBAgIDPoz6MA0GCSqGSIb3DQEBBAUAMIHEMQswCQYDVQQGEwJa
+QTEVMBMGA1UECBMMV2VzdGVybiBDYXBlMRIwEAYDVQQHEwlDYXBlIFRvd24xHTAb
+BgNVBAoTFFRoYXd0ZSBDb25zdWx0aW5nIGNjMSgwJgYDVQQLEx9DZXJ0aWZpY2F0
+aW9uIFNlcnZpY2VzIERpdmlzaW9uMRkwFwYDVQQDExBUaGF3dGUgU2VydmVyIENB
+MSYwJAYJKoZIhvcNAQkBFhdzZXJ2ZXItY2VydHNAdGhhd3RlLmNvbTAeFw0wNDA4
+MjcwOTEzMjNaFw0wNjA5MTcxNDQ4MjlaMIG/MQswCQYDVQQGEwJDQTEZMBcGA1UE
+CBMQQnJpdGlzaCBDb2x1bWJpYTESMBAGA1UEBxMJVmFuY291dmVyMSwwKgYDVQQK
+EyNWYW5jb3V2ZXIgQ2l0eSBTYXZpbmdzIENyZWRpdCBVbmlvbjEUMBIGA1UECxML
+V2ViIEhvc3RpbmcxGDAWBgNVBAMTD3d3dy52YW5jaXR5LmNvbTEjMCEGCSqGSIb3
+DQEJARYUaG9zdG1hc3RlckBjdWNiYy5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0A
+MIGJAoGBALtc21pS+6njj9KkWcrRQt5Yva75YNE8o2aQQTA4aDi8WO1nLkC0qSWw
+V/0wO8K0gIe1WV/RluAKNU7oOmz8DGMRDF+CS5zFLKgKQJ3CxYwaWNKISAWrRkQu
+lp+oAm5EPqAaxtPTE4Fghv1EnZkA4g12g6PxYkAa2KeT80/8M8aBAgMBAAGjgZ8w
+gZwwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMDkGA1UdHwQyMDAwLqAs
+oCqGKGh0dHA6Ly9jcmwudGhhd3RlLmNvbS9UaGF3dGVTZXJ2ZXJDQS5jcmwwMgYI
+KwYBBQUHAQEEJjAkMCIGCCsGAQUFBzABhhZodHRwOi8vb2NzcC50aGF3dGUuY29t
+MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEEBQADgYEAiOi2YuiopBCQpCM6kJkp
+Tu251MgDkn82qx33rxYeZKuv68qvJfucfbiQgqrjVsp1X0Vuv0Uu3vpLs44Gq5Na
+05dDmmAzk3BRrOikMjOhZV4F/+e/NoUTjgi0QSWCavEZvEcW2Ids4xrRS1290TUS
+Fou+stRrYkGIyc3OUG4hZHY=
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/samples/x509/two-crls.pem b/samples/x509/two-crls.pem
new file mode 100644
index 0000000..5ddca1e
--- /dev/null
+++ b/samples/x509/two-crls.pem
@@ -0,0 +1,46 @@
+-----BEGIN CERTIFICATE-----
+MIIINjCCBx6gAwIBAgIKB3SNcwAAAAAAlDANBgkqhkiG9w0BAQUFADCBojELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xKjAoBgNVBAMTIVVTRVJUUlVTVCAtIFNlcnZlciBB
+dXRoZW50aWNhdGlvbjAeFw0wNTA0MDUxODM1MDZaFw0wNzAzMDYwMzIyMDRaMHYx
+CzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENp
+dHkxEjAQBgNVBAoTCVVTRVJUUlVTVDERMA8GA1UECxMIREFUQUNvcnAxGjAYBgNV
+BAMTEXd3dy51c2VydHJ1c3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA1yFt+Fjn7VJaPv7lv5IyQTjx7mFv2myDOci0sf13SjWo6D8Lv/8tC7Xt
+VoDXyonDY4ulBu2wIoKNocbtyNQGjb7RaYMxpxMrFydypIWXVfz3yuvJr74ZeGc1
+0X+vLTzThsQe/QLkqxDq0btjGfuaYe0wfogOGh6nptWNAiCvvrAO9TBE4NW5q7F2
+ZZQD/MhVgG2o+rGUOL7ieEWNtX7P596hCUaji6t2UIVQXViReCGjot0dw9wLGJ38
+hLIX+KdI5arB00ODSeo1X+EobDOpL6xiIh1vRJS7Cb59/cXk/P+STGOXVlP+d1xT
+W66rfYuvdKzqMICxbghXhQF9tD0mZQIDAQABo4IElzCCBJMwCwYDVR0PBAQDAgG4
+MBMGA1UdJQQMMAoGCCsGAQUFBwMBMB0GA1UdDgQWBBSgPNyE/1EGrMbLIevLBQfX
+EMJo5jCB0wYDVR0jBIHLMIHIgBR1ASiXxkYbNG7ooJEVcZJ57rcDzqGBnaSBmjCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmWCEAAVbCcaVP6zgr6vVP70ooswDAYDVR0TAQH/BAIwADCBkwYDVR0f
+BIGLMIGIMEGgP6A9hjtodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVNFUlRSVVNU
+LVNlcnZlckF1dGhlbnRpY2F0aW9uLmNybDBDoEGgP4Y9aHR0cDovL3d3dy51dG5z
+ZWN1cml0eS5jb20vVVNFUlRSVVNULVNlcnZlckF1dGhlbnRpY2F0aW9uLmNybDCB
+tAYIKwYBBQUHAQEEgacwgaQwTwYIKwYBBQUHMAKGQ2h0dHA6Ly93d3cudXNlcnRy
+dXN0LmNvbS9DQUNlcnRzL1VTRVJUUlVTVC1TZXJ2ZXJBdXRoZW50aWNhdGlvbi5j
+cnQwUQYIKwYBBQUHMAKGRWh0dHA6Ly93d3cudXRuc2VjdXJpdHkuY29tL0NBQ2Vy
+dHMvVVNFUlRSVVNULVNlcnZlckF1dGhlbnRpY2F0aW9uLmNydDCCAh0GA1UdIASC
+AhQwggIQMIICDAYIKoZIhvpfAQEwggH+MCgGCCsGAQUFBwIBFhxodHRwOi8vd3d3
+LnVzZXJ0cnVzdC5jb20vQ1BTMIIB0AYIKwYBBQUHAgIwggHCGoIBvlRoaXMgY2Vy
+dGlmaWNhdGUgaW5jb3Jwb3JhdGVzIGJ5IHJlZmVyZW5jZSwgYW5kIGl0cyB1c2Ug
+aXMgc3RyaWN0bHkgc3ViamVjdCB0bywgdGhlIFVTRVJGaXJzdCBDZXJ0aWZpY2F0
+aW9uIFByYWN0aWNlcyBTdGF0ZW1lbnQgKENQUykuIFB1cnN1YW50IHRvIHRoZSBD
+UFMsIFV0YWggU3RhdGUgbGF3LCBhbmQgRmVkZXJhbCBsYXcsIGNlcnRhaW4gd2Fy
+cmFudGllcyBhcmUgZGlzY2xhaW1lZCBhbmQgbGlhYmlsaXR5IGlzIGxpbWl0ZWQu
+IENvcGllcyBvZiB0aGUgQ1BTIGFyZSBhdmFpbGFibGUgYXQ6IGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbS9DUFM7IG9yIGJ5IG1haWwgYXQgVVNFUlRydXN0LCBJbmMu
+LCAyNjUgRWFzdCAxMDAgU291dGgsIFNhbHQgTGFrZSBDaXR5LCBVVCA4NDExMS4g
+Q29weXJpZ2h0KGMpIDIwMDIgVVNFUlRydXN0LCBJbmMuIEFsbCBSaWdodHMgUmVz
+ZXJ2ZWQuMA0GCSqGSIb3DQEBBQUAA4IBAQDPZpUYi6Nz5wSo+hbzYmBKJvG1N7PN
+etSdYz+h7lIwKZ56sue6oPm/T5VjY7upz8W5GL1q5YLNOr836pxXvNgg2L4ajPUA
+nq3EZtNgkt0iZmGISQwFcgUDnYJ4L56c84vXlreLS2xAD3rL+XeIE/d08OcxLpSB
+udQKfNEd84tM564hEkD5ah99qJbckBFqRNf89ZijW7xPUavbhGStaeaCvdllekRD
+ZYtppwGMlA1Lw74p74GpgAwzRtc3vkya4Ls/FZ7d7/R/cOkLX+MYp6SAi+GsHEYz
+55ACEUNhFU6X6sIkhFgxqDe0hL/AcKCV+WTJ0pSGXCFdUbPGsPQCy3ck
+-----END CERTIFICATE-----
diff --git a/samples/x509/x509_foo.pem b/samples/x509/x509_foo.pem
new file mode 100644
index 0000000..c7601e9
--- /dev/null
+++ b/samples/x509/x509_foo.pem
@@ -0,0 +1,85 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8c:fe:11:83:01:53:a6:90
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Dec 11 15:31:41 2006 GMT
+ Not After : Nov 5 15:31:41 2028 GMT
+ Subject: C=US, ST=Maryland, L=Forest Hill, O=httpcomponents, OU=test certificates, CN=foo.com/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c8:63:af:96:82:3e:8c:a9:d1:1d:62:ae:85:80:
+ 7e:71:32:04:c1:98:5a:80:a2:74:7f:7a:c8:63:c5:
+ 8d:82:e8:c1:ec:f9:69:82:98:d4:83:8a:4d:8d:81:
+ 95:88:68:e0:ef:38:5f:6e:38:42:b6:53:46:5f:24:
+ 41:b6:2d:c6:71:a1:e2:04:82:0f:e6:7c:82:36:7f:
+ 80:cb:cb:52:58:6a:39:bf:96:5c:f0:14:1c:c0:77:
+ f4:64:72:cd:ea:c0:fd:9b:6b:95:4a:9f:fa:52:a8:
+ d2:e5:9c:a1:cc:5e:45:ce:fb:d4:a3:7c:70:f1:f7:
+ 9c:76:74:ad:5d:07:c7:86:40:67:2e:94:e3:1c:4e:
+ 6d:ee:2b:b5:25:58:d3:b8:4d:29:70:1b:da:87:67:
+ 56:a8:33:71:88:83:90:b5:7c:8a:5b:c4:9a:83:56:
+ 31:6a:e9:f1:40:6a:91:37:29:12:16:21:09:8a:77:
+ 71:39:20:27:03:12:ba:ab:fc:06:a9:c6:77:ce:f1:
+ 41:4d:c5:55:92:38:b5:bb:64:07:e2:b3:8c:3f:73:
+ cf:c4:02:0c:90:1f:0e:36:47:47:4d:ca:35:0e:66:
+ c4:e8:17:c3:1c:0a:c3:a9:46:31:a8:95:25:3c:69:
+ 4c:aa:b2:9b:dd:f0:85:89:3d:de:5d:e8:70:47:b9:
+ e5:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 9F:14:77:BF:3F:3A:B6:CA:38:82:42:48:16:2C:DA:D0:CB:5E:87:D8
+ X509v3 Authority Key Identifier:
+ keyid:7B:9A:DA:8F:90:99:4E:52:D2:AC:DB:B3:03:52:CA:87:A6:0D:3E:0D
+
+ Signature Algorithm: sha1WithRSAEncryption
+ b7:8d:19:84:c9:ae:ac:40:29:26:89:e5:0b:72:fc:7c:cf:3d:
+ 5e:b8:29:3d:7d:27:b3:ec:11:2d:92:2f:3e:76:67:cc:5d:ed:
+ ca:ee:c1:f4:94:8f:1f:e2:32:51:d2:b6:d2:0a:3a:66:09:02:
+ d8:9b:30:b7:37:10:4a:78:93:96:d1:17:23:34:1a:4e:73:62:
+ 65:18:ef:5a:b9:7b:f6:18:33:f8:21:88:97:12:52:c9:e9:54:
+ aa:73:c5:af:0e:29:2f:d0:99:82:09:69:b4:66:06:be:6d:96:
+ d1:fc:45:8d:e4:37:84:b4:57:45:f3:5e:42:2e:92:59:35:c6:
+ 30:89:8c:06:cb:f0:95:43:bc:36:4e:75:e5:1b:e9:ab:69:93:
+ b3:fa:8c:2b:f9:c2:fa:27:f6:5e:b1:b7:44:59:f8:e8:4b:5f:
+ 9c:50:48:44:1f:09:4d:ac:0b:bc:8e:56:76:52:a4:a0:b2:44:
+ 96:96:16:1d:31:30:0f:f4:23:c7:89:4b:fd:37:b1:5c:4f:9f:
+ 08:b6:ff:c8:e1:f2:91:10:83:50:62:30:e9:bd:07:31:49:a4:
+ d8:6f:d7:6b:e6:c0:78:58:b3:60:96:4e:f3:c4:3b:4c:f3:41:
+ f9:d7:c5:6f:8a:14:dc:3f:b1:47:2f:e1:a7:ea:0e:23:e5:f9:
+ 08:f7:cf:92
+-----BEGIN CERTIFICATE-----
+MIIERjCCAy6gAwIBAgIJAIz+EYMBU6aQMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzE0MVoXDTI4MTEwNTE1MzE0MVowgaQx
+CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0
+IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl
+cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs
+aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B
+lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy
+zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY
+07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8
+BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV
+JTxpTKqym93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB
+hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE
+FJ8Ud78/OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNS
+yoemDT4NMA0GCSqGSIb3DQEBBQUAA4IBAQC3jRmEya6sQCkmieULcvx8zz1euCk9
+fSez7BEtki8+dmfMXe3K7sH0lI8f4jJR0rbSCjpmCQLYmzC3NxBKeJOW0RcjNBpO
+c2JlGO9auXv2GDP4IYiXElLJ6VSqc8WvDikv0JmCCWm0Zga+bZbR/EWN5DeEtFdF
+815CLpJZNcYwiYwGy/CVQ7w2TnXlG+mraZOz+owr+cL6J/ZesbdEWfjoS1+cUEhE
+HwlNrAu8jlZ2UqSgskSWlhYdMTAP9CPHiUv9N7FcT58Itv/I4fKREINQYjDpvQcx
+SaTYb9dr5sB4WLNglk7zxDtM80H518VvihTcP7FHL+Gn6g4j5fkI98+S
+-----END CERTIFICATE-----
diff --git a/samples/x509/x509_foo_bar.pem b/samples/x509/x509_foo_bar.pem
new file mode 100644
index 0000000..04c9ddc
--- /dev/null
+++ b/samples/x509/x509_foo_bar.pem
@@ -0,0 +1,88 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8c:fe:11:83:01:53:a6:91
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Dec 11 15:36:29 2006 GMT
+ Not After : Nov 5 15:36:29 2028 GMT
+ Subject: C=US, ST=Maryland, L=Forest Hill, O=httpcomponents, OU=test certificates, CN=foo.com/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c8:63:af:96:82:3e:8c:a9:d1:1d:62:ae:85:80:
+ 7e:71:32:04:c1:98:5a:80:a2:74:7f:7a:c8:63:c5:
+ 8d:82:e8:c1:ec:f9:69:82:98:d4:83:8a:4d:8d:81:
+ 95:88:68:e0:ef:38:5f:6e:38:42:b6:53:46:5f:24:
+ 41:b6:2d:c6:71:a1:e2:04:82:0f:e6:7c:82:36:7f:
+ 80:cb:cb:52:58:6a:39:bf:96:5c:f0:14:1c:c0:77:
+ f4:64:72:cd:ea:c0:fd:9b:6b:95:4a:9f:fa:52:a8:
+ d2:e5:9c:a1:cc:5e:45:ce:fb:d4:a3:7c:70:f1:f7:
+ 9c:76:74:ad:5d:07:c7:86:40:67:2e:94:e3:1c:4e:
+ 6d:ee:2b:b5:25:58:d3:b8:4d:29:70:1b:da:87:67:
+ 56:a8:33:71:88:83:90:b5:7c:8a:5b:c4:9a:83:56:
+ 31:6a:e9:f1:40:6a:91:37:29:12:16:21:09:8a:77:
+ 71:39:20:27:03:12:ba:ab:fc:06:a9:c6:77:ce:f1:
+ 41:4d:c5:55:92:38:b5:bb:64:07:e2:b3:8c:3f:73:
+ cf:c4:02:0c:90:1f:0e:36:47:47:4d:ca:35:0e:66:
+ c4:e8:17:c3:1c:0a:c3:a9:46:31:a8:95:25:3c:69:
+ 4c:aa:b2:9b:dd:f0:85:89:3d:de:5d:e8:70:47:b9:
+ e5:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 9F:14:77:BF:3F:3A:B6:CA:38:82:42:48:16:2C:DA:D0:CB:5E:87:D8
+ X509v3 Authority Key Identifier:
+ keyid:7B:9A:DA:8F:90:99:4E:52:D2:AC:DB:B3:03:52:CA:87:A6:0D:3E:0D
+
+ X509v3 Subject Alternative Name:
+ DNS:bar.com
+ Signature Algorithm: sha1WithRSAEncryption
+ 75:0c:a9:ac:d6:41:99:59:ef:b9:55:a3:57:8d:ac:7b:2f:cf:
+ 4d:f9:18:4a:12:70:cb:58:f4:fe:37:05:65:1f:f2:a5:95:28:
+ be:98:87:18:33:b5:0e:02:f7:63:72:0f:cd:54:36:ea:e8:54:
+ b1:2c:3a:1b:48:06:46:26:81:0d:ef:f4:2d:47:25:5d:9a:09:
+ cd:75:f5:aa:94:b9:e4:e6:9d:c5:6e:f7:6e:bc:e2:4b:4b:31:
+ 46:01:ab:64:4f:dd:de:0e:64:92:2a:3a:20:40:f8:ec:e3:fa:
+ c1:89:e5:99:9e:c4:28:ff:5c:aa:35:b0:96:7b:c7:9e:75:1c:
+ 67:64:ac:72:82:cd:62:cf:6b:37:d7:1c:a7:cb:6e:ab:66:f2:
+ f3:c3:b2:84:ac:06:8c:97:e1:3a:e7:6a:7d:33:59:70:3c:d1:
+ 1f:1e:05:ce:6e:d4:b1:56:b2:71:5c:38:b8:39:a1:10:72:6b:
+ 02:c9:8c:3e:98:ff:f9:74:4a:f7:fe:36:db:1a:be:f1:b7:3a:
+ 1e:88:dd:b5:b0:b2:ba:0f:df:bc:16:6f:66:a4:17:4a:65:3c:
+ 9b:c2:15:70:c9:96:33:3d:19:40:ef:1e:7b:74:24:04:73:19:
+ 7c:2c:bb:3f:f9:2b:55:b5:b1:fe:e1:13:22:65:2e:f8:d6:60:
+ db:67:b0:13
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgIJAIz+EYMBU6aRMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzYyOVoXDTI4MTEwNTE1MzYyOVowgaQx
+CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0
+IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl
+cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs
+aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B
+lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy
+zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY
+07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8
+BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV
+JTxpTKqym93whYk93l3ocEe55c0CAwEAAaOBkDCBjTAJBgNVHRMEAjAAMCwGCWCG
+SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E
+FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz
+A1LKh6YNPg0wEgYDVR0RBAswCYIHYmFyLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEA
+dQyprNZBmVnvuVWjV42sey/PTfkYShJwy1j0/jcFZR/ypZUovpiHGDO1DgL3Y3IP
+zVQ26uhUsSw6G0gGRiaBDe/0LUclXZoJzXX1qpS55OadxW73brziS0sxRgGrZE/d
+3g5kkio6IED47OP6wYnlmZ7EKP9cqjWwlnvHnnUcZ2SscoLNYs9rN9ccp8tuq2by
+88OyhKwGjJfhOudqfTNZcDzRHx4Fzm7UsVaycVw4uDmhEHJrAsmMPpj/+XRK9/42
+2xq+8bc6HojdtbCyug/fvBZvZqQXSmU8m8IVcMmWMz0ZQO8ee3QkBHMZfCy7P/kr
+VbWx/uETImUu+NZg22ewEw==
+-----END CERTIFICATE-----
diff --git a/samples/x509/x509_foo_bar_hanako.pem b/samples/x509/x509_foo_bar_hanako.pem
new file mode 100644
index 0000000..4e80578
--- /dev/null
+++ b/samples/x509/x509_foo_bar_hanako.pem
@@ -0,0 +1,88 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8c:fe:11:83:01:53:a6:92
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Dec 11 15:38:13 2006 GMT
+ Not After : Nov 5 15:38:13 2028 GMT
+ Subject: C=US, ST=Maryland, L=Forest Hill, O=httpcomponents, OU=test certificates, CN=foo.com/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c8:63:af:96:82:3e:8c:a9:d1:1d:62:ae:85:80:
+ 7e:71:32:04:c1:98:5a:80:a2:74:7f:7a:c8:63:c5:
+ 8d:82:e8:c1:ec:f9:69:82:98:d4:83:8a:4d:8d:81:
+ 95:88:68:e0:ef:38:5f:6e:38:42:b6:53:46:5f:24:
+ 41:b6:2d:c6:71:a1:e2:04:82:0f:e6:7c:82:36:7f:
+ 80:cb:cb:52:58:6a:39:bf:96:5c:f0:14:1c:c0:77:
+ f4:64:72:cd:ea:c0:fd:9b:6b:95:4a:9f:fa:52:a8:
+ d2:e5:9c:a1:cc:5e:45:ce:fb:d4:a3:7c:70:f1:f7:
+ 9c:76:74:ad:5d:07:c7:86:40:67:2e:94:e3:1c:4e:
+ 6d:ee:2b:b5:25:58:d3:b8:4d:29:70:1b:da:87:67:
+ 56:a8:33:71:88:83:90:b5:7c:8a:5b:c4:9a:83:56:
+ 31:6a:e9:f1:40:6a:91:37:29:12:16:21:09:8a:77:
+ 71:39:20:27:03:12:ba:ab:fc:06:a9:c6:77:ce:f1:
+ 41:4d:c5:55:92:38:b5:bb:64:07:e2:b3:8c:3f:73:
+ cf:c4:02:0c:90:1f:0e:36:47:47:4d:ca:35:0e:66:
+ c4:e8:17:c3:1c:0a:c3:a9:46:31:a8:95:25:3c:69:
+ 4c:aa:b2:9b:dd:f0:85:89:3d:de:5d:e8:70:47:b9:
+ e5:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 9F:14:77:BF:3F:3A:B6:CA:38:82:42:48:16:2C:DA:D0:CB:5E:87:D8
+ X509v3 Authority Key Identifier:
+ keyid:7B:9A:DA:8F:90:99:4E:52:D2:AC:DB:B3:03:52:CA:87:A6:0D:3E:0D
+
+ X509v3 Subject Alternative Name:
+ DNS:bar.com, DNS:花子.co.jp
+ Signature Algorithm: sha1WithRSAEncryption
+ 5e:66:ce:d9:21:8c:8a:b5:d9:d5:c5:5b:dd:2e:0c:32:48:43:
+ ce:13:8a:41:49:78:a2:ed:76:2f:d1:0f:50:52:f1:bf:fb:e8:
+ 05:19:08:7c:f4:78:40:07:30:35:99:55:23:1f:97:49:4d:0a:
+ 92:2c:5b:d1:7e:a4:c7:a8:ba:71:4b:14:96:a8:c1:e7:bd:13:
+ 38:70:f0:64:21:1a:7f:5e:53:0a:3e:55:da:75:8b:49:2c:f4:
+ e0:a5:b8:2f:ba:50:35:89:c9:02:f4:4c:25:35:85:a7:a3:06:
+ 78:bb:19:df:b0:c8:21:5b:81:ec:90:1a:9a:57:e3:e7:43:c6:
+ 6f:cb:72:f4:d7:67:3b:0a:0e:26:28:a4:b9:a5:bd:47:75:1b:
+ a2:0f:6a:29:67:e1:dc:ef:b8:11:40:bb:ed:58:d4:bc:8d:0b:
+ dd:fe:24:db:87:a7:ee:bd:32:9f:00:e1:68:5f:0d:b6:b1:62:
+ 0a:1d:8a:e6:84:22:11:b2:15:0d:a2:11:97:bf:9d:26:da:8f:
+ b5:c3:da:16:99:0e:83:92:ae:e5:0a:37:d7:7d:40:78:c0:86:
+ e0:80:98:e9:c8:4b:5b:36:a0:6d:8f:83:02:db:1e:6b:7e:c2:
+ ca:2a:a4:e8:2a:63:44:ee:91:44:82:ac:1e:f3:ff:c0:6a:bd:
+ 5b:f9:08:fe
+-----BEGIN CERTIFICATE-----
+MIIEajCCA1KgAwIBAgIJAIz+EYMBU6aSMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1MzgxM1oXDTI4MTEwNTE1MzgxM1owgaQx
+CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0
+IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl
+cnRpZmljYXRlczEQMA4GA1UEAxMHZm9vLmNvbTElMCMGCSqGSIb3DQEJARYWanVs
+aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B
+lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy
+zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY
+07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8
+BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV
+JTxpTKqym93whYk93l3ocEe55c0CAwEAAaOBnjCBmzAJBgNVHRMEAjAAMCwGCWCG
+SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E
+FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz
+A1LKh6YNPg0wIAYDVR0RBBkwF4IHYmFyLmNvbYIM6Iqx5a2QLmNvLmpwMA0GCSqG
+SIb3DQEBBQUAA4IBAQBeZs7ZIYyKtdnVxVvdLgwySEPOE4pBSXii7XYv0Q9QUvG/
+++gFGQh89HhABzA1mVUjH5dJTQqSLFvRfqTHqLpxSxSWqMHnvRM4cPBkIRp/XlMK
+PlXadYtJLPTgpbgvulA1ickC9EwlNYWnowZ4uxnfsMghW4HskBqaV+PnQ8Zvy3L0
+12c7Cg4mKKS5pb1HdRuiD2opZ+Hc77gRQLvtWNS8jQvd/iTbh6fuvTKfAOFoXw22
+sWIKHYrmhCIRshUNohGXv50m2o+1w9oWmQ6Dkq7lCjfXfUB4wIbggJjpyEtbNqBt
+j4MC2x5rfsLKKqToKmNE7pFEgqwe8//Aar1b+Qj+
+-----END CERTIFICATE-----
diff --git a/samples/x509/x509_hanako.pem b/samples/x509/x509_hanako.pem
new file mode 100644
index 0000000..548c546
--- /dev/null
+++ b/samples/x509/x509_hanako.pem
@@ -0,0 +1,85 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8c:fe:11:83:01:53:a6:93
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Dec 11 15:42:15 2006 GMT
+ Not After : Nov 5 15:42:15 2028 GMT
+ Subject: C=US, ST=Maryland, L=Forest Hill, O=httpcomponents, OU=test certificates, CN=\xE8\x8A\xB1\xE5\xAD\x90.co.jp/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c8:63:af:96:82:3e:8c:a9:d1:1d:62:ae:85:80:
+ 7e:71:32:04:c1:98:5a:80:a2:74:7f:7a:c8:63:c5:
+ 8d:82:e8:c1:ec:f9:69:82:98:d4:83:8a:4d:8d:81:
+ 95:88:68:e0:ef:38:5f:6e:38:42:b6:53:46:5f:24:
+ 41:b6:2d:c6:71:a1:e2:04:82:0f:e6:7c:82:36:7f:
+ 80:cb:cb:52:58:6a:39:bf:96:5c:f0:14:1c:c0:77:
+ f4:64:72:cd:ea:c0:fd:9b:6b:95:4a:9f:fa:52:a8:
+ d2:e5:9c:a1:cc:5e:45:ce:fb:d4:a3:7c:70:f1:f7:
+ 9c:76:74:ad:5d:07:c7:86:40:67:2e:94:e3:1c:4e:
+ 6d:ee:2b:b5:25:58:d3:b8:4d:29:70:1b:da:87:67:
+ 56:a8:33:71:88:83:90:b5:7c:8a:5b:c4:9a:83:56:
+ 31:6a:e9:f1:40:6a:91:37:29:12:16:21:09:8a:77:
+ 71:39:20:27:03:12:ba:ab:fc:06:a9:c6:77:ce:f1:
+ 41:4d:c5:55:92:38:b5:bb:64:07:e2:b3:8c:3f:73:
+ cf:c4:02:0c:90:1f:0e:36:47:47:4d:ca:35:0e:66:
+ c4:e8:17:c3:1c:0a:c3:a9:46:31:a8:95:25:3c:69:
+ 4c:aa:b2:9b:dd:f0:85:89:3d:de:5d:e8:70:47:b9:
+ e5:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 9F:14:77:BF:3F:3A:B6:CA:38:82:42:48:16:2C:DA:D0:CB:5E:87:D8
+ X509v3 Authority Key Identifier:
+ keyid:7B:9A:DA:8F:90:99:4E:52:D2:AC:DB:B3:03:52:CA:87:A6:0D:3E:0D
+
+ Signature Algorithm: sha1WithRSAEncryption
+ b2:76:ee:2d:e8:91:5f:ca:be:50:e9:e8:a3:08:0f:78:1d:21:
+ 39:7a:f0:fc:88:b7:3c:f1:f9:2a:ae:17:c8:1a:84:c8:74:d7:
+ a3:57:ef:7c:ff:a1:56:68:55:43:5d:7e:d9:5a:f3:03:d4:07:
+ 51:b0:22:40:27:1a:48:50:f4:b1:ca:b2:90:5d:6d:18:82:8f:
+ 48:0c:98:b0:ac:5f:c4:ab:8c:5b:eb:ed:c6:1b:d9:c2:ba:27:
+ f7:c9:7b:dd:a5:d6:d8:3f:ed:8e:28:ed:5f:ec:e0:90:5e:fd:
+ cc:bd:53:dc:3c:6b:47:2d:b8:39:84:04:28:02:ef:ce:09:30:
+ 3b:53:eb:b9:25:45:fa:ff:d8:b9:6a:5a:19:4e:12:ae:e9:50:
+ 5c:51:2d:b8:69:aa:e6:80:1d:23:a3:98:87:16:9d:5a:70:f4:
+ 1b:0e:ee:a7:b8:ea:18:9d:82:7d:fd:84:a8:75:5a:32:8a:d9:
+ 57:0b:ff:76:11:b0:2e:30:52:2d:0f:06:d1:56:e9:27:0c:0a:
+ e3:21:80:84:57:48:f5:39:e5:16:9e:50:89:4e:74:f8:e3:af:
+ 54:94:35:61:88:77:5a:c3:ed:6d:7a:49:ca:70:9e:49:e7:df:
+ 5d:05:37:11:4c:1d:52:34:19:31:85:90:d7:64:8a:53:42:14:
+ 97:08:a1:10
+-----BEGIN CERTIFICATE-----
+MIIESzCCAzOgAwIBAgIJAIz+EYMBU6aTMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE1NDIxNVoXDTI4MTEwNTE1NDIxNVowgakx
+CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0
+IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl
+cnRpZmljYXRlczEVMBMGA1UEAwwM6Iqx5a2QLmNvLmpwMSUwIwYJKoZIhvcNAQkB
+FhZqdWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjU
+g4pNjYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQc
+wHf0ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t
+7iu1JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAn
+AxK6q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArD
+qUYxqJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwG
+CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNV
+HQ4EFgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLS
+rNuzA1LKh6YNPg0wDQYJKoZIhvcNAQEFBQADggEBALJ27i3okV/KvlDp6KMID3gd
+ITl68PyItzzx+SquF8gahMh016NX73z/oVZoVUNdftla8wPUB1GwIkAnGkhQ9LHK
+spBdbRiCj0gMmLCsX8SrjFvr7cYb2cK6J/fJe92l1tg/7Y4o7V/s4JBe/cy9U9w8
+a0ctuDmEBCgC784JMDtT67klRfr/2LlqWhlOEq7pUFxRLbhpquaAHSOjmIcWnVpw
+9BsO7qe46hidgn39hKh1WjKK2VcL/3YRsC4wUi0PBtFW6ScMCuMhgIRXSPU55Rae
+UIlOdPjjr1SUNWGId1rD7W16Scpwnknn310FNxFMHVI0GTGFkNdkilNCFJcIoRA=
+-----END CERTIFICATE-----
diff --git a/samples/x509/x509_no_cns_foo.pem b/samples/x509/x509_no_cns_foo.pem
new file mode 100644
index 0000000..5e77ce4
--- /dev/null
+++ b/samples/x509/x509_no_cns_foo.pem
@@ -0,0 +1,87 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8c:fe:11:83:01:53:a6:98
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Dec 11 16:26:10 2006 GMT
+ Not After : Nov 5 16:26:10 2028 GMT
+ Subject: C=US, ST=Maryland, L=Forest Hill, O=httpcomponents, OU=test certificates/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c8:63:af:96:82:3e:8c:a9:d1:1d:62:ae:85:80:
+ 7e:71:32:04:c1:98:5a:80:a2:74:7f:7a:c8:63:c5:
+ 8d:82:e8:c1:ec:f9:69:82:98:d4:83:8a:4d:8d:81:
+ 95:88:68:e0:ef:38:5f:6e:38:42:b6:53:46:5f:24:
+ 41:b6:2d:c6:71:a1:e2:04:82:0f:e6:7c:82:36:7f:
+ 80:cb:cb:52:58:6a:39:bf:96:5c:f0:14:1c:c0:77:
+ f4:64:72:cd:ea:c0:fd:9b:6b:95:4a:9f:fa:52:a8:
+ d2:e5:9c:a1:cc:5e:45:ce:fb:d4:a3:7c:70:f1:f7:
+ 9c:76:74:ad:5d:07:c7:86:40:67:2e:94:e3:1c:4e:
+ 6d:ee:2b:b5:25:58:d3:b8:4d:29:70:1b:da:87:67:
+ 56:a8:33:71:88:83:90:b5:7c:8a:5b:c4:9a:83:56:
+ 31:6a:e9:f1:40:6a:91:37:29:12:16:21:09:8a:77:
+ 71:39:20:27:03:12:ba:ab:fc:06:a9:c6:77:ce:f1:
+ 41:4d:c5:55:92:38:b5:bb:64:07:e2:b3:8c:3f:73:
+ cf:c4:02:0c:90:1f:0e:36:47:47:4d:ca:35:0e:66:
+ c4:e8:17:c3:1c:0a:c3:a9:46:31:a8:95:25:3c:69:
+ 4c:aa:b2:9b:dd:f0:85:89:3d:de:5d:e8:70:47:b9:
+ e5:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 9F:14:77:BF:3F:3A:B6:CA:38:82:42:48:16:2C:DA:D0:CB:5E:87:D8
+ X509v3 Authority Key Identifier:
+ keyid:7B:9A:DA:8F:90:99:4E:52:D2:AC:DB:B3:03:52:CA:87:A6:0D:3E:0D
+
+ X509v3 Subject Alternative Name:
+ DNS:foo.com
+ Signature Algorithm: sha1WithRSAEncryption
+ 8e:5e:fc:a0:c8:f3:15:db:0c:cb:a1:75:b0:68:3f:22:43:bc:
+ b4:5e:72:52:03:e0:15:8a:ec:e3:5c:b3:01:c6:bb:21:0b:ba:
+ 1b:da:ad:14:32:73:ff:b7:a1:87:ff:47:a0:6f:a8:a8:20:88:
+ 1c:fb:88:3a:64:bb:49:dd:30:9e:4c:89:63:b6:34:e2:35:57:
+ 21:bd:da:e9:fe:80:80:19:04:14:fd:67:39:3d:33:ea:48:d3:
+ ee:f9:00:e4:b2:76:cb:73:22:0d:c5:ee:44:d3:12:b5:ae:4f:
+ 61:59:eb:5f:c6:99:ca:2a:95:50:d8:b8:d2:97:ae:67:64:7c:
+ 98:05:12:06:f5:a0:0f:bc:f6:a9:68:45:f1:88:03:6f:bc:16:
+ 68:58:e0:e7:72:37:ea:f5:8a:9f:dd:19:12:d8:b7:c0:d0:b0:
+ a8:05:6a:8b:13:3e:27:4a:89:99:04:ad:80:07:39:de:2d:9a:
+ 4c:cb:c0:42:ed:c0:de:c9:ef:1f:f3:c7:4c:1a:3e:e5:42:fb:
+ da:7f:52:d6:46:72:34:2b:15:7f:54:28:9f:c8:ca:4e:24:6b:
+ 88:43:3e:7c:c1:65:72:04:0f:db:ce:04:04:5c:d8:1f:20:97:
+ 15:bf:4e:fe:13:23:2b:6f:ba:99:8f:5e:b8:c0:75:53:56:85:
+ 17:33:3f:06
+-----BEGIN CERTIFICATE-----
+MIIESjCCAzKgAwIBAgIJAIz+EYMBU6aYMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MjYxMFoXDTI4MTEwNTE2MjYxMFowgZIx
+CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0
+IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl
+cnRpZmljYXRlczElMCMGCSqGSIb3DQEJARYWanVsaXVzZGF2aWVzQGdtYWlsLmNv
+bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMhjr5aCPoyp0R1iroWA
+fnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2BlYho4O84X244QrZTRl8kQbYt
+xnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRyzerA/ZtrlUqf+lKo0uWcocxe
+Rc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY07hNKXAb2odnVqgzcYiDkLV8
+ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8BqnGd87xQU3FVZI4tbtkB+Kz
+jD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiVJTxpTKqym93whYk93l3ocEe5
+5c0CAwEAAaOBkDCBjTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1PcGVuU1NM
+IEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUnxR3vz86tso4gkJIFiza
+0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuzA1LKh6YNPg0wEgYDVR0RBAsw
+CYIHZm9vLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAjl78oMjzFdsMy6F1sGg/IkO8
+tF5yUgPgFYrs41yzAca7IQu6G9qtFDJz/7ehh/9HoG+oqCCIHPuIOmS7Sd0wnkyJ
+Y7Y04jVXIb3a6f6AgBkEFP1nOT0z6kjT7vkA5LJ2y3MiDcXuRNMSta5PYVnrX8aZ
+yiqVUNi40peuZ2R8mAUSBvWgD7z2qWhF8YgDb7wWaFjg53I36vWKn90ZEti3wNCw
+qAVqixM+J0qJmQStgAc53i2aTMvAQu3A3snvH/PHTBo+5UL72n9S1kZyNCsVf1Qo
+n8jKTiRriEM+fMFlcgQP284EBFzYHyCXFb9O/hMjK2+6mY9euMB1U1aFFzM/Bg==
+-----END CERTIFICATE-----
diff --git a/samples/x509/x509_three_cns_foo_bar_hanako.pem b/samples/x509/x509_three_cns_foo_bar_hanako.pem
new file mode 100644
index 0000000..a57ef79
--- /dev/null
+++ b/samples/x509/x509_three_cns_foo_bar_hanako.pem
@@ -0,0 +1,86 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8c:fe:11:83:01:53:a6:97
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Dec 11 16:19:45 2006 GMT
+ Not After : Nov 5 16:19:45 2028 GMT
+ Subject: C=US, ST=Maryland, L=Forest Hill, O=httpcomponents, OU=test certificates, CN=foo.com, CN=bar.com, CN=\xE8\x8A\xB1\xE5\xAD\x90.co.jp/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c8:63:af:96:82:3e:8c:a9:d1:1d:62:ae:85:80:
+ 7e:71:32:04:c1:98:5a:80:a2:74:7f:7a:c8:63:c5:
+ 8d:82:e8:c1:ec:f9:69:82:98:d4:83:8a:4d:8d:81:
+ 95:88:68:e0:ef:38:5f:6e:38:42:b6:53:46:5f:24:
+ 41:b6:2d:c6:71:a1:e2:04:82:0f:e6:7c:82:36:7f:
+ 80:cb:cb:52:58:6a:39:bf:96:5c:f0:14:1c:c0:77:
+ f4:64:72:cd:ea:c0:fd:9b:6b:95:4a:9f:fa:52:a8:
+ d2:e5:9c:a1:cc:5e:45:ce:fb:d4:a3:7c:70:f1:f7:
+ 9c:76:74:ad:5d:07:c7:86:40:67:2e:94:e3:1c:4e:
+ 6d:ee:2b:b5:25:58:d3:b8:4d:29:70:1b:da:87:67:
+ 56:a8:33:71:88:83:90:b5:7c:8a:5b:c4:9a:83:56:
+ 31:6a:e9:f1:40:6a:91:37:29:12:16:21:09:8a:77:
+ 71:39:20:27:03:12:ba:ab:fc:06:a9:c6:77:ce:f1:
+ 41:4d:c5:55:92:38:b5:bb:64:07:e2:b3:8c:3f:73:
+ cf:c4:02:0c:90:1f:0e:36:47:47:4d:ca:35:0e:66:
+ c4:e8:17:c3:1c:0a:c3:a9:46:31:a8:95:25:3c:69:
+ 4c:aa:b2:9b:dd:f0:85:89:3d:de:5d:e8:70:47:b9:
+ e5:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 9F:14:77:BF:3F:3A:B6:CA:38:82:42:48:16:2C:DA:D0:CB:5E:87:D8
+ X509v3 Authority Key Identifier:
+ keyid:7B:9A:DA:8F:90:99:4E:52:D2:AC:DB:B3:03:52:CA:87:A6:0D:3E:0D
+
+ Signature Algorithm: sha1WithRSAEncryption
+ 6b:99:6f:c6:a2:d4:d3:b6:8f:8b:f7:cb:d4:cb:66:f7:79:b3:
+ 4b:e1:e7:f4:c4:ee:7e:d1:5f:ef:14:cb:7e:ce:2f:99:3b:c7:
+ d9:ed:d2:63:35:4f:20:0a:c6:50:9c:63:ef:61:e9:fa:ee:7b:
+ c3:1e:99:92:08:2d:22:2f:32:bb:73:71:ca:8d:cf:45:75:58:
+ a8:00:f8:ea:df:b9:4a:da:6e:69:fe:0b:11:c5:e6:0a:72:ea:
+ 0d:50:b3:62:23:55:85:80:e5:fe:c5:44:e9:ff:27:e0:1d:f2:
+ 02:58:73:56:b3:39:60:8b:42:a4:b2:7e:93:51:2d:2b:d8:12:
+ b8:90:14:45:7a:dd:7b:e4:27:c2:6b:1b:ad:9b:fb:63:93:da:
+ 5a:93:e0:e3:b4:ee:04:8f:7a:da:69:76:54:9a:f0:d0:52:28:
+ fe:80:ae:8f:51:21:7d:59:8d:46:50:4a:94:05:09:fa:34:d8:
+ d3:b4:b8:d4:43:3d:47:49:c7:68:6e:c9:c7:4d:6f:e0:17:1d:
+ a3:bb:79:77:af:0c:b2:7e:42:7a:88:98:8c:f1:5a:26:3a:cc:
+ b3:9d:ce:38:c8:54:13:24:2c:79:a7:3f:b4:a3:19:24:37:5c:
+ 0e:01:ca:b4:0e:c5:f3:94:4f:22:f2:13:b3:6e:7a:68:47:a6:
+ 9b:90:3f:11
+-----BEGIN CERTIFICATE-----
+MIIEbzCCA1egAwIBAgIJAIz+EYMBU6aXMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTk0NVoXDTI4MTEwNTE2MTk0NVowgc0x
+CzAJBgNVBAYTAlVTMREwDwYDVQQIDAhNYXJ5bGFuZDEUMBIGA1UEBwwLRm9yZXN0
+IEhpbGwxFzAVBgNVBAoMDmh0dHBjb21wb25lbnRzMRowGAYDVQQLDBF0ZXN0IGNl
+cnRpZmljYXRlczEQMA4GA1UEAwwHZm9vLmNvbTEQMA4GA1UEAwwHYmFyLmNvbTEV
+MBMGA1UEAwwM6Iqx5a2QLmNvLmpwMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyGOv
+loI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pNjYGViGjg7zhf
+bjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0ZHLN6sD9m2uV
+Sp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1JVjTuE0pcBva
+h2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6q/wGqcZ3zvFB
+TcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYxqJUlPGlMqrKb
+3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQf
+Fh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUnxR3vz86
+tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuzA1LKh6YNPg0w
+DQYJKoZIhvcNAQEFBQADggEBAGuZb8ai1NO2j4v3y9TLZvd5s0vh5/TE7n7RX+8U
+y37OL5k7x9nt0mM1TyAKxlCcY+9h6frue8MemZIILSIvMrtzccqNz0V1WKgA+Orf
+uUrabmn+CxHF5gpy6g1Qs2IjVYWA5f7FROn/J+Ad8gJYc1azOWCLQqSyfpNRLSvY
+EriQFEV63XvkJ8JrG62b+2OT2lqT4OO07gSPetppdlSa8NBSKP6Aro9RIX1ZjUZQ
+SpQFCfo02NO0uNRDPUdJx2huycdNb+AXHaO7eXevDLJ+QnqImIzxWiY6zLOdzjjI
+VBMkLHmnP7SjGSQ3XA4ByrQOxfOUTyLyE7NuemhHppuQPxE=
+-----END CERTIFICATE-----
diff --git a/samples/x509/x509_wild_co_jp.pem b/samples/x509/x509_wild_co_jp.pem
new file mode 100644
index 0000000..1dc9ae7
--- /dev/null
+++ b/samples/x509/x509_wild_co_jp.pem
@@ -0,0 +1,85 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8c:fe:11:83:01:53:a6:95
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Dec 11 16:16:30 2006 GMT
+ Not After : Nov 5 16:16:30 2028 GMT
+ Subject: C=US, ST=Maryland, L=Forest Hill, O=httpcomponents, OU=test certificates, CN=*.co.jp/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c8:63:af:96:82:3e:8c:a9:d1:1d:62:ae:85:80:
+ 7e:71:32:04:c1:98:5a:80:a2:74:7f:7a:c8:63:c5:
+ 8d:82:e8:c1:ec:f9:69:82:98:d4:83:8a:4d:8d:81:
+ 95:88:68:e0:ef:38:5f:6e:38:42:b6:53:46:5f:24:
+ 41:b6:2d:c6:71:a1:e2:04:82:0f:e6:7c:82:36:7f:
+ 80:cb:cb:52:58:6a:39:bf:96:5c:f0:14:1c:c0:77:
+ f4:64:72:cd:ea:c0:fd:9b:6b:95:4a:9f:fa:52:a8:
+ d2:e5:9c:a1:cc:5e:45:ce:fb:d4:a3:7c:70:f1:f7:
+ 9c:76:74:ad:5d:07:c7:86:40:67:2e:94:e3:1c:4e:
+ 6d:ee:2b:b5:25:58:d3:b8:4d:29:70:1b:da:87:67:
+ 56:a8:33:71:88:83:90:b5:7c:8a:5b:c4:9a:83:56:
+ 31:6a:e9:f1:40:6a:91:37:29:12:16:21:09:8a:77:
+ 71:39:20:27:03:12:ba:ab:fc:06:a9:c6:77:ce:f1:
+ 41:4d:c5:55:92:38:b5:bb:64:07:e2:b3:8c:3f:73:
+ cf:c4:02:0c:90:1f:0e:36:47:47:4d:ca:35:0e:66:
+ c4:e8:17:c3:1c:0a:c3:a9:46:31:a8:95:25:3c:69:
+ 4c:aa:b2:9b:dd:f0:85:89:3d:de:5d:e8:70:47:b9:
+ e5:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 9F:14:77:BF:3F:3A:B6:CA:38:82:42:48:16:2C:DA:D0:CB:5E:87:D8
+ X509v3 Authority Key Identifier:
+ keyid:7B:9A:DA:8F:90:99:4E:52:D2:AC:DB:B3:03:52:CA:87:A6:0D:3E:0D
+
+ Signature Algorithm: sha1WithRSAEncryption
+ 34:b1:68:25:56:53:31:db:33:46:bd:4a:85:0b:bd:d7:b5:11:
+ 30:8a:2e:77:09:f3:0c:ea:6b:5f:db:e7:f7:93:f7:7c:29:78:
+ 4b:37:24:ab:83:c4:51:94:dd:75:ce:09:a9:3d:a2:ed:6d:d4:
+ cb:ae:61:b8:51:d0:07:1d:8a:fc:3b:8c:b6:04:19:84:d5:cc:
+ 4d:7c:6c:71:79:c8:60:17:c1:d7:d7:44:15:e1:d9:32:ce:9e:
+ 99:d5:c7:f0:bc:27:8c:ad:3e:46:fd:5d:69:7a:36:a0:a3:46:
+ b2:5f:1f:86:3c:b6:d6:94:d7:99:4b:e2:a5:d2:6d:e9:f9:0a:
+ 65:5e:e8:ed:c0:6e:5f:61:c2:29:68:6a:62:62:b6:81:2f:1d:
+ d3:69:d8:a1:df:d4:0d:eb:90:a7:02:1f:f3:44:38:4b:09:4c:
+ ca:ca:df:65:50:63:cb:11:40:f3:44:73:0f:1c:b9:d2:a9:3d:
+ 67:e5:45:39:50:34:72:b5:b8:c9:3d:7c:c5:fa:5f:fe:59:92:
+ 2c:6a:77:9f:58:bb:31:9e:48:00:b9:97:bf:a0:c3:05:10:93:
+ 2b:c8:4c:ce:8e:0e:13:7e:e7:39:a8:cd:04:5e:83:dc:43:f2:
+ 65:85:e6:b1:67:8d:29:d8:8c:87:a9:bb:16:57:83:11:62:e1:
+ 47:e1:b9:0c
+-----BEGIN CERTIFICATE-----
+MIIERjCCAy6gAwIBAgIJAIz+EYMBU6aVMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTYzMFoXDTI4MTEwNTE2MTYzMFowgaQx
+CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0
+IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl
+cnRpZmljYXRlczEQMA4GA1UEAxQHKi5jby5qcDElMCMGCSqGSIb3DQEJARYWanVs
+aXVzZGF2aWVzQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAMhjr5aCPoyp0R1iroWAfnEyBMGYWoCidH96yGPFjYLowez5aYKY1IOKTY2B
+lYho4O84X244QrZTRl8kQbYtxnGh4gSCD+Z8gjZ/gMvLUlhqOb+WXPAUHMB39GRy
+zerA/ZtrlUqf+lKo0uWcocxeRc771KN8cPH3nHZ0rV0Hx4ZAZy6U4xxObe4rtSVY
+07hNKXAb2odnVqgzcYiDkLV8ilvEmoNWMWrp8UBqkTcpEhYhCYp3cTkgJwMSuqv8
+BqnGd87xQU3FVZI4tbtkB+KzjD9zz8QCDJAfDjZHR03KNQ5mxOgXwxwKw6lGMaiV
+JTxpTKqym93whYk93l3ocEe55c0CAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB
+hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE
+FJ8Ud78/OrbKOIJCSBYs2tDLXofYMB8GA1UdIwQYMBaAFHua2o+QmU5S0qzbswNS
+yoemDT4NMA0GCSqGSIb3DQEBBQUAA4IBAQA0sWglVlMx2zNGvUqFC73XtREwii53
+CfMM6mtf2+f3k/d8KXhLNySrg8RRlN11zgmpPaLtbdTLrmG4UdAHHYr8O4y2BBmE
+1cxNfGxxechgF8HX10QV4dkyzp6Z1cfwvCeMrT5G/V1pejago0ayXx+GPLbWlNeZ
+S+Kl0m3p+QplXujtwG5fYcIpaGpiYraBLx3Tadih39QN65CnAh/zRDhLCUzKyt9l
+UGPLEUDzRHMPHLnSqT1n5UU5UDRytbjJPXzF+l/+WZIsanefWLsxnkgAuZe/oMMF
+EJMryEzOjg4Tfuc5qM0EXoPcQ/JlheaxZ40p2IyHqbsWV4MRYuFH4bkM
+-----END CERTIFICATE-----
diff --git a/samples/x509/x509_wild_foo.pem b/samples/x509/x509_wild_foo.pem
new file mode 100644
index 0000000..62ecdf3
--- /dev/null
+++ b/samples/x509/x509_wild_foo.pem
@@ -0,0 +1,85 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8c:fe:11:83:01:53:a6:94
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Dec 11 16:15:55 2006 GMT
+ Not After : Nov 5 16:15:55 2028 GMT
+ Subject: C=US, ST=Maryland, L=Forest Hill, O=httpcomponents, OU=test certificates, CN=*.foo.com/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c8:63:af:96:82:3e:8c:a9:d1:1d:62:ae:85:80:
+ 7e:71:32:04:c1:98:5a:80:a2:74:7f:7a:c8:63:c5:
+ 8d:82:e8:c1:ec:f9:69:82:98:d4:83:8a:4d:8d:81:
+ 95:88:68:e0:ef:38:5f:6e:38:42:b6:53:46:5f:24:
+ 41:b6:2d:c6:71:a1:e2:04:82:0f:e6:7c:82:36:7f:
+ 80:cb:cb:52:58:6a:39:bf:96:5c:f0:14:1c:c0:77:
+ f4:64:72:cd:ea:c0:fd:9b:6b:95:4a:9f:fa:52:a8:
+ d2:e5:9c:a1:cc:5e:45:ce:fb:d4:a3:7c:70:f1:f7:
+ 9c:76:74:ad:5d:07:c7:86:40:67:2e:94:e3:1c:4e:
+ 6d:ee:2b:b5:25:58:d3:b8:4d:29:70:1b:da:87:67:
+ 56:a8:33:71:88:83:90:b5:7c:8a:5b:c4:9a:83:56:
+ 31:6a:e9:f1:40:6a:91:37:29:12:16:21:09:8a:77:
+ 71:39:20:27:03:12:ba:ab:fc:06:a9:c6:77:ce:f1:
+ 41:4d:c5:55:92:38:b5:bb:64:07:e2:b3:8c:3f:73:
+ cf:c4:02:0c:90:1f:0e:36:47:47:4d:ca:35:0e:66:
+ c4:e8:17:c3:1c:0a:c3:a9:46:31:a8:95:25:3c:69:
+ 4c:aa:b2:9b:dd:f0:85:89:3d:de:5d:e8:70:47:b9:
+ e5:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 9F:14:77:BF:3F:3A:B6:CA:38:82:42:48:16:2C:DA:D0:CB:5E:87:D8
+ X509v3 Authority Key Identifier:
+ keyid:7B:9A:DA:8F:90:99:4E:52:D2:AC:DB:B3:03:52:CA:87:A6:0D:3E:0D
+
+ Signature Algorithm: sha1WithRSAEncryption
+ 7d:22:a4:6e:89:e7:ad:54:29:47:e0:91:e5:bb:1a:f6:30:5b:
+ df:01:37:56:68:a1:65:fe:24:41:19:2b:bf:8f:7f:ff:7a:77:
+ 72:23:d2:bc:3d:00:27:cd:e1:ba:5f:9c:2a:b4:55:43:59:55:
+ 26:01:f8:6b:61:43:6c:d8:bb:3e:ed:7f:f5:18:03:a9:f1:56:
+ 04:7f:22:31:ba:f4:19:ac:06:5f:76:b8:53:bb:25:33:6d:1f:
+ 3b:6e:88:fa:81:9f:9f:69:b7:eb:cd:c7:8c:8f:be:7a:3b:ce:
+ 6c:6c:7c:8e:e3:bf:4c:30:c9:fb:3e:d0:53:66:ec:5c:1d:b0:
+ 2d:64:e3:b1:81:48:e6:86:c3:7f:24:b8:85:56:a9:74:80:6c:
+ be:04:5f:d1:a4:af:21:86:38:a1:8d:87:4a:af:00:43:42:75:
+ 14:81:1b:d6:7a:b7:23:1b:99:f4:58:f9:d2:d2:87:76:bd:27:
+ 0a:04:70:15:2c:a3:a1:16:60:16:a4:2d:ba:b8:9c:6f:e7:bd:
+ 87:58:bc:6f:5e:86:b9:cb:57:06:45:2f:cd:9e:97:74:3f:44:
+ af:79:6e:70:3a:72:e4:42:94:6b:ac:2d:a7:74:7b:a6:e3:90:
+ 1c:f1:fd:54:37:55:aa:c3:12:90:24:4c:b5:06:54:06:b4:08:
+ b5:ed:9f:27
+-----BEGIN CERTIFICATE-----
+MIIESDCCAzCgAwIBAgIJAIz+EYMBU6aUMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTU1NVoXDTI4MTEwNTE2MTU1NVowgaYx
+CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0
+IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl
+cnRpZmljYXRlczESMBAGA1UEAxQJKi5mb28uY29tMSUwIwYJKoZIhvcNAQkBFhZq
+dWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pN
+jYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0
+ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1
+JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6
+q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYx
+qJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCG
+SAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4E
+FgQUnxR3vz86tso4gkJIFiza0Mteh9gwHwYDVR0jBBgwFoAUe5raj5CZTlLSrNuz
+A1LKh6YNPg0wDQYJKoZIhvcNAQEFBQADggEBAH0ipG6J561UKUfgkeW7GvYwW98B
+N1ZooWX+JEEZK7+Pf/96d3Ij0rw9ACfN4bpfnCq0VUNZVSYB+GthQ2zYuz7tf/UY
+A6nxVgR/IjG69BmsBl92uFO7JTNtHztuiPqBn59pt+vNx4yPvno7zmxsfI7jv0ww
+yfs+0FNm7FwdsC1k47GBSOaGw38kuIVWqXSAbL4EX9GkryGGOKGNh0qvAENCdRSB
+G9Z6tyMbmfRY+dLSh3a9JwoEcBUso6EWYBakLbq4nG/nvYdYvG9ehrnLVwZFL82e
+l3Q/RK95bnA6cuRClGusLad0e6bjkBzx/VQ3VarDEpAkTLUGVAa0CLXtnyc=
+-----END CERTIFICATE-----
diff --git a/samples/x509/x509_wild_foo_bar_hanako.pem b/samples/x509/x509_wild_foo_bar_hanako.pem
new file mode 100644
index 0000000..2c751b7
--- /dev/null
+++ b/samples/x509/x509_wild_foo_bar_hanako.pem
@@ -0,0 +1,88 @@
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 8c:fe:11:83:01:53:a6:96
+ Signature Algorithm: sha1WithRSAEncryption
+ Issuer: C=CA, ST=BC, L=Vancouver, O=www.cucbc.com, OU=commons_ssl, CN=demo_intermediate_ca/emailAddress=juliusdavies at gmail.com
+ Validity
+ Not Before: Dec 11 16:17:31 2006 GMT
+ Not After : Nov 5 16:17:31 2028 GMT
+ Subject: C=US, ST=Maryland, L=Forest Hill, O=httpcomponents, OU=test certificates, CN=*.foo.com/emailAddress=juliusdavies at gmail.com
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public Key: (2048 bit)
+ Modulus (2048 bit):
+ 00:c8:63:af:96:82:3e:8c:a9:d1:1d:62:ae:85:80:
+ 7e:71:32:04:c1:98:5a:80:a2:74:7f:7a:c8:63:c5:
+ 8d:82:e8:c1:ec:f9:69:82:98:d4:83:8a:4d:8d:81:
+ 95:88:68:e0:ef:38:5f:6e:38:42:b6:53:46:5f:24:
+ 41:b6:2d:c6:71:a1:e2:04:82:0f:e6:7c:82:36:7f:
+ 80:cb:cb:52:58:6a:39:bf:96:5c:f0:14:1c:c0:77:
+ f4:64:72:cd:ea:c0:fd:9b:6b:95:4a:9f:fa:52:a8:
+ d2:e5:9c:a1:cc:5e:45:ce:fb:d4:a3:7c:70:f1:f7:
+ 9c:76:74:ad:5d:07:c7:86:40:67:2e:94:e3:1c:4e:
+ 6d:ee:2b:b5:25:58:d3:b8:4d:29:70:1b:da:87:67:
+ 56:a8:33:71:88:83:90:b5:7c:8a:5b:c4:9a:83:56:
+ 31:6a:e9:f1:40:6a:91:37:29:12:16:21:09:8a:77:
+ 71:39:20:27:03:12:ba:ab:fc:06:a9:c6:77:ce:f1:
+ 41:4d:c5:55:92:38:b5:bb:64:07:e2:b3:8c:3f:73:
+ cf:c4:02:0c:90:1f:0e:36:47:47:4d:ca:35:0e:66:
+ c4:e8:17:c3:1c:0a:c3:a9:46:31:a8:95:25:3c:69:
+ 4c:aa:b2:9b:dd:f0:85:89:3d:de:5d:e8:70:47:b9:
+ e5:cd
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Basic Constraints:
+ CA:FALSE
+ Netscape Comment:
+ OpenSSL Generated Certificate
+ X509v3 Subject Key Identifier:
+ 9F:14:77:BF:3F:3A:B6:CA:38:82:42:48:16:2C:DA:D0:CB:5E:87:D8
+ X509v3 Authority Key Identifier:
+ keyid:7B:9A:DA:8F:90:99:4E:52:D2:AC:DB:B3:03:52:CA:87:A6:0D:3E:0D
+
+ X509v3 Subject Alternative Name:
+ DNS:*.bar.com, DNS:*.花子.co.jp
+ Signature Algorithm: sha1WithRSAEncryption
+ 68:6d:60:be:0f:9f:e5:c7:a6:21:5f:ae:02:c1:9d:ba:5c:b8:
+ f1:68:4d:12:e3:5e:5a:8d:b0:6a:0c:ae:e5:cf:e4:60:ef:33:
+ 84:dc:6b:13:00:c8:be:95:d5:18:9e:1c:b3:d3:00:e2:5c:1f:
+ 14:c0:a5:e5:d1:20:d3:a0:1d:99:e0:63:a0:a9:08:c0:aa:83:
+ 26:ac:fd:2e:58:1e:98:e9:da:64:7d:dd:6a:0d:15:33:23:5d:
+ b4:cc:f6:20:49:db:17:8c:75:bd:ab:61:fb:ee:25:76:df:c8:
+ 6a:21:4e:ea:0a:f1:33:fa:57:ea:a9:61:18:e7:4e:33:85:83:
+ 65:92:76:d4:9d:1e:76:e4:8b:68:b0:45:70:5c:50:49:4e:46:
+ 77:63:0f:20:83:4d:9c:d7:dc:a2:f1:30:21:e4:b8:b7:01:df:
+ 17:42:69:92:24:c5:81:57:85:ca:a8:5a:f4:00:86:4a:06:58:
+ 3a:35:96:45:7f:fd:1d:3f:dc:dc:2a:1c:d2:ae:25:b6:ed:b6:
+ 34:5d:fc:c0:e8:64:a2:44:35:eb:0e:38:17:ab:a6:da:45:3e:
+ 98:c2:02:20:a6:02:6c:0d:b2:6d:65:f1:e7:57:59:dd:dc:ce:
+ b3:3a:d4:0f:9b:54:c8:42:93:66:30:c3:1d:fc:33:eb:19:c5:
+ 10:7a:b0:f7
+-----BEGIN CERTIFICATE-----
+MIIEcDCCA1igAwIBAgIJAIz+EYMBU6aWMA0GCSqGSIb3DQEBBQUAMIGiMQswCQYD
+VQQGEwJDQTELMAkGA1UECBMCQkMxEjAQBgNVBAcTCVZhbmNvdXZlcjEWMBQGA1UE
+ChMNd3d3LmN1Y2JjLmNvbTEUMBIGA1UECxQLY29tbW9uc19zc2wxHTAbBgNVBAMU
+FGRlbW9faW50ZXJtZWRpYXRlX2NhMSUwIwYJKoZIhvcNAQkBFhZqdWxpdXNkYXZp
+ZXNAZ21haWwuY29tMB4XDTA2MTIxMTE2MTczMVoXDTI4MTEwNTE2MTczMVowgaYx
+CzAJBgNVBAYTAlVTMREwDwYDVQQIEwhNYXJ5bGFuZDEUMBIGA1UEBxMLRm9yZXN0
+IEhpbGwxFzAVBgNVBAoTDmh0dHBjb21wb25lbnRzMRowGAYDVQQLExF0ZXN0IGNl
+cnRpZmljYXRlczESMBAGA1UEAxQJKi5mb28uY29tMSUwIwYJKoZIhvcNAQkBFhZq
+dWxpdXNkYXZpZXNAZ21haWwuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAyGOvloI+jKnRHWKuhYB+cTIEwZhagKJ0f3rIY8WNgujB7PlpgpjUg4pN
+jYGViGjg7zhfbjhCtlNGXyRBti3GcaHiBIIP5nyCNn+Ay8tSWGo5v5Zc8BQcwHf0
+ZHLN6sD9m2uVSp/6UqjS5ZyhzF5FzvvUo3xw8fecdnStXQfHhkBnLpTjHE5t7iu1
+JVjTuE0pcBvah2dWqDNxiIOQtXyKW8Sag1YxaunxQGqRNykSFiEJindxOSAnAxK6
+q/wGqcZ3zvFBTcVVkji1u2QH4rOMP3PPxAIMkB8ONkdHTco1DmbE6BfDHArDqUYx
+qJUlPGlMqrKb3fCFiT3eXehwR7nlzQIDAQABo4GiMIGfMAkGA1UdEwQCMAAwLAYJ
+YIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1Ud
+DgQWBBSfFHe/Pzq2yjiCQkgWLNrQy16H2DAfBgNVHSMEGDAWgBR7mtqPkJlOUtKs
+27MDUsqHpg0+DTAkBgNVHREEHTAbggkqLmJhci5jb22CDiou6Iqx5a2QLmNvLmpw
+MA0GCSqGSIb3DQEBBQUAA4IBAQBobWC+D5/lx6YhX64CwZ26XLjxaE0S415ajbBq
+DK7lz+Rg7zOE3GsTAMi+ldUYnhyz0wDiXB8UwKXl0SDToB2Z4GOgqQjAqoMmrP0u
+WB6Y6dpkfd1qDRUzI120zPYgSdsXjHW9q2H77iV238hqIU7qCvEz+lfqqWEY504z
+hYNlknbUnR525ItosEVwXFBJTkZ3Yw8gg02c19yi8TAh5Li3Ad8XQmmSJMWBV4XK
+qFr0AIZKBlg6NZZFf/0dP9zcKhzSriW27bY0XfzA6GSiRDXrDjgXq6baRT6YwgIg
+pgJsDbJtZfHnV1nd3M6zOtQPm1TIQpNmMMMd/DPrGcUQerD3
+-----END CERTIFICATE-----
diff --git a/src/java/org/apache/commons/httpclient/contrib/ssl/AuthSSLProtocolSocketFactory.java b/src/java/org/apache/commons/httpclient/contrib/ssl/AuthSSLProtocolSocketFactory.java
new file mode 100644
index 0000000..03bf14e
--- /dev/null
+++ b/src/java/org/apache/commons/httpclient/contrib/ssl/AuthSSLProtocolSocketFactory.java
@@ -0,0 +1,196 @@
+/*
+ * $Header$
+ * $Revision: 129 $
+ * $Date: 2007-11-14 19:21:33 -0800 (Wed, 14 Nov 2007) $
+ *
+ * ====================================================================
+ *
+ * Copyright 2002-2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.httpclient.contrib.ssl;
+
+import org.apache.commons.ssl.HttpSecureProtocol;
+import org.apache.commons.ssl.KeyMaterial;
+import org.apache.commons.ssl.TrustMaterial;
+
+import java.io.IOException;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+
+/**
+ * <p/>
+ * AuthSSLProtocolSocketFactory can be used to validate the identity of the HTTPS
+ * server against a list of trusted certificates and to authenticate to the HTTPS
+ * server using a private key.
+ * </p>
+ * <p/>
+ * <p/>
+ * AuthSSLProtocolSocketFactory will enable server authentication when supplied with
+ * a {@link java.security.KeyStore truststore} file containg one or several trusted certificates.
+ * The client secure socket will reject the connection during the SSL session handshake
+ * if the target HTTPS server attempts to authenticate itself with a non-trusted
+ * certificate.
+ * </p>
+ * <p/>
+ * <p/>
+ * Use JDK keytool utility to import a trusted certificate and generate a truststore file:
+ * <pre>
+ * keytool -import -alias "my server cert" -file server.crt -keystore my.truststore
+ * </pre>
+ * </p>
+ * <p/>
+ * <p/>
+ * AuthSSLProtocolSocketFactory will enable client authentication when supplied with
+ * a {@link java.security.KeyStore keystore} file containg a private key/public certificate pair.
+ * The client secure socket will use the private key to authenticate itself to the target
+ * HTTPS server during the SSL session handshake if requested to do so by the server.
+ * The target HTTPS server will in its turn verify the certificate presented by the client
+ * in order to establish client's authenticity
+ * </p>
+ * <p/>
+ * <p/>
+ * Use the following sequence of actions to generate a keystore file
+ * </p>
+ * <ul>
+ * <li>
+ * <p/>
+ * Use JDK keytool utility to generate a new key
+ * <pre>keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore</pre>
+ * For simplicity use the same password for the key as that of the keystore
+ * </p>
+ * </li>
+ * <li>
+ * <p/>
+ * Issue a certificate signing request (CSR)
+ * <pre>keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * <li>
+ * <p/>
+ * Send the certificate request to the trusted Certificate Authority for signature.
+ * One may choose to act as her own CA and sign the certificate request using a PKI
+ * tool, such as OpenSSL.
+ * </p>
+ * </li>
+ * <li>
+ * <p/>
+ * Import the trusted CA root certificate
+ * <pre>keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * <li>
+ * <p/>
+ * Import the PKCS#7 file containg the complete certificate chain
+ * <pre>keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * <li>
+ * <p/>
+ * Verify the content the resultant keystore file
+ * <pre>keytool -list -v -keystore my.keystore</pre>
+ * </p>
+ * </li>
+ * </ul>
+ * <p/>
+ * Example of using custom protocol socket factory for a specific host:
+ * <pre>
+ * Protocol authhttps = new Protocol("https",
+ * new AuthSSLProtocolSocketFactory(
+ * new URL("file:my.keystore"), "mypassword",
+ * new URL("file:my.truststore"), "mypassword"), 443);
+ * <p/>
+ * HttpClient client = new HttpClient();
+ * client.getHostConfiguration().setHost("localhost", 443, authhttps);
+ * // use relative url only
+ * GetMethod httpget = new GetMethod("/");
+ * client.executeMethod(httpget);
+ * </pre>
+ * </p>
+ * <p/>
+ * Example of using custom protocol socket factory per default instead of the standard one:
+ * <pre>
+ * Protocol authhttps = new Protocol("https",
+ * new AuthSSLProtocolSocketFactory(
+ * new URL("file:my.keystore"), "mypassword",
+ * new URL("file:my.truststore"), "mypassword"), 443);
+ * Protocol.registerProtocol("https", authhttps);
+ * <p/>
+ * HttpClient client = new HttpClient();
+ * GetMethod httpget = new GetMethod("https://localhost/");
+ * client.executeMethod(httpget);
+ * </pre>
+ * </p>
+ *
+ * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a>
+ * <p/>
+ * <p/>
+ * DISCLAIMER: HttpClient developers DO NOT actively support this component.
+ * The component is provided as a reference material, which may be inappropriate
+ * for use without additional customization.
+ * </p>
+ */
+
+public class AuthSSLProtocolSocketFactory extends HttpSecureProtocol {
+
+ /**
+ * Constructor for AuthSSLProtocolSocketFactory. Either a keystore or truststore file
+ * must be given. Otherwise SSL context initialization error will result.
+ *
+ * @param keystoreUrl URL of the keystore file. May be <tt>null</tt> if HTTPS client
+ * authentication is not to be used.
+ * @param keystorePassword Password to unlock the keystore. IMPORTANT: this implementation
+ * assumes that the same password is used to protect the key and the keystore itself.
+ * @param truststoreUrl URL of the truststore file. May be <tt>null</tt> if HTTPS server
+ * authentication is not to be used.
+ * @param truststorePassword Password to unlock the truststore.
+ */
+ public AuthSSLProtocolSocketFactory(final URL keystoreUrl,
+ final String keystorePassword,
+ final URL truststoreUrl,
+ final String truststorePassword)
+ throws GeneralSecurityException, IOException {
+
+ super();
+
+ // prepare key material
+ if (keystoreUrl != null) {
+ char[] ksPass = null;
+ if (keystorePassword != null) {
+ ksPass = keystorePassword.toCharArray();
+ }
+ KeyMaterial km = new KeyMaterial(keystoreUrl, ksPass);
+ super.setKeyMaterial(km);
+ }
+
+ // prepare trust material1
+ if (truststoreUrl != null) {
+ char[] tsPass = null;
+ if (truststorePassword != null) {
+ tsPass = truststorePassword.toCharArray();
+ }
+ TrustMaterial tm = new KeyMaterial(truststoreUrl, tsPass);
+ super.setTrustMaterial(tm);
+ }
+ }
+
+}
diff --git a/src/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java b/src/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java
new file mode 100644
index 0000000..ab84dd1
--- /dev/null
+++ b/src/java/org/apache/commons/httpclient/contrib/ssl/EasySSLProtocolSocketFactory.java
@@ -0,0 +1,102 @@
+/*
+ * $Header$
+ * $Revision: 129 $
+ * $Date: 2007-11-14 19:21:33 -0800 (Wed, 14 Nov 2007) $
+ *
+ * ====================================================================
+ *
+ * Copyright 2002-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.httpclient.contrib.ssl;
+
+import org.apache.commons.ssl.HttpSecureProtocol;
+import org.apache.commons.ssl.TrustMaterial;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.security.GeneralSecurityException;
+
+/**
+ * <p/>
+ * EasySSLProtocolSocketFactory can be used to creats SSL {@link Socket}s
+ * that accept self-signed certificates.
+ * </p>
+ * <p/>
+ * This socket factory SHOULD NOT be used for productive systems
+ * due to security reasons, unless it is a concious decision and
+ * you are perfectly aware of security implications of accepting
+ * self-signed certificates
+ * </p>
+ * <p/>
+ * <p/>
+ * Example of using custom protocol socket factory for a specific host:
+ * <pre>
+ * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
+ * <p/>
+ * HttpClient client = new HttpClient();
+ * client.getHostConfiguration().setHost("localhost", 443, easyhttps);
+ * // use relative url only
+ * GetMethod httpget = new GetMethod("/");
+ * client.executeMethod(httpget);
+ * </pre>
+ * </p>
+ * <p/>
+ * Example of using custom protocol socket factory per default instead of the standard one:
+ * <pre>
+ * Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
+ * Protocol.registerProtocol("https", easyhttps);
+ * <p/>
+ * HttpClient client = new HttpClient();
+ * GetMethod httpget = new GetMethod("https://localhost/");
+ * client.executeMethod(httpget);
+ * </pre>
+ * </p>
+ *
+ * @author <a href="mailto:oleg -at- ural.ru">Oleg Kalnichevski</a>
+ * <p/>
+ * <p/>
+ * DISCLAIMER: HttpClient developers DO NOT actively support this component.
+ * The component is provided as a reference material, which may be inappropriate
+ * for use without additional customization.
+ * </p>
+ */
+
+public class EasySSLProtocolSocketFactory extends HttpSecureProtocol {
+
+ /**
+ * Constructor for EasySSLProtocolSocketFactory.
+ *
+ * @throws GeneralSecurityException GeneralSecurityException
+ * @throws IOException IOException
+ */
+ public EasySSLProtocolSocketFactory()
+ throws GeneralSecurityException, IOException {
+ super();
+ super.useDefaultJavaCiphers();
+ super.setTrustMaterial(TrustMaterial.TRUST_ALL);
+ super.setCheckHostname(false);
+ super.setCheckExpiry(false);
+ super.setCheckCRL(false );
+ }
+
+}
diff --git a/src/java/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java b/src/java/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java
new file mode 100644
index 0000000..05e207d
--- /dev/null
+++ b/src/java/org/apache/commons/httpclient/contrib/ssl/StrictSSLProtocolSocketFactory.java
@@ -0,0 +1,131 @@
+/*
+ * $Header$
+ * $Revision: 129 $
+ * $Date: 2007-11-14 19:21:33 -0800 (Wed, 14 Nov 2007) $
+ *
+ * ====================================================================
+ *
+ * Copyright 1999-2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * [Additional notices, if required by prior licensing conditions]
+ *
+ * Alternatively, the contents of this file may be used under the
+ * terms of the GNU Lesser General Public License Version 2 or later
+ * (the "LGPL"), in which case the provisions of the LGPL are
+ * applicable instead of those above. See terms of LGPL at
+ * <http://www.gnu.org/copyleft/lesser.txt>.
+ * If you wish to allow use of your version of this file only under
+ * the terms of the LGPL and not to allow others to use your version
+ * of this file under the Apache Software License, indicate your
+ * decision by deleting the provisions above and replace them with
+ * the notice and other provisions required by the LGPL. If you do
+ * not delete the provisions above, a recipient may use your version
+ * of this file under either the Apache Software License or the LGPL.
+ */
+
+package org.apache.commons.httpclient.contrib.ssl;
+
+import org.apache.commons.ssl.HttpSecureProtocol;
+
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+/**
+ * A <code>SecureProtocolSocketFactory</code> that uses JSSE to create
+ * SSL sockets. It will also support host name verification to help preventing
+ * man-in-the-middle attacks. Host name verification is turned <b>on</b> by
+ * default but one will be able to turn it off, which might be a useful feature
+ * during development. Host name verification will make sure the SSL sessions
+ * server host name matches with the the host name returned in the
+ * server certificates "Common Name" field of the "SubjectDN" entry.
+ *
+ * @author <a href="mailto:hauer at psicode.com">Sebastian Hauer</a>
+ * <p/>
+ * DISCLAIMER: HttpClient developers DO NOT actively support this component.
+ * The component is provided as a reference material, which may be inappropriate
+ * for use without additional customization.
+ * </p>
+ */
+public class StrictSSLProtocolSocketFactory extends HttpSecureProtocol {
+
+ /**
+ * Constructor for StrictSSLProtocolSocketFactory.
+ *
+ * @param verifyHostname The host name verification flag. If set to
+ * <code>true</code> the SSL sessions server host name will be compared
+ * to the host name returned in the server certificates "Common Name"
+ * field of the "SubjectDN" entry. If these names do not match a
+ * Exception is thrown to indicate this. Enabling host name verification
+ * will help to prevent from man-in-the-middle attacks. If set to
+ * <code>false</code> host name verification is turned off.
+ * <p/>
+ * Code sample:
+ * <p/>
+ * <blockquote>
+ * Protocol stricthttps = new Protocol(
+ * "https", new StrictSSLProtocolSocketFactory(true), 443);
+ * <p/>
+ * HttpClient client = new HttpClient();
+ * client.getHostConfiguration().setHost("localhost", 443, stricthttps);
+ * </blockquote>
+ */
+ public StrictSSLProtocolSocketFactory(boolean verifyHostname)
+ throws GeneralSecurityException, IOException {
+ super();
+ super.setCheckHostname(verifyHostname);
+ }
+
+ /**
+ * Constructor for StrictSSLProtocolSocketFactory.
+ * Host name verification will be enabled by default.
+ */
+ public StrictSSLProtocolSocketFactory()
+ throws GeneralSecurityException, IOException {
+ this(true);
+ }
+
+ /**
+ * Set the host name verification flag.
+ *
+ * @param verifyHostname The host name verification flag. If set to
+ * <code>true</code> the SSL sessions server host name will be compared
+ * to the host name returned in the server certificates "Common Name"
+ * field of the "SubjectDN" entry. If these names do not match a
+ * Exception is thrown to indicate this. Enabling host name verification
+ * will help to prevent from man-in-the-middle attacks. If set to
+ * <code>false</code> host name verification is turned off.
+ */
+ public void setHostnameVerification(boolean verifyHostname) {
+ super.setCheckHostname(verifyHostname);
+ }
+
+ /**
+ * Gets the status of the host name verification flag.
+ *
+ * @return Host name verification flag. Either <code>true</code> if host
+ * name verification is turned on, or <code>false</code> if host name
+ * verification is turned off.
+ */
+ public boolean getHostnameVerification() {
+ return super.getCheckHostname();
+ }
+
+}
diff --git a/src/java/org/apache/commons/httpclient/contrib/ssl/TrustSSLProtocolSocketFactory.java b/src/java/org/apache/commons/httpclient/contrib/ssl/TrustSSLProtocolSocketFactory.java
new file mode 100644
index 0000000..fc1a847
--- /dev/null
+++ b/src/java/org/apache/commons/httpclient/contrib/ssl/TrustSSLProtocolSocketFactory.java
@@ -0,0 +1,199 @@
+/*
+ * ====================================================================
+ *
+ * Copyright 1999-2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.httpclient.contrib.ssl;
+
+import org.apache.commons.ssl.HttpSecureProtocol;
+import org.apache.commons.ssl.KeyMaterial;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+
+/**
+ * <p/>
+ * TrustSSLProtocolSocketFactory allows you exercise full control over the
+ * HTTPS server certificates you are going to trust. Instead of relying
+ * on the Certificate Authorities already present in "jre/lib/security/cacerts",
+ * TrustSSLProtocolSocketFactory only trusts the public certificates you provide
+ * to its constructor.
+ * </p>
+ * <p/>
+ * TrustSSLProtocolSocketFactory can be used to create SSL {@link Socket}s
+ * that accepts self-signed certificates. Unlike EasySSLProtocolSocketFactory,
+ * TrustSSLProtocolSocketFactory can be used in production. This is because
+ * it forces you to pre-install the self-signed certificate you are going to
+ * trust locally.
+ * <p/>
+ * TrustSSLProtocolSocketFactory can parse both Java Keystore Files (*.jks)
+ * and base64 PEM encoded public certificates (*.pem).
+ * </p>
+ * <p/>
+ * Example of using TrustSSLProtocolSocketFactory
+ * <pre>
+ * 1. First we must find the certificate we want to trust. In this example
+ * we'll use gmail.google.com's certificate.
+ * <p/>
+ * openssl s_client -showcerts -connect gmail.google.com:443
+ * <p/>
+ * 2. Cut & paste into a "cert.pem" any certificates you are interested in
+ * trusting in accordance with your security policies. In this example I'll
+ * actually use the current "gmail.google.com" certificate (instead of the
+ * Thawte CA certificate that signed the gmail certificate - that would be
+ * too boring) - but it expires on June 7th, 2006, so this example won't be
+ * useful for very long!
+ * <p/>
+ * Here's what my "cert.pem" file looks like:
+ * <p/>
+ * -----BEGIN CERTIFICATE-----
+ * MIIDFjCCAn+gAwIBAgIDP3PeMA0GCSqGSIb3DQEBBAUAMEwxCzAJBgNVBAYTAlpB
+ * MSUwIwYDVQQKExxUaGF3dGUgQ29uc3VsdGluZyAoUHR5KSBMdGQuMRYwFAYDVQQD
+ * Ew1UaGF3dGUgU0dDIENBMB4XDTA1MDYwNzIyMTI1N1oXDTA2MDYwNzIyMTI1N1ow
+ * ajELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1v
+ * dW50YWluIFZpZXcxEzARBgNVBAoTCkdvb2dsZSBJbmMxGTAXBgNVBAMTEGdtYWls
+ * Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALoRiWYW0hZw
+ * 9TSn3s9912syZg1CP2TaC86PU1Ao2qf3pVu7Mx10Wl8W+aKZrQlvrYjTwku4sEh+
+ * 9uI+gWnfmCd0OyVcXr1eFOGCYiiyaPv79Wtb0m0d8GuiRSJhYkZGzGlgFViws2vR
+ * BAMCD2fdp7WGJUVGYOO+s52dgAMUHQXxAgMBAAGjgecwgeQwKAYDVR0lBCEwHwYI
+ * KwYBBQUHAwEGCCsGAQUFBwMCBglghkgBhvhCBAEwNgYDVR0fBC8wLTAroCmgJ4Yl
+ * aHR0cDovL2NybC50aGF3dGUuY29tL1RoYXd0ZVNHQ0NBLmNybDByBggrBgEFBQcB
+ * AQRmMGQwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3NwLnRoYXd0ZS5jb20wPgYIKwYB
+ * BQUHMAKGMmh0dHA6Ly93d3cudGhhd3RlLmNvbS9yZXBvc2l0b3J5L1RoYXd0ZV9T
+ * R0NfQ0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQEEBQADgYEAktM1l1cV
+ * ebi+Uo6fCE/eLnvvY6QbNNCsU5Pi9B5E1BlEUG+AGpgzE2cSPw1N4ZZb+2AWWwjx
+ * H8/IrJ143KZZXM49ri3Z2e491Jj8qitrMauT7/hb16Jw6I02/74/do4TtHu/Eifr
+ * EZCaSOobSHGeufHjlqlC3ehC4Bx4mLexIMk=
+ * -----END CERTIFICATE-----
+ * <p/>
+ * 3. Run "openssl x509" to analyze the certificate more deeply. This helps
+ * us answer questions like "Do we really want to trust it? When does it
+ * expire? What's the value of the CN (Common Name) field?".
+ * <p/>
+ * "openssl x509" is also super cool, and will impress all your friends,
+ * coworkers, family, and that cute girl at the starbucks. :-)
+ * <p/>
+ * If you dig through "man x509" you'll find this example. Run it:
+ * <p/>
+ * openssl x509 -in cert.pem -noout -text
+ * <p/>
+ * 4. Rename "cert.pem" to "gmail.pem" so that step 5 works.
+ * <p/>
+ * 5. Setup the TrustSSLProtocolSocketFactory to trust "gmail.google.com"
+ * for URLS of the form "https-gmail://" - but don't trust anything else
+ * when using "https-gmail://":
+ * <p/>
+ * TrustSSLProtocolSocketFactory sf = new TrustSSLProtocolSocketFactory( "/path/to/gmail.pem" );
+ * Protocol trustHttps = new Protocol("https-gmail", sf, 443);
+ * Protocol.registerProtocol("https-gmail", trustHttps);
+ * <p/>
+ * HttpClient client = new HttpClient();
+ * GetMethod httpget = new GetMethod("https-gmail://gmail.google.com/");
+ * client.executeMethod(httpget);
+ * <p/>
+ * 6. Notice that "https-gmail://" cannot connect to "www.wellsfargo.com" -
+ * the server's certificate isn't trusted! It would still work using
+ * regular "https://" because Java would use the "jre/lib/security/cacerts"
+ * file.
+ * <p/>
+ * httpget = new GetMethod("https-gmail://www.wellsfargo.com/");
+ * client.executeMethod(httpget);
+ * <p/>
+ * javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found
+ * <p/>
+ * <p/>
+ * 7. Of course "https-gmail://" cannot connect to hosts where the CN field
+ * in the certificate doesn't match the hostname. The same is supposed to
+ * be true of regular "https://", but HTTPClient is a bit lenient.
+ * <p/>
+ * httpget = new GetMethod("https-gmail://gmail.com/");
+ * client.executeMethod(httpget);
+ * <p/>
+ * javax.net.ssl.SSLException: hostname in certificate didn't match: <gmail.com> != <gmail.google.com>
+ * <p/>
+ * <p/>
+ * 8. You can use "*.jks" files instead of "*.pem" if you prefer. Use the 2nd constructor
+ * in that case to pass along the JKS password:
+ * <p/>
+ * new TrustSSLProtocolSocketFactory( "/path/to/gmail.jks", "my_password".toCharArray() );
+ * <p/>
+ * </pre>
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * <p/>
+ * <p/>
+ * DISCLAIMER: HttpClient developers DO NOT actively support this component.
+ * The component is provided as a reference material, which may be inappropriate
+ * for use without additional customization.
+ * </p>
+ * @since 17-Feb-2006
+ */
+
+public class TrustSSLProtocolSocketFactory extends HttpSecureProtocol {
+
+ /**
+ * @param pathToTrustStore Path to either a ".jks" Java Key Store, or a
+ * ".pem" base64 encoded certificate. If it's a
+ * ".pem" base64 certificate, the file must start
+ * with "------BEGIN CERTIFICATE-----", and must end
+ * with "-------END CERTIFICATE--------".
+ */
+ public TrustSSLProtocolSocketFactory(String pathToTrustStore)
+ throws GeneralSecurityException, IOException {
+ this(pathToTrustStore, null);
+ }
+
+ /**
+ * @param pathToTrustStore Path to either a ".jks" Java Key Store, or a
+ * ".pem" base64 encoded certificate. If it's a
+ * ".pem" base64 certificate, the file must start
+ * with "------BEGIN CERTIFICATE-----", and must end
+ * with "-------END CERTIFICATE--------".
+ * @param password Password to open the ".jks" file. If "truststore"
+ * is a ".pem" file, then password can be null; if
+ * password isn't null and we're using a ".pem" file,
+ * then technically, this becomes the password to
+ * open up the special in-memory keystore we create
+ * to hold the ".pem" file, but it's not important at
+ * all.
+ * @throws CertificateException
+ * @throws KeyStoreException
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ * @throws KeyManagementException
+ */
+ public TrustSSLProtocolSocketFactory(String pathToTrustStore, char[] password)
+ throws GeneralSecurityException, IOException {
+ super();
+ KeyMaterial km = new KeyMaterial(pathToTrustStore, password);
+ super.setTrustMaterial(km);
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/ASN1Structure.java b/src/java/org/apache/commons/ssl/ASN1Structure.java
new file mode 100644
index 0000000..6dd69ca
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/ASN1Structure.java
@@ -0,0 +1,112 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/ASN1Structure.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import org.apache.commons.ssl.util.Hex;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 16-Nov-2005
+ */
+class ASN1Structure {
+ List derIntegers = new LinkedList();
+ Set oids = new TreeSet();
+ String oid1;
+ String oid2;
+ String oid3;
+ byte[] salt;
+ byte[] iv;
+ int iterationCount;
+ int keySize;
+ byte[] bigPayload;
+ byte[] smallPayload;
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer(256);
+ buf.append("------ ASN.1 PKCS Structure ------");
+ buf.append("\noid1: ");
+ buf.append(oid1);
+ if (oid2 != null) {
+ buf.append("\noid2: ");
+ buf.append(oid2);
+ }
+ buf.append("\nsalt: ");
+ if (salt != null) {
+ buf.append(Hex.encode(salt));
+ } else {
+ buf.append("[null]");
+ }
+ buf.append("\nic: ");
+ buf.append(Integer.toString(iterationCount));
+ if (keySize != 0) {
+ buf.append("\nkeySize: ");
+ buf.append(Integer.toString(keySize * 8));
+ }
+ if (oid2 != null) {
+ buf.append("\noid3: ");
+ buf.append(oid3);
+ }
+ if (oid2 != null) {
+ buf.append("\niv: ");
+ if (iv != null) {
+ buf.append(Hex.encode(iv));
+ } else {
+ buf.append("[null]");
+ }
+ }
+ if (bigPayload != null) {
+ buf.append("\nbigPayload-length: ");
+ buf.append(bigPayload.length);
+ }
+ if (smallPayload != null) {
+ buf.append("\nsmallPayload-length: ");
+ buf.append(smallPayload.length);
+ }
+ if (!oids.isEmpty()) {
+ Iterator it = oids.iterator();
+ buf.append("\nAll oids:");
+ while (it.hasNext()) {
+ buf.append("\n");
+ buf.append((String) it.next());
+ }
+ }
+ return buf.toString();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/ASN1Util.java b/src/java/org/apache/commons/ssl/ASN1Util.java
new file mode 100644
index 0000000..c73a224
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/ASN1Util.java
@@ -0,0 +1,211 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/ASN1Util.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import org.apache.commons.ssl.asn1.ASN1InputStream;
+import org.apache.commons.ssl.asn1.DEREncodable;
+import org.apache.commons.ssl.asn1.DERInteger;
+import org.apache.commons.ssl.asn1.DERObjectIdentifier;
+import org.apache.commons.ssl.asn1.DEROctetString;
+import org.apache.commons.ssl.asn1.DERPrintableString;
+import org.apache.commons.ssl.asn1.DERSequence;
+import org.apache.commons.ssl.asn1.DERSet;
+import org.apache.commons.ssl.asn1.DERTaggedObject;
+import org.apache.commons.ssl.util.Hex;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Vector;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 16-Nov-2005
+ */
+public class ASN1Util {
+ public static boolean DEBUG = false;
+ public final static BigInteger BIGGEST =
+ new BigInteger(Integer.toString(Integer.MAX_VALUE));
+
+ public static ASN1Structure analyze(byte[] asn1)
+ throws IOException {
+ ASN1InputStream asn = new ASN1InputStream(asn1);
+ DERSequence seq = (DERSequence) asn.readObject();
+ ASN1Structure pkcs8 = new ASN1Structure();
+ ASN1Util.analyze(seq, pkcs8, 0);
+ return pkcs8;
+ }
+
+ public static void main(String[] args) throws Exception {
+ DEBUG = true;
+ FileInputStream in = new FileInputStream(args[0]);
+ byte[] bytes = Util.streamToBytes(in);
+ List list = PEMUtil.decode(bytes);
+ if (!list.isEmpty()) {
+ bytes = ((PEMItem) list.get(0)).getDerBytes();
+ }
+
+ ASN1Structure asn1 = analyze(bytes);
+ while (asn1.bigPayload != null) {
+ System.out.println("------------------------------------------");
+ System.out.println(asn1);
+ System.out.println("------------------------------------------");
+ asn1 = analyze(asn1.bigPayload);
+ }
+ }
+
+
+ public static void analyze(DEREncodable seq, ASN1Structure pkcs8,
+ int depth) {
+ String tag = null;
+ if (depth >= 2) {
+ pkcs8.derIntegers = null;
+ }
+ Enumeration en;
+ if (seq instanceof DERSequence) {
+ en = ((DERSequence) seq).getObjects();
+ } else if (seq instanceof DERSet) {
+ en = ((DERSet) seq).getObjects();
+ } else if (seq instanceof DERTaggedObject) {
+ DERTaggedObject derTag = (DERTaggedObject) seq;
+ tag = Integer.toString(derTag.getTagNo());
+ Vector v = new Vector();
+ v.add(derTag.getObject());
+ en = v.elements();
+ } else {
+ throw new IllegalArgumentException("DEREncodable must be one of: DERSequence, DERSet, DERTaggedObject");
+ }
+ while (en != null && en.hasMoreElements()) {
+ DEREncodable obj = (DEREncodable) en.nextElement();
+ if (!(obj instanceof DERSequence) &&
+ !(obj instanceof DERSet) &&
+ !(obj instanceof DERTaggedObject)) {
+ String str = obj.toString();
+ String name = obj.getClass().getName();
+ name = name.substring(name.lastIndexOf('.') + 1);
+ if (tag != null) {
+ name = " [tag=" + tag + "] " + name;
+ }
+ for (int i = 0; i < depth; i++) {
+ name = " " + name;
+ }
+ if (obj instanceof DERInteger) {
+ DERInteger dInt = (DERInteger) obj;
+ if (pkcs8.derIntegers != null) {
+ pkcs8.derIntegers.add(dInt);
+ }
+ BigInteger big = dInt.getValue();
+ int intValue = big.intValue();
+ if (BIGGEST.compareTo(big) >= 0 && intValue > 0) {
+ if (pkcs8.iterationCount == 0) {
+ pkcs8.iterationCount = intValue;
+ } else if (pkcs8.keySize == 0) {
+ pkcs8.keySize = intValue;
+ }
+ }
+ str = dInt.getValue().toString();
+ } else if (obj instanceof DERObjectIdentifier) {
+ DERObjectIdentifier id = (DERObjectIdentifier) obj;
+ str = id.getId();
+ pkcs8.oids.add(str);
+ if (pkcs8.oid1 == null) {
+ pkcs8.oid1 = str;
+ } else if (pkcs8.oid2 == null) {
+ pkcs8.oid2 = str;
+ } else if (pkcs8.oid3 == null) {
+ pkcs8.oid3 = str;
+ }
+ } else {
+ pkcs8.derIntegers = null;
+ if (obj instanceof DEROctetString) {
+ DEROctetString oct = (DEROctetString) obj;
+ byte[] octets = oct.getOctets();
+ int len = Math.min(10, octets.length);
+ boolean probablyBinary = false;
+ for (int i = 0; i < len; i++) {
+ byte b = octets[i];
+ boolean isBinary = b > 128 || b < 0;
+ if (isBinary) {
+ probablyBinary = true;
+ break;
+ }
+ }
+ if (probablyBinary && octets.length > 64) {
+ if (pkcs8.bigPayload == null) {
+ pkcs8.bigPayload = octets;
+ }
+ str = "probably binary";
+ } else {
+ str = Hex.encode(octets);
+ if (octets.length <= 64) {
+ if (octets.length % 8 == 0) {
+ if (pkcs8.salt == null) {
+ pkcs8.salt = octets;
+ } else if (pkcs8.iv == null) {
+ pkcs8.iv = octets;
+ }
+ } else {
+ if (pkcs8.smallPayload == null) {
+ pkcs8.smallPayload = octets;
+ }
+ }
+ }
+ }
+ str += " (length=" + octets.length + ")";
+ } else if (obj instanceof DERPrintableString) {
+ DERPrintableString dps = (DERPrintableString) obj;
+ str = dps.getString();
+ }
+ }
+
+ if (DEBUG) {
+ System.out.println(name + ": [" + str + "]");
+ }
+ } else {
+ if (tag != null && DEBUG) {
+ String name = obj.getClass().getName();
+ name = name.substring(name.lastIndexOf('.') + 1);
+ name = " [tag=" + tag + "] " + name;
+ for (int i = 0; i < depth; i++) {
+ name = " " + name;
+ }
+ System.out.println(name);
+ }
+ analyze(obj, pkcs8, depth + 1);
+ }
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/Base64.java b/src/java/org/apache/commons/ssl/Base64.java
new file mode 100644
index 0000000..aac382f
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Base64.java
@@ -0,0 +1,535 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Base64.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+/**
+ * Provides Base64 encoding and decoding as defined by RFC 2045.
+ * <p/>
+ * <p>This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite>
+ * from RFC 2045 <cite>Multipurpose Internet Mail Extensions (MIME) Part One:
+ * Format of Internet Message Bodies</cite> by Freed and Borenstein.</p>
+ *
+ * @author Apache Software Foundation
+ * @version $Id: Base64.java 121 2007-11-14 05:26:57Z julius $
+ * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
+ * @since 1.0-dev
+ */
+public class Base64 {
+
+ /**
+ * Chunk size per RFC 2045 section 6.8.
+ * <p/>
+ * <p>The character limit does not count the trailing CRLF, but counts
+ * all other characters, including any equal signs.</p>
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
+ */
+ static final int CHUNK_SIZE = 76;
+
+ /**
+ * Chunk separator per RFC 2045 section 2.1.
+ *
+ * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
+ */
+ static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes();
+
+ /** The base length. */
+ static final int BASELENGTH = 255;
+
+ /** Lookup length. */
+ static final int LOOKUPLENGTH = 64;
+
+ /** Used to calculate the number of bits in a byte. */
+ static final int EIGHTBIT = 8;
+
+ /** Used when encoding something which has fewer than 24 bits. */
+ static final int SIXTEENBIT = 16;
+
+ /** Used to determine how many bits data contains. */
+ static final int TWENTYFOURBITGROUP = 24;
+
+ /** Used to get the number of Quadruples. */
+ static final int FOURBYTE = 4;
+
+ /** Used to test the sign of a byte. */
+ static final int SIGN = -128;
+
+ /** Byte used to pad output. */
+ static final byte PAD = (byte) '=';
+
+ /**
+ * Contains the Base64 values <code>0</code> through <code>63</code> accessed by using character encodings as
+ * indices.
+ * <p/>
+ * For example, <code>base64Alphabet['+']</code> returns <code>62</code>.
+ * </p>
+ * <p/>
+ * The value of undefined encodings is <code>-1</code>.
+ * </p>
+ */
+ private static byte[] base64Alphabet = new byte[BASELENGTH];
+
+ /**
+ * <p/>
+ * Contains the Base64 encodings <code>A</code> through <code>Z</code>, followed by <code>a</code> through
+ * <code>z</code>, followed by <code>0</code> through <code>9</code>, followed by <code>+</code>, and
+ * <code>/</code>.
+ * </p>
+ * <p/>
+ * This array is accessed by using character values as indices.
+ * </p>
+ * <p/>
+ * For example, <code>lookUpBase64Alphabet[62] </code> returns <code>'+'</code>.
+ * </p>
+ */
+ private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
+
+ // Populating the lookup and character arrays
+ static {
+ for (int i = 0; i < BASELENGTH; i++) {
+ base64Alphabet[i] = (byte) -1;
+ }
+ for (int i = 'Z'; i >= 'A'; i--) {
+ base64Alphabet[i] = (byte) (i - 'A');
+ }
+ for (int i = 'z'; i >= 'a'; i--) {
+ base64Alphabet[i] = (byte) (i - 'a' + 26);
+ }
+ for (int i = '9'; i >= '0'; i--) {
+ base64Alphabet[i] = (byte) (i - '0' + 52);
+ }
+
+ base64Alphabet['+'] = 62;
+ base64Alphabet['/'] = 63;
+
+ for (int i = 0; i <= 25; i++) {
+ lookUpBase64Alphabet[i] = (byte) ('A' + i);
+ }
+
+ for (int i = 26, j = 0; i <= 51; i++, j++) {
+ lookUpBase64Alphabet[i] = (byte) ('a' + j);
+ }
+
+ for (int i = 52, j = 0; i <= 61; i++, j++) {
+ lookUpBase64Alphabet[i] = (byte) ('0' + j);
+ }
+
+ lookUpBase64Alphabet[62] = (byte) '+';
+ lookUpBase64Alphabet[63] = (byte) '/';
+ }
+
+ /**
+ * Returns whether or not the <code>octect</code> is in the base 64 alphabet.
+ *
+ * @param b The value to test
+ * @return <code>true</code> if the value is defined in the the base 64 alphabet, <code>false</code> otherwise.
+ */
+ public static boolean isBase64(byte b) {
+ return (b == PAD) || (b >= 0 && base64Alphabet[b] >= 0);
+ }
+
+ /**
+ * Tests a given byte array to see if it contains
+ * only valid characters within the Base64 alphabet.
+ *
+ * @param arrayOctect byte array to test
+ * @return <code>true</code> if all bytes are valid characters in the Base64
+ * alphabet or if the byte array is empty; false, otherwise
+ */
+ public static boolean isArrayByteBase64(byte[] arrayOctect) {
+
+ arrayOctect = discardWhitespace(arrayOctect);
+
+ int length = arrayOctect.length;
+ if (length == 0) {
+ // shouldn't a 0 length array be valid base64 data?
+ // return false;
+ return true;
+ }
+ for (int i = 0; i < length; i++) {
+ if (!isBase64(arrayOctect[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Encodes binary data using the base64 algorithm but
+ * does not chunk the output.
+ *
+ * @param binaryData binary data to encode
+ * @return Base64 characters
+ */
+ public static byte[] encodeBase64(byte[] binaryData) {
+ return encodeBase64(binaryData, false);
+ }
+
+ /**
+ * Encodes binary data using the base64 algorithm and chunks
+ * the encoded output into 76 character blocks
+ *
+ * @param binaryData binary data to encode
+ * @return Base64 characters chunked in 76 character blocks
+ */
+ public static byte[] encodeBase64Chunked(byte[] binaryData) {
+ return encodeBase64(binaryData, true);
+ }
+
+
+ /**
+ * Decodes an Object using the base64 algorithm. This method
+ * is provided in order to satisfy the requirements of the
+ * Decoder interface, and will throw a DecoderException if the
+ * supplied object is not of type byte[].
+ *
+ * @param pObject Object to decode
+ * @return An object (of type byte[]) containing the
+ * binary data which corresponds to the byte[] supplied.
+ * @throws IllegalArgumentException if the parameter supplied is not
+ * of type byte[]
+ */
+ public Object decode(Object pObject) throws IllegalArgumentException {
+ if (!(pObject instanceof byte[])) {
+ throw new IllegalArgumentException("Parameter supplied to Base64 decode is not a byte[]");
+ }
+ return decode((byte[]) pObject);
+ }
+
+ /**
+ * Decodes a byte[] containing containing
+ * characters in the Base64 alphabet.
+ *
+ * @param pArray A byte array containing Base64 character data
+ * @return a byte array containing binary data
+ */
+ public byte[] decode(byte[] pArray) {
+ return decodeBase64(pArray);
+ }
+
+ /**
+ * Encodes binary data using the base64 algorithm, optionally
+ * chunking the output into 76 character blocks.
+ *
+ * @param binaryData Array containing binary data to encode.
+ * @param isChunked if <code>true</code> this encoder will chunk
+ * the base64 output into 76 character blocks
+ * @return Base64-encoded data.
+ */
+ public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {
+ int lengthDataBits = binaryData.length * EIGHTBIT;
+ int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
+ int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
+ byte encodedData[];
+ int encodedDataLength;
+ int nbrChunks = 0;
+
+ if (fewerThan24bits != 0) {
+ //data not divisible by 24 bit
+ encodedDataLength = (numberTriplets + 1) * 4;
+ } else {
+ // 16 or 8 bit
+ encodedDataLength = numberTriplets * 4;
+ }
+
+ // If the output is to be "chunked" into 76 character sections,
+ // for compliance with RFC 2045 MIME, then it is important to
+ // allow for extra length to account for the separator(s)
+ if (isChunked) {
+
+ nbrChunks =
+ (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math.ceil((float) encodedDataLength / CHUNK_SIZE));
+ encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
+ }
+
+ encodedData = new byte[encodedDataLength];
+
+ byte k, l, b1, b2, b3;
+ int dataIndex;
+ int i;
+ int encodedIndex = 0;
+ int nextSeparatorIndex = CHUNK_SIZE;
+ int chunksSoFar = 0;
+
+ //log.debug("number of triplets = " + numberTriplets);
+ for (i = 0; i < numberTriplets; i++) {
+ dataIndex = i * 3;
+ b1 = binaryData[dataIndex];
+ b2 = binaryData[dataIndex + 1];
+ b3 = binaryData[dataIndex + 2];
+
+ //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
+
+ l = (byte) (b2 & 0x0f);
+ k = (byte) (b1 & 0x03);
+
+ byte val1 =
+ ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+ byte val2 =
+ ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+ byte val3 =
+ ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
+
+ encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
+ //log.debug( "val2 = " + val2 );
+ //log.debug( "k4 = " + (k<<4) );
+ //log.debug( "vak = " + (val2 | (k<<4)) );
+ encodedData[encodedIndex + 1] =
+ lookUpBase64Alphabet[val2 | (k << 4)];
+ encodedData[encodedIndex + 2] =
+ lookUpBase64Alphabet[(l << 2) | val3];
+ encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
+
+ encodedIndex += 4;
+
+ // If we are chunking, let's put a chunk separator down.
+ if (isChunked) {
+ // this assumes that CHUNK_SIZE % 4 == 0
+ if (encodedIndex == nextSeparatorIndex) {
+ System.arraycopy(CHUNK_SEPARATOR,
+ 0,
+ encodedData,
+ encodedIndex,
+ CHUNK_SEPARATOR.length);
+ chunksSoFar++;
+ nextSeparatorIndex =
+ (CHUNK_SIZE * (chunksSoFar + 1)) +
+ (chunksSoFar * CHUNK_SEPARATOR.length);
+ encodedIndex += CHUNK_SEPARATOR.length;
+ }
+ }
+ }
+
+ // form integral number of 6-bit groups
+ dataIndex = i * 3;
+
+ if (fewerThan24bits == EIGHTBIT) {
+ b1 = binaryData[dataIndex];
+ k = (byte) (b1 & 0x03);
+ //log.debug("b1=" + b1);
+ //log.debug("b1<<2 = " + (b1>>2) );
+ byte val1 =
+ ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+ encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
+ encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
+ encodedData[encodedIndex + 2] = PAD;
+ encodedData[encodedIndex + 3] = PAD;
+ } else if (fewerThan24bits == SIXTEENBIT) {
+
+ b1 = binaryData[dataIndex];
+ b2 = binaryData[dataIndex + 1];
+ l = (byte) (b2 & 0x0f);
+ k = (byte) (b1 & 0x03);
+
+ byte val1 =
+ ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+ byte val2 =
+ ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+
+ encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
+ encodedData[encodedIndex + 1] =
+ lookUpBase64Alphabet[val2 | (k << 4)];
+ encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
+ encodedData[encodedIndex + 3] = PAD;
+ }
+
+ if (isChunked) {
+ // we also add a separator to the end of the final chunk.
+ if (chunksSoFar < nbrChunks) {
+ System.arraycopy(CHUNK_SEPARATOR,
+ 0,
+ encodedData,
+ encodedDataLength - CHUNK_SEPARATOR.length,
+ CHUNK_SEPARATOR.length);
+ }
+ }
+
+ return encodedData;
+ }
+
+ /**
+ * Decodes Base64 data into octects
+ *
+ * @param base64Data Byte array containing Base64 data
+ * @return Array containing decoded data.
+ */
+ public static byte[] decodeBase64(byte[] base64Data) {
+ // RFC 2045 requires that we discard ALL non-Base64 characters
+ base64Data = discardNonBase64(base64Data);
+
+ // handle the edge case, so we don't have to worry about it later
+ if (base64Data.length == 0) {
+ return new byte[0];
+ }
+
+ int numberQuadruple = base64Data.length / FOURBYTE;
+ byte decodedData[];
+ byte b1, b2, b3, b4, marker0, marker1;
+
+ // Throw away anything not in base64Data
+ int dataIndex;
+ int encodedIndex = 0;
+ {
+ // this sizes the output array properly - rlw
+ int lastData = base64Data.length;
+ // ignore the '=' padding
+ while (base64Data[lastData - 1] == PAD) {
+ if (--lastData == 0) {
+ return new byte[0];
+ }
+ }
+ decodedData = new byte[lastData - numberQuadruple];
+ }
+
+ for (int i = 0; i < numberQuadruple; i++) {
+ dataIndex = i * 4;
+ marker0 = base64Data[dataIndex + 2];
+ marker1 = base64Data[dataIndex + 3];
+
+ b1 = base64Alphabet[base64Data[dataIndex]];
+ b2 = base64Alphabet[base64Data[dataIndex + 1]];
+
+ if (marker0 != PAD && marker1 != PAD) {
+ //No PAD e.g 3cQl
+ b3 = base64Alphabet[marker0];
+ b4 = base64Alphabet[marker1];
+
+ decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+ decodedData[encodedIndex + 1] =
+ (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+ decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
+ } else if (marker0 == PAD) {
+ //Two PAD e.g. 3c[Pad][Pad]
+ decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+ } else // if ( marker1 == PAD ) (always true at this point)
+ {
+ //One PAD e.g. 3cQ[Pad]
+ b3 = base64Alphabet[marker0];
+
+ decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+ decodedData[encodedIndex + 1] =
+ (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+ }
+ encodedIndex += 3;
+ }
+ return decodedData;
+ }
+
+ /**
+ * Discards any whitespace from a base-64 encoded block.
+ *
+ * @param data The base-64 encoded data to discard the whitespace
+ * from.
+ * @return The data, less whitespace (see RFC 2045).
+ */
+ static byte[] discardWhitespace(byte[] data) {
+ byte groomedData[] = new byte[data.length];
+ int bytesCopied = 0;
+
+ for (int i = 0; i < data.length; i++) {
+ switch (data[i]) {
+ case (byte) ' ':
+ case (byte) '\n':
+ case (byte) '\r':
+ case (byte) '\t':
+ break;
+ default:
+ groomedData[bytesCopied++] = data[i];
+ }
+ }
+
+ byte packedData[] = new byte[bytesCopied];
+
+ System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
+
+ return packedData;
+ }
+
+ /**
+ * Discards any characters outside of the base64 alphabet, per
+ * the requirements on page 25 of RFC 2045 - "Any characters
+ * outside of the base64 alphabet are to be ignored in base64
+ * encoded data."
+ *
+ * @param data The base-64 encoded data to groom
+ * @return The data, less non-base64 characters (see RFC 2045).
+ */
+ static byte[] discardNonBase64(byte[] data) {
+ byte groomedData[] = new byte[data.length];
+ int bytesCopied = 0;
+
+ for (int i = 0; i < data.length; i++) {
+ if (isBase64(data[i])) {
+ groomedData[bytesCopied++] = data[i];
+ }
+ }
+
+ byte packedData[] = new byte[bytesCopied];
+
+ System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
+
+ return packedData;
+ }
+
+ // Implementation of the Encoder Interface
+
+ /**
+ * Encodes an Object using the base64 algorithm. This method
+ * is provided in order to satisfy the requirements of the
+ * Encoder interface, and will throw an EncoderException if the
+ * supplied object is not of type byte[].
+ *
+ * @param pObject Object to encode
+ * @return An object (of type byte[]) containing the
+ * base64 encoded data which corresponds to the byte[] supplied.
+ * @throws IllegalArgumentException if the parameter supplied is not
+ * of type byte[]
+ */
+ public Object encode(Object pObject) throws IllegalArgumentException {
+ if (!(pObject instanceof byte[])) {
+ throw new IllegalArgumentException("Parameter supplied to Base64 encode is not a byte[]");
+ }
+ return encode((byte[]) pObject);
+ }
+
+ /**
+ * Encodes a byte[] containing binary data, into a byte[] containing
+ * characters in the Base64 alphabet.
+ *
+ * @param pArray a byte array containing binary data
+ * @return A byte array containing only Base64 character data
+ */
+ public byte[] encode(byte[] pArray) {
+ return encodeBase64(pArray, false);
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/Base64InputStream.java b/src/java/org/apache/commons/ssl/Base64InputStream.java
new file mode 100644
index 0000000..ef55f64
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Base64InputStream.java
@@ -0,0 +1,120 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Base64InputStream.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 22-Feb-2007
+ */
+public class Base64InputStream extends FilterInputStream {
+ private final static byte[] LINE_ENDING =
+ System.getProperty("line.separator").getBytes();
+
+ final boolean decodeMode;
+
+ byte[] currentLine = null;
+ int pos = 0;
+
+ public Base64InputStream(InputStream base64, boolean decodeMode) {
+ super(base64);
+ this.decodeMode = decodeMode;
+ }
+
+ public int read() throws IOException {
+ getLine();
+ if (currentLine == null) {
+ return -1;
+ } else {
+ byte b = currentLine[pos++];
+ if (pos >= currentLine.length) {
+ currentLine = null;
+ }
+ return b;
+ }
+ }
+
+ public int read(byte b[], int off, int len) throws IOException {
+ if (b == null) {
+ throw new NullPointerException();
+ } else if ((off < 0) || (off > b.length) || (len < 0) ||
+ ((off + len) > b.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return 0;
+ }
+
+ getLine();
+ if (currentLine == null) {
+ return -1;
+ }
+ int size = Math.min(currentLine.length - pos, len);
+ System.arraycopy(currentLine, pos, b, off, size);
+ if (size >= currentLine.length - pos) {
+ currentLine = null;
+ } else {
+ pos += size;
+ }
+ return size;
+ }
+
+ private void getLine() throws IOException {
+ if (currentLine == null) {
+ if (decodeMode) {
+ String line = Util.readLine(in);
+ if (line != null) {
+ byte[] b = line.getBytes();
+ currentLine = Base64.decodeBase64(b);
+ pos = 0;
+ }
+ } else {
+ // It will expand to 64 bytes (16 * 4) after base64 encoding!
+ byte[] b = Util.streamToBytes(in, 16 * 3);
+ if (b.length > 0) {
+ b = Base64.encodeBase64(b);
+
+ int lfLen = LINE_ENDING.length;
+ currentLine = new byte[b.length + lfLen];
+ System.arraycopy(b, 0, currentLine, 0, b.length);
+ System.arraycopy(LINE_ENDING, 0, currentLine, b.length, lfLen);
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/CRLUtil.java b/src/java/org/apache/commons/ssl/CRLUtil.java
new file mode 100644
index 0000000..744502d
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/CRLUtil.java
@@ -0,0 +1,75 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/CRLUtil.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+/*
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.DERObject;
+import org.bouncycastle.asn1.DERTaggedObject;
+import org.bouncycastle.asn1.x509.CRLDistPoint;
+import org.bouncycastle.asn1.x509.DistributionPoint;
+import org.bouncycastle.asn1.x509.DistributionPointName;
+import org.bouncycastle.x509.extension.X509ExtensionUtil;
+*/
+
+import java.io.IOException;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 20-Dec-2005
+ */
+public class CRLUtil {
+
+ public static String getURLToCRL(byte[] extension2_5_29_31)
+ throws IOException {
+
+ throw new UnsupportedOperationException("not yet implemented");
+
+ /*
+ byte[] bytes = extension2_5_29_31;
+ ASN1Encodable asn1 = X509ExtensionUtil.fromExtensionValue(bytes);
+ DERObject obj = asn1.getDERObject();
+ CRLDistPoint distPoint = CRLDistPoint.getInstance(obj);
+ DistributionPoint[] points = distPoint.getDistributionPoints();
+ DistributionPointName dpn = points[0].getDistributionPoint();
+ obj = dpn.getName().toASN1Object();
+ ASN1Sequence seq = ASN1Sequence.getInstance(obj);
+ DERTaggedObject tag = (DERTaggedObject) seq.getObjectAt(0);
+ bytes = ASN1OctetString.getInstance(tag, false).getOctets();
+ return new String(bytes);
+ */
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/Certificates.java b/src/java/org/apache/commons/ssl/Certificates.java
new file mode 100644
index 0000000..2c8926f
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Certificates.java
@@ -0,0 +1,591 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Certificates.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.math.BigInteger;
+import java.net.URL;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CRL;
+import java.security.cert.CRLException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.security.cert.X509Extension;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 19-Aug-2005
+ */
+public class Certificates {
+
+ public final static CertificateFactory CF;
+ public final static String LINE_ENDING = System.getProperty("line.separator");
+
+ private final static HashMap crl_cache = new HashMap();
+
+ public final static String CRL_EXTENSION = "2.5.29.31";
+ public final static String OCSP_EXTENSION = "1.3.6.1.5.5.7.1.1";
+ private final static DateFormat DF = new SimpleDateFormat("yyyy/MMM/dd");
+
+ public interface SerializableComparator extends Comparator, Serializable {
+ }
+
+ public final static SerializableComparator COMPARE_BY_EXPIRY =
+ new SerializableComparator() {
+ public int compare(Object o1, Object o2) {
+ X509Certificate c1 = (X509Certificate) o1;
+ X509Certificate c2 = (X509Certificate) o2;
+ if (c1 == c2) // this deals with case where both are null
+ {
+ return 0;
+ }
+ if (c1 == null) // non-null is always bigger than null
+ {
+ return -1;
+ }
+ if (c2 == null) {
+ return 1;
+ }
+ if (c1.equals(c2)) {
+ return 0;
+ }
+ Date d1 = c1.getNotAfter();
+ Date d2 = c2.getNotAfter();
+ int c = d1.compareTo(d2);
+ if (c == 0) {
+ String s1 = JavaImpl.getSubjectX500(c1);
+ String s2 = JavaImpl.getSubjectX500(c2);
+ c = s1.compareTo(s2);
+ if (c == 0) {
+ s1 = JavaImpl.getIssuerX500(c1);
+ s2 = JavaImpl.getIssuerX500(c2);
+ c = s1.compareTo(s2);
+ if (c == 0) {
+ BigInteger big1 = c1.getSerialNumber();
+ BigInteger big2 = c2.getSerialNumber();
+ c = big1.compareTo(big2);
+ if (c == 0) {
+ try {
+ byte[] b1 = c1.getEncoded();
+ byte[] b2 = c2.getEncoded();
+ int len1 = b1.length;
+ int len2 = b2.length;
+ int i = 0;
+ for (; i < len1 && i < len2; i++) {
+ c = ((int) b1[i]) - ((int) b2[i]);
+ if (c != 0) {
+ break;
+ }
+ }
+ if (c == 0) {
+ c = b1.length - b2.length;
+ }
+ }
+ catch (CertificateEncodingException cee) {
+ // I give up. They can be equal if they
+ // really want to be this badly.
+ c = 0;
+ }
+ }
+ }
+ }
+ }
+ return c;
+ }
+ };
+
+ static {
+ CertificateFactory cf = null;
+ try {
+ cf = CertificateFactory.getInstance("X.509");
+ }
+ catch (CertificateException ce) {
+ ce.printStackTrace(System.out);
+ }
+ finally {
+ CF = cf;
+ }
+ }
+
+ public static String toPEMString(X509Certificate cert)
+ throws CertificateEncodingException {
+ return toString(cert.getEncoded());
+ }
+
+ public static String toString(byte[] x509Encoded) {
+ byte[] encoded = Base64.encodeBase64(x509Encoded);
+ StringBuffer buf = new StringBuffer(encoded.length + 100);
+ buf.append("-----BEGIN CERTIFICATE-----\n");
+ for (int i = 0; i < encoded.length; i += 64) {
+ if (encoded.length - i >= 64) {
+ buf.append(new String(encoded, i, 64));
+ } else {
+ buf.append(new String(encoded, i, encoded.length - i));
+ }
+ buf.append(LINE_ENDING);
+ }
+ buf.append("-----END CERTIFICATE-----");
+ buf.append(LINE_ENDING);
+ return buf.toString();
+ }
+
+ public static String toString(X509Certificate cert) {
+ return toString(cert, false);
+ }
+
+ public static String toString(X509Certificate cert, boolean htmlStyle) {
+ String cn = getCN(cert);
+ String startStart = DF.format(cert.getNotBefore());
+ String endDate = DF.format(cert.getNotAfter());
+ String subject = JavaImpl.getSubjectX500(cert);
+ String issuer = JavaImpl.getIssuerX500(cert);
+ Iterator crls = getCRLs(cert).iterator();
+ if (subject.equals(issuer)) {
+ issuer = "self-signed";
+ }
+ StringBuffer buf = new StringBuffer(128);
+ if (htmlStyle) {
+ buf.append("<strong class=\"cn\">");
+ }
+ buf.append(cn);
+ if (htmlStyle) {
+ buf.append("</strong>");
+ }
+ buf.append(LINE_ENDING);
+ buf.append("Valid: ");
+ buf.append(startStart);
+ buf.append(" - ");
+ buf.append(endDate);
+ buf.append(LINE_ENDING);
+ buf.append("s: ");
+ buf.append(subject);
+ buf.append(LINE_ENDING);
+ buf.append("i: ");
+ buf.append(issuer);
+ while (crls.hasNext()) {
+ buf.append(LINE_ENDING);
+ buf.append("CRL: ");
+ buf.append((String) crls.next());
+ }
+ buf.append(LINE_ENDING);
+ return buf.toString();
+ }
+
+ public static List getCRLs(X509Extension cert) {
+ // What follows is a poor man's CRL extractor, for those lacking
+ // a BouncyCastle "bcprov.jar" in their classpath.
+
+ // It's a very basic state-machine: look for a standard URL scheme
+ // (such as http), and then start looking for a terminator. After
+ // running hexdump a few times on these things, it looks to me like
+ // the UTF-8 value "65533" seems to happen near where these things
+ // terminate. (Of course this stuff is ASN.1 and not UTF-8, but
+ // I happen to like some of the functions available to the String
+ // object). - juliusdavies at cucbc.com, May 10th, 2006
+ byte[] bytes = cert.getExtensionValue(CRL_EXTENSION);
+ LinkedList httpCRLS = new LinkedList();
+ LinkedList ftpCRLS = new LinkedList();
+ LinkedList otherCRLS = new LinkedList();
+ if (bytes == null) {
+ // just return empty list
+ return httpCRLS;
+ } else {
+ String s;
+ try {
+ s = new String(bytes, "UTF-8");
+ }
+ catch (UnsupportedEncodingException uee) {
+ // We're screwed if this thing has more than one CRL, because
+ // the "indeOf( (char) 65533 )" below isn't going to work.
+ s = new String(bytes);
+ }
+ int pos = 0;
+ while (pos >= 0) {
+ int x = -1, y;
+ int[] indexes = new int[4];
+ indexes[0] = s.indexOf("http", pos);
+ indexes[1] = s.indexOf("ldap", pos);
+ indexes[2] = s.indexOf("file", pos);
+ indexes[3] = s.indexOf("ftp", pos);
+ Arrays.sort(indexes);
+ for (int i = 0; i < indexes.length; i++) {
+ if (indexes[i] >= 0) {
+ x = indexes[i];
+ break;
+ }
+ }
+ if (x >= 0) {
+ y = s.indexOf((char) 65533, x);
+ String crl = y > x ? s.substring(x, y - 1) : s.substring(x);
+ if (y > x && crl.endsWith("0")) {
+ crl = crl.substring(0, crl.length() - 1);
+ }
+ String crlTest = crl.trim().toLowerCase();
+ if (crlTest.startsWith("http")) {
+ httpCRLS.add(crl);
+ } else if (crlTest.startsWith("ftp")) {
+ ftpCRLS.add(crl);
+ } else {
+ otherCRLS.add(crl);
+ }
+ pos = y;
+ } else {
+ pos = -1;
+ }
+ }
+ }
+
+ httpCRLS.addAll(ftpCRLS);
+ httpCRLS.addAll(otherCRLS);
+ return httpCRLS;
+ }
+
+ public static void checkCRL(X509Certificate cert)
+ throws CertificateException {
+ // String name = cert.getSubjectX500Principal().toString();
+ byte[] bytes = cert.getExtensionValue("2.5.29.31");
+ if (bytes == null) {
+ // log.warn( "Cert doesn't contain X509v3 CRL Distribution Points (2.5.29.31): " + name );
+ } else {
+ List crlList = getCRLs(cert);
+ Iterator it = crlList.iterator();
+ while (it.hasNext()) {
+ String url = (String) it.next();
+ CRLHolder holder = (CRLHolder) crl_cache.get(url);
+ if (holder == null) {
+ holder = new CRLHolder(url);
+ crl_cache.put(url, holder);
+ }
+ // success == false means we couldn't actually load the CRL
+ // (probably due to an IOException), so let's try the next one in
+ // our list.
+ boolean success = holder.checkCRL(cert);
+ if (success) {
+ break;
+ }
+ }
+ }
+
+ }
+
+ public static BigInteger getFingerprint(X509Certificate x509)
+ throws CertificateEncodingException {
+ return getFingerprint(x509.getEncoded());
+ }
+
+ public static BigInteger getFingerprint(byte[] x509)
+ throws CertificateEncodingException {
+ MessageDigest sha1;
+ try {
+ sha1 = MessageDigest.getInstance("SHA1");
+ }
+ catch (NoSuchAlgorithmException nsae) {
+ throw JavaImpl.newRuntimeException(nsae);
+ }
+
+ sha1.reset();
+ byte[] result = sha1.digest(x509);
+ return new BigInteger(result);
+ }
+
+ private static class CRLHolder {
+ private final String urlString;
+
+ private File tempCRLFile;
+ private long creationTime;
+ private Set passedTest = new HashSet();
+ private Set failedTest = new HashSet();
+
+ CRLHolder(String urlString) {
+ if (urlString == null) {
+ throw new NullPointerException("urlString can't be null");
+ }
+ this.urlString = urlString;
+ }
+
+ public synchronized boolean checkCRL(X509Certificate cert)
+ throws CertificateException {
+ CRL crl = null;
+ long now = System.currentTimeMillis();
+ if (now - creationTime > 24 * 60 * 60 * 1000) {
+ // Expire cache every 24 hours
+ if (tempCRLFile != null && tempCRLFile.exists()) {
+ tempCRLFile.delete();
+ }
+ tempCRLFile = null;
+ passedTest.clear();
+
+ /*
+ Note: if any certificate ever fails the check, we will
+ remember that fact.
+
+ This breaks with temporary "holds" that CRL's can issue.
+ Apparently a certificate can have a temporary "hold" on its
+ validity, but I'm not interested in supporting that. If a "held"
+ certificate is suddenly "unheld", you're just going to need
+ to restart your JVM.
+ */
+ // failedTest.clear(); <-- DO NOT UNCOMMENT!
+ }
+
+ BigInteger fingerprint = getFingerprint(cert);
+ if (failedTest.contains(fingerprint)) {
+ throw new CertificateException("Revoked by CRL (cached response)");
+ }
+ if (passedTest.contains(fingerprint)) {
+ return true;
+ }
+
+ if (tempCRLFile == null) {
+ try {
+ // log.info( "Trying to load CRL [" + urlString + "]" );
+ URL url = new URL(urlString);
+ File tempFile = File.createTempFile("crl", ".tmp");
+ tempFile.deleteOnExit();
+
+ OutputStream out = new FileOutputStream(tempFile);
+ out = new BufferedOutputStream(out);
+ InputStream in = new BufferedInputStream(url.openStream());
+ try {
+ Util.pipeStream(in, out);
+ }
+ catch (IOException ioe) {
+ // better luck next time
+ tempFile.delete();
+ throw ioe;
+ }
+ this.tempCRLFile = tempFile;
+ this.creationTime = System.currentTimeMillis();
+ }
+ catch (IOException ioe) {
+ // log.warn( "Cannot check CRL: " + e );
+ }
+ }
+
+ if (tempCRLFile != null && tempCRLFile.exists()) {
+ try {
+ InputStream in = new FileInputStream(tempCRLFile);
+ in = new BufferedInputStream(in);
+ synchronized (CF) {
+ crl = CF.generateCRL(in);
+ }
+ in.close();
+ if (crl.isRevoked(cert)) {
+ // log.warn( "Revoked by CRL [" + urlString + "]: " + name );
+ passedTest.remove(fingerprint);
+ failedTest.add(fingerprint);
+ throw new CertificateException("Revoked by CRL");
+ } else {
+ passedTest.add(fingerprint);
+ }
+ }
+ catch (IOException ioe) {
+ // couldn't load CRL that's supposed to be stored in Temp file.
+ // log.warn( );
+ }
+ catch (CRLException crle) {
+ // something is wrong with the CRL
+ // log.warn( );
+ }
+ }
+ return crl != null;
+ }
+ }
+
+ public static String getCN(X509Certificate cert) {
+ String[] cns = getCNs(cert);
+ boolean foundSomeCNs = cns != null && cns.length >= 1;
+ return foundSomeCNs ? cns[0] : null;
+ }
+
+ public static String[] getCNs(X509Certificate cert) {
+ LinkedList cnList = new LinkedList();
+ /*
+ Sebastian Hauer's original StrictSSLProtocolSocketFactory used
+ getName() and had the following comment:
+
+ Parses a X.500 distinguished name for the value of the
+ "Common Name" field. This is done a bit sloppy right
+ now and should probably be done a bit more according to
+ <code>RFC 2253</code>.
+
+ I've noticed that toString() seems to do a better job than
+ getName() on these X500Principal objects, so I'm hoping that
+ addresses Sebastian's concern.
+
+ For example, getName() gives me this:
+ 1.2.840.113549.1.9.1=#16166a756c6975736461766965734063756362632e636f6d
+
+ whereas toString() gives me this:
+ EMAILADDRESS=juliusdavies at cucbc.com
+
+ Looks like toString() even works with non-ascii domain names!
+ I tested it with "花子.co.jp" and it worked fine.
+ */
+ String subjectPrincipal = cert.getSubjectX500Principal().toString();
+ StringTokenizer st = new StringTokenizer(subjectPrincipal, ",");
+ while (st.hasMoreTokens()) {
+ String tok = st.nextToken();
+ int x = tok.indexOf("CN=");
+ if (x >= 0) {
+ cnList.add(tok.substring(x + 3));
+ }
+ }
+ if (!cnList.isEmpty()) {
+ String[] cns = new String[cnList.size()];
+ cnList.toArray(cns);
+ return cns;
+ } else {
+ return null;
+ }
+ }
+
+
+ /**
+ * Extracts the array of SubjectAlt DNS names from an X509Certificate.
+ * Returns null if there aren't any.
+ * <p/>
+ * Note: Java doesn't appear able to extract international characters
+ * from the SubjectAlts. It can only extract international characters
+ * from the CN field.
+ * <p/>
+ * (Or maybe the version of OpenSSL I'm using to test isn't storing the
+ * international characters correctly in the SubjectAlts?).
+ *
+ * @param cert X509Certificate
+ * @return Array of SubjectALT DNS names stored in the certificate.
+ */
+ public static String[] getDNSSubjectAlts(X509Certificate cert) {
+ LinkedList subjectAltList = new LinkedList();
+ Collection c = null;
+ try {
+ c = cert.getSubjectAlternativeNames();
+ }
+ catch (CertificateParsingException cpe) {
+ // Should probably log.debug() this?
+ cpe.printStackTrace();
+ }
+ if (c != null) {
+ Iterator it = c.iterator();
+ while (it.hasNext()) {
+ List list = (List) it.next();
+ int type = ((Integer) list.get(0)).intValue();
+ // If type is 2, then we've got a dNSName
+ if (type == 2) {
+ String s = (String) list.get(1);
+ subjectAltList.add(s);
+ }
+ }
+ }
+ if (!subjectAltList.isEmpty()) {
+ String[] subjectAlts = new String[subjectAltList.size()];
+ subjectAltList.toArray(subjectAlts);
+ return subjectAlts;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Trims off any null entries on the array. Returns a shrunk array.
+ *
+ * @param chain X509Certificate[] chain to trim
+ * @return Shrunk array with all trailing null entries removed.
+ */
+ public static X509Certificate[] trimChain(X509Certificate[] chain) {
+ for (int i = 0; i < chain.length; i++) {
+ if (chain[i] == null) {
+ X509Certificate[] newChain = new X509Certificate[i];
+ System.arraycopy(chain, 0, newChain, 0, i);
+ return newChain;
+ }
+ }
+ return chain;
+ }
+
+ /**
+ * Returns a chain of type X509Certificate[].
+ *
+ * @param chain Certificate[] chain to cast to X509Certificate[]
+ * @return chain of type X509Certificate[].
+ */
+ public static X509Certificate[] x509ifyChain(Certificate[] chain) {
+ if (chain instanceof X509Certificate[]) {
+ return (X509Certificate[]) chain;
+ } else {
+ X509Certificate[] x509Chain = new X509Certificate[chain.length];
+ System.arraycopy(chain, 0, x509Chain, 0, chain.length);
+ return x509Chain;
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ for (int i = 0; i < args.length; i++) {
+ FileInputStream in = new FileInputStream(args[i]);
+ TrustMaterial tm = new TrustMaterial(in);
+ Iterator it = tm.getCertificates().iterator();
+ while (it.hasNext()) {
+ X509Certificate x509 = (X509Certificate) it.next();
+ System.out.println(toString(x509));
+ }
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/ComboInputStream.java b/src/java/org/apache/commons/ssl/ComboInputStream.java
new file mode 100644
index 0000000..d431009
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/ComboInputStream.java
@@ -0,0 +1,96 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/ComboInputStream.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 22-Feb-2007
+ */
+public class ComboInputStream extends InputStream {
+ private boolean headDone;
+ private InputStream head;
+ private InputStream tail;
+
+ public ComboInputStream(InputStream head, InputStream tail) {
+ this.head = head != null ? head : tail;
+ this.tail = tail != null ? tail : head;
+ }
+
+ public int read() throws IOException {
+ int c;
+ if (headDone) {
+ c = tail.read();
+ } else {
+ c = head.read();
+ if (c == -1) {
+ headDone = true;
+ c = tail.read();
+ }
+ }
+ return c;
+ }
+
+ public int available() throws IOException {
+ return tail.available() + head.available();
+ }
+
+ public void close() throws IOException {
+ try {
+ head.close();
+ }
+ finally {
+ if (head != tail) {
+ tail.close();
+ }
+ }
+ }
+
+ public int read(byte b[], int off, int len) throws IOException {
+ int c;
+ if (headDone) {
+ c = tail.read(b, off, len);
+ } else {
+ c = head.read(b, off, len);
+ if (c == -1) {
+ headDone = true;
+ c = tail.read(b, off, len);
+ }
+ }
+ return c;
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/DerivedKey.java b/src/java/org/apache/commons/ssl/DerivedKey.java
new file mode 100644
index 0000000..9e1ed4d
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/DerivedKey.java
@@ -0,0 +1,49 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/DerivedKey.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 7-Nov-2006
+ */
+public class DerivedKey {
+ public final byte[] key;
+ public final byte[] iv;
+
+ DerivedKey(byte[] key, byte[] iv) {
+ this.key = key;
+ this.iv = iv;
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/HostPort.java b/src/java/org/apache/commons/ssl/HostPort.java
new file mode 100644
index 0000000..1826c0a
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/HostPort.java
@@ -0,0 +1,55 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/HostPort.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 14-July-2006
+ */
+public class HostPort {
+ public final String host;
+ public final int port;
+ public final InetAddress addr;
+
+ public HostPort(String host, int port) throws UnknownHostException {
+ this.host = host;
+ this.port = port;
+ this.addr = InetAddress.getByName(host);
+ }
+
+ public String toString() { return host + ":" + port; }
+}
diff --git a/src/java/org/apache/commons/ssl/HostnameVerifier.java b/src/java/org/apache/commons/ssl/HostnameVerifier.java
new file mode 100644
index 0000000..c6f22c2
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/HostnameVerifier.java
@@ -0,0 +1,481 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/HostnameVerifier.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.TreeSet;
+
+/**
+ * Interface for checking if a hostname matches the names stored inside the
+ * server's X.509 certificate. Correctly implements
+ * javax.net.ssl.HostnameVerifier, but that interface is not recommended.
+ * Instead we added several check() methods that take SSLSocket,
+ * or X509Certificate, or ultimately (they all end up calling this one),
+ * String. (It's easier to supply JUnit with Strings instead of mock
+ * SSLSession objects!)
+ * </p><p>Our check() methods throw exceptions if the name is
+ * invalid, whereas javax.net.ssl.HostnameVerifier just returns true/false.
+ * <p/>
+ * We provide the HostnameVerifier.DEFAULT, HostnameVerifier.STRICT, and
+ * HostnameVerifier.ALLOW_ALL implementations. We also provide the more
+ * specialized HostnameVerifier.DEFAULT_AND_LOCALHOST, as well as
+ * HostnameVerifier.STRICT_IE6. But feel free to define your own
+ * implementations!
+ * <p/>
+ * Inspired by Sebastian Hauer's original StrictSSLProtocolSocketFactory in the
+ * HttpClient "contrib" repository.
+ *
+ * @author Julius Davies
+ * @author <a href="mailto:hauer at psicode.com">Sebastian Hauer</a>
+ * @since 8-Dec-2006
+ */
+public interface HostnameVerifier extends javax.net.ssl.HostnameVerifier {
+
+ boolean verify(String host, SSLSession session);
+
+ void check(String host, SSLSocket ssl) throws IOException;
+
+ void check(String host, X509Certificate cert) throws SSLException;
+
+ void check(String host, String[] cns, String[] subjectAlts)
+ throws SSLException;
+
+ void check(String[] hosts, SSLSocket ssl) throws IOException;
+
+ void check(String[] hosts, X509Certificate cert) throws SSLException;
+
+
+ /**
+ * Checks to see if the supplied hostname matches any of the supplied CNs
+ * or "DNS" Subject-Alts. Most implementations only look at the first CN,
+ * and ignore any additional CNs. Most implementations do look at all of
+ * the "DNS" Subject-Alts. The CNs or Subject-Alts may contain wildcards
+ * according to RFC 2818.
+ *
+ * @param cns CN fields, in order, as extracted from the X.509
+ * certificate.
+ * @param subjectAlts Subject-Alt fields of type 2 ("DNS"), as extracted
+ * from the X.509 certificate.
+ * @param hosts The array of hostnames to verify.
+ * @throws SSLException If verification failed.
+ */
+ void check(String[] hosts, String[] cns, String[] subjectAlts)
+ throws SSLException;
+
+
+ /**
+ * The DEFAULT HostnameVerifier works the same way as Curl and Firefox.
+ * <p/>
+ * The hostname must match either the first CN, or any of the subject-alts.
+ * A wildcard can occur in the CN, and in any of the subject-alts.
+ * <p/>
+ * The only difference between DEFAULT and STRICT is that a wildcard (such
+ * as "*.foo.com") with DEFAULT matches all subdomains, including
+ * "a.b.foo.com".
+ */
+ public final static HostnameVerifier DEFAULT =
+ new AbstractVerifier() {
+ public final void check(final String[] hosts, final String[] cns,
+ final String[] subjectAlts)
+ throws SSLException {
+ check(hosts, cns, subjectAlts, false, false);
+ }
+
+ public final String toString() { return "DEFAULT"; }
+ };
+
+
+ /**
+ * The DEFAULT_AND_LOCALHOST HostnameVerifier works like the DEFAULT
+ * one with one additional relaxation: a host of "localhost",
+ * "localhost.localdomain", "127.0.0.1", "::1" will always pass, no matter
+ * what is in the server's certificate.
+ */
+ public final static HostnameVerifier DEFAULT_AND_LOCALHOST =
+ new AbstractVerifier() {
+ public final void check(final String[] hosts, final String[] cns,
+ final String[] subjectAlts)
+ throws SSLException {
+ if (isLocalhost(hosts[0])) {
+ return;
+ }
+ check(hosts, cns, subjectAlts, false, false);
+ }
+
+ public final String toString() { return "DEFAULT_AND_LOCALHOST"; }
+ };
+
+ /**
+ * The STRICT HostnameVerifier works the same way as java.net.URL in Sun
+ * Java 1.4, Sun Java 5, Sun Java 6. It's also pretty close to IE6.
+ * This implementation appears to be compliant with RFC 2818 for dealing
+ * with wildcards.
+ * <p/>
+ * The hostname must match either the first CN, or any of the subject-alts.
+ * A wildcard can occur in the CN, and in any of the subject-alts. The
+ * one divergence from IE6 is how we only check the first CN. IE6 allows
+ * a match against any of the CNs present. We decided to follow in
+ * Sun Java 1.4's footsteps and only check the first CN.
+ * <p/>
+ * A wildcard such as "*.foo.com" matches only subdomains in the same
+ * level, for example "a.foo.com". It does not match deeper subdomains
+ * such as "a.b.foo.com".
+ */
+ public final static HostnameVerifier STRICT =
+ new AbstractVerifier() {
+ public final void check(final String[] host, final String[] cns,
+ final String[] subjectAlts)
+ throws SSLException {
+ check(host, cns, subjectAlts, false, true);
+ }
+
+ public final String toString() { return "STRICT"; }
+ };
+
+ /**
+ * The STRICT_IE6 HostnameVerifier works just like the STRICT one with one
+ * minor variation: the hostname can match against any of the CN's in the
+ * server's certificate, not just the first one. This behaviour is
+ * identical to IE6's behaviour.
+ */
+ public final static HostnameVerifier STRICT_IE6 =
+ new AbstractVerifier() {
+ public final void check(final String[] host, final String[] cns,
+ final String[] subjectAlts)
+ throws SSLException {
+ check(host, cns, subjectAlts, true, true);
+ }
+
+ public final String toString() { return "STRICT_IE6"; }
+ };
+
+ /**
+ * The ALLOW_ALL HostnameVerifier essentially turns hostname verification
+ * off. This implementation is a no-op, and never throws the SSLException.
+ */
+ public final static HostnameVerifier ALLOW_ALL =
+ new AbstractVerifier() {
+ public final void check(final String[] host, final String[] cns,
+ final String[] subjectAlts) {
+ // Allow everything - so never blowup.
+ }
+
+ public final String toString() { return "ALLOW_ALL"; }
+ };
+
+ abstract class AbstractVerifier implements HostnameVerifier {
+
+ /**
+ * This contains a list of 2nd-level domains that aren't allowed to
+ * have wildcards when combined with country-codes.
+ * For example: [*.co.uk].
+ * <p/>
+ * The [*.co.uk] problem is an interesting one. Should we just hope
+ * that CA's would never foolishly allow such a certificate to happen?
+ * Looks like we're the only implementation guarding against this.
+ * Firefox, Curl, Sun Java 1.4, 5, 6 don't bother with this check.
+ */
+ private final static String[] BAD_COUNTRY_2LDS =
+ {"ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info",
+ "lg", "ne", "net", "or", "org"};
+
+ private final static String[] LOCALHOSTS = {"::1", "127.0.0.1",
+ "localhost",
+ "localhost.localdomain"};
+
+
+ static {
+ // Just in case developer forgot to manually sort the array. :-)
+ Arrays.sort(BAD_COUNTRY_2LDS);
+ Arrays.sort(LOCALHOSTS);
+ }
+
+ protected AbstractVerifier() {}
+
+ /**
+ * The javax.net.ssl.HostnameVerifier contract.
+ *
+ * @param host 'hostname' we used to create our socket
+ * @param session SSLSession with the remote server
+ * @return true if the host matched the one in the certificate.
+ */
+ public boolean verify(String host, SSLSession session) {
+ try {
+ Certificate[] certs = session.getPeerCertificates();
+ X509Certificate x509 = (X509Certificate) certs[0];
+ check(new String[]{host}, x509);
+ return true;
+ }
+ catch (SSLException e) {
+ return false;
+ }
+ }
+
+ public void check(String host, SSLSocket ssl) throws IOException {
+ check(new String[]{host}, ssl);
+ }
+
+ public void check(String host, X509Certificate cert)
+ throws SSLException {
+ check(new String[]{host}, cert);
+ }
+
+ public void check(String host, String[] cns, String[] subjectAlts)
+ throws SSLException {
+ check(new String[]{host}, cns, subjectAlts);
+ }
+
+ public void check(String host[], SSLSocket ssl)
+ throws IOException {
+ if (host == null) {
+ throw new NullPointerException("host to verify is null");
+ }
+
+ SSLSession session = ssl.getSession();
+ if (session == null) {
+ // In our experience this only happens under IBM 1.4.x when
+ // spurious (unrelated) certificates show up in the server'
+ // chain. Hopefully this will unearth the real problem:
+ InputStream in = ssl.getInputStream();
+ in.available();
+ /*
+ If you're looking at the 2 lines of code above because
+ you're running into a problem, you probably have two
+ options:
+
+ #1. Clean up the certificate chain that your server
+ is presenting (e.g. edit "/etc/apache2/server.crt"
+ or wherever it is your server's certificate chain
+ is defined).
+
+ OR
+
+ #2. Upgrade to an IBM 1.5.x or greater JVM, or switch
+ to a non-IBM JVM.
+ */
+
+ // If ssl.getInputStream().available() didn't cause an
+ // exception, maybe at least now the session is available?
+ session = ssl.getSession();
+ if (session == null) {
+ // If it's still null, probably a startHandshake() will
+ // unearth the real problem.
+ ssl.startHandshake();
+
+ // Okay, if we still haven't managed to cause an exception,
+ // might as well go for the NPE. Or maybe we're okay now?
+ session = ssl.getSession();
+ }
+ }
+ Certificate[] certs;
+ try {
+ certs = session.getPeerCertificates();
+ } catch (SSLPeerUnverifiedException spue) {
+ InputStream in = ssl.getInputStream();
+ in.available();
+ // Didn't trigger anything interesting? Okay, just throw
+ // original.
+ throw spue;
+ }
+ X509Certificate x509 = (X509Certificate) certs[0];
+ check(host, x509);
+ }
+
+ public void check(String[] host, X509Certificate cert)
+ throws SSLException {
+ String[] cns = Certificates.getCNs(cert);
+ String[] subjectAlts = Certificates.getDNSSubjectAlts(cert);
+ check(host, cns, subjectAlts);
+ }
+
+ public void check(final String[] hosts, final String[] cns,
+ final String[] subjectAlts, final boolean ie6,
+ final boolean strictWithSubDomains)
+ throws SSLException {
+ // Build up lists of allowed hosts For logging/debugging purposes.
+ StringBuffer buf = new StringBuffer(32);
+ buf.append('<');
+ for (int i = 0; i < hosts.length; i++) {
+ String h = hosts[i];
+ h = h != null ? h.trim().toLowerCase() : "";
+ hosts[i] = h;
+ if (i > 0) {
+ buf.append('/');
+ }
+ buf.append(h);
+ }
+ buf.append('>');
+ String hostnames = buf.toString();
+ // Build the list of names we're going to check. Our DEFAULT and
+ // STRICT implementations of the HostnameVerifier only use the
+ // first CN provided. All other CNs are ignored.
+ // (Firefox, wget, curl, Sun Java 1.4, 5, 6 all work this way).
+ TreeSet names = new TreeSet();
+ if (cns != null && cns.length > 0 && cns[0] != null) {
+ names.add(cns[0]);
+ if (ie6) {
+ for (int i = 1; i < cns.length; i++) {
+ names.add(cns[i]);
+ }
+ }
+ }
+ if (subjectAlts != null) {
+ for (int i = 0; i < subjectAlts.length; i++) {
+ if (subjectAlts[i] != null) {
+ names.add(subjectAlts[i]);
+ }
+ }
+ }
+ if (names.isEmpty()) {
+ String msg = "Certificate for " + hosts[0] + " doesn't contain CN or DNS subjectAlt";
+ throw new SSLException(msg);
+ }
+
+ // StringBuffer for building the error message.
+ buf = new StringBuffer();
+
+ boolean match = false;
+ out:
+ for (Iterator it = names.iterator(); it.hasNext();) {
+ // Don't trim the CN, though!
+ String cn = (String) it.next();
+ cn = cn.toLowerCase();
+ // Store CN in StringBuffer in case we need to report an error.
+ buf.append(" <");
+ buf.append(cn);
+ buf.append('>');
+ if (it.hasNext()) {
+ buf.append(" OR");
+ }
+
+ // The CN better have at least two dots if it wants wildcard
+ // action. It also can't be [*.co.uk] or [*.co.jp] or
+ // [*.org.uk], etc...
+ boolean doWildcard = cn.startsWith("*.") &&
+ cn.lastIndexOf('.') >= 0 &&
+ !isIP4Address(cn) &&
+ acceptableCountryWildcard(cn);
+
+ for (int i = 0; i < hosts.length; i++) {
+ final String hostName = hosts[i].trim().toLowerCase();
+ if (doWildcard) {
+ match = hostName.endsWith(cn.substring(1));
+ if (match && strictWithSubDomains) {
+ // If we're in strict mode, then [*.foo.com] is not
+ // allowed to match [a.b.foo.com]
+ match = countDots(hostName) == countDots(cn);
+ }
+ } else {
+ match = hostName.equals(cn);
+ }
+ if (match) {
+ break out;
+ }
+ }
+ }
+ if (!match) {
+ throw new SSLException("hostname in certificate didn't match: " + hostnames + " !=" + buf);
+ }
+ }
+
+ public static boolean isIP4Address(final String cn) {
+ boolean isIP4 = true;
+ String tld = cn;
+ int x = cn.lastIndexOf('.');
+ // We only bother analyzing the characters after the final dot
+ // in the name.
+ if (x >= 0 && x + 1 < cn.length()) {
+ tld = cn.substring(x + 1);
+ }
+ for (int i = 0; i < tld.length(); i++) {
+ if (!Character.isDigit(tld.charAt(0))) {
+ isIP4 = false;
+ break;
+ }
+ }
+ return isIP4;
+ }
+
+ public static boolean acceptableCountryWildcard(final String cn) {
+ int cnLen = cn.length();
+ if (cnLen >= 7 && cnLen <= 9) {
+ // Look for the '.' in the 3rd-last position:
+ if (cn.charAt(cnLen - 3) == '.') {
+ // Trim off the [*.] and the [.XX].
+ String s = cn.substring(2, cnLen - 3);
+ // And test against the sorted array of bad 2lds:
+ int x = Arrays.binarySearch(BAD_COUNTRY_2LDS, s);
+ return x < 0;
+ }
+ }
+ return true;
+ }
+
+ public static boolean isLocalhost(String host) {
+ host = host != null ? host.trim().toLowerCase() : "";
+ if (host.startsWith("::1")) {
+ int x = host.lastIndexOf('%');
+ if (x >= 0) {
+ host = host.substring(0, x);
+ }
+ }
+ int x = Arrays.binarySearch(LOCALHOSTS, host);
+ return x >= 0;
+ }
+
+ /**
+ * Counts the number of dots "." in a string.
+ *
+ * @param s string to count dots from
+ * @return number of dots
+ */
+ public static int countDots(final String s) {
+ int count = 0;
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == '.') {
+ count++;
+ }
+ }
+ return count;
+ }
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/HttpSecureProtocol.java b/src/java/org/apache/commons/ssl/HttpSecureProtocol.java
new file mode 100644
index 0000000..9624865
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/HttpSecureProtocol.java
@@ -0,0 +1,93 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/HttpSecureProtocol.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import org.apache.commons.httpclient.params.HttpConnectionParams;
+import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.security.GeneralSecurityException;
+
+/**
+ * Hook into HttpClient.
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 5-May-2006
+ */
+public class HttpSecureProtocol extends SSLClient
+ implements SecureProtocolSocketFactory {
+
+ public HttpSecureProtocol()
+ throws GeneralSecurityException, IOException {
+ super();
+ }
+
+ /**
+ * Attempts to get a new socket connection to the given host within the
+ * given time limit.
+ * <p/>
+ * To circumvent the limitations of older JREs that do not support connect
+ * timeout a controller thread is executed. The controller thread attempts
+ * to create a new socket within the given limit of time. If socket
+ * constructor does not return until the timeout expires, the controller
+ * terminates and throws an
+ * {@link org.apache.commons.httpclient.ConnectTimeoutException}
+ * </p>
+ *
+ * @param host the host name/IP
+ * @param port the port on the host
+ * @param localAddress the local host name/IP to bind the socket to
+ * @param localPort the port on the local machine
+ * @param params {@link org.apache.commons.httpclient.params.HttpConnectionParams Http connection parameters}
+ * @return Socket a new socket
+ * @throws java.io.IOException if an I/O error occurs while creating the socket
+ * @throws java.net.UnknownHostException if the IP address of the host cannot be
+ * determined
+ */
+ public Socket createSocket(final String host,
+ final int port,
+ final InetAddress localAddress,
+ final int localPort,
+ final HttpConnectionParams params)
+ throws IOException {
+ if (params == null) {
+ throw new IllegalArgumentException("Parameters may not be null");
+ }
+ int timeout = params.getConnectionTimeout();
+ return super.createSocket(host, port, localAddress, localPort, timeout);
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/Java13.java b/src/java/org/apache/commons/ssl/Java13.java
new file mode 100644
index 0000000..b8a2721
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Java13.java
@@ -0,0 +1,290 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Java13.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import com.sun.net.ssl.KeyManager;
+import com.sun.net.ssl.KeyManagerFactory;
+import com.sun.net.ssl.SSLContext;
+import com.sun.net.ssl.TrustManager;
+import com.sun.net.ssl.TrustManagerFactory;
+import com.sun.net.ssl.X509KeyManager;
+import com.sun.net.ssl.X509TrustManager;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.URL;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.Provider;
+import java.security.Security;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 30-Jun-2006
+ */
+public final class Java13 extends JavaImpl {
+ private final static Java13 instance = new Java13();
+
+ private Java13() {
+ try {
+ Class c = Class.forName("javax.crypto.Cipher");
+ Class[] sig = {String.class};
+ String[] args = {"DES/CBC/PKCS5Padding"};
+ Method m = c.getMethod("getInstance", sig);
+ m.invoke(null, args);
+ }
+ catch (Exception e) {
+ try {
+ Class c = Class.forName("com.sun.crypto.provider.SunJCE");
+ Security.addProvider((Provider) c.newInstance());
+ // System.out.println( "jce not loaded: " + e + " - loading SunJCE!" );
+ //e.printStackTrace( System.out );
+ }
+ catch (Exception e2) {
+ System.out.println("com.sun.crypto.provider.SunJCE unavailable: " + e2);
+ // e2.printStackTrace( System.out );
+ }
+ }
+ try {
+ URL u = new URL("https://vancity.com/");
+ u.openConnection();
+ }
+ catch (Exception e) {
+ // System.out.println( "java.net.URL support of https not loaded: " + e + " - attempting to load com.sun.net.ssl.internal.ssl.Provider!" );
+ Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider());
+ System.setProperty("java.protocol.handler.pkgs", "com.sun.net.ssl.internal.www.protocol");
+ }
+ // System.out.println( "old HANDLER: " + HANDLER );
+ }
+
+ public static Java13 getInstance() {
+ return instance;
+ }
+
+ public final String getVersion() {
+ return "Java13";
+ }
+
+ protected final String retrieveSubjectX500(X509Certificate cert) {
+ return cert.getSubjectDN().toString();
+ }
+
+ protected final String retrieveIssuerX500(X509Certificate cert) {
+ return cert.getIssuerDN().toString();
+ }
+
+ protected final Certificate[] retrievePeerCerts(SSLSession sslSession)
+ throws SSLPeerUnverifiedException {
+ javax.security.cert.X509Certificate[] chain;
+ chain = sslSession.getPeerCertificateChain();
+ X509Certificate[] newChain = new X509Certificate[chain.length];
+ try {
+ for (int i = 0; i < chain.length; i++) {
+ javax.security.cert.X509Certificate javaxCert = chain[i];
+ byte[] encoded = javaxCert.getEncoded();
+ ByteArrayInputStream in = new ByteArrayInputStream(encoded);
+ synchronized (Certificates.CF) {
+ Certificate c = Certificates.CF.generateCertificate(in);
+ newChain[i] = (X509Certificate) c;
+ }
+ }
+ }
+ catch (Exception e) {
+ throw buildRuntimeException(e);
+ }
+ return newChain;
+ }
+
+ protected final Object buildKeyManagerFactory(KeyStore ks, char[] password)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ UnrecoverableKeyException {
+ String alg = KeyManagerFactory.getDefaultAlgorithm();
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(alg);
+ kmf.init(ks, password);
+ // overwrite password
+ for (int i = 0; i < password.length; i++) {
+ password[i] = '*';
+ }
+ return kmf;
+ }
+
+ protected final Object buildTrustManagerFactory(KeyStore ks)
+ throws NoSuchAlgorithmException, KeyStoreException {
+ String alg = TrustManagerFactory.getDefaultAlgorithm();
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(alg);
+ tmf.init(ks);
+ return tmf;
+ }
+
+
+ protected final Object[] retrieveKeyManagers(Object keyManagerFactory) {
+ KeyManagerFactory kmf = (KeyManagerFactory) keyManagerFactory;
+ return kmf.getKeyManagers();
+ }
+
+ protected final Object[] retrieveTrustManagers(Object trustManagerFactory) {
+ TrustManagerFactory tmf = (TrustManagerFactory) trustManagerFactory;
+ return tmf.getTrustManagers();
+ }
+
+ protected final SSLSocketFactory buildSSLSocketFactory(Object ssl) {
+ return ((SSLContext) ssl).getSocketFactory();
+ }
+
+ protected final SSLServerSocketFactory buildSSLServerSocketFactory(Object ssl) {
+ return ((SSLContext) ssl).getServerSocketFactory();
+ }
+
+ protected final RuntimeException buildRuntimeException(Exception cause) {
+ ByteArrayOutputStream byteOut = new ByteArrayOutputStream(512);
+ PrintStream ps = new PrintStream(byteOut);
+ ps.println(cause.toString());
+ cause.printStackTrace(ps);
+ ps.flush();
+ String originalCause = byteOut.toString();
+ return new RuntimeException(originalCause);
+ }
+
+ protected final SSLSocket buildSocket(SSL ssl) {
+ // Not supported in Java 1.3.
+ throw new UnsupportedOperationException();
+ }
+
+ protected final SSLSocket buildSocket(SSL ssl, String remoteHost,
+ int remotePort, InetAddress localHost,
+ int localPort, int connectTimeout)
+ throws IOException {
+ // Connect Timeout ignored for Java 1.3
+ SSLSocketFactory sf = ssl.getSSLSocketFactory();
+ SSLSocket s = (SSLSocket) connectSocket(null, sf, remoteHost,
+ remotePort, localHost,
+ localPort, -1);
+ ssl.doPreConnectSocketStuff(s);
+ ssl.doPostConnectSocketStuff(s, remoteHost);
+ return s;
+ }
+
+ protected final Socket connectSocket(Socket s, SocketFactory sf,
+ String remoteHost, int remotePort,
+ InetAddress localHost, int localPort,
+ int timeout)
+ throws IOException {
+ // Connect Timeout ignored for Java 1.3
+ if (s == null) {
+ if (sf == null) {
+ s = new Socket(remoteHost, remotePort, localHost, localPort);
+ } else {
+ s = sf.createSocket(remoteHost, remotePort, localHost, localPort);
+ }
+ }
+ return s;
+ }
+
+
+ protected final SSLServerSocket buildServerSocket(SSL ssl) {
+ // Not supported in Java 1.3.
+ throw new UnsupportedOperationException();
+ }
+
+ protected final void wantClientAuth(Object o, boolean wantClientAuth) {
+ // Not supported in Java 1.3.
+ }
+
+ protected final void enabledProtocols(Object o, String[] enabledProtocols) {
+ // Not supported in Java 1.3.
+ }
+
+ protected void checkTrusted(Object trustManager, X509Certificate[] chain,
+ String authType)
+ throws CertificateException {
+ X509TrustManager tm = (X509TrustManager) trustManager;
+ boolean result = tm.isServerTrusted(chain);
+ if (!result) {
+ throw new CertificateException("commons-ssl java13 mode: certificate chain not trusted");
+ }
+ }
+
+
+ protected final Object initSSL(SSL ssl, TrustChain tc, KeyMaterial k)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ CertificateException, KeyManagementException, IOException {
+ SSLContext context = SSLContext.getInstance(ssl.getDefaultProtocol());
+ TrustManager[] trustManagers = null;
+ KeyManager[] keyManagers = null;
+ if (tc != null) {
+ trustManagers = (TrustManager[]) tc.getTrustManagers();
+ }
+ if (k != null) {
+ keyManagers = (KeyManager[]) k.getKeyManagers();
+ }
+ if (keyManagers != null) {
+ for (int i = 0; i < keyManagers.length; i++) {
+ if (keyManagers[i] instanceof X509KeyManager) {
+ X509KeyManager km = (X509KeyManager) keyManagers[i];
+ keyManagers[i] = new Java13KeyManagerWrapper(km, k, ssl);
+ }
+ }
+ }
+ if (trustManagers != null) {
+ for (int i = 0; i < trustManagers.length; i++) {
+ if (trustManagers[i] instanceof X509TrustManager) {
+ X509TrustManager tm = (X509TrustManager) trustManagers[i];
+ trustManagers[i] = new Java13TrustManagerWrapper(tm, tc, ssl);
+ }
+ }
+ }
+ context.init(keyManagers, trustManagers, null);
+ return context;
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/Java13KeyManagerWrapper.java b/src/java/org/apache/commons/ssl/Java13KeyManagerWrapper.java
new file mode 100644
index 0000000..9222496
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Java13KeyManagerWrapper.java
@@ -0,0 +1,82 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Java13KeyManagerWrapper.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import com.sun.net.ssl.X509KeyManager;
+
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 30-Jun-2006
+ */
+public class Java13KeyManagerWrapper implements X509KeyManager {
+
+ private final X509KeyManager keyManager;
+ // private final KeyMaterial keyMaterial; <-- maybe use one day in the
+ // private final SSL ssl; <-- in the future?
+
+ public Java13KeyManagerWrapper(X509KeyManager m, KeyMaterial km, SSL h) {
+ this.keyManager = m;
+ // this.keyMaterial = km; <-- maybe use one day in the
+ // this.ssl = h; <-- in the future?
+ }
+
+ public String chooseClientAlias(String keyType, Principal[] issuers) {
+ return keyManager.chooseClientAlias(keyType, issuers);
+ }
+
+ public String chooseServerAlias(String keyType, Principal[] issuers) {
+ return keyManager.chooseServerAlias(keyType, issuers);
+ }
+
+ public X509Certificate[] getCertificateChain(String alias) {
+ return keyManager.getCertificateChain(alias);
+ }
+
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ return keyManager.getClientAliases(keyType, issuers);
+ }
+
+ public PrivateKey getPrivateKey(String alias) {
+ return keyManager.getPrivateKey(alias);
+ }
+
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ return keyManager.getServerAliases(keyType, issuers);
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/Java13TrustManagerWrapper.java b/src/java/org/apache/commons/ssl/Java13TrustManagerWrapper.java
new file mode 100644
index 0000000..0821015
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Java13TrustManagerWrapper.java
@@ -0,0 +1,99 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Java13TrustManagerWrapper.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import com.sun.net.ssl.X509TrustManager;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 30-Jun-2006
+ */
+public class Java13TrustManagerWrapper implements X509TrustManager {
+
+ private final X509TrustManager trustManager;
+ private final TrustChain trustChain;
+ private final SSL ssl;
+
+ public Java13TrustManagerWrapper(X509TrustManager m, TrustChain tc, SSL h) {
+ this.trustManager = m;
+ this.trustChain = tc;
+ this.ssl = h;
+ }
+
+ public boolean isClientTrusted(X509Certificate[] chain) {
+ ssl.setCurrentClientChain(chain);
+ boolean firstTest = trustManager.isClientTrusted(chain);
+ return test(firstTest, chain);
+ }
+
+ public boolean isServerTrusted(X509Certificate[] chain) {
+ ssl.setCurrentServerChain(chain);
+ boolean firstTest = trustManager.isServerTrusted(chain);
+ return test(firstTest, chain);
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return trustManager.getAcceptedIssuers();
+ }
+
+ private boolean test(boolean firstTest, X509Certificate[] chain) {
+ // Even if the first test failed, we might still be okay as long as
+ // this SSLServer or SSLClient is setup to trust all certificates.
+ if (!firstTest) {
+ if (!trustChain.contains(TrustMaterial.TRUST_ALL)) {
+ return false;
+ }
+ }
+
+ try {
+ for (int i = 0; i < chain.length; i++) {
+ X509Certificate c = chain[i];
+ if (ssl.getCheckExpiry()) {
+ c.checkValidity();
+ }
+ if (ssl.getCheckCRL()) {
+ Certificates.checkCRL(c);
+ }
+ }
+ return true;
+ }
+ catch (CertificateException ce) {
+ return false;
+ }
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/Java14.java b/src/java/org/apache/commons/ssl/Java14.java
new file mode 100644
index 0000000..d416391
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Java14.java
@@ -0,0 +1,258 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Java14.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509KeyManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 30-Jun-2006
+ */
+public final class Java14 extends JavaImpl {
+ private static Java14 instance = new Java14();
+
+ private Java14() {
+ try {
+ SSLSocketFactory.getDefault().createSocket();
+ }
+ catch (IOException ioe) {
+ ioe.hashCode();
+ }
+ }
+
+ public static Java14 getInstance() {
+ return instance;
+ }
+
+ public final String getVersion() {
+ return "Java14";
+ }
+
+ protected final String retrieveSubjectX500(X509Certificate cert) {
+ return cert.getSubjectX500Principal().toString();
+ }
+
+ protected final String retrieveIssuerX500(X509Certificate cert) {
+ return cert.getIssuerX500Principal().toString();
+ }
+
+ protected final Certificate[] retrievePeerCerts(SSLSession sslSession)
+ throws SSLPeerUnverifiedException {
+ return sslSession.getPeerCertificates();
+ }
+
+ protected final Object buildKeyManagerFactory(KeyStore ks, char[] password)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ UnrecoverableKeyException {
+ String alg = KeyManagerFactory.getDefaultAlgorithm();
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(alg);
+ kmf.init(ks, password);
+ // overwrite password
+ for (int i = 0; i < password.length; i++) {
+ password[i] = '*';
+ }
+ return kmf;
+ }
+
+ protected final Object buildTrustManagerFactory(KeyStore ks)
+ throws NoSuchAlgorithmException, KeyStoreException {
+ String alg = TrustManagerFactory.getDefaultAlgorithm();
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(alg);
+ tmf.init(ks);
+ return tmf;
+ }
+
+ protected final Object[] retrieveKeyManagers(Object keyManagerFactory) {
+ KeyManagerFactory kmf = (KeyManagerFactory) keyManagerFactory;
+ return kmf.getKeyManagers();
+ }
+
+ protected final Object[] retrieveTrustManagers(Object trustManagerFactory) {
+ TrustManagerFactory tmf = (TrustManagerFactory) trustManagerFactory;
+ return tmf.getTrustManagers();
+ }
+
+ protected final SSLSocketFactory buildSSLSocketFactory(Object ssl) {
+ return ((SSLContext) ssl).getSocketFactory();
+ }
+
+ protected final SSLServerSocketFactory buildSSLServerSocketFactory(Object ssl) {
+ return ((SSLContext) ssl).getServerSocketFactory();
+ }
+
+ protected final RuntimeException buildRuntimeException(Exception cause) {
+ return new RuntimeException(cause);
+ }
+
+ protected final SSLSocket buildSocket(SSL ssl) throws IOException {
+ SSLSocketFactory sf = ssl.getSSLSocketFactory();
+ SSLSocket s = (SSLSocket) sf.createSocket();
+ ssl.doPreConnectSocketStuff(s);
+ return s;
+ }
+
+ protected final SSLSocket buildSocket(SSL ssl, String remoteHost,
+ int remotePort, InetAddress localHost,
+ int localPort, int timeout)
+ throws IOException {
+ SSLSocket s = buildSocket(ssl);
+ s = (SSLSocket) connectSocket(s, null, remoteHost, remotePort,
+ localHost, localPort, timeout);
+ ssl.doPostConnectSocketStuff(s, remoteHost);
+ return s;
+ }
+
+ protected final Socket connectSocket(Socket s, SocketFactory sf,
+ String remoteHost, int remotePort,
+ InetAddress localHost, int localPort,
+ int timeout)
+ throws IOException {
+ if (s == null) {
+ if (sf == null) {
+ s = new Socket();
+ } else {
+ s = sf.createSocket();
+ }
+ }
+ InetSocketAddress dest = new InetSocketAddress(remoteHost, remotePort);
+ InetSocketAddress src = new InetSocketAddress(localHost, localPort);
+ s.bind(src);
+ s.connect(dest, timeout);
+ return s;
+ }
+
+ protected final SSLServerSocket buildServerSocket(SSL ssl)
+ throws IOException {
+ ServerSocket s = ssl.getSSLServerSocketFactory().createServerSocket();
+ SSLServerSocket ss = (SSLServerSocket) s;
+ ssl.doPreConnectServerSocketStuff(ss);
+ return ss;
+ }
+
+ protected final void wantClientAuth(Object o, boolean wantClientAuth) {
+ SSLSocket s;
+ SSLServerSocket ss;
+ if (o instanceof SSLSocket) {
+ s = (SSLSocket) o;
+ s.setWantClientAuth(wantClientAuth);
+ } else if (o instanceof SSLServerSocket) {
+ ss = (SSLServerSocket) o;
+ ss.setWantClientAuth(wantClientAuth);
+ } else {
+ throw new ClassCastException("need SSLSocket or SSLServerSocket");
+ }
+ }
+
+ protected final void enabledProtocols(Object o, String[] enabledProtocols) {
+ SSLSocket s;
+ SSLServerSocket ss;
+ if (o instanceof SSLSocket) {
+ s = (SSLSocket) o;
+ s.setEnabledProtocols(enabledProtocols);
+ } else if (o instanceof SSLServerSocket) {
+ ss = (SSLServerSocket) o;
+ ss.setEnabledProtocols(enabledProtocols);
+ } else {
+ throw new ClassCastException("need SSLSocket or SSLServerSocket");
+ }
+ }
+
+ protected void checkTrusted(Object trustManager, X509Certificate[] chain,
+ String authType)
+ throws CertificateException {
+ X509TrustManager tm = (X509TrustManager) trustManager;
+ tm.checkServerTrusted(chain, authType);
+ }
+
+ protected final Object initSSL(SSL ssl, TrustChain tc, KeyMaterial k)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ CertificateException, KeyManagementException, IOException {
+ SSLContext context = SSLContext.getInstance(ssl.getDefaultProtocol());
+ TrustManager[] trustManagers = null;
+ KeyManager[] keyManagers = null;
+ if (tc != null) {
+ trustManagers = (TrustManager[]) tc.getTrustManagers();
+ }
+ if (k != null) {
+ keyManagers = (KeyManager[]) k.getKeyManagers();
+ }
+ if (keyManagers != null) {
+ for (int i = 0; i < keyManagers.length; i++) {
+ if (keyManagers[i] instanceof X509KeyManager) {
+ X509KeyManager km = (X509KeyManager) keyManagers[i];
+ keyManagers[i] = new Java14KeyManagerWrapper(km, k, ssl);
+ }
+ }
+ }
+ if (trustManagers != null) {
+ for (int i = 0; i < trustManagers.length; i++) {
+ if (trustManagers[i] instanceof X509TrustManager) {
+ X509TrustManager tm = (X509TrustManager) trustManagers[i];
+ trustManagers[i] = new Java14TrustManagerWrapper(tm, tc, ssl);
+ }
+ }
+ }
+ context.init(keyManagers, trustManagers, null);
+ return context;
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/Java14KeyManagerWrapper.java b/src/java/org/apache/commons/ssl/Java14KeyManagerWrapper.java
new file mode 100644
index 0000000..2f8f03d
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Java14KeyManagerWrapper.java
@@ -0,0 +1,82 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Java14KeyManagerWrapper.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.X509KeyManager;
+import java.net.Socket;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 30-Mar-2006
+ */
+public class Java14KeyManagerWrapper implements X509KeyManager {
+ private final X509KeyManager keyManager;
+ // private final KeyMaterial keyMaterial;
+ // private final SSL ssl;
+
+ public Java14KeyManagerWrapper(X509KeyManager m, KeyMaterial km, SSL h) {
+ this.keyManager = m;
+ // this.keyMaterial = km;
+ // this.ssl = h;
+ }
+
+ public String chooseClientAlias(String[] keyType, Principal[] issuers,
+ Socket socket) {
+ return keyManager.chooseClientAlias(keyType, issuers, socket);
+ }
+
+ public String chooseServerAlias(String keyType, Principal[] issuers,
+ Socket socket) {
+ return keyManager.chooseServerAlias(keyType, issuers, socket);
+ }
+
+ public X509Certificate[] getCertificateChain(String alias) {
+ return keyManager.getCertificateChain(alias);
+ }
+
+ public String[] getClientAliases(String keyType, Principal[] issuers) {
+ return keyManager.getClientAliases(keyType, issuers);
+ }
+
+ public PrivateKey getPrivateKey(String alias) {
+ return keyManager.getPrivateKey(alias);
+ }
+
+ public String[] getServerAliases(String keyType, Principal[] issuers) {
+ return keyManager.getServerAliases(keyType, issuers);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/Java14TrustManagerWrapper.java b/src/java/org/apache/commons/ssl/Java14TrustManagerWrapper.java
new file mode 100644
index 0000000..93f0ac6
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Java14TrustManagerWrapper.java
@@ -0,0 +1,128 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Java14TrustManagerWrapper.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.X509TrustManager;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.X509Certificate;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 30-Mar-2006
+ */
+public class Java14TrustManagerWrapper implements X509TrustManager {
+ private final X509TrustManager trustManager;
+ private final TrustChain trustChain;
+ private final SSL ssl;
+
+ public Java14TrustManagerWrapper(X509TrustManager m, TrustChain tc, SSL h) {
+ this.trustManager = m;
+ this.trustChain = tc;
+ this.ssl = h;
+ }
+
+ public void checkClientTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ ssl.setCurrentClientChain(chain);
+ CertificateException ce = null;
+ try {
+ trustManager.checkClientTrusted(chain, authType);
+ }
+ catch (CertificateException e) {
+ ce = e;
+ }
+ testShouldWeThrow(ce, chain);
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType)
+ throws CertificateException {
+ ssl.setCurrentServerChain(chain);
+ CertificateException ce = null;
+ try {
+ trustManager.checkServerTrusted(chain, authType);
+ }
+ catch (CertificateException e) {
+ ce = e;
+ }
+ testShouldWeThrow(ce, chain);
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return trustManager.getAcceptedIssuers();
+ }
+
+ private void testShouldWeThrow(CertificateException checkException,
+ X509Certificate[] chain)
+ throws CertificateException {
+ if (checkException != null) {
+ Throwable root = getRootThrowable(checkException);
+ boolean expiryProblem = root instanceof CertificateExpiredException;
+ if (expiryProblem) {
+ if (ssl.getCheckExpiry()) {
+ // We're expired, and this factory cares.
+ throw checkException;
+ }
+ } else {
+ // Probably the cert isn't trusted. Only let it through if
+ // this factory trusts everything.
+ if (!trustChain.contains(TrustMaterial.TRUST_ALL)) {
+ throw checkException;
+ }
+ }
+ }
+
+ for (int i = 0; i < chain.length; i++) {
+ X509Certificate c = chain[i];
+ if (ssl.getCheckExpiry()) {
+ c.checkValidity();
+ }
+ if (ssl.getCheckCRL()) {
+ Certificates.checkCRL(c);
+ }
+ }
+ }
+
+ private static Throwable getRootThrowable(Throwable t) {
+ if (t == null) {
+ return t;
+ }
+ Throwable cause = t.getCause();
+ while (cause != null && !t.equals(cause)) {
+ t = cause;
+ cause = t.getCause();
+ }
+ return t;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/JavaImpl.java b/src/java/org/apache/commons/ssl/JavaImpl.java
new file mode 100644
index 0000000..b189fb2
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/JavaImpl.java
@@ -0,0 +1,245 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/JavaImpl.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 30-Jun-2006
+ */
+public abstract class JavaImpl {
+ private static JavaImpl HANDLER;
+
+ static {
+ JavaImpl h = null;
+ try {
+ h = Java14.getInstance();
+ }
+ catch (Throwable t) {
+ // System.out.println( t.toString() );
+ System.out.println("commons-ssl reverting to: Java 1.3 + jsse.jar");
+ }
+ if (h == null) {
+ h = Java13.getInstance();
+ }
+ HANDLER = h;
+ }
+
+ public static void downgrade() {
+ if (HANDLER instanceof Java14) {
+ HANDLER = Java13.getInstance();
+ }
+ }
+
+ public static boolean isJava13() {
+ return HANDLER instanceof Java13;
+ }
+
+ public static void uprade() {
+ if (HANDLER instanceof Java13) {
+ HANDLER = Java14.getInstance();
+ }
+ }
+
+ public abstract String getVersion();
+
+ protected abstract Object buildKeyManagerFactory(KeyStore ks, char[] pass)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ UnrecoverableKeyException;
+
+ protected abstract Object[] retrieveKeyManagers(Object keyManagerFactory);
+
+ protected abstract Object buildTrustManagerFactory(KeyStore ks)
+ throws NoSuchAlgorithmException, KeyStoreException;
+
+ protected abstract Object[] retrieveTrustManagers(Object trustManagerFactory);
+
+ protected abstract String retrieveSubjectX500(X509Certificate cert);
+
+ protected abstract String retrieveIssuerX500(X509Certificate cert);
+
+ protected abstract Certificate[] retrievePeerCerts(SSLSession sslSession)
+ throws SSLPeerUnverifiedException;
+
+ protected abstract SSLSocketFactory buildSSLSocketFactory(Object ssl);
+
+ protected abstract SSLServerSocketFactory buildSSLServerSocketFactory(Object ssl);
+
+ protected abstract SSLSocket buildSocket(SSL ssl)
+ throws IOException;
+
+ protected abstract SSLSocket buildSocket(SSL ssl, String remoteHost,
+ int remotePort,
+ InetAddress localHost,
+ int localPort, int connectTimeout)
+ throws IOException;
+
+ protected abstract Socket connectSocket(Socket s, SocketFactory sf,
+ String remoteHost, int remotePort,
+ InetAddress localHost, int localPort,
+ int timeout)
+ throws IOException;
+
+ protected abstract SSLServerSocket buildServerSocket(SSL ssl)
+ throws IOException;
+
+ protected abstract void wantClientAuth(Object o, boolean wantClientAuth);
+
+ protected abstract void enabledProtocols(Object o, String[] enabledProtocols);
+
+ protected abstract RuntimeException buildRuntimeException(Exception cause);
+
+ protected abstract Object initSSL(SSL ssl, TrustChain tc, KeyMaterial km)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ CertificateException, KeyManagementException, IOException;
+
+ protected abstract void checkTrusted(Object trustManager,
+ X509Certificate[] chain,
+ String authType)
+ throws CertificateException;
+
+ public static Object init(SSL ssl, TrustChain trustChain, KeyMaterial keyMaterial)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ CertificateException, KeyManagementException, IOException {
+ return HANDLER.initSSL(ssl, trustChain, keyMaterial);
+ }
+
+ public static RuntimeException newRuntimeException(Exception cause) {
+ return HANDLER.buildRuntimeException(cause);
+ }
+
+ public static SSLSocketFactory getSSLSocketFactory(Object sslContext) {
+ return HANDLER.buildSSLSocketFactory(sslContext);
+ }
+
+ public static SSLServerSocketFactory getSSLServerSocketFactory(Object sslContext) {
+ return HANDLER.buildSSLServerSocketFactory(sslContext);
+ }
+
+ public static String getSubjectX500(X509Certificate cert) {
+ return HANDLER.retrieveSubjectX500(cert);
+ }
+
+ public static String getIssuerX500(X509Certificate cert) {
+ return HANDLER.retrieveIssuerX500(cert);
+ }
+
+ public static Object newKeyManagerFactory(KeyStore ks, char[] password)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ UnrecoverableKeyException {
+ return HANDLER.buildKeyManagerFactory(ks, password);
+ }
+
+ public static Object[] getKeyManagers(Object keyManagerFactory) {
+ return HANDLER.retrieveKeyManagers(keyManagerFactory);
+ }
+
+ public static Object newTrustManagerFactory(KeyStore ks)
+ throws NoSuchAlgorithmException, KeyStoreException {
+ return HANDLER.buildTrustManagerFactory(ks);
+ }
+
+ public static Object[] getTrustManagers(Object trustManagerFactory) {
+ return HANDLER.retrieveTrustManagers(trustManagerFactory);
+ }
+
+ public static SSLSocket createSocket(SSL ssl)
+ throws IOException {
+ return HANDLER.buildSocket(ssl);
+ }
+
+ public static SSLSocket createSocket(SSL ssl, String remoteHost,
+ int remotePort, InetAddress localHost,
+ int localPort, int connectTimeout)
+ throws IOException {
+ return HANDLER.buildSocket(ssl, remoteHost, remotePort, localHost,
+ localPort, connectTimeout);
+ }
+
+ protected static Socket connect(Socket s, SocketFactory sf,
+ String remoteHost, int remotePort,
+ InetAddress localHost, int localPort,
+ int timeout)
+ throws IOException {
+ return HANDLER.connectSocket(s, sf, remoteHost, remotePort, localHost,
+ localPort, timeout);
+ }
+
+ public static SSLServerSocket createServerSocket(SSL ssl)
+ throws IOException {
+ return HANDLER.buildServerSocket(ssl);
+ }
+
+ public static void setWantClientAuth(Object o, boolean wantClientAuth) {
+ HANDLER.wantClientAuth(o, wantClientAuth);
+ }
+
+ public static void setEnabledProtocols(Object o, String[] enabledProtocols) {
+ HANDLER.enabledProtocols(o, enabledProtocols);
+ }
+
+ public static Certificate[] getPeerCertificates(SSLSession session)
+ throws SSLPeerUnverifiedException {
+ return HANDLER.retrievePeerCerts(session);
+ }
+
+ public static void testTrust(Object trustManager, X509Certificate[] chain,
+ String authType)
+ throws CertificateException {
+ HANDLER.checkTrusted(trustManager, chain, authType);
+ }
+
+ public static void load() {
+ HANDLER.hashCode();
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/KeyMaterial.java b/src/java/org/apache/commons/ssl/KeyMaterial.java
new file mode 100644
index 0000000..fcfc9a3
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/KeyMaterial.java
@@ -0,0 +1,201 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/KeyMaterial.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 27-Feb-2006
+ */
+public class KeyMaterial extends TrustMaterial {
+ private final Object keyManagerFactory;
+ private final String alias;
+ private final X509Certificate[] associatedChain;
+
+ public KeyMaterial(InputStream jks, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(Util.streamToBytes(jks), password);
+ }
+
+ public KeyMaterial(InputStream jks, InputStream key, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(jks != null ? Util.streamToBytes(jks) : null,
+ key != null ? Util.streamToBytes(key) : null,
+ password);
+ }
+
+ public KeyMaterial(String pathToJksFile, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(new File(pathToJksFile), password);
+ }
+
+ public KeyMaterial(String pathToCerts, String pathToKey, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(pathToCerts != null ? new File(pathToCerts) : null,
+ pathToKey != null ? new File(pathToKey) : null,
+ password);
+ }
+
+ public KeyMaterial(File jksFile, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(new FileInputStream(jksFile), password);
+ }
+
+ public KeyMaterial(File certsFile, File keyFile, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(certsFile != null ? new FileInputStream(certsFile) : null,
+ keyFile != null ? new FileInputStream(keyFile) : null,
+ password);
+ }
+
+
+ public KeyMaterial(URL urlToJKS, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(urlToJKS.openStream(), password);
+ }
+
+ public KeyMaterial(URL urlToCerts, URL urlToKey, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(urlToCerts.openStream(), urlToKey.openStream(), password);
+ }
+
+ public KeyMaterial(byte[] jks, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(jks, null, password);
+ }
+
+ public KeyMaterial(byte[] jksOrCerts, byte[] key, char[] password)
+ throws GeneralSecurityException, IOException {
+ // We're not a simple trust type, so set "simpleTrustType" value to 0.
+ // Only TRUST_ALL and TRUST_THIS_JVM are simple trust types.
+ super(KeyStoreBuilder.build(jksOrCerts, key, password), 0);
+ KeyStore ks = getKeyStore();
+ Enumeration en = ks.aliases();
+ String myAlias = null;
+ X509Certificate[] myChain;
+ while (en.hasMoreElements()) {
+ String alias = (String) en.nextElement();
+ if (ks.isKeyEntry(alias)) {
+ if (myAlias != null) {
+ throw new KeyStoreException("commons-ssl KeyMaterial only supports keystores with a single private key.");
+ }
+ myAlias = alias;
+ }
+ }
+ if (myAlias != null) {
+ Certificate[] chain = ks.getCertificateChain(myAlias);
+ if (chain != null) {
+ myChain = Certificates.x509ifyChain(chain);
+ } else {
+ // is password wrong?
+ throw new KeyStoreException("Could not find KeyMaterial's associated certificate chain!");
+ }
+ } else {
+ throw new KeyStoreException("KeyMaterial provided does not contain any keys!");
+ }
+ this.alias = myAlias;
+ // Cleanup chain to remove any spurious entries.
+ if (myChain != null) {
+ myChain = X509CertificateChainBuilder.buildPath(myChain[0], myChain);
+ }
+ this.associatedChain = myChain;
+ this.keyManagerFactory = JavaImpl.newKeyManagerFactory(ks, password);
+ }
+
+ public Object[] getKeyManagers() {
+ return JavaImpl.getKeyManagers(keyManagerFactory);
+ }
+
+ public X509Certificate[] getAssociatedCertificateChain() {
+ return associatedChain;
+ }
+
+ public KeyStore getKeyStore() {
+ return super.getKeyStore();
+ }
+
+ public String getAlias() {
+ return alias;
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (args.length < 2) {
+ System.out.println("Usage1: java org.apache.commons.ssl.KeyMaterial [password] [pkcs12 or jks]");
+ System.out.println("Usage2: java org.apache.commons.ssl.KeyMaterial [password] [private-key] [cert-chain]");
+ System.exit(1);
+ }
+ char[] password = args[0].toCharArray();
+ String path1 = args[1];
+ String path2 = null;
+ if (args.length >= 3) {
+ path2 = args[2];
+ }
+
+ KeyMaterial km = new KeyMaterial(path1, path2, password);
+ System.out.println(km);
+ }
+
+ public String toString() {
+ X509Certificate[] certs = getAssociatedCertificateChain();
+ StringBuffer buf = new StringBuffer(1024);
+ buf.append("Alias: ");
+ buf.append(alias);
+ buf.append('\n');
+ if (certs != null) {
+ for (int i = 0; i < certs.length; i++) {
+ buf.append(Certificates.toString(certs[i]));
+ try {
+ buf.append(Certificates.toPEMString(certs[i]));
+ }
+ catch (CertificateEncodingException cee) {
+ buf.append(cee.toString());
+ buf.append('\n');
+ }
+ }
+ }
+ return buf.toString();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/KeyStoreBuilder.java b/src/java/org/apache/commons/ssl/KeyStoreBuilder.java
new file mode 100644
index 0000000..ab5008b
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/KeyStoreBuilder.java
@@ -0,0 +1,625 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/KeyStoreBuilder.java $
+ * $Revision: 129 $
+ * $Date: 2007-11-14 19:21:33 -0800 (Wed, 14 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import org.apache.commons.ssl.asn1.ASN1EncodableVector;
+import org.apache.commons.ssl.asn1.DERInteger;
+import org.apache.commons.ssl.asn1.DERSequence;
+import org.apache.commons.ssl.util.Hex;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Builds Java Key Store files out of pkcs12 files, or out of pkcs8 files +
+ * certificate chains. Also supports OpenSSL style private keys (encrypted or
+ * unencrypted).
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 4-Nov-2006
+ */
+public class KeyStoreBuilder {
+ private final static String PKCS7_ENCRYPTED = "1.2.840.113549.1.7.6";
+
+ public static KeyStore build(byte[] jksOrCerts, char[] password)
+ throws IOException, CertificateException, KeyStoreException,
+ NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, ProbablyBadPasswordException,
+ UnrecoverableKeyException {
+ return build(jksOrCerts, null, password);
+ }
+
+ public static KeyStore build(byte[] jksOrCerts, byte[] privateKey,
+ char[] password)
+ throws IOException, CertificateException, KeyStoreException,
+ NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, ProbablyBadPasswordException,
+ UnrecoverableKeyException {
+ BuildResult br1 = parse(jksOrCerts, password);
+ BuildResult br2 = null;
+ KeyStore jks = null;
+ if (br1.jks != null) {
+ jks = br1.jks;
+ } else if (privateKey != null && privateKey.length > 0) {
+ br2 = parse(privateKey, password);
+ if (br2.jks != null) {
+ jks = br2.jks;
+ }
+ }
+
+ // If we happened to find a JKS file, let's just return that.
+ // JKS files get priority (in case some weirdo specifies both a PKCS12
+ // and a JKS file!).
+ if (jks != null) {
+ // Make sure the keystore we found is not corrupt.
+ validate(jks, password);
+ return jks;
+ }
+
+ Key key = br1.key;
+ X509Certificate[] chain = br1.chain;
+ boolean atLeastOneNotSet = key == null || chain == null;
+ if (atLeastOneNotSet && br2 != null) {
+ if (br2.key != null) {
+ // Notice that the key from build-result-2 gets priority over the
+ // key from build-result-1 (if both had valid keys).
+ key = br2.key;
+ }
+ if (chain == null) {
+ chain = br2.chain;
+ }
+ }
+
+ atLeastOneNotSet = key == null || chain == null;
+ if (atLeastOneNotSet) {
+ String missing = "";
+ if (key == null) {
+ missing = " [Private key missing (bad password?)]";
+ }
+ if (chain == null) {
+ missing += " [Certificate chain missing]";
+ }
+ throw new KeyStoreException("Can't build keystore:" + missing);
+ } else {
+
+ X509Certificate theOne = buildChain(key, chain);
+ String alias = "alias";
+ // The theOne is not null, then our chain was probably altered.
+ // Need to trim out the newly introduced null entries at the end of
+ // our chain.
+ if (theOne != null) {
+ chain = Certificates.trimChain(chain);
+ alias = Certificates.getCN(theOne);
+ alias = alias.replace(' ', '_');
+ }
+
+ KeyStore ks = KeyStore.getInstance("jks");
+ ks.load(null, password);
+ ks.setKeyEntry(alias, key, password, chain);
+ return ks;
+ }
+ }
+
+ /**
+ * Builds the chain up such that chain[ 0 ] contains the public key
+ * corresponding to the supplied private key.
+ *
+ * @param key private key
+ * @param chain array of certificates to build chain from
+ * @return theOne!
+ * @throws KeyStoreException no certificates correspond to private key
+ * @throws CertificateException java libraries complaining
+ * @throws NoSuchAlgorithmException java libraries complaining
+ * @throws InvalidKeyException java libraries complaining
+ * @throws NoSuchProviderException java libraries complaining
+ */
+ public static X509Certificate buildChain(Key key, Certificate[] chain)
+ throws CertificateException, KeyStoreException,
+ NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException {
+ X509Certificate theOne = null;
+ if (key instanceof RSAPrivateCrtKey) {
+ final RSAPrivateCrtKey rsa = (RSAPrivateCrtKey) key;
+ BigInteger publicExponent = rsa.getPublicExponent();
+ BigInteger modulus = rsa.getModulus();
+ for (int i = 0; i < chain.length; i++) {
+ X509Certificate c = (X509Certificate) chain[i];
+ PublicKey pub = c.getPublicKey();
+ if (pub instanceof RSAPublicKey) {
+ RSAPublicKey certKey = (RSAPublicKey) pub;
+ BigInteger pe = certKey.getPublicExponent();
+ BigInteger mod = certKey.getModulus();
+ if (publicExponent.equals(pe) && modulus.equals(mod)) {
+ theOne = c;
+ }
+ }
+ }
+ if (theOne == null) {
+ throw new KeyStoreException("Can't build keystore: [No certificates belong to the private-key]");
+ }
+ X509Certificate[] newChain;
+ newChain = X509CertificateChainBuilder.buildPath(theOne, chain);
+ Arrays.fill(chain, null);
+ System.arraycopy(newChain, 0, chain, 0, newChain.length);
+ }
+ return theOne;
+ }
+
+ public static void validate(KeyStore jks, char[] password)
+ throws CertificateException, KeyStoreException,
+ NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, UnrecoverableKeyException {
+ Enumeration en = jks.aliases();
+ String privateKeyAlias = null;
+ while (en.hasMoreElements()) {
+ String alias = (String) en.nextElement();
+ boolean isKey = jks.isKeyEntry(alias);
+ if (isKey) {
+ if (privateKeyAlias != null) {
+ throw new KeyStoreException("Only 1 private key per keystore allowed for Commons-SSL");
+ } else {
+ privateKeyAlias = alias;
+ }
+ }
+ }
+ if (privateKeyAlias == null) {
+ throw new KeyStoreException("No private keys found in keystore!");
+ }
+ PrivateKey key = (PrivateKey) jks.getKey(privateKeyAlias, password);
+ Certificate[] chain = jks.getCertificateChain(privateKeyAlias);
+ X509Certificate[] x509Chain = Certificates.x509ifyChain(chain);
+ X509Certificate theOne = buildChain(key, x509Chain);
+ // The theOne is not null, then our chain was probably altered.
+ // Need to trim out the newly introduced null entries at the end of
+ // our chain.
+ if (theOne != null) {
+ x509Chain = Certificates.trimChain(x509Chain);
+ jks.deleteEntry(privateKeyAlias);
+ jks.setKeyEntry(privateKeyAlias, key, password, x509Chain);
+ }
+ }
+
+ protected static class BuildResult {
+ protected final Key key;
+ protected final X509Certificate[] chain;
+ protected final KeyStore jks;
+
+ protected BuildResult(Key key, Certificate[] chain, KeyStore jks) {
+ this.key = key;
+ this.jks = jks;
+ if (chain == null) {
+ this.chain = null;
+ } else if (chain instanceof X509Certificate[]) {
+ this.chain = (X509Certificate[]) chain;
+ } else {
+ X509Certificate[] x509 = new X509Certificate[chain.length];
+ System.arraycopy(chain, 0, x509, 0, chain.length);
+ this.chain = x509;
+ }
+ }
+ }
+
+
+ public static BuildResult parse(byte[] stuff, char[] password)
+ throws IOException, CertificateException, KeyStoreException,
+ ProbablyBadPasswordException {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ Key key = null;
+ Certificate[] chain = null;
+ try {
+ PKCS8Key pkcs8Key = new PKCS8Key(stuff, password);
+ key = pkcs8Key.getPrivateKey();
+ }
+ catch (ProbablyBadPasswordException pbpe) {
+ throw pbpe;
+ }
+ catch (GeneralSecurityException gse) {
+ // no luck
+ }
+
+ List pemItems = PEMUtil.decode(stuff);
+ Iterator it = pemItems.iterator();
+ LinkedList certificates = new LinkedList();
+ while (it.hasNext()) {
+ PEMItem item = (PEMItem) it.next();
+ byte[] derBytes = item.getDerBytes();
+ String type = item.pemType.trim().toUpperCase();
+ if (type.startsWith("CERT") ||
+ type.startsWith("X509") ||
+ type.startsWith("PKCS7")) {
+ ByteArrayInputStream in = new ByteArrayInputStream(derBytes);
+ X509Certificate c = (X509Certificate) cf.generateCertificate(in);
+ certificates.add(c);
+ }
+ chain = toChain(certificates);
+ }
+
+ if (chain != null || key != null) {
+ return new BuildResult(key, chain, null);
+ }
+
+ boolean isProbablyPKCS12 = false;
+ boolean isASN = false;
+ boolean isProbablyJKS = stuff.length >= 4 &&
+ stuff[0] == (byte) 0xFE &&
+ stuff[1] == (byte) 0xED &&
+ stuff[2] == (byte) 0xFE &&
+ stuff[3] == (byte) 0xED;
+
+ ASN1Structure asn1 = null;
+ try {
+ asn1 = ASN1Util.analyze(stuff);
+ isASN = true;
+ isProbablyPKCS12 = asn1.oids.contains(PKCS7_ENCRYPTED);
+ if (!isProbablyPKCS12 && asn1.bigPayload != null) {
+ asn1 = ASN1Util.analyze(asn1.bigPayload);
+ isProbablyPKCS12 = asn1.oids.contains(PKCS7_ENCRYPTED);
+ }
+ }
+ catch (Exception e) {
+ // isProbablyPKCS12 and isASN are set properly by now.
+ }
+
+ ByteArrayInputStream stuffStream = new ByteArrayInputStream(stuff);
+ if (isProbablyJKS) {
+ try {
+ return tryJKS("jks", stuffStream, password);
+ }
+ catch (ProbablyBadPasswordException pbpe) {
+ throw pbpe;
+ }
+ catch (GeneralSecurityException gse) {
+ // jks didn't work.
+ }
+ catch (IOException ioe) {
+ // jks didn't work.
+ }
+ }
+ if (isASN) {
+ if (isProbablyPKCS12) {
+ try {
+ return tryJKS("pkcs12", stuffStream, password);
+ }
+ catch (ProbablyBadPasswordException pbpe) {
+ throw pbpe;
+ }
+ catch (GeneralSecurityException gse) {
+ // pkcs12 didn't work.
+ }
+ catch (IOException ioe) {
+ // pkcs12 didn't work.
+ }
+ } else {
+ // Okay, it's ASN.1, but it's not PKCS12. Only one possible
+ // interesting things remains: X.509.
+ stuffStream.reset();
+
+ try {
+ certificates = new LinkedList();
+ Collection certs = cf.generateCertificates(stuffStream);
+ it = certs.iterator();
+ while (it.hasNext()) {
+ X509Certificate x509 = (X509Certificate) it.next();
+ certificates.add(x509);
+ }
+ chain = toChain(certificates);
+ if (chain != null && chain.length > 0) {
+ return new BuildResult(null, chain, null);
+ }
+ }
+ catch (CertificateException ce) {
+ // oh well
+ }
+
+ stuffStream.reset();
+ // Okay, still no luck. Maybe it's an ASN.1 DER stream
+ // containing only a single certificate? (I don't completely
+ // trust CertificateFactory.generateCertificates).
+ try {
+ Certificate c = cf.generateCertificate(stuffStream);
+ X509Certificate x509 = (X509Certificate) c;
+ chain = toChain(Collections.singleton(x509));
+ if (chain != null && chain.length > 0) {
+ return new BuildResult(null, chain, null);
+ }
+ }
+ catch (CertificateException ce) {
+ // oh well
+ }
+ }
+ }
+
+ if (!isProbablyJKS) {
+ String hex = Hex.encode(stuff, 0, 4);
+ try {
+ BuildResult br = tryJKS("jks", stuffStream, password);
+ // no exception thrown, so must be JKS.
+ System.out.println("Please report bug!");
+ System.out.println("JKS usually start with binary FE ED FE ED, but this JKS started with: [" + hex + "]");
+ return br;
+ }
+ catch (ProbablyBadPasswordException pbpe) {
+ System.out.println("Please report bug!");
+ System.out.println("JKS usually start with binary FE ED FE ED, but this JKS started with: [" + hex + "]");
+ throw pbpe;
+ }
+ catch (GeneralSecurityException gse) {
+ // jks didn't work.
+ }
+ catch (IOException ioe) {
+ // jks didn't work.
+ }
+ }
+
+ if (!isProbablyPKCS12) {
+ try {
+ BuildResult br = tryJKS("pkcs12", stuffStream, password);
+ // no exception thrown, so must be PKCS12.
+ System.out.println("Please report bug!");
+ System.out.println("PKCS12 detection failed to realize this was PKCS12!");
+ System.out.println(asn1);
+ return br;
+ }
+ catch (ProbablyBadPasswordException pbpe) {
+ System.out.println("Please report bug!");
+ System.out.println("PKCS12 detection failed to realize this was PKCS12!");
+ System.out.println(asn1);
+ throw pbpe;
+ }
+ catch (GeneralSecurityException gse) {
+ // pkcs12 didn't work.
+ }
+ catch (IOException ioe) {
+ // pkcs12 didn't work.
+ }
+ }
+ throw new KeyStoreException("failed to extract any certificates or private keys - maybe bad password?");
+ }
+
+ private static BuildResult tryJKS(String keystoreType,
+ ByteArrayInputStream in,
+ char[] password)
+ throws GeneralSecurityException, IOException {
+ in.reset();
+ keystoreType = keystoreType.trim().toLowerCase();
+ boolean isPKCS12 = "pkcs12".equals(keystoreType);
+ KeyStore jksKeyStore = KeyStore.getInstance(keystoreType);
+ try {
+ Key key = null;
+ Certificate[] chain = null;
+ jksKeyStore.load(in, password);
+ Enumeration en = jksKeyStore.aliases();
+ while (en.hasMoreElements()) {
+ String alias = (String) en.nextElement();
+ if (jksKeyStore.isKeyEntry(alias)) {
+ key = jksKeyStore.getKey(alias, password);
+ if (key != null && key instanceof PrivateKey) {
+ chain = jksKeyStore.getCertificateChain(alias);
+ break;
+ }
+ }
+ if (isPKCS12 && en.hasMoreElements()) {
+ System.out.println("what kind of weird pkcs12 file has more than one alias?");
+ }
+ }
+ if (isPKCS12) {
+ // PKCS12 is supposed to be just a key and a chain, anyway.
+ jksKeyStore = null;
+ }
+ return new BuildResult(key, chain, jksKeyStore);
+ }
+ catch (GeneralSecurityException gse) {
+ throw gse;
+ }
+ catch (IOException ioe) {
+ ioe.printStackTrace();
+
+ String msg = ioe.getMessage();
+ msg = msg != null ? msg.trim().toLowerCase() : "";
+ if (isPKCS12) {
+ int x = msg.indexOf("failed to decrypt");
+ int y = msg.indexOf("verify mac");
+ x = Math.max(x, y);
+ if (x >= 0) {
+ throw new ProbablyBadPasswordException("Probably bad PKCS12 password: " + ioe);
+ }
+ } else {
+ int x = msg.indexOf("password");
+ if (x >= 0) {
+ throw new ProbablyBadPasswordException("Probably bad JKS password: " + ioe);
+ }
+ }
+ ioe.printStackTrace();
+ throw ioe;
+ }
+ }
+
+ private static X509Certificate[] toChain(Collection certs) {
+ if (certs != null && !certs.isEmpty()) {
+ X509Certificate[] x509Chain = new X509Certificate[certs.size()];
+ certs.toArray(x509Chain);
+ return x509Chain;
+ } else {
+ return null;
+ }
+ }
+
+
+ public static void main(String[] args) throws Exception {
+ if (args.length < 2) {
+ System.out.println("KeyStoreBuilder: creates '[alias].jks' (Java Key Store)");
+ System.out.println(" -topk8 mode: creates '[alias].pem' (x509 chain + unencrypted pkcs8)");
+ System.out.println("[alias] will be set to the first CN value of the X509 certificate.");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println("Usage1: [password] [file:pkcs12]");
+ System.out.println("Usage2: [password] [file:private-key] [file:certificate-chain]");
+ System.out.println("Usage3: -topk8 [password] [file:jks]");
+ System.out.println("-------------------------------------------------------------------");
+ System.out.println("[private-key] can be openssl format, or pkcs8.");
+ System.out.println("[password] decrypts [private-key], and also encrypts outputted JKS file.");
+ System.out.println("All files can be PEM or DER.");
+ System.exit(1);
+ }
+ char[] password = args[0].toCharArray();
+ boolean toPKCS8 = false;
+ if ("-topk8".equalsIgnoreCase(args[0])) {
+ toPKCS8 = true;
+ password = args[1].toCharArray();
+ args[1] = args[2];
+ args[2] = null;
+ }
+
+ FileInputStream fin1 = new FileInputStream(args[1]);
+ byte[] bytes1 = Util.streamToBytes(fin1);
+ byte[] bytes2 = null;
+ if (args.length > 2 && args[2] != null) {
+ FileInputStream fin2 = new FileInputStream(args[2]);
+ bytes2 = Util.streamToBytes(fin2);
+ }
+
+ KeyStore ks = build(bytes1, bytes2, password);
+ Enumeration en = ks.aliases();
+ String alias = null;
+ while (en.hasMoreElements()) {
+ if (alias == null) {
+ alias = (String) en.nextElement();
+ } else {
+ System.out.println("Generated keystore contains more than 1 alias!?!?");
+ }
+ }
+
+ String suffix = toPKCS8 ? ".pem" : ".jks";
+ File f = new File(alias + suffix);
+ int count = 1;
+ while (f.exists()) {
+ f = new File(alias + "_" + count + suffix);
+ count++;
+ }
+
+ FileOutputStream jks = new FileOutputStream(f);
+ if (toPKCS8) {
+ List pemItems = new LinkedList();
+ PrivateKey key = (PrivateKey) ks.getKey(alias, password);
+ Certificate[] chain = ks.getCertificateChain(alias);
+ byte[] pkcs8DerBytes = null;
+ if (key instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey rsa = (RSAPrivateCrtKey) key;
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ vec.add(new DERInteger(BigInteger.ZERO));
+ vec.add(new DERInteger(rsa.getModulus()));
+ vec.add(new DERInteger(rsa.getPublicExponent()));
+ vec.add(new DERInteger(rsa.getPrivateExponent()));
+ vec.add(new DERInteger(rsa.getPrimeP()));
+ vec.add(new DERInteger(rsa.getPrimeQ()));
+ vec.add(new DERInteger(rsa.getPrimeExponentP()));
+ vec.add(new DERInteger(rsa.getPrimeExponentQ()));
+ vec.add(new DERInteger(rsa.getCrtCoefficient()));
+ DERSequence seq = new DERSequence(vec);
+ byte[] derBytes = PKCS8Key.encode(seq);
+ PKCS8Key pkcs8 = new PKCS8Key(derBytes, null);
+ pkcs8DerBytes = pkcs8.getDecryptedBytes();
+ } else if (key instanceof DSAPrivateKey) {
+ DSAPrivateKey dsa = (DSAPrivateKey) key;
+ DSAParams params = dsa.getParams();
+ BigInteger g = params.getG();
+ BigInteger p = params.getP();
+ BigInteger q = params.getQ();
+ BigInteger x = dsa.getX();
+ BigInteger y = q.modPow(x, p);
+
+ ASN1EncodableVector vec = new ASN1EncodableVector();
+ vec.add(new DERInteger(BigInteger.ZERO));
+ vec.add(new DERInteger(p));
+ vec.add(new DERInteger(q));
+ vec.add(new DERInteger(g));
+ vec.add(new DERInteger(y));
+ vec.add(new DERInteger(x));
+ DERSequence seq = new DERSequence(vec);
+ byte[] derBytes = PKCS8Key.encode(seq);
+ PKCS8Key pkcs8 = new PKCS8Key(derBytes, null);
+ pkcs8DerBytes = pkcs8.getDecryptedBytes();
+ }
+ if (chain != null && chain.length > 0) {
+ for (int i = 0; i < chain.length; i++) {
+ X509Certificate x509 = (X509Certificate) chain[i];
+ byte[] derBytes = x509.getEncoded();
+ PEMItem item = new PEMItem(derBytes, "CERTIFICATE");
+ pemItems.add(item);
+ }
+ }
+ if (pkcs8DerBytes != null) {
+ PEMItem item = new PEMItem(pkcs8DerBytes, "PRIVATE KEY");
+ pemItems.add(item);
+ }
+ byte[] pem = PEMUtil.encode(pemItems);
+ jks.write(pem);
+ } else {
+ ks.store(jks, password);
+ }
+ jks.flush();
+ jks.close();
+ System.out.println("Successfuly wrote: [" + f.getPath() + "]");
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/LDAPSocket.java b/src/java/org/apache/commons/ssl/LDAPSocket.java
new file mode 100644
index 0000000..9a2fd78
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/LDAPSocket.java
@@ -0,0 +1,83 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/LDAPSocket.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.SocketFactory;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 28-Feb-2006
+ */
+public class LDAPSocket extends SSLClient {
+ private final static LDAPSocket instance;
+
+ static {
+ LDAPSocket sf = null;
+ try {
+ sf = new LDAPSocket();
+ }
+ catch (Exception e) {
+ System.out.println("could not create LDAPSocket: " + e);
+ e.printStackTrace();
+ }
+ finally {
+ instance = sf;
+ }
+ }
+
+ private LDAPSocket() throws GeneralSecurityException, IOException {
+ super();
+
+ // For now we setup the usual trust infrastructure, but consumers
+ // are encouraged to call getInstance().addTrustMaterial() or
+ // getInstance().setTrustMaterial() to customize the trust.
+ if (TrustMaterial.JSSE_CACERTS != null) {
+ setTrustMaterial(TrustMaterial.JSSE_CACERTS);
+ } else {
+ setTrustMaterial(TrustMaterial.CACERTS);
+ }
+ }
+
+ public static SocketFactory getDefault() {
+ return getInstance();
+ }
+
+ public static LDAPSocket getInstance() {
+ return instance;
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/LogHelper.java b/src/java/org/apache/commons/ssl/LogHelper.java
new file mode 100644
index 0000000..63c80d3
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/LogHelper.java
@@ -0,0 +1,87 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/LogHelper.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import org.apache.log4j.Logger;
+
+/**
+ * <p/>
+ * Wraps a Log4j Logger. This non-public class is the one actually interacting
+ * with the log4j.jar library. That way LogWrapper can safely attempt to use
+ * log4j.jar, but still degrade gracefully and provide logging via standard-out
+ * even if log4j is unavailable.
+ * <p/>
+ * The interactions with log4j.jar could be done directly inside LogWrapper
+ * as long as the Java code is compiled by Java 1.4 or greater (still works
+ * at runtime in Java 1.3). The interactions with log4j.jar only need to be
+ * pushed out into a separate class like this for people using a Java 1.3
+ * compiler, which creates bytecode that is more strict with depedency
+ * checking.
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 3-Aug-2006
+ */
+final class LogHelper {
+ private final Logger l;
+
+ LogHelper(Class c) { l = Logger.getLogger(c); }
+
+ LogHelper(String s) { l = Logger.getLogger(s); }
+
+ void debug(Object o) { l.debug(o); }
+
+ void debug(Object o, Throwable t) { l.debug(o, t); }
+
+ void info(Object o) { l.info(o); }
+
+ void info(Object o, Throwable t) { l.info(o, t); }
+
+ void warn(Object o) { l.warn(o); }
+
+ void warn(Object o, Throwable t) { l.warn(o, t); }
+
+ void error(Object o) { l.error(o); }
+
+ void error(Object o, Throwable t) { l.error(o, t); }
+
+ void fatal(Object o) { l.fatal(o); }
+
+ void fatal(Object o, Throwable t) { l.fatal(o, t); }
+
+ boolean isDebugEnabled() { return l.isDebugEnabled(); }
+
+ boolean isInfoEnabled() { return l.isInfoEnabled(); }
+
+ Object getLog4jLogger() { return l; }
+}
diff --git a/src/java/org/apache/commons/ssl/LogWrapper.java b/src/java/org/apache/commons/ssl/LogWrapper.java
new file mode 100644
index 0000000..3646b76
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/LogWrapper.java
@@ -0,0 +1,295 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/LogWrapper.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * <p/>
+ * LogWrapper can be used for situations where log4j might not be available on
+ * the classpath. It presents the most basic and critical components of the
+ * log4j API, and passes all log calls through to log4j if possible. If log4j
+ * is not available, logging is sent to standard-out by default.
+ * <p/>
+ * This default logging to standard-out (which only occurs if log4j is NOT
+ * available) can be disabled or changed via the static setBackupStream() and
+ * setBackupLogFile() methods.
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 3-Aug-2006
+ */
+public class LogWrapper {
+
+ // final static String[] LEVELS = {"DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
+ final static String[] LEVELS = {"+", " ", "!", "*", "#"};
+ final static String TIMESTAMP_PATTERN = "zzz:yyyy-MM-dd/HH:mm:ss.SSS";
+ final static int TIMESTAMP_LENGTH = TIMESTAMP_PATTERN.length();
+ final static String LINE_SEPARATOR = System.getProperty("line.separator");
+ final static DateFormat DF = new SimpleDateFormat(TIMESTAMP_PATTERN);
+
+ private final static LogWrapper NOOP = new LogWrapper();
+
+ /** Should we print DEBUG statements if log4j is not available? */
+ private final static boolean DEBUG = true;
+
+ /** true if log4j is available */
+ public final static boolean log4j;
+
+ /**
+ * OutputStream to log to if log4j is not available. Set it to null to
+ * disable.
+ */
+ private static volatile OutputStream backup = System.out;
+
+ /** The wrappingPrintStream is lazy-initted if we have to log a stacktrace. */
+ private static volatile PrintStream wrappingPrintStream = null;
+
+ private final LogHelper h;
+
+ static {
+ boolean avail = false;
+ try {
+ // LogHelper's constructor will blow up if log4j.jar isn't on the
+ // classpath.
+ LogHelper lh = new LogHelper(LogWrapper.class);
+ lh.hashCode();
+ avail = true;
+ }
+ catch (Throwable t) {
+ avail = false;
+ }
+ finally {
+ log4j = avail;
+ }
+ }
+
+ public static boolean isLog4jAvailable() { return log4j; }
+
+ public static LogWrapper getLogger(Class c) {
+ return log4j ? new LogWrapper(c) : NOOP;
+ }
+
+ public static LogWrapper getLogger(String s) {
+ return log4j ? new LogWrapper(s) : NOOP;
+ }
+
+ private LogWrapper() { this.h = null; }
+
+ private LogWrapper(Class c) { this.h = new LogHelper(c); }
+
+ private LogWrapper(String s) { this.h = new LogHelper(s); }
+
+ public void debug(Object o) {
+ if (t(0, o, null)) {
+ h.debug(o);
+ }
+ }
+
+ public void debug(Object o, Throwable t) {
+ if (t(0, o, t)) {
+ h.debug(o, t);
+ }
+ }
+
+ public void info(Object o) {
+ if (t(1, o, null)) {
+ h.info(o);
+ }
+ }
+
+ public void info(Object o, Throwable t) {
+ if (t(1, o, t)) {
+ h.info(o, t);
+ }
+ }
+
+ public void warn(Object o) {
+ if (t(2, o, null)) {
+ h.warn(o);
+ }
+ }
+
+ public void warn(Object o, Throwable t) {
+ if (t(2, o, t)) {
+ h.warn(o, t);
+ }
+ }
+
+ public void error(Object o) {
+ if (t(3, o, null)) {
+ h.error(o);
+ }
+ }
+
+ public void error(Object o, Throwable t) {
+ if (t(3, o, t)) {
+ h.error(o, t);
+ }
+ }
+
+ public void fatal(Object o) {
+ if (t(4, o, null)) {
+ h.fatal(o);
+ }
+ }
+
+ public void fatal(Object o, Throwable t) {
+ if (t(4, o, t)) {
+ h.fatal(o, t);
+ }
+ }
+
+ public boolean isDebugEnabled() { return log4j ? h.isDebugEnabled() : DEBUG;}
+
+ public boolean isInfoEnabled() { return !log4j || h.isInfoEnabled(); }
+
+ public Object getLog4jLogger() { return log4j ? h.getLog4jLogger() : null; }
+
+
+ /**
+ * Tests if log4j is available. If not, logs to backup OutputStream (if
+ * backup != null).
+ *
+ * @param level log4j logging level for this statement
+ * @param o object to log
+ * @param t throwable to log
+ * @return true if log4j is available, false if log4j is not. If it returns
+ * false, as a side-effect, it will also log the statement.
+ */
+ private boolean t(int level, Object o, Throwable t) {
+ if (log4j) {
+ return true;
+ } else {
+ // LogWrapper doesn't log debug statements if Log4j is not available
+ // and DEBUG is false.
+ if (backup != null && (DEBUG || level > 0)) {
+ String s = ""; // log4j allows null
+ if (o != null) {
+ try {
+ s = (String) o;
+ }
+ catch (ClassCastException cce) {
+ s = o.toString();
+ }
+ }
+ int len = s.length() + TIMESTAMP_LENGTH + 9;
+ String timestamp = DF.format(new Date());
+ StringBuffer buf = new StringBuffer(len);
+ buf.append(timestamp);
+ if (LEVELS[level].length() == 1) {
+ buf.append(LEVELS[level]);
+ } else {
+ buf.append(' ');
+ buf.append(LEVELS[level]);
+ buf.append(' ');
+ }
+ buf.append(s);
+ buf.append(LINE_SEPARATOR);
+ s = buf.toString();
+ byte[] logBytes = s.getBytes();
+ try {
+ if (t == null) {
+ backup.write(logBytes);
+ } else {
+ synchronized (backup) {
+ backup.write(logBytes);
+ if (t != null) {
+ if (wrappingPrintStream == null) {
+ wrappingPrintStream = new PrintStream(backup, false);
+ }
+ t.printStackTrace(wrappingPrintStream);
+ wrappingPrintStream.flush();
+ }
+ }
+ }
+ backup.flush(); // J2RE 1.5.0 IBM J9 2.3 Linux x86-32 needs this.
+ }
+ catch (IOException ioe) {
+ throw new RuntimeException(ioe.toString());
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Set file to log to if log4j is not available.
+ *
+ * @param f path to use for backup log file (if log4j not available)
+ * @throws IOException if we can't write to the given path
+ */
+ public static void setBackupLogFile(String f)
+ throws IOException {
+ if (!log4j) {
+ OutputStream out = new FileOutputStream(f, true);
+ out = new BufferedOutputStream(out);
+ setBackupStream(out);
+ }
+ }
+
+ /**
+ * Set PrintStream to log to if log4j is not available. Set to null to
+ * disable. Default value is System.out.
+ *
+ * @param os outputstream to use for backup logging (if log4j not available)
+ */
+ public static void setBackupStream(OutputStream os) {
+ // synchronize on the old backup - don't want to pull the rug out from
+ // under him if he's working on a big stacktrace or something like that.
+ if (backup != null) {
+ synchronized (backup) {
+ wrappingPrintStream = null;
+ backup = os;
+ }
+ } else {
+ wrappingPrintStream = null;
+ backup = os;
+ }
+ }
+
+ /**
+ * Get the PrintStream we're logging to if log4j is not available.
+ *
+ * @return OutputStream we're using as our log4j replacement.
+ */
+ public static OutputStream getBackupStream() { return backup; }
+
+}
diff --git a/src/java/org/apache/commons/ssl/OpenSSL.java b/src/java/org/apache/commons/ssl/OpenSSL.java
new file mode 100644
index 0000000..f580d4a
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/OpenSSL.java
@@ -0,0 +1,720 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/OpenSSL.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import org.apache.commons.ssl.util.Hex;
+
+import javax.crypto.Cipher;
+import javax.crypto.CipherInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.StringTokenizer;
+
+/**
+ * Class for encrypting or decrypting data with a password (PBE - password
+ * based encryption). Compatible with "openssl enc" unix utility. An OpenSSL
+ * compatible cipher name must be specified along with the password (try "man enc" on a
+ * unix box to see what's possible). Some examples:
+ * <ul><li>des, des3, des-ede3-cbc
+ * <li>aes128, aes192, aes256, aes-256-cbc
+ * <li>rc2, rc4, bf</ul>
+ * <pre>
+ * <em style="color: green;">// Encrypt!</em>
+ * byte[] encryptedData = OpenSSL.encrypt( "des3", password, data );
+ * </pre>
+ * <p/>
+ * If you want to specify a raw key and iv directly (without using PBE), use
+ * the methods that take byte[] key, byte[] iv. Those byte[] arrays can be
+ * the raw binary, or they can be ascii (hex representation: '0' - 'F'). If
+ * you want to use PBE to derive the key and iv, then use the methods that
+ * take char[] password.
+ * <p/>
+ * This class is able to decrypt files encrypted with "openssl" unix utility.
+ * <p/>
+ * The "openssl" unix utility is able to decrypt files encrypted by this class.
+ * <p/>
+ * This class is also able to encrypt and decrypt its own files.
+ *
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at gmail.com</a>
+ * @since 18-Oct-2007
+ */
+public class OpenSSL {
+
+
+ /**
+ * Decrypts data using a password and an OpenSSL compatible cipher
+ * name.
+ *
+ * @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
+ * unix box to see what's possible). Some examples:
+ * <ul><li>des, des3, des-ede3-cbc
+ * <li>aes128, aes192, aes256, aes-256-cbc
+ * <li>rc2, rc4, bf</ul>
+ * @param pwd password to use for this PBE decryption
+ * @param encrypted byte array to decrypt. Can be raw, or base64.
+ * @return decrypted bytes
+ * @throws IOException problems with encrypted bytes (unlikely!)
+ * @throws GeneralSecurityException problems decrypting
+ */
+ public static byte[] decrypt(String cipher, char[] pwd, byte[] encrypted)
+ throws IOException, GeneralSecurityException {
+ ByteArrayInputStream in = new ByteArrayInputStream(encrypted);
+ InputStream decrypted = decrypt(cipher, pwd, in);
+ return Util.streamToBytes(decrypted);
+ }
+
+ /**
+ * Decrypts data using a password and an OpenSSL compatible cipher
+ * name.
+ *
+ * @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
+ * unix box to see what's possible). Some examples:
+ * <ul><li>des, des3, des-ede3-cbc
+ * <li>aes128, aes192, aes256, aes-256-cbc
+ * <li>rc2, rc4, bf</ul>
+ * @param pwd password to use for this PBE decryption
+ * @param encrypted InputStream to decrypt. Can be raw, or base64.
+ * @return decrypted bytes as an InputStream
+ * @throws IOException problems with InputStream
+ * @throws GeneralSecurityException problems decrypting
+ */
+ public static InputStream decrypt(String cipher, char[] pwd,
+ InputStream encrypted)
+ throws IOException, GeneralSecurityException {
+ CipherInfo cipherInfo = lookup(cipher);
+ boolean salted = false;
+
+ // First 16 bytes of raw binary will hopefully be OpenSSL's
+ // "Salted__[8 bytes of hex]" thing. Might be in Base64, though.
+ byte[] saltLine = Util.streamToBytes(encrypted, 16);
+ if (saltLine.length <= 0) {
+ throw new IOException("encrypted InputStream is empty");
+ }
+ String firstEightBytes = "";
+ if (saltLine.length >= 8) {
+ firstEightBytes = new String(saltLine, 0, 8);
+ }
+ if ("SALTED__".equalsIgnoreCase(firstEightBytes)) {
+ salted = true;
+ } else {
+ // Maybe the reason we didn't find the salt is because we're in
+ // base64.
+ if (Base64.isArrayByteBase64(saltLine)) {
+ InputStream head = new ByteArrayInputStream(saltLine);
+ // Need to put that 16 byte "saltLine" back into the Stream.
+ encrypted = new ComboInputStream(head, encrypted);
+ encrypted = new Base64InputStream(encrypted, true);
+ saltLine = Util.streamToBytes(encrypted, 16);
+
+ if (saltLine.length >= 8) {
+ firstEightBytes = new String(saltLine, 0, 8);
+ }
+ if ("SALTED__".equalsIgnoreCase(firstEightBytes)) {
+ salted = true;
+ }
+ }
+ }
+
+ byte[] salt = null;
+ if (salted) {
+ salt = new byte[8];
+ System.arraycopy(saltLine, 8, salt, 0, 8);
+ } else {
+ // Encrypted data wasn't salted. Need to put the "saltLine" we
+ // extracted back into the stream.
+ InputStream head = new ByteArrayInputStream(saltLine);
+ encrypted = new ComboInputStream(head, encrypted);
+ }
+
+ int keySize = cipherInfo.keySize;
+ int ivSize = cipherInfo.ivSize;
+ boolean des2 = cipherInfo.des2;
+ DerivedKey dk = deriveKey(pwd, salt, keySize, ivSize, des2);
+ Cipher c = PKCS8Key.generateCipher(
+ cipherInfo.javaCipher, cipherInfo.blockMode, dk, des2, null, true
+ );
+
+ return new CipherInputStream(encrypted, c);
+ }
+
+ /**
+ * Encrypts data using a password and an OpenSSL compatible cipher
+ * name.
+ *
+ * @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
+ * unix box to see what's possible). Some examples:
+ * <ul><li>des, des3, des-ede3-cbc
+ * <li>aes128, aes192, aes256, aes-256-cbc
+ * <li>rc2, rc4, bf</ul>
+ * @param pwd password to use for this PBE encryption
+ * @param data byte array to encrypt
+ * @return encrypted bytes as an array in base64. First 16 bytes include the
+ * special OpenSSL "Salted__" info encoded into base64.
+ * @throws IOException problems with the data byte array
+ * @throws GeneralSecurityException problems encrypting
+ */
+ public static byte[] encrypt(String cipher, char[] pwd, byte[] data)
+ throws IOException, GeneralSecurityException {
+ // base64 is the default output format.
+ return encrypt(cipher, pwd, data, true);
+ }
+
+ /**
+ * Encrypts data using a password and an OpenSSL compatible cipher
+ * name.
+ *
+ * @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
+ * unix box to see what's possible). Some examples:
+ * <ul><li>des, des3, des-ede3-cbc
+ * <li>aes128, aes192, aes256, aes-256-cbc
+ * <li>rc2, rc4, bf</ul>
+ * @param pwd password to use for this PBE encryption
+ * @param data InputStream to encrypt
+ * @return encrypted bytes as an InputStream. First 16 bytes include the
+ * special OpenSSL "Salted__" info encoded into base64.
+ * @throws IOException problems with the data InputStream
+ * @throws GeneralSecurityException problems encrypting
+ */
+ public static InputStream encrypt(String cipher, char[] pwd,
+ InputStream data)
+ throws IOException, GeneralSecurityException {
+ // base64 is the default output format.
+ return encrypt(cipher, pwd, data, true);
+ }
+
+ /**
+ * Encrypts data using a password and an OpenSSL compatible cipher
+ * name.
+ *
+ * @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
+ * unix box to see what's possible). Some examples:
+ * <ul><li>des, des3, des-ede3-cbc
+ * <li>aes128, aes192, aes256, aes-256-cbc
+ * <li>rc2, rc4, bf</ul>
+ * @param pwd password to use for this PBE encryption
+ * @param data byte array to encrypt
+ * @param toBase64 true if resulting InputStream should contain base64,
+ * <br>false if InputStream should contain raw binary.
+ * @return encrypted bytes as an array. First 16 bytes include the
+ * special OpenSSL "Salted__" info.
+ * @throws IOException problems with the data byte array
+ * @throws GeneralSecurityException problems encrypting
+ */
+ public static byte[] encrypt(String cipher, char[] pwd, byte[] data,
+ boolean toBase64)
+ throws IOException, GeneralSecurityException {
+ // we use a salt by default.
+ return encrypt(cipher, pwd, data, toBase64, true);
+ }
+
+ /**
+ * Encrypts data using a password and an OpenSSL compatible cipher
+ * name.
+ *
+ * @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
+ * unix box to see what's possible). Some examples:
+ * <ul><li>des, des3, des-ede3-cbc
+ * <li>aes128, aes192, aes256, aes-256-cbc
+ * <li>rc2, rc4, bf</ul>
+ * @param pwd password to use for this PBE encryption
+ * @param data InputStream to encrypt
+ * @param toBase64 true if resulting InputStream should contain base64,
+ * <br>false if InputStream should contain raw binary.
+ * @return encrypted bytes as an InputStream. First 16 bytes include the
+ * special OpenSSL "Salted__" info.
+ * @throws IOException problems with the data InputStream
+ * @throws GeneralSecurityException problems encrypting
+ */
+ public static InputStream encrypt(String cipher, char[] pwd,
+ InputStream data, boolean toBase64)
+ throws IOException, GeneralSecurityException {
+ // we use a salt by default.
+ return encrypt(cipher, pwd, data, toBase64, true);
+ }
+
+ /**
+ * Encrypts data using a password and an OpenSSL compatible cipher
+ * name.
+ *
+ * @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
+ * unix box to see what's possible). Some examples:
+ * <ul><li>des, des3, des-ede3-cbc
+ * <li>aes128, aes192, aes256, aes-256-cbc
+ * <li>rc2, rc4, bf</ul>
+ * @param pwd password to use for this PBE encryption
+ * @param data byte array to encrypt
+ * @param toBase64 true if resulting InputStream should contain base64,
+ * <br>false if InputStream should contain raw binary.
+ * @param useSalt true if a salt should be used to derive the key.
+ * <br>false otherwise. (Best security practises
+ * always recommend using a salt!).
+ * @return encrypted bytes as an array. First 16 bytes include the
+ * special OpenSSL "Salted__" info if <code>useSalt</code> is true.
+ * @throws IOException problems with the data InputStream
+ * @throws GeneralSecurityException problems encrypting
+ */
+ public static byte[] encrypt(String cipher, char[] pwd, byte[] data,
+ boolean toBase64, boolean useSalt)
+ throws IOException, GeneralSecurityException {
+ ByteArrayInputStream in = new ByteArrayInputStream(data);
+ InputStream encrypted = encrypt(cipher, pwd, in, toBase64, useSalt);
+ return Util.streamToBytes(encrypted);
+ }
+
+ /**
+ * Encrypts data using a password and an OpenSSL compatible cipher
+ * name.
+ *
+ * @param cipher The OpenSSL compatible cipher to use (try "man enc" on a
+ * unix box to see what's possible). Some examples:
+ * <ul><li>des, des3, des-ede3-cbc
+ * <li>aes128, aes192, aes256, aes-256-cbc
+ * <li>rc2, rc4, bf</ul>
+ * @param pwd password to use for this PBE encryption
+ * @param data InputStream to encrypt
+ * @param toBase64 true if resulting InputStream should contain base64,
+ * <br>false if InputStream should contain raw binary.
+ * @param useSalt true if a salt should be used to derive the key.
+ * <br>false otherwise. (Best security practises
+ * always recommend using a salt!).
+ * @return encrypted bytes as an InputStream. First 16 bytes include the
+ * special OpenSSL "Salted__" info if <code>useSalt</code> is true.
+ * @throws IOException problems with the data InputStream
+ * @throws GeneralSecurityException problems encrypting
+ */
+ public static InputStream encrypt(String cipher, char[] pwd,
+ InputStream data, boolean toBase64,
+ boolean useSalt)
+ throws IOException, GeneralSecurityException {
+ CipherInfo cipherInfo = lookup(cipher);
+ byte[] salt = null;
+ if (useSalt) {
+ SecureRandom rand = SecureRandom.getInstance("SHA1PRNG");
+ salt = new byte[8];
+ rand.nextBytes(salt);
+ }
+
+ int keySize = cipherInfo.keySize;
+ int ivSize = cipherInfo.ivSize;
+ boolean des2 = cipherInfo.des2;
+ DerivedKey dk = deriveKey(pwd, salt, keySize, ivSize, des2);
+ Cipher c = PKCS8Key.generateCipher(
+ cipherInfo.javaCipher, cipherInfo.blockMode, dk, des2, null, false
+ );
+
+ InputStream cipherStream = new CipherInputStream(data, c);
+
+ if (useSalt) {
+ byte[] saltLine = new byte[16];
+ byte[] salted = "Salted__".getBytes();
+ System.arraycopy(salted, 0, saltLine, 0, salted.length);
+ System.arraycopy(salt, 0, saltLine, salted.length, salt.length);
+ InputStream head = new ByteArrayInputStream(saltLine);
+ cipherStream = new ComboInputStream(head, cipherStream);
+ }
+ if (toBase64) {
+ cipherStream = new Base64InputStream(cipherStream, false);
+ }
+ return cipherStream;
+ }
+
+
+ public static byte[] decrypt(String cipher, byte[] key, byte[] iv,
+ byte[] encrypted)
+ throws IOException, GeneralSecurityException {
+ ByteArrayInputStream in = new ByteArrayInputStream(encrypted);
+ InputStream decrypted = decrypt(cipher, key, iv, in);
+ return Util.streamToBytes(decrypted);
+ }
+
+ public static InputStream decrypt(String cipher, byte[] key, byte[] iv,
+ InputStream encrypted)
+ throws IOException, GeneralSecurityException {
+ CipherInfo cipherInfo = lookup(cipher);
+ byte[] firstLine = Util.streamToBytes(encrypted, 16);
+ if (Base64.isArrayByteBase64(firstLine)) {
+ InputStream head = new ByteArrayInputStream(firstLine);
+ // Need to put that 16 byte "firstLine" back into the Stream.
+ encrypted = new ComboInputStream(head, encrypted);
+ encrypted = new Base64InputStream(encrypted, true);
+ } else {
+ // Encrypted data wasn't base64. Need to put the "firstLine" we
+ // extracted back into the stream.
+ InputStream head = new ByteArrayInputStream(firstLine);
+ encrypted = new ComboInputStream(head, encrypted);
+ }
+
+ int keySize = cipherInfo.keySize;
+ int ivSize = cipherInfo.ivSize;
+ if (key.length == keySize / 4) // Looks like key is in hex
+ {
+ key = Hex.decode(key);
+ }
+ if (iv.length == ivSize / 4) // Looks like IV is in hex
+ {
+ iv = Hex.decode(iv);
+ }
+ DerivedKey dk = new DerivedKey(key, iv);
+ Cipher c = PKCS8Key.generateCipher(cipherInfo.javaCipher,
+ cipherInfo.blockMode,
+ dk, cipherInfo.des2, null, true);
+ return new CipherInputStream(encrypted, c);
+ }
+
+ public static byte[] encrypt(String cipher, byte[] key, byte[] iv,
+ byte[] data)
+ throws IOException, GeneralSecurityException {
+ return encrypt(cipher, key, iv, data, true);
+ }
+
+ public static byte[] encrypt(String cipher, byte[] key, byte[] iv,
+ byte[] data, boolean toBase64)
+ throws IOException, GeneralSecurityException {
+ ByteArrayInputStream in = new ByteArrayInputStream(data);
+ InputStream encrypted = encrypt(cipher, key, iv, in, toBase64);
+ return Util.streamToBytes(encrypted);
+ }
+
+
+ public static InputStream encrypt(String cipher, byte[] key, byte[] iv,
+ InputStream data)
+ throws IOException, GeneralSecurityException {
+ return encrypt(cipher, key, iv, data, true);
+ }
+
+ public static InputStream encrypt(String cipher, byte[] key, byte[] iv,
+ InputStream data, boolean toBase64)
+ throws IOException, GeneralSecurityException {
+ CipherInfo cipherInfo = lookup(cipher);
+ int keySize = cipherInfo.keySize;
+ int ivSize = cipherInfo.ivSize;
+ if (key.length == keySize / 4) {
+ key = Hex.decode(key);
+ }
+ if (iv.length == ivSize / 4) {
+ iv = Hex.decode(iv);
+ }
+ DerivedKey dk = new DerivedKey(key, iv);
+ Cipher c = PKCS8Key.generateCipher(cipherInfo.javaCipher,
+ cipherInfo.blockMode,
+ dk, cipherInfo.des2, null, false);
+
+ InputStream cipherStream = new CipherInputStream(data, c);
+ if (toBase64) {
+ cipherStream = new Base64InputStream(cipherStream, false);
+ }
+ return cipherStream;
+ }
+
+
+ public static DerivedKey deriveKey(char[] password, byte[] salt,
+ int keySize, boolean des2)
+ throws NoSuchAlgorithmException {
+ return deriveKey(password, salt, keySize, 0, des2);
+ }
+
+ public static DerivedKey deriveKey(char[] password, byte[] salt,
+ int keySize, int ivSize, boolean des2)
+ throws NoSuchAlgorithmException {
+ if (des2) {
+ keySize = 128;
+ }
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] pwdAsBytes = new byte[password.length];
+ for (int i = 0; i < password.length; i++) {
+ pwdAsBytes[i] = (byte) password[i];
+ }
+
+ md.reset();
+ byte[] keyAndIv = new byte[(keySize / 8) + (ivSize / 8)];
+ if (salt == null || salt.length == 0) {
+ // Unsalted! Bad idea!
+ salt = null;
+ }
+ byte[] result;
+ int currentPos = 0;
+ while (currentPos < keyAndIv.length) {
+ md.update(pwdAsBytes);
+ if (salt != null) {
+ // First 8 bytes of salt ONLY! That wasn't obvious to me
+ // when using AES encrypted private keys in "Traditional
+ // SSLeay Format".
+ //
+ // Example:
+ // DEK-Info: AES-128-CBC,8DA91D5A71988E3D4431D9C2C009F249
+ //
+ // Only the first 8 bytes are salt, but the whole thing is
+ // re-used again later as the IV. MUCH gnashing of teeth!
+ md.update(salt, 0, 8);
+ }
+ result = md.digest();
+ int stillNeed = keyAndIv.length - currentPos;
+ // Digest gave us more than we need. Let's truncate it.
+ if (result.length > stillNeed) {
+ byte[] b = new byte[stillNeed];
+ System.arraycopy(result, 0, b, 0, b.length);
+ result = b;
+ }
+ System.arraycopy(result, 0, keyAndIv, currentPos, result.length);
+ currentPos += result.length;
+ if (currentPos < keyAndIv.length) {
+ // Next round starts with a hash of the hash.
+ md.reset();
+ md.update(result);
+ }
+ }
+ if (des2) {
+ keySize = 192;
+ byte[] buf = new byte[keyAndIv.length + 8];
+ // Make space where 3rd key needs to go (16th - 24th bytes):
+ System.arraycopy(keyAndIv, 0, buf, 0, 16);
+ if (ivSize > 0) {
+ System.arraycopy(keyAndIv, 16, buf, 24, keyAndIv.length - 16);
+ }
+ keyAndIv = buf;
+ // copy first 8 bytes into last 8 bytes to create 2DES key.
+ System.arraycopy(keyAndIv, 0, keyAndIv, 16, 8);
+ }
+ if (ivSize == 0) {
+ // if ivSize == 0, then "keyAndIv" array is actually all key.
+
+ // Must be "Traditional SSLeay Format" encrypted private key in
+ // PEM. The "salt" in its entirety (not just first 8 bytes) will
+ // probably be re-used later as the IV (initialization vector).
+ return new DerivedKey(keyAndIv, salt);
+ } else {
+ byte[] key = new byte[keySize / 8];
+ byte[] iv = new byte[ivSize / 8];
+ System.arraycopy(keyAndIv, 0, key, 0, key.length);
+ System.arraycopy(keyAndIv, key.length, iv, 0, iv.length);
+ return new DerivedKey(key, iv);
+ }
+ }
+
+
+ public static class CipherInfo {
+ public final String javaCipher;
+ public final String blockMode;
+ public final int keySize;
+ public final int ivSize;
+ public final boolean des2;
+
+ public CipherInfo(String javaCipher, String blockMode, int keySize,
+ int ivSize, boolean des2) {
+ this.javaCipher = javaCipher;
+ this.blockMode = blockMode;
+ this.keySize = keySize;
+ this.ivSize = ivSize;
+ this.des2 = des2;
+ }
+
+ public String toString() {
+ return javaCipher + "/" + blockMode + " " + keySize + "bit des2=" + des2;
+ }
+ }
+
+ /**
+ * Converts the way OpenSSL names its ciphers into a Java-friendly naming.
+ *
+ * @param openSSLCipher OpenSSL cipher name, e.g. "des3" or "des-ede3-cbc".
+ * Try "man enc" on a unix box to see what's possible.
+ * @return CipherInfo object with the Java-friendly cipher information.
+ */
+ public static CipherInfo lookup(String openSSLCipher) {
+ openSSLCipher = openSSLCipher.trim();
+ if (openSSLCipher.charAt(0) == '-') {
+ openSSLCipher = openSSLCipher.substring(1);
+ }
+ String javaCipher = openSSLCipher.toUpperCase();
+ String blockMode = "CBC";
+ int keySize = -1;
+ int ivSize = 64;
+ boolean des2 = false;
+
+
+ StringTokenizer st = new StringTokenizer(openSSLCipher, "-");
+ if (st.hasMoreTokens()) {
+ javaCipher = st.nextToken().toUpperCase();
+ if (st.hasMoreTokens()) {
+ // Is this the middle token? Or the last token?
+ String tok = st.nextToken();
+ if (st.hasMoreTokens()) {
+ try {
+ keySize = Integer.parseInt(tok);
+ }
+ catch (NumberFormatException nfe) {
+ // I guess 2nd token isn't an integer
+ String upper = tok.toUpperCase();
+ if (upper.startsWith("EDE3")) {
+ javaCipher = "DESede";
+ } else if (upper.startsWith("EDE")) {
+ javaCipher = "DESede";
+ des2 = true;
+ }
+ }
+ blockMode = st.nextToken().toUpperCase();
+ } else {
+ try {
+ keySize = Integer.parseInt(tok);
+ }
+ catch (NumberFormatException nfe) {
+ // It's the last token, so must be mode (usually "CBC").
+ blockMode = tok.toUpperCase();
+ if (blockMode.startsWith("EDE3")) {
+ javaCipher = "DESede";
+ blockMode = "ECB";
+ } else if (blockMode.startsWith("EDE")) {
+ javaCipher = "DESede";
+ blockMode = "ECB";
+ des2 = true;
+ }
+ }
+ }
+ }
+ }
+ if (javaCipher.startsWith("BF")) {
+ javaCipher = "Blowfish";
+ } else if (javaCipher.startsWith("TWOFISH")) {
+ javaCipher = "Twofish";
+ ivSize = 128;
+ } else if (javaCipher.startsWith("IDEA")) {
+ javaCipher = "IDEA";
+ } else if (javaCipher.startsWith("CAST6")) {
+ javaCipher = "CAST6";
+ ivSize = 128;
+ } else if (javaCipher.startsWith("CAST")) {
+ javaCipher = "CAST5";
+ } else if (javaCipher.startsWith("GOST")) {
+ keySize = 256;
+ } else if (javaCipher.startsWith("DESX")) {
+ javaCipher = "DESX";
+ } else if ("DES3".equals(javaCipher)) {
+ javaCipher = "DESede";
+ } else if ("DES2".equals(javaCipher)) {
+ javaCipher = "DESede";
+ des2 = true;
+ } else if (javaCipher.startsWith("RIJNDAEL")) {
+ javaCipher = "Rijndael";
+ ivSize = 128;
+ } else if (javaCipher.startsWith("SEED")) {
+ javaCipher = "SEED";
+ ivSize = 128;
+ } else if (javaCipher.startsWith("SERPENT")) {
+ javaCipher = "Serpent";
+ ivSize = 128;
+ } else if (javaCipher.startsWith("Skipjack")) {
+ javaCipher = "Skipjack";
+ ivSize = 128;
+ } else if (javaCipher.startsWith("RC6")) {
+ javaCipher = "RC6";
+ ivSize = 128;
+ } else if (javaCipher.startsWith("TEA")) {
+ javaCipher = "TEA";
+ } else if (javaCipher.startsWith("XTEA")) {
+ javaCipher = "XTEA";
+ } else if (javaCipher.startsWith("AES")) {
+ if (javaCipher.startsWith("AES128")) {
+ keySize = 128;
+ } else if (javaCipher.startsWith("AES192")) {
+ keySize = 192;
+ } else if (javaCipher.startsWith("AES256")) {
+ keySize = 256;
+ }
+ javaCipher = "AES";
+ ivSize = 128;
+ } else if (javaCipher.startsWith("CAMELLIA")) {
+ if (javaCipher.startsWith("CAMELLIA128")) {
+ keySize = 128;
+ } else if (javaCipher.startsWith("CAMELLIA192")) {
+ keySize = 192;
+ } else if (javaCipher.startsWith("CAMELLIA256")) {
+ keySize = 256;
+ }
+ javaCipher = "CAMELLIA";
+ ivSize = 128;
+ }
+ if (keySize == -1) {
+ if (javaCipher.startsWith("DESede")) {
+ keySize = 192;
+ } else if (javaCipher.startsWith("DES")) {
+ keySize = 64;
+ } else {
+ // RC2, RC4, RC5 and Blowfish ?
+ keySize = 128;
+ }
+ }
+ return new CipherInfo(javaCipher, blockMode, keySize, ivSize, des2);
+ }
+
+
+ /**
+ * @param args command line arguments: [password] [cipher] [file-to-decrypt]
+ * <br>[cipher] == OpenSSL cipher name, e.g. "des3" or "des-ede3-cbc".
+ * Try "man enc" on a unix box to see what's possible.
+ * @throws IOException problems with the [file-to-decrypt]
+ * @throws GeneralSecurityException decryption problems
+ */
+ public static void main(String[] args)
+ throws IOException, GeneralSecurityException {
+ if (args.length < 3) {
+ System.out.println(Version.versionString());
+ System.out.println("Pure-java utility to decrypt files previously encrypted by \'openssl enc\'");
+ System.out.println();
+ System.out.println("Usage: java -cp commons-ssl.jar org.apache.commons.ssl.OpenSSL [args]");
+ System.out.println(" [args] == [password] [cipher] [file-to-decrypt]");
+ System.out.println(" [cipher] == des, des3, des-ede3-cbc, aes256, rc2, rc4, bf, bf-cbc, etc...");
+ System.out.println(" Try 'man enc' on a unix box to see what's possible.");
+ System.out.println();
+ System.out.println("This utility can handle base64 or raw, salted or unsalted.");
+ System.out.println();
+ System.exit(1);
+ }
+ char[] password = args[0].toCharArray();
+
+ InputStream in = new FileInputStream(args[2]);
+ in = decrypt(args[1], password, in);
+
+ // in = encrypt( args[ 1 ], pwdAsBytes, in, true );
+
+ Util.pipeStream(in, System.out, false);
+ byte[] output = Util.streamToBytes(in);
+ System.out.write(output);
+ System.out.flush();
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/OpenSSLTest.java b/src/java/org/apache/commons/ssl/OpenSSLTest.java
new file mode 100644
index 0000000..1b1c034
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/OpenSSLTest.java
@@ -0,0 +1,92 @@
+package org.apache.commons.ssl;
+
+import org.apache.commons.ssl.util.Hex;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Arrays;
+
+/**
+ * @author Julius Davies
+ * @since 3-Jul-2007
+ */
+public class OpenSSLTest {
+
+ public static void main(String[] args) throws Exception {
+ String path = args[0];
+ File f = new File(path);
+ if (f.isDirectory()) {
+ File[] files = f.listFiles();
+ Arrays.sort(files);
+ for (int i = 0; i < files.length; i++) {
+ process(files[i], 0);
+ }
+ } else {
+ System.out.println("Attempting decrypt!");
+
+ String keyS = "1234567890ABDEF01234567890ABDEFF";
+ String ivS = "1234567890ABDEF01234567890ABDEFF";
+ byte[] key = Hex.decode(keyS.getBytes());
+ byte[] iv = Hex.decode(ivS.getBytes());
+ FileInputStream in = new FileInputStream(f);
+ InputStream decrypted = OpenSSL.decrypt("aes128", key, iv, in);
+ byte[] b = Util.streamToBytes(decrypted);
+ System.out.println(new String(b));
+ }
+ }
+
+
+ private static void process(File f, int depth) {
+ String name = f.getName();
+ if ("CVS".equalsIgnoreCase(name)) {
+ return;
+ }
+ if (name.toUpperCase().startsWith("README")) {
+ return;
+ }
+
+ if (f.isDirectory()) {
+ if (depth <= 3) {
+ File[] files = f.listFiles();
+ Arrays.sort(files);
+ for (int i = 0; i < files.length; i++) {
+ process(files[i], depth + 1);
+ }
+ } else {
+ System.out.println("IGNORING [" + f + "]. Directory too deep (" + depth + ").");
+ }
+ } else {
+ if (f.isFile() && f.canRead()) {
+ String fileName = f.getName();
+ int x = fileName.indexOf('.');
+ if (x < 0) {
+ return;
+ }
+ String cipher = fileName.substring(0, x);
+ String cipherPadded = Util.pad(cipher, 20, false);
+ String filePadded = Util.pad(fileName, 25, false);
+ try {
+ FileInputStream in = new FileInputStream(f);
+ byte[] encrypted = Util.streamToBytes(in);
+ char[] pwd = "changeit".toCharArray();
+
+ byte[] result = OpenSSL.decrypt(cipher, pwd, encrypted);
+ String s = new String(result, "ISO-8859-1");
+
+ boolean success = "Hello World!".equals(s);
+ if (success) {
+ System.out.println("SUCCESS \t" + cipherPadded + "\t" + filePadded);
+ } else {
+ System.out.println("FAILURE*\t" + cipherPadded + "\t" + filePadded + "\tDECRYPT RESULTS DON'T MATCH");
+ }
+ }
+ catch (Exception e) {
+ System.out.println("FAILURE*\t" + cipherPadded + "\t" + filePadded + "\t" + e);
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/PBETestCreate.java b/src/java/org/apache/commons/ssl/PBETestCreate.java
new file mode 100644
index 0000000..f962e10
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/PBETestCreate.java
@@ -0,0 +1,79 @@
+package org.apache.commons.ssl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.TreeSet;
+
+/**
+ * @author Julius Davies
+ * @since 4-Jul-2007
+ */
+public class PBETestCreate {
+
+ public static void main(String[] args) throws Exception {
+ FileInputStream in = new FileInputStream(args[0]);
+ Properties p = new Properties();
+ p.load(in);
+ in.close();
+
+ String targetDir = p.getProperty("target");
+ File dir = new File(targetDir);
+ dir.mkdirs();
+ if (!dir.exists()) {
+ throw new IOException(dir.getCanonicalPath() + " doesn't exist!");
+ }
+
+ TreeSet ciphers = new TreeSet();
+ Iterator it = p.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ String key = (String) entry.getKey();
+ if (!"target".equalsIgnoreCase(key)) {
+ ciphers.add(key);
+ ciphers.add(key + "-cbc");
+ ciphers.add(key + "-cfb");
+ ciphers.add(key + "-cfb1");
+ ciphers.add(key + "-cfb8");
+ ciphers.add(key + "-ecb");
+ ciphers.add(key + "-ofb");
+ }
+ }
+
+ byte[] toEncrypt = "Hello World!".getBytes("UTF-8");
+ char[] pwd = "changeit".toCharArray();
+ it = ciphers.iterator();
+ while (it.hasNext()) {
+ String cipher = (String) it.next();
+ String cipherPadded = Util.pad(cipher, 15, false);
+ String fileNameBase64 = cipher + ".base64";
+ String fileNameRaw = cipher + ".raw";
+ String d = dir.getCanonicalPath() + "/";
+ try {
+ byte[] base64 = OpenSSL.encrypt(cipher, pwd, toEncrypt, true);
+ FileOutputStream out = new FileOutputStream(d + fileNameBase64);
+ out.write(base64);
+ out.close();
+ }
+ catch (Exception e) {
+ System.err.println("FAILURE \t" + cipherPadded + "\t" + fileNameBase64 + "\t" + e);
+ }
+
+ try {
+ byte[] raw = OpenSSL.encrypt(cipher, pwd, toEncrypt, false);
+ FileOutputStream out = new FileOutputStream(d + fileNameRaw);
+ out.write(raw);
+ out.close();
+ }
+ catch (Exception e) {
+ System.err.println("FAILURE \t" + cipherPadded + "\t" + fileNameRaw + "\t" + e);
+ }
+
+ }
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/PEMItem.java b/src/java/org/apache/commons/ssl/PEMItem.java
new file mode 100644
index 0000000..9b40464
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/PEMItem.java
@@ -0,0 +1,106 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/PEMItem.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import org.apache.commons.ssl.util.Hex;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 13-Aug-2006
+ */
+public class PEMItem {
+ public final static String DEK_INFO = "dek-info";
+
+ private final byte[] derBytes;
+ public final String pemType;
+ public final Map properties;
+
+ public final String dekInfo;
+ public final byte[] iv;
+ public final String cipher;
+ public final boolean des2;
+ public final String mode;
+ public final int keySizeInBits;
+
+ public PEMItem(byte[] derBytes, String type) {
+ this(derBytes, type, null);
+ }
+
+ public PEMItem(byte[] derBytes, String type, Map properties) {
+ this.derBytes = derBytes;
+ this.pemType = type;
+ if (properties == null) {
+ properties = new TreeMap(); // empty map
+ }
+ this.properties = Collections.unmodifiableMap(properties);
+ String di = (String) properties.get(DEK_INFO);
+ String diCipher = "";
+ String diIV = "";
+ if (di != null) {
+ StringTokenizer st = new StringTokenizer(di, ",");
+ if (st.hasMoreTokens()) {
+ diCipher = st.nextToken().trim().toLowerCase();
+ }
+ if (st.hasMoreTokens()) {
+ diIV = st.nextToken().trim().toLowerCase();
+ }
+ }
+ this.dekInfo = diCipher;
+ this.iv = Hex.decode(diIV);
+ if (!"".equals(diCipher)) {
+ OpenSSL.CipherInfo cipherInfo = OpenSSL.lookup(diCipher);
+ this.cipher = cipherInfo.javaCipher;
+ this.mode = cipherInfo.blockMode;
+ this.keySizeInBits = cipherInfo.keySize;
+ this.des2 = cipherInfo.des2;
+ } else {
+ this.mode = "";
+ cipher = "UNKNOWN";
+ keySizeInBits = -1;
+ des2 = false;
+ }
+ }
+
+ public byte[] getDerBytes() {
+ byte[] b = new byte[derBytes.length];
+ System.arraycopy(derBytes, 0, b, 0, derBytes.length);
+ return b;
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/PEMUtil.java b/src/java/org/apache/commons/ssl/PEMUtil.java
new file mode 100644
index 0000000..69cab97
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/PEMUtil.java
@@ -0,0 +1,238 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/PEMUtil.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 13-Aug-2006
+ */
+public class PEMUtil {
+ final static String LINE_SEPARATOR = System.getProperty("line.separator");
+
+ public static byte[] encode(Collection items) throws IOException {
+ final byte[] LINE_SEPARATOR_BYTES = LINE_SEPARATOR.getBytes("UTF-8");
+ ByteArrayOutputStream out = new ByteArrayOutputStream(4096);
+ Iterator it = items.iterator();
+ while (it.hasNext()) {
+ PEMItem item = (PEMItem) it.next();
+ out.write("-----BEGIN ".getBytes("UTF-8"));
+ out.write(item.pemType.getBytes("UTF-8"));
+ out.write("-----".getBytes("UTF-8"));
+ out.write(LINE_SEPARATOR_BYTES);
+
+ byte[] derBytes = item.getDerBytes();
+ ByteArrayInputStream bin = new ByteArrayInputStream(derBytes);
+ byte[] line = Util.streamToBytes(bin, 48);
+ while (line.length == 48) {
+ byte[] base64Line = Base64.encodeBase64(line);
+ out.write(base64Line);
+ out.write(LINE_SEPARATOR_BYTES);
+ line = Util.streamToBytes(bin, 48);
+ }
+ if (line.length > 0) {
+ byte[] base64Line = Base64.encodeBase64(line);
+ out.write(base64Line);
+ out.write(LINE_SEPARATOR_BYTES);
+ }
+ out.write("-----END ".getBytes("UTF-8"));
+ out.write(item.pemType.getBytes("UTF-8"));
+ out.write("-----".getBytes("UTF-8"));
+ out.write(LINE_SEPARATOR_BYTES);
+ }
+ return out.toByteArray();
+ }
+
+ public static List decode(byte[] pemBytes) {
+ LinkedList pemItems = new LinkedList();
+ ByteArrayInputStream in = new ByteArrayInputStream(pemBytes);
+ String line = Util.readLine(in);
+ while (line != null) {
+ int len = 0;
+ byte[] decoded;
+ ArrayList listOfByteArrays = new ArrayList(64);
+ Map properties = new HashMap();
+ String type = "[unknown]";
+ while (line != null && !beginBase64(line)) {
+ line = Util.readLine(in);
+ }
+ if (line != null) {
+ String upperLine = line.toUpperCase();
+ int x = upperLine.indexOf("-BEGIN") + "-BEGIN".length();
+ int y = upperLine.indexOf("-", x);
+ type = upperLine.substring(x, y).trim();
+ line = Util.readLine(in);
+ }
+ while (line != null && !endBase64(line)) {
+ line = Util.trim(line);
+ if (!"".equals(line)) {
+ int x = line.indexOf(':');
+ if (x > 0) {
+ String k = line.substring(0, x).trim();
+ String v = "";
+ if (line.length() > x + 1) {
+ v = line.substring(x + 1).trim();
+ }
+ properties.put(k.toLowerCase(), v.toLowerCase());
+ } else {
+ byte[] base64 = line.getBytes();
+ byte[] rawBinary = Base64.decodeBase64(base64);
+ listOfByteArrays.add(rawBinary);
+ len += rawBinary.length;
+ }
+ }
+ line = Util.readLine(in);
+ }
+ if (line != null) {
+ line = Util.readLine(in);
+ }
+
+ if (!listOfByteArrays.isEmpty()) {
+ decoded = new byte[len];
+ int pos = 0;
+ Iterator it = listOfByteArrays.iterator();
+ while (it.hasNext()) {
+ byte[] oneLine = (byte[]) it.next();
+ System.arraycopy(oneLine, 0, decoded, pos, oneLine.length);
+ pos += oneLine.length;
+ }
+ PEMItem item = new PEMItem(decoded, type, properties);
+ pemItems.add(item);
+ }
+ }
+
+ // closing ByteArrayInputStream is a NO-OP
+ // in.close();
+
+ return pemItems;
+ }
+
+ private static boolean beginBase64(String line) {
+ line = line != null ? line.trim().toUpperCase() : "";
+ int x = line.indexOf("-BEGIN");
+ return x > 0 && startsAndEndsWithDashes(line);
+ }
+
+ private static boolean endBase64(String line) {
+ line = line != null ? line.trim().toUpperCase() : "";
+ int x = line.indexOf("-END");
+ return x > 0 && startsAndEndsWithDashes(line);
+ }
+
+ private static boolean startsAndEndsWithDashes(String line) {
+ line = Util.trim(line);
+ char c = line.charAt(0);
+ char d = line.charAt(line.length() - 1);
+ return c == '-' && d == '-';
+ }
+
+ public static String formatRSAPrivateKey(RSAPrivateCrtKey key) {
+ StringBuffer buf = new StringBuffer(2048);
+ buf.append("Private-Key:");
+ buf.append(LINE_SEPARATOR);
+ buf.append("modulus:");
+ buf.append(LINE_SEPARATOR);
+ buf.append(formatBigInteger(key.getModulus(), 129 * 2));
+ buf.append(LINE_SEPARATOR);
+ buf.append("publicExponent: ");
+ buf.append(key.getPublicExponent());
+ buf.append(LINE_SEPARATOR);
+ buf.append("privateExponent:");
+ buf.append(LINE_SEPARATOR);
+ buf.append(formatBigInteger(key.getPrivateExponent(), 128 * 2));
+ buf.append(LINE_SEPARATOR);
+ buf.append("prime1:");
+ buf.append(LINE_SEPARATOR);
+ buf.append(formatBigInteger(key.getPrimeP(), 65 * 2));
+ buf.append(LINE_SEPARATOR);
+ buf.append("prime2:");
+ buf.append(LINE_SEPARATOR);
+ buf.append(formatBigInteger(key.getPrimeQ(), 65 * 2));
+ buf.append(LINE_SEPARATOR);
+ buf.append("exponent1:");
+ buf.append(LINE_SEPARATOR);
+ buf.append(formatBigInteger(key.getPrimeExponentP(), 65 * 2));
+ buf.append(LINE_SEPARATOR);
+ buf.append("exponent2:");
+ buf.append(LINE_SEPARATOR);
+ buf.append(formatBigInteger(key.getPrimeExponentQ(), 65 * 2));
+ buf.append(LINE_SEPARATOR);
+ buf.append("coefficient:");
+ buf.append(LINE_SEPARATOR);
+ buf.append(formatBigInteger(key.getCrtCoefficient(), 65 * 2));
+ return buf.toString();
+ }
+
+ public static String formatBigInteger(BigInteger bi, int length) {
+ String s = bi.toString(16);
+ StringBuffer buf = new StringBuffer(s.length());
+ int zeroesToAppend = length - s.length();
+ int count = 0;
+ buf.append(" ");
+ for (int i = 0; i < zeroesToAppend; i++) {
+ count++;
+ buf.append('0');
+ if (i % 2 == 1) {
+ buf.append(':');
+ }
+ }
+ for (int i = 0; i < s.length() - 2; i++) {
+ count++;
+ buf.append(s.charAt(i));
+ if (i % 2 == 1) {
+ buf.append(':');
+ }
+ if (count % 30 == 0) {
+ buf.append(LINE_SEPARATOR);
+ buf.append(" ");
+ }
+ }
+ buf.append(s.substring(s.length() - 2));
+ return buf.toString();
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/PKCS8Key.java b/src/java/org/apache/commons/ssl/PKCS8Key.java
new file mode 100644
index 0000000..195b02a
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/PKCS8Key.java
@@ -0,0 +1,1034 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/PKCS8Key.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import org.apache.commons.ssl.asn1.ASN1EncodableVector;
+import org.apache.commons.ssl.asn1.ASN1OutputStream;
+import org.apache.commons.ssl.asn1.DEREncodable;
+import org.apache.commons.ssl.asn1.DERInteger;
+import org.apache.commons.ssl.asn1.DERNull;
+import org.apache.commons.ssl.asn1.DERObjectIdentifier;
+import org.apache.commons.ssl.asn1.DEROctetString;
+import org.apache.commons.ssl.asn1.DERSequence;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.Mac;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.RC2ParameterSpec;
+import javax.crypto.spec.RC5ParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.spec.KeySpec;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Utility for decrypting PKCS8 private keys. Way easier to use than
+ * javax.crypto.EncryptedPrivateKeyInfo since all you need is the byte[] array
+ * and the password. You don't need to know anything else about the PKCS8
+ * key you pass in.
+ * </p><p>
+ * Can handle base64 PEM, or raw DER.
+ * Can handle PKCS8 Version 1.5 and 2.0.
+ * Can also handle OpenSSL encrypted or unencrypted private keys (DSA or RSA).
+ * </p><p>
+ * The PKCS12 key derivation (the "pkcs12()" method) comes from BouncyCastle.
+ * </p>
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @author <a href="bouncycastle.org">bouncycastle.org</a>
+ * @since 7-Nov-2006
+ */
+public class PKCS8Key {
+ public final static String RSA_OID = "1.2.840.113549.1.1.1";
+ public final static String DSA_OID = "1.2.840.10040.4.1";
+
+ public final static String PKCS8_UNENCRYPTED = "PRIVATE KEY";
+ public final static String PKCS8_ENCRYPTED = "ENCRYPTED PRIVATE KEY";
+ public final static String OPENSSL_RSA = "RSA PRIVATE KEY";
+ public final static String OPENSSL_DSA = "DSA PRIVATE KEY";
+
+ private final PrivateKey privateKey;
+ private final byte[] decryptedBytes;
+ private final String transformation;
+ private final int keySize;
+ private final boolean isDSA;
+ private final boolean isRSA;
+
+ static {
+ JavaImpl.load();
+ }
+
+ /**
+ * @param in pkcs8 file to parse (pem or der, encrypted or unencrypted)
+ * @param password password to decrypt the pkcs8 file. Ignored if the
+ * supplied pkcs8 is already unencrypted.
+ * @throws GeneralSecurityException If a parsing or decryption problem
+ * occured.
+ * @throws IOException If the supplied InputStream could not be read.
+ */
+ public PKCS8Key(final InputStream in, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(Util.streamToBytes(in), password);
+ }
+
+ /**
+ * @param in pkcs8 file to parse (pem or der, encrypted or unencrypted)
+ * @param password password to decrypt the pkcs8 file. Ignored if the
+ * supplied pkcs8 is already unencrypted.
+ * @throws GeneralSecurityException If a parsing or decryption problem
+ * occured.
+ */
+ public PKCS8Key(final ByteArrayInputStream in, char[] password)
+ throws GeneralSecurityException {
+ this(Util.streamToBytes(in), password);
+ }
+
+ /**
+ * @param encoded pkcs8 file to parse (pem or der, encrypted or unencrypted)
+ * @param password password to decrypt the pkcs8 file. Ignored if the
+ * supplied pkcs8 is already unencrypted.
+ * @throws GeneralSecurityException If a parsing or decryption problem
+ * occured.
+ */
+ public PKCS8Key(final byte[] encoded, char[] password)
+ throws GeneralSecurityException {
+ DecryptResult decryptResult =
+ new DecryptResult("UNENCRYPTED", 0, encoded);
+
+ List pemItems = PEMUtil.decode(encoded);
+ PEMItem keyItem = null;
+ byte[] derBytes = null;
+ if (pemItems.isEmpty()) {
+ // must be DER encoded - PEMUtil wasn't able to extract anything.
+ derBytes = encoded;
+ } else {
+ Iterator it = pemItems.iterator();
+ boolean opensslRSA = false;
+ boolean opensslDSA = false;
+
+ while (it.hasNext()) {
+ PEMItem item = (PEMItem) it.next();
+ String type = item.pemType.trim().toUpperCase();
+ boolean plainPKCS8 = type.startsWith(PKCS8_UNENCRYPTED);
+ boolean encryptedPKCS8 = type.startsWith(PKCS8_ENCRYPTED);
+ boolean rsa = type.startsWith(OPENSSL_RSA);
+ boolean dsa = type.startsWith(OPENSSL_DSA);
+ if (plainPKCS8 || encryptedPKCS8 || rsa || dsa) {
+ opensslRSA = opensslRSA || rsa;
+ opensslDSA = opensslDSA || dsa;
+ if (derBytes != null) {
+ throw new ProbablyNotPKCS8Exception("More than one pkcs8 or OpenSSL key found in the supplied PEM Base64 stream");
+ }
+ derBytes = item.getDerBytes();
+ keyItem = item;
+ decryptResult = new DecryptResult("UNENCRYPTED", 0, derBytes);
+ }
+ }
+ // after the loop is finished, did we find anything?
+ if (derBytes == null) {
+ throw new ProbablyNotPKCS8Exception("No pkcs8 or OpenSSL key found in the supplied PEM Base64 stream");
+ }
+
+ if (opensslDSA || opensslRSA) {
+ String c = keyItem.cipher.trim();
+ boolean encrypted = !"UNKNOWN".equals(c) && !"".equals(c);
+ if (encrypted) {
+ decryptResult = opensslDecrypt(keyItem, password);
+ }
+
+ String oid = RSA_OID;
+ if (opensslDSA) {
+ oid = DSA_OID;
+ }
+ derBytes = formatAsPKCS8(decryptResult.bytes, oid, null);
+
+ String tf = decryptResult.transformation;
+ int ks = decryptResult.keySize;
+ decryptResult = new DecryptResult(tf, ks, derBytes);
+ }
+ }
+
+ ASN1Structure pkcs8;
+ try {
+ pkcs8 = ASN1Util.analyze(derBytes);
+ }
+ catch (Exception e) {
+ throw new ProbablyNotPKCS8Exception("asn1 parse failure: " + e);
+ }
+
+ String oid = RSA_OID;
+ // With the OpenSSL unencrypted private keys in DER format, the only way
+ // to even have a hope of guessing what we've got (DSA or RSA?) is to
+ // count the number of DERIntegers occurring in the first DERSequence.
+ int derIntegerCount = -1;
+ if (pkcs8.derIntegers != null) {
+ derIntegerCount = pkcs8.derIntegers.size();
+ }
+ switch (derIntegerCount) {
+ case 6:
+ oid = DSA_OID;
+ case 9:
+ derBytes = formatAsPKCS8(derBytes, oid, pkcs8);
+ pkcs8.oid1 = oid;
+
+ String tf = decryptResult.transformation;
+ int ks = decryptResult.keySize;
+ decryptResult = new DecryptResult(tf, ks, derBytes);
+ break;
+ default:
+ break;
+ }
+
+ oid = pkcs8.oid1;
+ if (!oid.startsWith("1.2.840.113549.1")) {
+ boolean isOkay = false;
+ if (oid.startsWith("1.2.840.10040.4.")) {
+ String s = oid.substring("1.2.840.10040.4.".length());
+ // 1.2.840.10040.4.1 -- id-dsa
+ // 1.2.840.10040.4.3 -- id-dsa-with-sha1
+ isOkay = s.equals("1") || s.startsWith("1.") ||
+ s.equals("3") || s.startsWith("3.");
+ }
+ if (!isOkay) {
+ throw new ProbablyNotPKCS8Exception("Valid ASN.1, but not PKCS8 or OpenSSL format. OID=" + oid);
+ }
+ }
+
+ boolean isRSA = RSA_OID.equals(oid);
+ boolean isDSA = DSA_OID.equals(oid);
+ boolean encrypted = !isRSA && !isDSA;
+ byte[] decryptedPKCS8 = encrypted ? null : derBytes;
+
+ if (encrypted) {
+ decryptResult = decryptPKCS8(pkcs8, password);
+ decryptedPKCS8 = decryptResult.bytes;
+ }
+ if (encrypted) {
+ try {
+ pkcs8 = ASN1Util.analyze(decryptedPKCS8);
+ }
+ catch (Exception e) {
+ throw new ProbablyBadPasswordException("Decrypted stream not ASN.1. Probably bad decryption password.");
+ }
+ oid = pkcs8.oid1;
+ isDSA = DSA_OID.equals(oid);
+ }
+
+ KeySpec spec = new PKCS8EncodedKeySpec(decryptedPKCS8);
+ String type = "RSA";
+ PrivateKey pk;
+ try {
+ KeyFactory KF;
+ if (isDSA) {
+ type = "DSA";
+ KF = KeyFactory.getInstance("DSA");
+ } else {
+ KF = KeyFactory.getInstance("RSA");
+ }
+ pk = KF.generatePrivate(spec);
+ }
+ catch (Exception e) {
+ throw new ProbablyBadPasswordException("Cannot create " + type + " private key from decrypted stream. Probably bad decryption password. " + e);
+ }
+ if (pk != null) {
+ this.privateKey = pk;
+ this.isDSA = isDSA;
+ this.isRSA = !isDSA;
+ this.decryptedBytes = decryptedPKCS8;
+ this.transformation = decryptResult.transformation;
+ this.keySize = decryptResult.keySize;
+ } else {
+ throw new GeneralSecurityException("KeyFactory.generatePrivate() returned null and didn't throw exception!");
+ }
+ }
+
+ public boolean isRSA() {
+ return isRSA;
+ }
+
+ public boolean isDSA() {
+ return isDSA;
+ }
+
+ public String getTransformation() {
+ return transformation;
+ }
+
+ public int getKeySize() {
+ return keySize;
+ }
+
+ public byte[] getDecryptedBytes() {
+ return decryptedBytes;
+ }
+
+ public PrivateKey getPrivateKey() {
+ return privateKey;
+ }
+
+ public static class DecryptResult {
+ public final String transformation;
+ public final int keySize;
+ public final byte[] bytes;
+
+ protected DecryptResult(String transformation, int keySize,
+ byte[] decryptedBytes) {
+ this.transformation = transformation;
+ this.keySize = keySize;
+ this.bytes = decryptedBytes;
+ }
+ }
+
+ private static DecryptResult opensslDecrypt(final PEMItem item,
+ final char[] password)
+ throws GeneralSecurityException {
+ final String cipher = item.cipher;
+ final String mode = item.mode;
+ final int keySize = item.keySizeInBits;
+ final byte[] salt = item.iv;
+ final boolean des2 = item.des2;
+ final DerivedKey dk = OpenSSL.deriveKey(password, salt, keySize, des2);
+ return decrypt(cipher, mode, dk, des2, null, item.getDerBytes());
+ }
+
+ public static Cipher generateCipher(String cipher, String mode,
+ final DerivedKey dk,
+ final boolean des2,
+ final byte[] iv,
+ final boolean decryptMode)
+ throws NoSuchAlgorithmException, NoSuchPaddingException,
+ InvalidKeyException, InvalidAlgorithmParameterException {
+ if (des2 && dk.key.length >= 24) {
+ // copy first 8 bytes into last 8 bytes to create 2DES key.
+ System.arraycopy(dk.key, 0, dk.key, 16, 8);
+ }
+
+ final int keySize = dk.key.length * 8;
+ cipher = cipher.trim();
+ String cipherUpper = cipher.toUpperCase();
+ mode = mode.trim().toUpperCase();
+ // Is the cipher even available?
+ Cipher.getInstance(cipher);
+ String padding = "PKCS5Padding";
+ if (mode.startsWith("CFB") || mode.startsWith("OFB")) {
+ padding = "NoPadding";
+ }
+
+ String transformation = cipher + "/" + mode + "/" + padding;
+ if (cipherUpper.startsWith("RC4")) {
+ // RC4 does not take mode or padding.
+ transformation = cipher;
+ }
+
+ SecretKey secret = new SecretKeySpec(dk.key, cipher);
+ IvParameterSpec ivParams;
+ if (iv != null) {
+ ivParams = new IvParameterSpec(iv);
+ } else {
+ ivParams = dk.iv != null ? new IvParameterSpec(dk.iv) : null;
+ }
+
+ Cipher c = Cipher.getInstance(transformation);
+ int cipherMode = Cipher.ENCRYPT_MODE;
+ if (decryptMode) {
+ cipherMode = Cipher.DECRYPT_MODE;
+ }
+
+ // RC2 requires special params to inform engine of keysize.
+ if (cipherUpper.startsWith("RC2")) {
+ RC2ParameterSpec rcParams;
+ if (mode.startsWith("ECB") || ivParams == null) {
+ // ECB doesn't take an IV.
+ rcParams = new RC2ParameterSpec(keySize);
+ } else {
+ rcParams = new RC2ParameterSpec(keySize, ivParams.getIV());
+ }
+ c.init(cipherMode, secret, rcParams);
+ } else if (cipherUpper.startsWith("RC5")) {
+ RC5ParameterSpec rcParams;
+ if (mode.startsWith("ECB") || ivParams == null) {
+ // ECB doesn't take an IV.
+ rcParams = new RC5ParameterSpec(16, 12, 32);
+ } else {
+ rcParams = new RC5ParameterSpec(16, 12, 32, ivParams.getIV());
+ }
+ c.init(cipherMode, secret, rcParams);
+ } else if (mode.startsWith("ECB") || cipherUpper.startsWith("RC4")) {
+ // RC4 doesn't require any params.
+ // Any cipher using ECB does not require an IV.
+ c.init(cipherMode, secret);
+ } else {
+ // DES, DESede, AES, BlowFish require IVParams (when in CBC, CFB,
+ // or OFB mode). (In ECB mode they don't require IVParams).
+ c.init(cipherMode, secret, ivParams);
+ }
+ return c;
+ }
+
+ public static DecryptResult decrypt(String cipher, String mode,
+ final DerivedKey dk,
+ final boolean des2,
+ final byte[] iv,
+ final byte[] encryptedBytes)
+
+ throws NoSuchAlgorithmException, NoSuchPaddingException,
+ InvalidKeyException, InvalidAlgorithmParameterException,
+ IllegalBlockSizeException, BadPaddingException {
+ Cipher c = generateCipher(cipher, mode, dk, des2, iv, true);
+ final String transformation = c.getAlgorithm();
+ final int keySize = dk.key.length * 8;
+ byte[] decryptedBytes = c.doFinal(encryptedBytes);
+ return new DecryptResult(transformation, keySize, decryptedBytes);
+ }
+
+ private static DecryptResult decryptPKCS8(ASN1Structure pkcs8,
+ char[] password)
+ throws GeneralSecurityException {
+ boolean isVersion1 = true;
+ boolean isVersion2 = false;
+ boolean usePKCS12PasswordPadding = false;
+ boolean use2DES = false;
+ String cipher = null;
+ String hash = null;
+ int keySize = -1;
+ // Almost all PKCS8 encrypted keys use CBC. Looks like the AES OID's can
+ // support different modes, and RC4 doesn't use any mode at all!
+ String mode = "CBC";
+
+ // In PKCS8 Version 2 the IV is stored in the ASN.1 structure for
+ // us, so we don't need to derive it. Just leave "ivSize" set to 0 for
+ // those ones.
+ int ivSize = 0;
+
+ String oid = pkcs8.oid1;
+ if (oid.startsWith("1.2.840.113549.1.12.")) // PKCS12 key derivation!
+ {
+ usePKCS12PasswordPadding = true;
+
+ // Let's trim this OID to make life a little easier.
+ oid = oid.substring("1.2.840.113549.1.12.".length());
+
+ if (oid.equals("1.1") || oid.startsWith("1.1.")) {
+ // 1.2.840.113549.1.12.1.1
+ hash = "SHA1";
+ cipher = "RC4";
+ keySize = 128;
+ } else if (oid.equals("1.2") || oid.startsWith("1.2.")) {
+ // 1.2.840.113549.1.12.1.2
+ hash = "SHA1";
+ cipher = "RC4";
+ keySize = 40;
+ } else if (oid.equals("1.3") || oid.startsWith("1.3.")) {
+ // 1.2.840.113549.1.12.1.3
+ hash = "SHA1";
+ cipher = "DESede";
+ keySize = 192;
+ } else if (oid.equals("1.4") || oid.startsWith("1.4.")) {
+ // DES2 !!!
+
+ // 1.2.840.113549.1.12.1.4
+ hash = "SHA1";
+ cipher = "DESede";
+ keySize = 192;
+ use2DES = true;
+ // later on we'll copy the first 8 bytes of the 24 byte DESede key
+ // over top the last 8 bytes, making the key look like K1-K2-K1
+ // instead of the usual K1-K2-K3.
+ } else if (oid.equals("1.5") || oid.startsWith("1.5.")) {
+ // 1.2.840.113549.1.12.1.5
+ hash = "SHA1";
+ cipher = "RC2";
+ keySize = 128;
+ } else if (oid.equals("1.6") || oid.startsWith("1.6.")) {
+ // 1.2.840.113549.1.12.1.6
+ hash = "SHA1";
+ cipher = "RC2";
+ keySize = 40;
+ }
+ } else if (oid.startsWith("1.2.840.113549.1.5.")) {
+ // Let's trim this OID to make life a little easier.
+ oid = oid.substring("1.2.840.113549.1.5.".length());
+
+ if (oid.equals("1") || oid.startsWith("1.")) {
+ // 1.2.840.113549.1.5.1 -- pbeWithMD2AndDES-CBC
+ hash = "MD2";
+ cipher = "DES";
+ keySize = 64;
+ } else if (oid.equals("3") || oid.startsWith("3.")) {
+ // 1.2.840.113549.1.5.3 -- pbeWithMD5AndDES-CBC
+ hash = "MD5";
+ cipher = "DES";
+ keySize = 64;
+ } else if (oid.equals("4") || oid.startsWith("4.")) {
+ // 1.2.840.113549.1.5.4 -- pbeWithMD2AndRC2_CBC
+ hash = "MD2";
+ cipher = "RC2";
+ keySize = 64;
+ } else if (oid.equals("6") || oid.startsWith("6.")) {
+ // 1.2.840.113549.1.5.6 -- pbeWithMD5AndRC2_CBC
+ hash = "MD5";
+ cipher = "RC2";
+ keySize = 64;
+ } else if (oid.equals("10") || oid.startsWith("10.")) {
+ // 1.2.840.113549.1.5.10 -- pbeWithSHA1AndDES-CBC
+ hash = "SHA1";
+ cipher = "DES";
+ keySize = 64;
+ } else if (oid.equals("11") || oid.startsWith("11.")) {
+ // 1.2.840.113549.1.5.11 -- pbeWithSHA1AndRC2_CBC
+ hash = "SHA1";
+ cipher = "RC2";
+ keySize = 64;
+ } else if (oid.equals("12") || oid.startsWith("12.")) {
+ // 1.2.840.113549.1.5.12 - id-PBKDF2 - Key Derivation Function
+ isVersion2 = true;
+ } else if (oid.equals("13") || oid.startsWith("13.")) {
+ // 1.2.840.113549.1.5.13 - id-PBES2: PBES2 encryption scheme
+ isVersion2 = true;
+ } else if (oid.equals("14") || oid.startsWith("14.")) {
+ // 1.2.840.113549.1.5.14 - id-PBMAC1 message authentication scheme
+ isVersion2 = true;
+ }
+ }
+ if (isVersion2) {
+ isVersion1 = false;
+ hash = "HmacSHA1";
+ oid = pkcs8.oid2;
+
+ // really ought to be:
+ //
+ // if ( oid.startsWith( "1.2.840.113549.1.5.12" ) )
+ //
+ // but all my tests still pass, and I figure this to be more robust:
+ if (pkcs8.oid3 != null) {
+ oid = pkcs8.oid3;
+ }
+ if (oid.startsWith("1.3.6.1.4.1.3029.1.2")) {
+ // 1.3.6.1.4.1.3029.1.2 - Blowfish
+ cipher = "Blowfish";
+ mode = "CBC";
+ keySize = 128;
+ } else if (oid.startsWith("1.3.14.3.2.")) {
+ oid = oid.substring("1.3.14.3.2.".length());
+ if (oid.equals("6") || oid.startsWith("6.")) {
+ // 1.3.14.3.2.6 - desECB
+ cipher = "DES";
+ mode = "ECB";
+ keySize = 64;
+ } else if (oid.equals("7") || oid.startsWith("7.")) {
+ // 1.3.14.3.2.7 - desCBC
+ cipher = "DES";
+ mode = "CBC";
+ keySize = 64;
+ } else if (oid.equals("8") || oid.startsWith("8.")) {
+ // 1.3.14.3.2.8 - desOFB
+ cipher = "DES";
+ mode = "OFB";
+ keySize = 64;
+ } else if (oid.equals("9") || oid.startsWith("9.")) {
+ // 1.3.14.3.2.9 - desCFB
+ cipher = "DES";
+ mode = "CFB";
+ keySize = 64;
+ } else if (oid.equals("17") || oid.startsWith("17.")) {
+ // 1.3.14.3.2.17 - desEDE
+ cipher = "DESede";
+ mode = "CBC";
+ keySize = 192;
+
+ // If the supplied IV is all zeroes, then this is DES2
+ // (Well, that's what happened when I played with OpenSSL!)
+ if (allZeroes(pkcs8.iv)) {
+ mode = "ECB";
+ use2DES = true;
+ pkcs8.iv = null;
+ }
+ }
+ }
+
+ // AES
+ // 2.16.840.1.101.3.4.1.1 - id-aes128-ECB
+ // 2.16.840.1.101.3.4.1.2 - id-aes128-CBC
+ // 2.16.840.1.101.3.4.1.3 - id-aes128-OFB
+ // 2.16.840.1.101.3.4.1.4 - id-aes128-CFB
+ // 2.16.840.1.101.3.4.1.21 - id-aes192-ECB
+ // 2.16.840.1.101.3.4.1.22 - id-aes192-CBC
+ // 2.16.840.1.101.3.4.1.23 - id-aes192-OFB
+ // 2.16.840.1.101.3.4.1.24 - id-aes192-CFB
+ // 2.16.840.1.101.3.4.1.41 - id-aes256-ECB
+ // 2.16.840.1.101.3.4.1.42 - id-aes256-CBC
+ // 2.16.840.1.101.3.4.1.43 - id-aes256-OFB
+ // 2.16.840.1.101.3.4.1.44 - id-aes256-CFB
+ else if (oid.startsWith("2.16.840.1.101.3.4.1.")) {
+ cipher = "AES";
+ if (pkcs8.iv == null) {
+ ivSize = 128;
+ }
+ oid = oid.substring("2.16.840.1.101.3.4.1.".length());
+ int x = oid.indexOf('.');
+ int finalDigit;
+ if (x >= 0) {
+ finalDigit = Integer.parseInt(oid.substring(0, x));
+ } else {
+ finalDigit = Integer.parseInt(oid);
+ }
+ switch (finalDigit % 10) {
+ case 1:
+ mode = "ECB";
+ break;
+ case 2:
+ mode = "CBC";
+ break;
+ case 3:
+ mode = "OFB";
+ break;
+ case 4:
+ mode = "CFB";
+ break;
+ default:
+ throw new RuntimeException("Unknown AES final digit: " + finalDigit);
+ }
+ switch (finalDigit / 10) {
+ case 0:
+ keySize = 128;
+ break;
+ case 2:
+ keySize = 192;
+ break;
+ case 4:
+ keySize = 256;
+ break;
+ default:
+ throw new RuntimeException("Unknown AES final digit: " + finalDigit);
+ }
+ } else if (oid.startsWith("1.2.840.113549.3.")) {
+ // Let's trim this OID to make life a little easier.
+ oid = oid.substring("1.2.840.113549.3.".length());
+
+ if (oid.equals("2") || oid.startsWith("2.")) {
+ // 1.2.840.113549.3.2 - RC2-CBC
+ // Note: keysize determined in PKCS8 Version 2.0 ASN.1 field.
+ cipher = "RC2";
+ keySize = pkcs8.keySize * 8;
+ } else if (oid.equals("4") || oid.startsWith("4.")) {
+ // 1.2.840.113549.3.4 - RC4
+ // Note: keysize determined in PKCS8 Version 2.0 ASN.1 field.
+ cipher = "RC4";
+ keySize = pkcs8.keySize * 8;
+ } else if (oid.equals("7") || oid.startsWith("7.")) {
+ // 1.2.840.113549.3.7 - DES-EDE3-CBC
+ cipher = "DESede";
+ keySize = 192;
+ } else if (oid.equals("9") || oid.startsWith("9.")) {
+ // 1.2.840.113549.3.9 - RC5 CBC Pad
+ // Note: keysize determined in PKCS8 Version 2.0 ASN.1 field.
+ keySize = pkcs8.keySize * 8;
+ cipher = "RC5";
+
+ // Need to find out more about RC5.
+ // How do I create the RC5ParameterSpec?
+ // (int version, int rounds, int wordSize, byte[] iv)
+ }
+ }
+ }
+
+ // The pkcs8 structure has been thoroughly examined. If we don't have
+ // a cipher or hash at this point, then we don't support the file we
+ // were given.
+ if (cipher == null || hash == null) {
+ throw new ProbablyNotPKCS8Exception("Unsupported PKCS8 format. oid1=[" + pkcs8.oid1 + "], oid2=[" + pkcs8.oid2 + "]");
+ }
+
+ // In PKCS8 Version 1.5 we need to derive an 8 byte IV. In those cases
+ // the ASN.1 structure doesn't have the IV, anyway, so I can use that
+ // to decide whether to derive one or not.
+ //
+ // Note: if AES, then IV has to be 16 bytes.
+ if (pkcs8.iv == null) {
+ ivSize = 64;
+ }
+
+ byte[] salt = pkcs8.salt;
+ int ic = pkcs8.iterationCount;
+
+ // PKCS8 converts the password to a byte[] array using a simple
+ // cast. This byte[] array is ignored if we're using the PKCS12
+ // key derivation, since that employs a different technique.
+ byte[] pwd = new byte[password.length];
+ for (int i = 0; i < pwd.length; i++) {
+ pwd[i] = (byte) password[i];
+ }
+
+ DerivedKey dk;
+ if (usePKCS12PasswordPadding) {
+ MessageDigest md = MessageDigest.getInstance(hash);
+ dk = deriveKeyPKCS12(password, salt, ic, keySize, ivSize, md);
+ } else {
+ if (isVersion1) {
+ MessageDigest md = MessageDigest.getInstance(hash);
+ dk = deriveKeyV1(pwd, salt, ic, keySize, ivSize, md);
+ } else {
+ Mac mac = Mac.getInstance(hash);
+ dk = deriveKeyV2(pwd, salt, ic, keySize, ivSize, mac);
+ }
+ }
+
+
+ return decrypt(cipher, mode, dk, use2DES, pkcs8.iv, pkcs8.bigPayload);
+ }
+
+
+ public static DerivedKey deriveKeyV1(byte[] password, byte[] salt,
+ int iterations, int keySizeInBits,
+ int ivSizeInBits, MessageDigest md) {
+ int keySize = keySizeInBits / 8;
+ int ivSize = ivSizeInBits / 8;
+ md.reset();
+ md.update(password);
+ byte[] result = md.digest(salt);
+ for (int i = 1; i < iterations; i++) {
+ // Hash of the hash for each of the iterations.
+ result = md.digest(result);
+ }
+ byte[] key = new byte[keySize];
+ byte[] iv = new byte[ivSize];
+ System.arraycopy(result, 0, key, 0, key.length);
+ System.arraycopy(result, key.length, iv, 0, iv.length);
+ return new DerivedKey(key, iv);
+ }
+
+ public static DerivedKey deriveKeyPKCS12(char[] password, byte[] salt,
+ int iterations, int keySizeInBits,
+ int ivSizeInBits,
+ MessageDigest md) {
+ byte[] pwd;
+ if (password.length > 0) {
+ pwd = new byte[(password.length + 1) * 2];
+ for (int i = 0; i < password.length; i++) {
+ pwd[i * 2] = (byte) (password[i] >>> 8);
+ pwd[i * 2 + 1] = (byte) password[i];
+ }
+ } else {
+ pwd = new byte[0];
+ }
+ int keySize = keySizeInBits / 8;
+ int ivSize = ivSizeInBits / 8;
+ byte[] key = pkcs12(1, keySize, salt, pwd, iterations, md);
+ byte[] iv = pkcs12(2, ivSize, salt, pwd, iterations, md);
+ return new DerivedKey(key, iv);
+ }
+
+ /**
+ * This PKCS12 key derivation code comes from BouncyCastle.
+ *
+ * @param idByte 1 == key, 2 == iv
+ * @param n keysize or ivsize
+ * @param salt 8 byte salt
+ * @param password password
+ * @param iterationCount iteration-count
+ * @param md The message digest to use
+ * @return byte[] the derived key
+ */
+ private static byte[] pkcs12(int idByte, int n, byte[] salt,
+ byte[] password, int iterationCount,
+ MessageDigest md) {
+ int u = md.getDigestLength();
+ // sha1, md2, md5 all use 512 bits. But future hashes might not.
+ int v = 512 / 8;
+ md.reset();
+ byte[] D = new byte[v];
+ byte[] dKey = new byte[n];
+ for (int i = 0; i != D.length; i++) {
+ D[i] = (byte) idByte;
+ }
+ byte[] S;
+ if ((salt != null) && (salt.length != 0)) {
+ S = new byte[v * ((salt.length + v - 1) / v)];
+ for (int i = 0; i != S.length; i++) {
+ S[i] = salt[i % salt.length];
+ }
+ } else {
+ S = new byte[0];
+ }
+ byte[] P;
+ if ((password != null) && (password.length != 0)) {
+ P = new byte[v * ((password.length + v - 1) / v)];
+ for (int i = 0; i != P.length; i++) {
+ P[i] = password[i % password.length];
+ }
+ } else {
+ P = new byte[0];
+ }
+ byte[] I = new byte[S.length + P.length];
+ System.arraycopy(S, 0, I, 0, S.length);
+ System.arraycopy(P, 0, I, S.length, P.length);
+ byte[] B = new byte[v];
+ int c = (n + u - 1) / u;
+ for (int i = 1; i <= c; i++) {
+ md.update(D);
+ byte[] result = md.digest(I);
+ for (int j = 1; j != iterationCount; j++) {
+ result = md.digest(result);
+ }
+ for (int j = 0; j != B.length; j++) {
+ B[j] = result[j % result.length];
+ }
+ for (int j = 0; j < (I.length / v); j++) {
+ /*
+ * add a + b + 1, returning the result in a. The a value is treated
+ * as a BigInteger of length (b.length * 8) bits. The result is
+ * modulo 2^b.length in case of overflow.
+ */
+ int aOff = j * v;
+ int bLast = B.length - 1;
+ int x = (B[bLast] & 0xff) + (I[aOff + bLast] & 0xff) + 1;
+ I[aOff + bLast] = (byte) x;
+ x >>>= 8;
+ for (int k = B.length - 2; k >= 0; k--) {
+ x += (B[k] & 0xff) + (I[aOff + k] & 0xff);
+ I[aOff + k] = (byte) x;
+ x >>>= 8;
+ }
+ }
+ if (i == c) {
+ System.arraycopy(result, 0, dKey, (i - 1) * u, dKey.length - ((i - 1) * u));
+ } else {
+ System.arraycopy(result, 0, dKey, (i - 1) * u, result.length);
+ }
+ }
+ return dKey;
+ }
+
+ public static DerivedKey deriveKeyV2(byte[] password, byte[] salt,
+ int iterations, int keySizeInBits,
+ int ivSizeInBits, Mac mac)
+ throws InvalidKeyException {
+ int keySize = keySizeInBits / 8;
+ int ivSize = ivSizeInBits / 8;
+
+ // Because we're using an Hmac, we need to initialize with a SecretKey.
+ // HmacSHA1 doesn't need SecretKeySpec's 2nd parameter, hence the "N/A".
+ SecretKeySpec sk = new SecretKeySpec(password, "N/A");
+ mac.init(sk);
+ int macLength = mac.getMacLength();
+ int derivedKeyLength = keySize + ivSize;
+ int blocks = (derivedKeyLength + macLength - 1) / macLength;
+ byte[] blockIndex = new byte[4];
+ byte[] finalResult = new byte[blocks * macLength];
+ for (int i = 1; i <= blocks; i++) {
+ int offset = (i - 1) * macLength;
+ blockIndex[0] = (byte) (i >>> 24);
+ blockIndex[1] = (byte) (i >>> 16);
+ blockIndex[2] = (byte) (i >>> 8);
+ blockIndex[3] = (byte) i;
+ mac.reset();
+ mac.update(salt);
+ byte[] result = mac.doFinal(blockIndex);
+ System.arraycopy(result, 0, finalResult, offset, result.length);
+ for (int j = 1; j < iterations; j++) {
+ mac.reset();
+ result = mac.doFinal(result);
+ for (int k = 0; k < result.length; k++) {
+ finalResult[offset + k] ^= result[k];
+ }
+ }
+ }
+ byte[] key = new byte[keySize];
+ byte[] iv = new byte[ivSize];
+ System.arraycopy(finalResult, 0, key, 0, key.length);
+ System.arraycopy(finalResult, key.length, iv, 0, iv.length);
+ return new DerivedKey(key, iv);
+ }
+
+ public static byte[] formatAsPKCS8(byte[] privateKey, String oid,
+ ASN1Structure pkcs8) {
+ DERInteger derZero = new DERInteger(BigInteger.ZERO);
+ ASN1EncodableVector outterVec = new ASN1EncodableVector();
+ ASN1EncodableVector innerVec = new ASN1EncodableVector();
+ DEROctetString octetsToAppend;
+ try {
+ DERObjectIdentifier derOID = new DERObjectIdentifier(oid);
+ innerVec.add(derOID);
+ if (DSA_OID.equals(oid)) {
+ if (pkcs8 == null) {
+ try {
+ pkcs8 = ASN1Util.analyze(privateKey);
+ }
+ catch (Exception e) {
+ throw new RuntimeException("asn1 parse failure " + e);
+ }
+ }
+ if (pkcs8.derIntegers == null || pkcs8.derIntegers.size() < 6) {
+ throw new RuntimeException("invalid DSA key - can't find P, Q, G, X");
+ }
+
+ DERInteger[] ints = new DERInteger[pkcs8.derIntegers.size()];
+ pkcs8.derIntegers.toArray(ints);
+ DERInteger p = ints[1];
+ DERInteger q = ints[2];
+ DERInteger g = ints[3];
+ DERInteger x = ints[5];
+
+ byte[] encodedX = encode(x);
+ octetsToAppend = new DEROctetString(encodedX);
+ ASN1EncodableVector pqgVec = new ASN1EncodableVector();
+ pqgVec.add(p);
+ pqgVec.add(q);
+ pqgVec.add(g);
+ DERSequence pqg = new DERSequence(pqgVec);
+ innerVec.add(pqg);
+ } else {
+ innerVec.add(DERNull.INSTANCE);
+ octetsToAppend = new DEROctetString(privateKey);
+ }
+
+ DERSequence inner = new DERSequence(innerVec);
+ outterVec.add(derZero);
+ outterVec.add(inner);
+ outterVec.add(octetsToAppend);
+ DERSequence outter = new DERSequence(outterVec);
+ return encode(outter);
+ }
+ catch (IOException ioe) {
+ throw JavaImpl.newRuntimeException(ioe);
+ }
+ }
+
+ private static boolean allZeroes(byte[] b) {
+ for (int i = 0; i < b.length; i++) {
+ if (b[i] != 0) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static byte[] encode(DEREncodable der) throws IOException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
+ ASN1OutputStream out = new ASN1OutputStream(baos);
+ out.writeObject(der);
+ out.close();
+ return baos.toByteArray();
+ }
+
+ public static void main(String[] args) throws Exception {
+ String password = "changeit";
+ if (args.length == 0) {
+ System.out.println("Usage1: [password] [file:private-key] Prints decrypted PKCS8 key (base64).");
+ System.out.println("Usage2: [password] [file1] [file2] etc... Checks that all private keys are equal.");
+ System.out.println("Usage2 assumes that all files can be decrypted with the same password.");
+ } else if (args.length == 1 || args.length == 2) {
+ FileInputStream in = new FileInputStream(args[args.length - 1]);
+ if (args.length == 2) {
+ password = args[0];
+ }
+ byte[] bytes = Util.streamToBytes(in);
+ PKCS8Key key = new PKCS8Key(bytes, password.toCharArray());
+ PEMItem item = new PEMItem(key.getDecryptedBytes(), "PRIVATE KEY");
+ byte[] pem = PEMUtil.encode(Collections.singleton(item));
+ System.out.write(pem);
+ } else {
+ byte[] original = null;
+ File f = new File(args[0]);
+ int i = 0;
+ if (!f.exists()) {
+ // File0 doesn't exist, so it must be a password!
+ password = args[0];
+ i++;
+ }
+ for (; i < args.length; i++) {
+ FileInputStream in = new FileInputStream(args[i]);
+ byte[] bytes = Util.streamToBytes(in);
+ PKCS8Key key = null;
+ try {
+ key = new PKCS8Key(bytes, password.toCharArray());
+ }
+ catch (Exception e) {
+ System.out.println(" FAILED! " + args[i] + " " + e);
+ }
+ if (key != null) {
+ byte[] decrypted = key.getDecryptedBytes();
+ int keySize = key.getKeySize();
+ String keySizeStr = "" + keySize;
+ if (keySize < 10) {
+ keySizeStr = " " + keySizeStr;
+ } else if (keySize < 100) {
+ keySizeStr = " " + keySizeStr;
+ }
+ StringBuffer buf = new StringBuffer(key.getTransformation());
+ int maxLen = "Blowfish/CBC/PKCS5Padding".length();
+ for (int j = buf.length(); j < maxLen; j++) {
+ buf.append(' ');
+ }
+ String transform = buf.toString();
+ String type = key.isDSA() ? "DSA" : "RSA";
+
+ if (original == null) {
+ original = decrypted;
+ System.out.println(" SUCCESS \t" + type + "\t" + transform + "\t" + keySizeStr + "\t" + args[i]);
+ } else {
+ boolean identical = Arrays.equals(original, decrypted);
+ if (!identical) {
+ System.out.println("***FAILURE*** \t" + type + "\t" + transform + "\t" + keySizeStr + "\t" + args[i]);
+ } else {
+ System.out.println(" SUCCESS \t" + type + "\t" + transform + "\t" + keySizeStr + "\t" + args[i]);
+ }
+ }
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/Ping.java b/src/java/org/apache/commons/ssl/Ping.java
new file mode 100644
index 0000000..87bdf60
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Ping.java
@@ -0,0 +1,464 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Ping.java $
+ * $Revision: 129 $
+ * $Date: 2007-11-14 19:21:33 -0800 (Wed, 14 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.SSLSocket;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 30-Mar-2006
+ */
+public class Ping {
+ protected static SortedSet ARGS = new TreeSet();
+ protected static Map ARGS_MATCH = new HashMap();
+ protected final static Arg ARG_TARGET = new Arg("-t", "--target", "[hostname[:port]] default port=443", true);
+ protected final static Arg ARG_BIND = new Arg("-b", "--bind", "[hostname[:port]] default port=0 \"ANY\"");
+ protected final static Arg ARG_PROXY = new Arg("-r", "--proxy", "[hostname[:port]] default port=80");
+ protected final static Arg ARG_TRUST_CERT = new Arg("-tm", "--trust-cert", "[path to trust material] {pem, der, crt, jks}");
+ protected final static Arg ARG_CLIENT_CERT = new Arg("-km", "--client-cert", "[path to client's private key] {jks, pkcs12, pkcs8}");
+ protected final static Arg ARG_CERT_CHAIN = new Arg("-cc", "--cert-chain", "[path to client's cert chain for pkcs8/OpenSSL key]");
+ protected final static Arg ARG_PASSWORD = new Arg("-p", "--password", "[client cert password]");
+ protected final static Arg ARG_HOST_HEADER = new Arg("-h", "--host-header", "[http-host-header] in case -t is an IP address");
+ protected final static Arg ARG_PATH = new Arg("-u", "--path", "[path for GET/HEAD request] default=/");
+ protected final static Arg ARG_METHOD = new Arg("-m", "--method", "[http method to use] default=HEAD");
+
+ private static HostPort target;
+ private static HostPort local;
+ private static HostPort proxy;
+ private static String hostHeader;
+ private static String httpMethod = "HEAD";
+ private static String path = "/";
+ private static InetAddress targetAddress;
+ private static InetAddress localAddress;
+ private static int targetPort = 443;
+ private static int localPort = 0;
+ private static File clientCert;
+ private static File certChain;
+ private static char[] password;
+ private static TrustChain trustChain = new TrustChain();
+
+ static {
+ ARGS = Collections.unmodifiableSortedSet(ARGS);
+ ARGS_MATCH = Collections.unmodifiableMap(ARGS_MATCH);
+ }
+
+ public static void main(String[] args) throws Exception {
+ boolean showUsage = args.length == 0;
+ Exception parseException = null;
+ if (!showUsage) {
+ try {
+ parseArgs(args);
+ }
+ catch (Exception e) {
+ parseException = e;
+ showUsage = true;
+ }
+ }
+ if (showUsage) {
+ if (parseException != null) {
+ System.out.println();
+ System.out.println("* Error: " + parseException.getMessage() + ".");
+ parseException.printStackTrace(System.out);
+ System.out.println();
+ }
+ System.out.println("Usage: java -jar not-yet-commons-ssl-0.3.9.jar [options]");
+ System.out.println(Version.versionString());
+ System.out.println("Options: (*=required)");
+ Iterator it = ARGS.iterator();
+ while (it.hasNext()) {
+ Arg a = (Arg) it.next();
+ String s = Util.pad(a.shortArg, 3, false);
+ String l = Util.pad(a.longArg, 18, false);
+ String required = a.isRequired ? "*" : " ";
+ String d = a.description;
+ System.out.println(required + " " + s + " " + l + " " + d);
+ }
+ System.out.println();
+ String example = "java -jar commons-ssl.jar -t host.com:443 -c ./client.pfx -p `cat ./pass.txt` ";
+ System.out.println("Example:");
+ System.out.println();
+ System.out.println(example);
+ System.out.println();
+ System.exit(1);
+ return;
+ }
+
+ SSLClient ssl = new SSLClient();
+ Socket s = null;
+ InputStream in = null;
+ OutputStream out = null;
+ Exception socketException = null;
+ Exception trustException = null;
+ Exception hostnameException = null;
+ Exception crlException = null;
+ Exception expiryException = null;
+ String sslCipher = null;
+ try {
+ try {
+ ssl.setCheckHostname(false);
+ ssl.setCheckExpiry(false);
+ ssl.setCheckCRL(false);
+ ssl.addTrustMaterial(TrustMaterial.TRUST_ALL);
+ if (clientCert != null) {
+
+ KeyMaterial km;
+ if (certChain != null) {
+ km = new KeyMaterial(clientCert, certChain, password);
+ } else {
+ km = new KeyMaterial(clientCert, password);
+ }
+ if (password != null) {
+ for (int i = 0; i < password.length; i++) {
+ password[i] = 0;
+ }
+ }
+ ssl.setKeyMaterial(km);
+ }
+
+ if (!trustChain.isEmpty()) {
+ ssl.addTrustMaterial(trustChain);
+ }
+
+ ssl.setSoTimeout(10000);
+ ssl.setConnectTimeout(5000);
+
+ if (proxy != null) {
+ s = new Socket(proxy.host, proxy.port,
+ local.addr, local.port);
+ s.setSoTimeout(10000);
+ in = s.getInputStream();
+ out = s.getOutputStream();
+ String targetHost = target.host;
+ String line1 = "CONNECT " + targetHost + ":" + targetPort + " HTTP/1.1\r\n";
+ String line2 = "Proxy-Connection: keep-alive\r\n";
+ String line3 = "Host: " + targetHost + "\r\n\r\n";
+ out.write(line1.getBytes());
+ out.write(line2.getBytes());
+ out.write(line3.getBytes());
+ out.flush();
+
+ String read1 = Util.readLine(in);
+ if (read1.startsWith("HTTP/1.1 200")) {
+ int avail = in.available();
+ in.skip(avail);
+ Thread.yield();
+ avail = in.available();
+ while (avail != 0) {
+ in.skip(avail);
+ Thread.yield();
+ avail = in.available();
+ }
+ s = ssl.createSocket(s, targetHost, targetPort, true);
+ } else {
+ System.out.print(line1);
+ System.out.print(line2);
+ System.out.print(line3);
+ System.out.println("Server returned unexpected proxy response!");
+ System.out.println("=============================================");
+ System.out.println(read1);
+ String line = Util.readLine(in);
+ while (line != null) {
+ System.out.println(line);
+ line = Util.readLine(in);
+ }
+ System.exit(1);
+ }
+ } else {
+ s = ssl.createSocket(targetAddress, targetPort,
+ localAddress, localPort);
+ }
+
+ sslCipher = ((SSLSocket) s).getSession().getCipherSuite();
+ System.out.println("Cipher: " + sslCipher);
+ System.out.println("================================================================================");
+
+ String line1 = httpMethod + " " + path + " HTTP/1.1";
+ if (hostHeader == null) {
+ hostHeader = targetAddress.getHostName();
+ }
+ String line2 = "Host: " + hostHeader;
+ byte[] crlf = {'\r', '\n'};
+
+ System.out.println("Writing: ");
+ System.out.println("================================================================================");
+ System.out.println(line1);
+ System.out.println(line2);
+ System.out.println();
+
+ out = s.getOutputStream();
+ out.write(line1.getBytes());
+ out.write(crlf);
+ out.write(line2.getBytes());
+ out.write(crlf);
+ out.write(crlf);
+ out.flush();
+
+ in = s.getInputStream();
+
+ int c = in.read();
+ StringBuffer buf = new StringBuffer();
+ System.out.println("Reading: ");
+ System.out.println("================================================================================");
+ while (c >= 0) {
+ byte b = (byte) c;
+ buf.append((char) b);
+ System.out.print((char) b);
+ if (-1 == buf.toString().indexOf("\r\n\r\n")) {
+ c = in.read();
+ } else {
+ break;
+ }
+ }
+ }
+ catch (Exception e) {
+ socketException = e;
+ }
+ trustException = testTrust(ssl, sslCipher);
+ hostnameException = testHostname(ssl);
+ crlException = testCRL(ssl);
+ expiryException = testExpiry(ssl);
+ }
+ finally {
+ if (out != null) {
+ out.close();
+ }
+ if (in != null) {
+ in.close();
+ }
+ if (s != null) {
+ s.close();
+ }
+
+ X509Certificate[] peerChain = ssl.getCurrentServerChain();
+ if (peerChain != null) {
+ String title = "Server Certificate Chain for: ";
+ title = peerChain.length > 1 ? title : "Server Certificate for: ";
+ System.out.println(title + "[" + target + "]");
+ System.out.println("================================================================================");
+ for (int i = 0; i < peerChain.length; i++) {
+ X509Certificate cert = peerChain[i];
+ String certAsString = Certificates.toString(cert);
+ String certAsPEM = Certificates.toPEMString(cert);
+ if (i > 0) {
+ System.out.println();
+ }
+ System.out.print(certAsString);
+ System.out.print(certAsPEM);
+ }
+ }
+ if (hostnameException != null) {
+ hostnameException.printStackTrace();
+ System.out.println();
+ }
+ if (crlException != null) {
+ crlException.printStackTrace();
+ System.out.println();
+ }
+ if (expiryException != null) {
+ expiryException.printStackTrace();
+ System.out.println();
+ }
+ if (trustException != null) {
+ trustException.printStackTrace();
+ System.out.println();
+ }
+ if (socketException != null) {
+ socketException.printStackTrace();
+ System.out.println();
+ }
+ }
+ }
+
+ private static Exception testTrust(SSLClient ssl, String cipher) {
+ try {
+ X509Certificate[] chain = ssl.getCurrentServerChain();
+ String authType = Util.cipherToAuthType(cipher);
+ if (authType == null) {
+ // default of "RSA" just for Ping's purposes.
+ authType = "RSA";
+ }
+ if (chain != null) {
+ Object[] trustManagers = TrustMaterial.DEFAULT.getTrustManagers();
+ for (int i = 0; i < trustManagers.length; i++) {
+ JavaImpl.testTrust(trustManagers[i], chain, authType);
+ }
+ }
+ }
+ catch (Exception e) {
+ return e;
+ }
+ return null;
+ }
+
+ private static Exception testHostname(SSLClient ssl) {
+ try {
+ X509Certificate[] chain = ssl.getCurrentServerChain();
+ if (chain != null) {
+ String hostName = target.host;
+ HostnameVerifier.DEFAULT.check(hostName, chain[0]);
+ }
+ }
+ catch (Exception e) {
+ return e;
+ }
+ return null;
+ }
+
+ private static Exception testCRL(SSLClient ssl) {
+ try {
+ X509Certificate[] chain = ssl.getCurrentServerChain();
+ if (chain != null) {
+ for (int i = 0; i < chain.length; i++) {
+ Certificates.checkCRL(chain[i]);
+ }
+ }
+ }
+ catch (Exception e) {
+ return e;
+ }
+ return null;
+ }
+
+ private static Exception testExpiry(SSLClient ssl) {
+ try {
+ X509Certificate[] chain = ssl.getCurrentServerChain();
+ if (chain != null) {
+ for (int i = 0; i < chain.length; i++) {
+ chain[i].checkValidity();
+ }
+ }
+ }
+ catch (Exception e) {
+ return e;
+ }
+ return null;
+ }
+
+
+ public static class Arg implements Comparable {
+ public final String shortArg;
+ public final String longArg;
+ public final String description;
+ public final boolean isRequired;
+ private final int id;
+
+ public Arg(String s, String l, String d) {
+ this(s, l, d, false);
+ }
+
+ public Arg(String s, String l, String d, boolean isRequired) {
+ this.isRequired = isRequired;
+ this.shortArg = s;
+ this.longArg = l;
+ this.description = d;
+ this.id = ARGS.size();
+ ARGS.add(this);
+ if (s != null && s.length() >= 2) {
+ ARGS_MATCH.put(s, this);
+ }
+ if (l != null && l.length() >= 3) {
+ ARGS_MATCH.put(l, this);
+ }
+ }
+
+ public int compareTo(Object o) {
+ return id - ((Arg) o).id;
+ }
+
+ public String toString() {
+ return shortArg + "/" + longArg;
+ }
+ }
+
+ private static void parseArgs(String[] cargs) throws Exception {
+ Map args = Util.parseArgs(cargs);
+ Iterator it = args.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ Arg arg = (Arg) entry.getKey();
+ String[] values = (String[]) entry.getValue();
+ if (arg == ARG_TARGET) {
+ target = Util.toAddress(values[0], 443);
+ targetAddress = target.addr;
+ targetPort = target.port;
+ } else if (arg == ARG_BIND) {
+ local = Util.toAddress(values[0], 443);
+ localAddress = local.addr;
+ localPort = local.port;
+ } else if (arg == ARG_PROXY) {
+ proxy = Util.toAddress(values[0], 80);
+ } else if (arg == ARG_CLIENT_CERT) {
+ clientCert = new File(values[0]);
+ } else if (arg == ARG_CERT_CHAIN) {
+ certChain = new File(values[0]);
+ } else if (arg == ARG_PASSWORD) {
+ password = values[0].toCharArray();
+ } else if (arg == ARG_METHOD) {
+ httpMethod = values[0].trim();
+ } else if (arg == ARG_PATH) {
+ path = values[0].trim();
+ } else if (arg == ARG_HOST_HEADER) {
+ hostHeader = values[0].trim();
+ } else if (arg == ARG_TRUST_CERT) {
+ for (int i = 0; i < values.length; i++) {
+ File f = new File(values[i]);
+ if (f.exists()) {
+ TrustMaterial tm = new TrustMaterial(f);
+ trustChain.addTrustMaterial(tm);
+ }
+ }
+ }
+ }
+ args.clear();
+ for (int i = 0; i < cargs.length; i++) {
+ cargs[i] = null;
+ }
+
+ if (targetAddress == null) {
+ throw new IllegalArgumentException("\"" + ARG_TARGET + "\" is mandatory");
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/ProbablyBadPasswordException.java b/src/java/org/apache/commons/ssl/ProbablyBadPasswordException.java
new file mode 100644
index 0000000..83e96b6
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/ProbablyBadPasswordException.java
@@ -0,0 +1,51 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/ProbablyBadPasswordException.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 16-Nov-2005
+ */
+public class ProbablyBadPasswordException extends GeneralSecurityException {
+ public ProbablyBadPasswordException() { super(); }
+
+ public ProbablyBadPasswordException(String s) { super(s); }
+
+ // Need to wait for Java 5.0 !
+ // public ProbablyBadPasswordException( Throwable t ) { super( t ); }
+ // public ProbablyBadPasswordException( String s, Throwable t ) { super( s, t ); }
+
+}
diff --git a/src/java/org/apache/commons/ssl/ProbablyNotPKCS8Exception.java b/src/java/org/apache/commons/ssl/ProbablyNotPKCS8Exception.java
new file mode 100644
index 0000000..d0e54b5
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/ProbablyNotPKCS8Exception.java
@@ -0,0 +1,50 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/ProbablyNotPKCS8Exception.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.security.GeneralSecurityException;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 16-Nov-2005
+ */
+public class ProbablyNotPKCS8Exception extends GeneralSecurityException {
+ public ProbablyNotPKCS8Exception() { super(); }
+
+ public ProbablyNotPKCS8Exception(String s) { super(s); }
+
+ // Need to wait for Java 5.0 !
+ // public ProbablyNotPKCS8Exception( Throwable t ) { super( t ); }
+ // public ProbablyNotPKCS8Exception( String s, Throwable t ) { super( s, t ); }
+}
diff --git a/src/java/org/apache/commons/ssl/RMISocketFactoryImpl.java b/src/java/org/apache/commons/ssl/RMISocketFactoryImpl.java
new file mode 100644
index 0000000..3bbe2c5
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/RMISocketFactoryImpl.java
@@ -0,0 +1,578 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/RMISocketFactoryImpl.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ServerSocketFactory;
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLProtocolException;
+import javax.net.ssl.SSLSocket;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+import java.rmi.server.RMISocketFactory;
+import java.security.GeneralSecurityException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+
+/**
+ * An RMISocketFactory ideal for using RMI over SSL. The server secures both
+ * the registry and the remote objects. The client assumes that either both
+ * the registry and the remote objects will use SSL, or both will use
+ * plain-socket. The client is able to auto detect plain-socket registries
+ * and downgrades itself to accomodate those.
+ * <p/>
+ * Unlike most existing RMI over SSL solutions in use (including Java 5's
+ * javax.rmi.ssl.SslRMIClientSocketFactory), this one does proper SSL hostname
+ * verification. From the client perspective this is straighforward. From
+ * the server perspective we introduce a clever trick: we perform an initial
+ * "hostname verification" by trying the current value of
+ * "java.rmi.server.hostname" against our server certificate. If the
+ * "java.rmi.server.hostname" System Property isn't set, we set it ourselves
+ * using the CN value we extract from our server certificate! (Some
+ * complications arise should a wildcard certificate show up, but we try our
+ * best to deal with those).
+ * <p/>
+ * An SSL server cannot be started without a private key. We have defined some
+ * default behaviour for trying to find a private key to use that we believe
+ * is convenient and sensible:
+ * <p/>
+ * If running from inside Tomcat, we try to re-use Tomcat's private key and
+ * certificate chain (assuming Tomcat-SSL on port 8443 is enabled). If this
+ * isn't available, we look for the "javax.net.ssl.keyStore" System property.
+ * Finally, if that isn't available, we look for "~/.keystore" and assume
+ * a password of "changeit".
+ * <p/>
+ * If after all these attempts we still failed to find a private key, the
+ * RMISocketFactoryImpl() constructor will throw an SSLException.
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 22-Apr-2005
+ */
+public class RMISocketFactoryImpl extends RMISocketFactory {
+ public final static String RMI_HOSTNAME_KEY = "java.rmi.server.hostname";
+ private final static LogWrapper log = LogWrapper.getLogger(RMISocketFactoryImpl.class);
+
+ private volatile SocketFactory defaultClient;
+ private volatile ServerSocketFactory sslServer;
+ private volatile String localBindAddress = null;
+ private volatile int anonymousPort = 31099;
+ private Map clientMap = new TreeMap();
+ private Map serverSockets = new HashMap();
+ private final SocketFactory plainClient = SocketFactory.getDefault();
+
+ public RMISocketFactoryImpl() throws GeneralSecurityException, IOException {
+ this(true);
+ }
+
+ /**
+ * @param createDefaultServer If false, then we only set the default
+ * client, and the default server is set to null.
+ * If true, then a default server is also created.
+ * @throws GeneralSecurityException bad things
+ * @throws IOException bad things
+ */
+ public RMISocketFactoryImpl(boolean createDefaultServer)
+ throws GeneralSecurityException, IOException {
+ SSLServer defaultServer = createDefaultServer ? new SSLServer() : null;
+ SSLClient defaultClient = new SSLClient();
+
+ // RMI calls to localhost will not check that host matches CN in
+ // certificate. Hopefully this is acceptable. (The registry server
+ // will followup the registry lookup with the proper DNS name to get
+ // the remote object, anyway).
+ HostnameVerifier verifier = HostnameVerifier.DEFAULT_AND_LOCALHOST;
+ defaultClient.setHostnameVerifier(verifier);
+ if (defaultServer != null) {
+ defaultServer.setHostnameVerifier(verifier);
+ // The RMI server will try to re-use Tomcat's "port 8443" SSL
+ // Certificate if possible.
+ defaultServer.useTomcatSSLMaterial();
+ X509Certificate[] x509 = defaultServer.getAssociatedCertificateChain();
+ if (x509 == null || x509.length < 1) {
+ throw new SSLException("Cannot initialize RMI-SSL Server: no KeyMaterial!");
+ }
+ setServer(defaultServer);
+ }
+ setDefaultClient(defaultClient);
+ }
+
+ public void setServer(ServerSocketFactory f)
+ throws GeneralSecurityException, IOException {
+ this.sslServer = f;
+ if (f instanceof SSLServer) {
+ final HostnameVerifier VERIFIER;
+ VERIFIER = HostnameVerifier.DEFAULT_AND_LOCALHOST;
+
+ final SSLServer ssl = (SSLServer) f;
+ final X509Certificate[] chain = ssl.getAssociatedCertificateChain();
+ String[] cns = Certificates.getCNs(chain[0]);
+ String[] subjectAlts = Certificates.getDNSSubjectAlts(chain[0]);
+ LinkedList names = new LinkedList();
+ if (cns != null && cns.length > 0) {
+ // Only first CN is used. Not going to get into the IE6 nonsense
+ // where all CN values are used.
+ names.add(cns[0]);
+ }
+ if (subjectAlts != null && subjectAlts.length > 0) {
+ names.addAll(Arrays.asList(subjectAlts));
+ }
+
+ String rmiHostName = System.getProperty(RMI_HOSTNAME_KEY);
+ // If "java.rmi.server.hostname" is already set, don't mess with it.
+ // But blowup if it's not going to work with our SSL Server
+ // Certificate!
+ if (rmiHostName != null) {
+ try {
+ VERIFIER.check(rmiHostName, cns, subjectAlts);
+ }
+ catch (SSLException ssle) {
+ String s = ssle.toString();
+ throw new SSLException(RMI_HOSTNAME_KEY + " of " + rmiHostName + " conflicts with SSL Server Certificate: " + s);
+ }
+ } else {
+ // If SSL Cert only contains one non-wild name, just use that and
+ // hope for the best.
+ boolean hopingForBest = false;
+ if (names.size() == 1) {
+ String name = (String) names.get(0);
+ if (!name.startsWith("*")) {
+ System.setProperty(RMI_HOSTNAME_KEY, name);
+ log.warn("commons-ssl '" + RMI_HOSTNAME_KEY + "' set to '" + name + "' as found in my SSL Server Certificate.");
+ hopingForBest = true;
+ }
+ }
+ if (!hopingForBest) {
+ // Help me, Obi-Wan Kenobi; you're my only hope. All we can
+ // do now is grab our internet-facing addresses, reverse-lookup
+ // on them, and hope that one of them validates against our
+ // server cert.
+ Set s = getMyInternetFacingIPs();
+ Iterator it = s.iterator();
+ while (it.hasNext()) {
+ String name = (String) it.next();
+ try {
+ VERIFIER.check(name, cns, subjectAlts);
+ System.setProperty(RMI_HOSTNAME_KEY, name);
+ log.warn("commons-ssl '" + RMI_HOSTNAME_KEY + "' set to '" + name + "' as found by reverse-dns against my own IP.");
+ hopingForBest = true;
+ break;
+ }
+ catch (SSLException ssle) {
+ // next!
+ }
+ }
+ }
+ if (!hopingForBest) {
+ throw new SSLException("'" + RMI_HOSTNAME_KEY + "' not present. Must work with my SSL Server Certificate's CN field: " + names);
+ }
+ }
+ }
+ trustOurself();
+ }
+
+ public void setLocalBindAddress(String localBindAddress) {
+ this.localBindAddress = localBindAddress;
+ }
+
+ public void setAnonymousPort(int port) {
+ this.anonymousPort = port;
+ }
+
+ public void setDefaultClient(SocketFactory f)
+ throws GeneralSecurityException, IOException {
+ this.defaultClient = f;
+ trustOurself();
+ }
+
+ public void setClient(String host, SocketFactory f)
+ throws GeneralSecurityException, IOException {
+ if (f != null && sslServer != null) {
+ boolean clientIsCommonsSSL = f instanceof SSLClient;
+ boolean serverIsCommonsSSL = sslServer instanceof SSLServer;
+ if (clientIsCommonsSSL && serverIsCommonsSSL) {
+ SSLClient c = (SSLClient) f;
+ SSLServer s = (SSLServer) sslServer;
+ trustEachOther(c, s);
+ }
+ }
+ Set names = hostnamePossibilities(host);
+ Iterator it = names.iterator();
+ synchronized (this) {
+ while (it.hasNext()) {
+ clientMap.put(it.next(), f);
+ }
+ }
+ }
+
+ public void removeClient(String host) {
+ Set names = hostnamePossibilities(host);
+ Iterator it = names.iterator();
+ synchronized (this) {
+ while (it.hasNext()) {
+ clientMap.remove(it.next());
+ }
+ }
+ }
+
+ public synchronized void removeClient(SocketFactory sf) {
+ Iterator it = clientMap.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ Object o = entry.getValue();
+ if (sf.equals(o)) {
+ it.remove();
+ }
+ }
+ }
+
+ private Set hostnamePossibilities(String host) {
+ host = host != null ? host.toLowerCase().trim() : "";
+ if ("".equals(host)) {
+ return Collections.EMPTY_SET;
+ }
+ TreeSet names = new TreeSet();
+ names.add(host);
+ InetAddress[] addresses;
+ try {
+ // If they gave us "hostname.com", this will give us the various
+ // IP addresses:
+ addresses = InetAddress.getAllByName(host);
+ for (int i = 0; i < addresses.length; i++) {
+ String name1 = addresses[i].getHostName();
+ String name2 = addresses[i].getHostAddress();
+ names.add(name1.trim().toLowerCase());
+ names.add(name2.trim().toLowerCase());
+ }
+ }
+ catch (UnknownHostException uhe) {
+ /* oh well, nothing found, nothing to add for this client */
+ }
+
+ try {
+ host = InetAddress.getByName(host).getHostAddress();
+
+ // If they gave us "1.2.3.4", this will hopefully give us
+ // "hostname.com" so that we can then try and find any other
+ // IP addresses associated with that name.
+ host = InetAddress.getByName(host).getHostName();
+ names.add(host.trim().toLowerCase());
+ addresses = InetAddress.getAllByName(host);
+ for (int i = 0; i < addresses.length; i++) {
+ String name1 = addresses[i].getHostName();
+ String name2 = addresses[i].getHostAddress();
+ names.add(name1.trim().toLowerCase());
+ names.add(name2.trim().toLowerCase());
+ }
+ }
+ catch (UnknownHostException uhe) {
+ /* oh well, nothing found, nothing to add for this client */
+ }
+ return names;
+ }
+
+ private void trustOurself()
+ throws GeneralSecurityException, IOException {
+ if (defaultClient == null || sslServer == null) {
+ return;
+ }
+ boolean clientIsCommonsSSL = defaultClient instanceof SSLClient;
+ boolean serverIsCommonsSSL = sslServer instanceof SSLServer;
+ if (clientIsCommonsSSL && serverIsCommonsSSL) {
+ SSLClient c = (SSLClient) defaultClient;
+ SSLServer s = (SSLServer) sslServer;
+ trustEachOther(c, s);
+ }
+ }
+
+ private void trustEachOther(SSLClient client, SSLServer server)
+ throws GeneralSecurityException, IOException {
+ if (client != null && server != null) {
+ // Our own client should trust our own server.
+ X509Certificate[] certs = server.getAssociatedCertificateChain();
+ if (certs != null && certs[0] != null) {
+ TrustMaterial tm = new TrustMaterial(certs[0]);
+ client.addTrustMaterial(tm);
+ }
+
+ // Our own server should trust our own client.
+ certs = client.getAssociatedCertificateChain();
+ if (certs != null && certs[0] != null) {
+ TrustMaterial tm = new TrustMaterial(certs[0]);
+ server.addTrustMaterial(tm);
+ }
+ }
+ }
+
+ public ServerSocketFactory getServer() { return sslServer; }
+
+ public SocketFactory getDefaultClient() { return defaultClient; }
+
+ public synchronized SocketFactory getClient(String host) {
+ host = host != null ? host.trim().toLowerCase() : "";
+ return (SocketFactory) clientMap.get(host);
+ }
+
+ public synchronized ServerSocket createServerSocket(int port)
+ throws IOException {
+ // Re-use existing ServerSocket if possible.
+ if (port == 0) {
+ port = anonymousPort;
+ }
+ Integer key = new Integer(port);
+ ServerSocket ss = (ServerSocket) serverSockets.get(key);
+ if (ss == null || ss.isClosed()) {
+ if (ss != null && ss.isClosed()) {
+ System.out.println("found closed server on port: " + port);
+ }
+ log.debug("commons-ssl RMI server-socket: listening on port " + port);
+ ss = sslServer.createServerSocket(port);
+ serverSockets.put(key, ss);
+ }
+ return ss;
+ }
+
+ public Socket createSocket(String host, int port)
+ throws IOException {
+ host = host != null ? host.trim().toLowerCase() : "";
+ InetAddress local = null;
+ String bindAddress = localBindAddress;
+ if (bindAddress == null) {
+ bindAddress = System.getProperty(RMI_HOSTNAME_KEY);
+ if (bindAddress != null) {
+ local = InetAddress.getByName(bindAddress);
+ if (!local.isLoopbackAddress()) {
+ String ip = local.getHostAddress();
+ Set myInternetIps = getMyInternetFacingIPs();
+ if (!myInternetIps.contains(ip)) {
+ log.warn("Cannot bind to " + ip + " since it doesn't exist on this machine.");
+ // Not going to be able to bind as this. Our RMI_HOSTNAME_KEY
+ // must be set to some kind of proxy in front of us. So we
+ // still want to use it, but we can't bind to it.
+ local = null;
+ bindAddress = null;
+ }
+ }
+ }
+ }
+ if (bindAddress == null) {
+ // Our last resort - let's make sure we at least use something that's
+ // internet facing!
+ bindAddress = getMyDefaultIP();
+ }
+ if (local == null && bindAddress != null) {
+ local = InetAddress.getByName(bindAddress);
+ localBindAddress = local.getHostName();
+ }
+
+ SocketFactory sf;
+ synchronized (this) {
+ sf = (SocketFactory) clientMap.get(host);
+ }
+ if (sf == null) {
+ sf = defaultClient;
+ }
+
+ Socket s = null;
+ SSLSocket ssl = null;
+ int soTimeout = Integer.MIN_VALUE;
+ IOException reasonForPlainSocket = null;
+ boolean tryPlain = false;
+ try {
+ s = sf.createSocket(host, port, local, 0);
+ soTimeout = s.getSoTimeout();
+ if (!(s instanceof SSLSocket)) {
+ // Someone called setClient() or setDefaultClient() and passed in
+ // a plain socket factory. Okay, nothing to see, move along.
+ return s;
+ } else {
+ ssl = (SSLSocket) s;
+ }
+
+ // If we don't get the peer certs in 15 seconds, revert to plain
+ // socket.
+ ssl.setSoTimeout(15000);
+ ssl.getSession().getPeerCertificates();
+
+ // Everything worked out okay, so go back to original soTimeout.
+ ssl.setSoTimeout(soTimeout);
+ return ssl;
+ }
+ catch (IOException ioe) {
+ // SSL didn't work. Let's analyze the IOException to see if maybe
+ // we're accidentally attempting to talk to a plain-socket RMI
+ // server.
+ Throwable t = ioe;
+ while (!tryPlain && t != null) {
+ tryPlain = tryPlain || t instanceof EOFException;
+ tryPlain = tryPlain || t instanceof InterruptedIOException;
+ tryPlain = tryPlain || t instanceof SSLProtocolException;
+ t = t.getCause();
+ }
+ if (!tryPlain && ioe instanceof SSLPeerUnverifiedException) {
+ try {
+ if (ssl != null) {
+ ssl.startHandshake();
+ }
+ }
+ catch (IOException ioe2) {
+ // Stacktrace from startHandshake() will be more descriptive
+ // then the one we got from getPeerCertificates().
+ ioe = ioe2;
+ t = ioe2;
+ while (!tryPlain && t != null) {
+ tryPlain = tryPlain || t instanceof EOFException;
+ tryPlain = tryPlain || t instanceof InterruptedIOException;
+ tryPlain = tryPlain || t instanceof SSLProtocolException;
+ t = t.getCause();
+ }
+ }
+ }
+ if (!tryPlain) {
+ log.debug("commons-ssl RMI-SSL failed: " + ioe);
+ throw ioe;
+ } else {
+ reasonForPlainSocket = ioe;
+ }
+ }
+ finally {
+ // Some debug logging:
+ boolean isPlain = tryPlain || (s != null && ssl == null);
+ String socket = isPlain ? "RMI plain-socket " : "RMI ssl-socket ";
+ String localIP = local != null ? local.getHostAddress() : "ANY";
+ StringBuffer buf = new StringBuffer(64);
+ buf.append(socket);
+ buf.append(localIP);
+ buf.append(" --> ");
+ buf.append(host);
+ buf.append(":");
+ buf.append(port);
+ log.debug(buf.toString());
+ }
+
+ // SSL didn't work. Remote server either timed out, or sent EOF, or
+ // there was some kind of SSLProtocolException. (Any other problem
+ // would have caused an IOException to be thrown, so execution wouldn't
+ // have made it this far). Maybe plain socket will work in these three
+ // cases.
+ sf = plainClient;
+ s = JavaImpl.connect(null, sf, host, port, local, 0, 15000);
+ if (soTimeout != Integer.MIN_VALUE) {
+ s.setSoTimeout(soTimeout);
+ }
+
+ try {
+ // Plain socket worked! Let's remember that for next time an RMI call
+ // against this host happens.
+ setClient(host, plainClient);
+ String msg = "RMI downgrading from SSL to plain-socket for " + host + " because of " + reasonForPlainSocket;
+ log.warn(msg, reasonForPlainSocket);
+ }
+ catch (GeneralSecurityException gse) {
+ throw new RuntimeException("can't happen because we're using plain socket", gse);
+ // won't happen because we're using plain socket, not SSL.
+ }
+
+ return s;
+ }
+
+
+ public static String getMyDefaultIP() {
+ String anInternetIP = "64.111.122.211";
+ String ip = null;
+ try {
+ DatagramSocket dg = new DatagramSocket();
+ dg.setSoTimeout(250);
+ // 64.111.122.211 is juliusdavies.ca.
+ // This code doesn't actually send any packets (so no firewalls can
+ // get in the way). It's just a neat trick for getting our
+ // internet-facing interface card.
+ InetAddress addr = InetAddress.getByName(anInternetIP);
+ dg.connect(addr, 12345);
+ InetAddress localAddr = dg.getLocalAddress();
+ ip = localAddr.getHostAddress();
+ // log.debug( "Using bogus UDP socket (" + anInternetIP + ":12345), I think my IP address is: " + ip );
+ dg.close();
+ if (localAddr.isLoopbackAddress() || "0.0.0.0".equals(ip)) {
+ ip = null;
+ }
+ }
+ catch (IOException ioe) {
+ log.debug("Bogus UDP didn't work: " + ioe);
+ }
+ return ip;
+ }
+
+ public static SortedSet getMyInternetFacingIPs() throws SocketException {
+ TreeSet set = new TreeSet();
+ Enumeration en = NetworkInterface.getNetworkInterfaces();
+ while (en.hasMoreElements()) {
+ NetworkInterface ni = (NetworkInterface) en.nextElement();
+ Enumeration en2 = ni.getInetAddresses();
+ while (en2.hasMoreElements()) {
+ InetAddress addr = (InetAddress) en2.nextElement();
+ if (!addr.isLoopbackAddress()) {
+ String ip = addr.getHostAddress();
+ String reverse = addr.getHostName();
+ // IP:
+ set.add(ip);
+ // Reverse-Lookup:
+ set.add(reverse);
+
+ }
+ }
+ }
+ return set;
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/SSL.java b/src/java/org/apache/commons/ssl/SSL.java
new file mode 100644
index 0000000..f688694
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/SSL.java
@@ -0,0 +1,739 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/SSL.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Not thread-safe. (But who would ever share this thing across multiple
+ * threads???)
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since May 1, 2006
+ */
+public class SSL {
+ private final static String[] KNOWN_PROTOCOLS =
+ {"TLSv1", "SSLv3", "SSLv2", "SSLv2Hello"};
+
+ // SUPPORTED_CIPHERS_ARRAY is initialized in the static constructor.
+ private final static String[] SUPPORTED_CIPHERS;
+
+ public final static SortedSet KNOWN_PROTOCOLS_SET;
+ public final static SortedSet SUPPORTED_CIPHERS_SET;
+
+ // RC4
+ public final static String SSL_RSA_WITH_RC4_128_SHA = "SSL_RSA_WITH_RC4_128_SHA";
+
+ // 3DES
+ public final static String SSL_RSA_WITH_3DES_EDE_CBC_SHA = "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
+ public final static String SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA = "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ public final static String SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA = "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
+
+ // AES-128
+ public final static String TLS_RSA_WITH_AES_128_CBC_SHA = "TLS_RSA_WITH_AES_128_CBC_SHA";
+ public final static String TLS_DHE_RSA_WITH_AES_128_CBC_SHA = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
+ public final static String TLS_DHE_DSS_WITH_AES_128_CBC_SHA = "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
+
+ // AES-256
+ public final static String TLS_RSA_WITH_AES_256_CBC_SHA = "TLS_RSA_WITH_AES_256_CBC_SHA";
+ public final static String TLS_DHE_RSA_WITH_AES_256_CBC_SHA = "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
+ public final static String TLS_DHE_DSS_WITH_AES_256_CBC_SHA = "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
+
+ static {
+ TreeSet ts = new TreeSet(Collections.reverseOrder());
+ ts.addAll(Arrays.asList(KNOWN_PROTOCOLS));
+ KNOWN_PROTOCOLS_SET = Collections.unmodifiableSortedSet(ts);
+
+ // SSLSocketFactory.getDefault() sometimes blocks on FileInputStream
+ // reads of "/dev/random" (Linux only?). You might find you system
+ // stuck here. Move the mouse around a little!
+ SSLSocketFactory s = (SSLSocketFactory) SSLSocketFactory.getDefault();
+ ts = new TreeSet();
+ SUPPORTED_CIPHERS = s.getSupportedCipherSuites();
+ Arrays.sort(SUPPORTED_CIPHERS);
+ ts.addAll(Arrays.asList(SUPPORTED_CIPHERS));
+ SUPPORTED_CIPHERS_SET = Collections.unmodifiableSortedSet(ts);
+ }
+
+ private Object sslContext = null;
+ private int initCount = 0;
+ private SSLSocketFactory socketFactory = null;
+ private SSLServerSocketFactory serverSocketFactory = null;
+ private HostnameVerifier hostnameVerifier = HostnameVerifier.DEFAULT;
+ private boolean checkHostname = true;
+ private final ArrayList allowedNames = new ArrayList();
+ private boolean checkCRL = true;
+ private boolean checkExpiry = true;
+ private boolean useClientMode = false;
+ private boolean useClientModeDefault = true;
+ private int soTimeout = 24 * 60 * 60 * 1000; // default: one day
+ private int connectTimeout = 60 * 60 * 1000; // default: one hour
+ private TrustChain trustChain = null;
+ private KeyMaterial keyMaterial = null;
+ private String[] enabledCiphers = null;
+ private String[] enabledProtocols = null;
+ private String defaultProtocol = "TLS";
+ private X509Certificate[] currentServerChain;
+ private X509Certificate[] currentClientChain;
+ private boolean wantClientAuth = true;
+ private boolean needClientAuth = false;
+ private SSLWrapperFactory sslWrapperFactory = SSLWrapperFactory.NO_WRAP;
+
+ protected final boolean usingSystemProperties;
+
+ public SSL()
+ throws GeneralSecurityException, IOException {
+ boolean usingSysProps = false;
+ Properties props = System.getProperties();
+ boolean ksSet = props.containsKey("javax.net.ssl.keyStore");
+ boolean tsSet = props.containsKey("javax.net.ssl.trustStore");
+ if (ksSet) {
+ String path = System.getProperty("javax.net.ssl.keyStore");
+ String pwd = System.getProperty("javax.net.ssl.keyStorePassword");
+ pwd = pwd != null ? pwd : ""; // JSSE default is "".
+ File f = new File(path);
+ if (f.exists()) {
+ KeyMaterial km = new KeyMaterial(path, pwd.toCharArray());
+ setKeyMaterial(km);
+ usingSysProps = true;
+ }
+ }
+ boolean trustMaterialSet = false;
+ if (tsSet) {
+ String path = System.getProperty("javax.net.ssl.trustStore");
+ String pwd = System.getProperty("javax.net.ssl.trustStorePassword");
+ boolean pwdWasNull = pwd == null;
+ pwd = pwdWasNull ? "" : pwd; // JSSE default is "".
+ File f = new File(path);
+ if (f.exists()) {
+ TrustMaterial tm;
+ try {
+ tm = new TrustMaterial(path, pwd.toCharArray());
+ }
+ catch (GeneralSecurityException gse) {
+ // Probably a bad password. If we're using the default password,
+ // let's try and survive this setback.
+ if (pwdWasNull) {
+ tm = new TrustMaterial(path);
+ } else {
+ throw gse;
+ }
+ }
+
+ setTrustMaterial(tm);
+ usingSysProps = true;
+ trustMaterialSet = true;
+ }
+ }
+
+ /*
+ No default trust material was set. We'll use the JSSE standard way
+ where we test for "JSSE_CACERTS" first, and then fall back on
+ "CACERTS". We could just leave TrustMaterial null, but then our
+ setCheckCRL() and setCheckExpiry() features won't work. We need a
+ non-null TrustMaterial object in order to intercept and decorate
+ the JVM's default TrustManager.
+ */
+ if (!trustMaterialSet) {
+ setTrustMaterial(TrustMaterial.DEFAULT);
+ }
+ this.usingSystemProperties = usingSysProps;
+
+ // By default we only use the strong ciphers (128 bit and higher).
+ // Consumers can call "useDefaultJavaCiphers()" to get the 40 and 56 bit
+ // ciphers back that Java normally has turned on.
+ useStrongCiphers();
+ dirtyAndReloadIfYoung();
+ }
+
+ private void dirty() {
+ this.sslContext = null;
+ this.socketFactory = null;
+ this.serverSocketFactory = null;
+ }
+
+ private void dirtyAndReloadIfYoung()
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ dirty();
+ if (initCount >= 0 && initCount <= 5) {
+ // The first five init's we do early (before any sockets are
+ // created) in the hope that will trigger any explosions nice
+ // and early, with the correct exception type.
+
+ // After the first five init's, we revert to a regular
+ // dirty / init pattern, and the "init" happens very late:
+ // just before the socket is created. If badness happens, a
+ // wrapping RuntimeException will be thrown.
+ init();
+ }
+ }
+
+ public SSLContext getSSLContext()
+ throws GeneralSecurityException, IOException
+
+ {
+ Object obj = getSSLContextAsObject();
+ if (JavaImpl.isJava13()) {
+ try {
+ return (SSLContext) obj;
+ }
+ catch (ClassCastException cce) {
+ throw new ClassCastException("When using Java13 SSL, you must call SSL.getSSLContextAsObject() - " + cce);
+ }
+ }
+ return (SSLContext) obj;
+ }
+
+ /**
+ * @return com.sun.net.ssl.SSLContext or javax.net.ssl.SSLContext depending
+ * on the JSSE implementation we're using.
+ * @throws GeneralSecurityException problem creating SSLContext
+ * @throws IOException problem creating SSLContext
+ */
+ public Object getSSLContextAsObject()
+ throws GeneralSecurityException, IOException
+
+ {
+ if (sslContext == null) {
+ init();
+ }
+ return sslContext;
+ }
+
+ public void addTrustMaterial(TrustChain trustChain)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ if (this.trustChain == null || trustChain == TrustMaterial.TRUST_ALL) {
+ this.trustChain = trustChain;
+ } else {
+ this.trustChain.addTrustMaterial(trustChain);
+ }
+ dirtyAndReloadIfYoung();
+ }
+
+ public void setTrustMaterial(TrustChain trustChain)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ this.trustChain = trustChain;
+ dirtyAndReloadIfYoung();
+ }
+
+ public void setKeyMaterial(KeyMaterial keyMaterial)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ this.keyMaterial = keyMaterial;
+ dirtyAndReloadIfYoung();
+ }
+
+ public X509Certificate[] getAssociatedCertificateChain() {
+ if (keyMaterial != null) {
+ return keyMaterial.getAssociatedCertificateChain();
+ } else {
+ return null;
+ }
+ }
+
+ public String[] getEnabledCiphers() {
+ return enabledCiphers != null ? enabledCiphers : getDefaultCipherSuites();
+ }
+
+ public void useDefaultJavaCiphers() {
+ this.enabledCiphers = null;
+ }
+
+ public void useStrongCiphers() {
+ LinkedList list = new LinkedList();
+ addCipher(list, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, false);
+ addCipher(list, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, false);
+ addCipher(list, SSL_RSA_WITH_3DES_EDE_CBC_SHA, false);
+ addCipher(list, SSL_RSA_WITH_RC4_128_SHA, false);
+ addCipher(list, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, false);
+ addCipher(list, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, false);
+ addCipher(list, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, false);
+ addCipher(list, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, false);
+ addCipher(list, TLS_RSA_WITH_AES_128_CBC_SHA, false);
+ addCipher(list, TLS_RSA_WITH_AES_256_CBC_SHA, false);
+ String[] strongCiphers = new String[list.size()];
+ list.toArray(strongCiphers);
+ String[] currentCiphers = getEnabledCiphers();
+ // Current ciphers must be default or something. Odd that it's null,
+ // though.
+ if (currentCiphers == null) {
+ setEnabledCiphers(strongCiphers);
+ }
+
+ Arrays.sort(strongCiphers);
+ Arrays.sort(currentCiphers);
+ // Let's only call "setEnabledCiphers" if our array is actually different
+ // than what's already set.
+ if (!Arrays.equals(strongCiphers, currentCiphers)) {
+ setEnabledCiphers(strongCiphers);
+ }
+ }
+
+ public void setEnabledCiphers(String[] ciphers) {
+ HashSet desired = new HashSet(Arrays.asList(ciphers));
+ desired.removeAll(SUPPORTED_CIPHERS_SET);
+ if (!desired.isEmpty()) {
+ throw new IllegalArgumentException("following ciphers not supported: " + desired);
+ }
+ this.enabledCiphers = ciphers;
+ }
+
+ public String[] getEnabledProtocols() {
+ return enabledProtocols != null ? enabledProtocols : KNOWN_PROTOCOLS;
+ }
+
+ public void setEnabledProtocols(String[] protocols) {
+ HashSet desired = new HashSet(Arrays.asList(protocols));
+ desired.removeAll(KNOWN_PROTOCOLS_SET);
+ if (!desired.isEmpty()) {
+ throw new IllegalArgumentException("following protocols not supported: " + desired);
+ }
+ this.enabledProtocols = protocols;
+ }
+
+ public String getDefaultProtocol() {
+ return defaultProtocol;
+ }
+
+ public void setDefaultProtocol(String protocol) {
+ this.defaultProtocol = protocol;
+ dirty();
+ }
+
+ public boolean getCheckHostname() {
+ return checkHostname;
+ }
+
+ /**
+ * @return String[] array of alternate "allowed names" to try against a
+ * server's x509 CN field if the host/ip we used didn't match.
+ * Returns an empty list if there are no "allowedNames" currently
+ * set.
+ */
+ public List getAllowedNames() {
+ return Collections.unmodifiableList(allowedNames);
+ }
+
+ /**
+ * Offers a secure way to use virtual-hosting and SSL in some situations:
+ * for example you want to connect to "bar.com" but you know in advance
+ * that the SSL Certificate on that server only contains "CN=foo.com". If
+ * you setAllowedNames( new String[] { "foo.com" } ) on your SSLClient in
+ * advance, you can connect securely, while still using "bar.com" as the
+ * host.
+ * <p/>
+ * Here's a code example using "cucbc.com" to connect, but anticipating
+ * "www.cucbc.com" in the server's certificate:
+ * <pre>
+ * SSLClient client = new SSLClient();
+ * client.setAllowedNames( new String[] { "www.cucbc.com" } );
+ * Socket s = client.createSocket( "cucbc.com", 443 );
+ * </pre>
+ * <p/>
+ * This technique is also useful if you don't want to use DNS, and want to
+ * connect using the IP address.
+ *
+ * @param allowedNames Collection of alternate "allowed names" to try against
+ * a server's x509 CN field if the host/ip we used didn't
+ * match. Set to null to force strict matching against
+ * host/ip passed into createSocket(). Null is the
+ * default value. Must be set in advance, before
+ * createSocket() is called.
+ */
+ public void addAllowedNames(Collection allowedNames) {
+ this.allowedNames.addAll(allowedNames);
+ }
+
+ public void addAllowedName(String allowedName) {
+ this.allowedNames.add(allowedName);
+ }
+
+ public void clearAllowedNames() {
+ this.allowedNames.clear();
+ }
+
+ public void setCheckHostname(boolean checkHostname) {
+ this.checkHostname = checkHostname;
+ }
+
+ public void setHostnameVerifier(HostnameVerifier verifier) {
+ if (verifier == null) {
+ verifier = HostnameVerifier.DEFAULT;
+ }
+ this.hostnameVerifier = verifier;
+ }
+
+ public HostnameVerifier getHostnameVerifier() {
+ return hostnameVerifier;
+ }
+
+ public boolean getCheckCRL() {
+ return checkCRL;
+ }
+
+ public void setCheckCRL(boolean checkCRL) {
+ this.checkCRL = checkCRL;
+ }
+
+ public boolean getCheckExpiry() {
+ return checkExpiry;
+ }
+
+ public void setCheckExpiry(boolean checkExpiry) {
+ this.checkExpiry = checkExpiry;
+ }
+
+ public void setSoTimeout(int soTimeout) {
+ if (soTimeout < 0) {
+ throw new IllegalArgumentException("soTimeout must not be negative");
+ }
+ this.soTimeout = soTimeout;
+ }
+
+ public int getSoTimeout() {
+ return soTimeout;
+ }
+
+ public void setConnectTimeout(int connectTimeout) {
+ if (connectTimeout < 0) {
+ throw new IllegalArgumentException("connectTimeout must not be negative");
+ }
+ this.connectTimeout = connectTimeout;
+ }
+
+ public void setUseClientMode(boolean useClientMode) {
+ this.useClientModeDefault = false;
+ this.useClientMode = useClientMode;
+ }
+
+ public boolean getUseClientModeDefault() {
+ return useClientModeDefault;
+ }
+
+ public boolean getUseClientMode() {
+ return useClientMode;
+ }
+
+ public void setWantClientAuth(boolean wantClientAuth) {
+ this.wantClientAuth = wantClientAuth;
+ }
+
+ public void setNeedClientAuth(boolean needClientAuth) {
+ this.needClientAuth = needClientAuth;
+ }
+
+ public boolean getWantClientAuth() {
+ return wantClientAuth;
+ }
+
+ public boolean getNeedClientAuth() {
+ return needClientAuth;
+ }
+
+ public SSLWrapperFactory getSSLWrapperFactory() {
+ return this.sslWrapperFactory;
+ }
+
+ public void setSSLWrapperFactory(SSLWrapperFactory wf) {
+ this.sslWrapperFactory = wf;
+ }
+
+ private void initThrowRuntime() {
+ try {
+ init();
+ }
+ catch (GeneralSecurityException gse) {
+ throw JavaImpl.newRuntimeException(gse);
+ }
+ catch (IOException ioe) {
+ throw JavaImpl.newRuntimeException(ioe);
+ }
+ }
+
+ private void init()
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ socketFactory = null;
+ serverSocketFactory = null;
+ this.sslContext = JavaImpl.init(this, trustChain, keyMaterial);
+ initCount++;
+ }
+
+ public void doPreConnectSocketStuff(SSLSocket s)
+ throws IOException {
+ if (!useClientModeDefault) {
+ s.setUseClientMode(useClientMode);
+ }
+ if (soTimeout > 0) {
+ s.setSoTimeout(soTimeout);
+ }
+ if (enabledProtocols != null) {
+ JavaImpl.setEnabledProtocols(s, enabledProtocols);
+ }
+ if (enabledCiphers != null) {
+ s.setEnabledCipherSuites(enabledCiphers);
+ }
+ }
+
+ public void doPostConnectSocketStuff(SSLSocket s, String host)
+ throws IOException {
+ if (checkHostname) {
+ int size = allowedNames.size() + 1;
+ String[] hosts = new String[size];
+ // hosts[ 0 ] MUST ALWAYS be the host given to createSocket().
+ hosts[0] = host;
+ int i = 1;
+ for (Iterator it = allowedNames.iterator(); it.hasNext(); i++) {
+ hosts[i] = (String) it.next();
+ }
+ hostnameVerifier.check(hosts, s);
+ }
+ }
+
+ public SSLSocket createSocket() throws IOException {
+ return sslWrapperFactory.wrap(JavaImpl.createSocket(this));
+ }
+
+ /**
+ * Attempts to get a new socket connection to the given host within the
+ * given time limit.
+ *
+ * @param remoteHost the host name/IP
+ * @param remotePort the port on the host
+ * @param localHost the local host name/IP to bind the socket to
+ * @param localPort the port on the local machine
+ * @param timeout the connection timeout (0==infinite)
+ * @return Socket a new socket
+ * @throws IOException if an I/O error occurs while creating the socket
+ * @throws UnknownHostException if the IP address of the host cannot be
+ * determined
+ */
+ public Socket createSocket(String remoteHost, int remotePort,
+ InetAddress localHost, int localPort,
+ int timeout)
+ throws IOException {
+ // Only use our factory-wide connectTimeout if this method was passed
+ // in a timeout of 0 (infinite).
+ int factoryTimeout = getConnectTimeout();
+ int connectTimeout = timeout == 0 ? factoryTimeout : timeout;
+ SSLSocket s = JavaImpl.createSocket(this, remoteHost, remotePort,
+ localHost, localPort,
+ connectTimeout);
+ return sslWrapperFactory.wrap(s);
+ }
+
+ public Socket createSocket(Socket s, String remoteHost, int remotePort,
+ boolean autoClose)
+ throws IOException {
+ SSLSocketFactory sf = getSSLSocketFactory();
+ s = sf.createSocket(s, remoteHost, remotePort, autoClose);
+ doPreConnectSocketStuff((SSLSocket) s);
+ doPostConnectSocketStuff((SSLSocket) s, remoteHost);
+ return sslWrapperFactory.wrap((SSLSocket) s);
+ }
+
+ public ServerSocket createServerSocket() throws IOException {
+ SSLServerSocket ss = JavaImpl.createServerSocket(this);
+ return getSSLWrapperFactory().wrap(ss, this);
+ }
+
+ /**
+ * Attempts to get a new socket connection to the given host within the
+ * given time limit.
+ *
+ * @param localHost the local host name/IP to bind against (null == ANY)
+ * @param port the port to listen on
+ * @param backlog number of connections allowed to queue up for accept().
+ * @return SSLServerSocket a new server socket
+ * @throws IOException if an I/O error occurs while creating thesocket
+ */
+ public ServerSocket createServerSocket(int port, int backlog,
+ InetAddress localHost)
+ throws IOException {
+ SSLServerSocketFactory f = getSSLServerSocketFactory();
+ ServerSocket ss = f.createServerSocket(port, backlog, localHost);
+ SSLServerSocket s = (SSLServerSocket) ss;
+ doPreConnectServerSocketStuff(s);
+ return getSSLWrapperFactory().wrap(s, this);
+ }
+
+ public void doPreConnectServerSocketStuff(SSLServerSocket s)
+ throws IOException {
+ if (soTimeout > 0) {
+ s.setSoTimeout(soTimeout);
+ }
+ if (enabledProtocols != null) {
+ JavaImpl.setEnabledProtocols(s, enabledProtocols);
+ }
+ if (enabledCiphers != null) {
+ s.setEnabledCipherSuites(enabledCiphers);
+ }
+
+ /*
+ setNeedClientAuth( false ) has an annoying side effect: it seems to
+ reset setWantClient( true ) back to to false. So I do things this
+ way to make sure setting things "true" happens after setting things
+ "false" - giving "true" priority.
+ */
+ if (!wantClientAuth) {
+ JavaImpl.setWantClientAuth(s, wantClientAuth);
+ }
+ if (!needClientAuth) {
+ s.setNeedClientAuth(needClientAuth);
+ }
+ if (wantClientAuth) {
+ JavaImpl.setWantClientAuth(s, wantClientAuth);
+ }
+ if (needClientAuth) {
+ s.setNeedClientAuth(needClientAuth);
+ }
+ }
+
+ public SSLSocketFactory getSSLSocketFactory() {
+ if (sslContext == null) {
+ initThrowRuntime();
+ }
+ if (socketFactory == null) {
+ socketFactory = JavaImpl.getSSLSocketFactory(sslContext);
+ }
+ return socketFactory;
+ }
+
+ public SSLServerSocketFactory getSSLServerSocketFactory() {
+ if (sslContext == null) {
+ initThrowRuntime();
+ }
+ if (serverSocketFactory == null) {
+ serverSocketFactory = JavaImpl.getSSLServerSocketFactory(sslContext);
+ }
+ return serverSocketFactory;
+ }
+
+ public int getConnectTimeout() {
+ return connectTimeout;
+ }
+
+ public String[] getDefaultCipherSuites() {
+ return getSSLSocketFactory().getDefaultCipherSuites();
+ }
+
+ public String[] getSupportedCipherSuites() {
+ String[] s = new String[SUPPORTED_CIPHERS.length];
+ System.arraycopy(SUPPORTED_CIPHERS, 0, s, 0, s.length);
+ return s;
+ }
+
+ public TrustChain getTrustChain() {
+ return trustChain;
+ }
+
+ public void setCurrentServerChain(X509Certificate[] chain) {
+ this.currentServerChain = chain;
+ }
+
+ public void setCurrentClientChain(X509Certificate[] chain) {
+ this.currentClientChain = chain;
+ }
+
+ public X509Certificate[] getCurrentServerChain() {
+ return currentServerChain;
+ }
+
+ public X509Certificate[] getCurrentClientChain() {
+ return currentClientChain;
+ }
+
+ public static void main(String[] args) {
+ for (int i = 0; i < SUPPORTED_CIPHERS.length; i++) {
+ System.out.println(SUPPORTED_CIPHERS[i]);
+ }
+ System.out.println();
+ System.out.println("----------------------------------------------");
+ addCipher(null, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, true);
+ addCipher(null, SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, true);
+ addCipher(null, SSL_RSA_WITH_3DES_EDE_CBC_SHA, true);
+ addCipher(null, SSL_RSA_WITH_RC4_128_SHA, true);
+ addCipher(null, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, true);
+ addCipher(null, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, true);
+ addCipher(null, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, true);
+ addCipher(null, TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true);
+ addCipher(null, TLS_RSA_WITH_AES_128_CBC_SHA, true);
+ addCipher(null, TLS_RSA_WITH_AES_256_CBC_SHA, true);
+ }
+
+ private static void addCipher(List l, String c, boolean printOnStandardOut) {
+ boolean supported = false;
+ if (c != null && SUPPORTED_CIPHERS_SET.contains(c)) {
+ if (l != null) {
+ l.add(c);
+ }
+ supported = true;
+ }
+ if (printOnStandardOut) {
+ System.out.println(c + ":\t" + supported);
+ }
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/SSLClient.java b/src/java/org/apache/commons/ssl/SSLClient.java
new file mode 100644
index 0000000..626c0b1
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/SSLClient.java
@@ -0,0 +1,233 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/SSLClient.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 27-Feb-2006
+ */
+public class SSLClient extends SSLSocketFactory {
+ private final SSL ssl;
+
+ public SSLClient()
+ throws GeneralSecurityException, IOException {
+ this.ssl = new SSL();
+ }
+
+ public void addTrustMaterial(TrustChain trustChain)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ ssl.addTrustMaterial(trustChain);
+ }
+
+ public void setTrustMaterial(TrustChain trustChain)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ ssl.setTrustMaterial(trustChain);
+ }
+
+ public void setKeyMaterial(KeyMaterial keyMaterial)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ ssl.setKeyMaterial(keyMaterial);
+ }
+
+ public void addAllowedName(String s) { ssl.addAllowedName(s); }
+
+ public void addAllowedNames(Collection c) { ssl.addAllowedNames(c); }
+
+ public void clearAllowedNames() { ssl.clearAllowedNames(); }
+
+ public void setCheckCRL(boolean b) { ssl.setCheckCRL(b); }
+
+ public void setCheckExpiry(boolean b) { ssl.setCheckExpiry(b); }
+
+ public void setCheckHostname(boolean b) { ssl.setCheckHostname(b); }
+
+ public void setConnectTimeout(int i) { ssl.setConnectTimeout(i); }
+
+ public void setDefaultProtocol(String s) { ssl.setDefaultProtocol(s); }
+
+ public void useDefaultJavaCiphers() { ssl.useDefaultJavaCiphers(); }
+
+ public void useStrongCiphers() { ssl.useStrongCiphers(); }
+
+ public void setEnabledCiphers(String[] ciphers) {
+ ssl.setEnabledCiphers(ciphers);
+ }
+
+ public void setEnabledProtocols(String[] protocols) {
+ ssl.setEnabledProtocols(protocols);
+ }
+
+ public void setHostnameVerifier(HostnameVerifier verifier) {
+ ssl.setHostnameVerifier(verifier);
+ }
+
+ public void setSoTimeout(int soTimeout) { ssl.setSoTimeout(soTimeout); }
+
+ public void setSSLWrapperFactory(SSLWrapperFactory wf) {
+ ssl.setSSLWrapperFactory(wf);
+ }
+
+ public void setNeedClientAuth(boolean b) { ssl.setNeedClientAuth(b); }
+
+ public void setWantClientAuth(boolean b) { ssl.setWantClientAuth(b); }
+
+ public void setUseClientMode(boolean b) { ssl.setUseClientMode(b); }
+
+ public List getAllowedNames() { return ssl.getAllowedNames(); }
+
+ public X509Certificate[] getAssociatedCertificateChain() {
+ return ssl.getAssociatedCertificateChain();
+ }
+
+ public boolean getCheckCRL() { return ssl.getCheckCRL(); }
+
+ public boolean getCheckExpiry() { return ssl.getCheckExpiry(); }
+
+ public boolean getCheckHostname() { return ssl.getCheckHostname(); }
+
+ public int getConnectTimeout() { return ssl.getConnectTimeout(); }
+
+ public String getDefaultProtocol() { return ssl.getDefaultProtocol(); }
+
+ public String[] getEnabledCiphers() { return ssl.getEnabledCiphers(); }
+
+ public String[] getEnabledProtocols() { return ssl.getEnabledProtocols(); }
+
+ public HostnameVerifier getHostnameVerifier() {
+ return ssl.getHostnameVerifier();
+ }
+
+ public int getSoTimeout() { return ssl.getSoTimeout(); }
+
+ public SSLWrapperFactory getSSLWrapperFactory() {
+ return ssl.getSSLWrapperFactory();
+ }
+
+ public boolean getNeedClientAuth() { return ssl.getNeedClientAuth(); }
+
+ public boolean getWantClientAuth() { return ssl.getWantClientAuth(); }
+
+ public boolean getUseClientMode() { /* SSLClient's default is true. */
+ return ssl.getUseClientModeDefault() || ssl.getUseClientMode();
+ }
+
+ public SSLContext getSSLContext() throws GeneralSecurityException, IOException {
+ return ssl.getSSLContext();
+ }
+
+ public TrustChain getTrustChain() { return ssl.getTrustChain(); }
+
+ public X509Certificate[] getCurrentServerChain() {
+ return ssl.getCurrentServerChain();
+ }
+
+ public String[] getDefaultCipherSuites() {
+ return ssl.getDefaultCipherSuites();
+ }
+
+ public String[] getSupportedCipherSuites() {
+ return ssl.getSupportedCipherSuites();
+ }
+
+ public Socket createSocket() throws IOException {
+ return ssl.createSocket();
+ }
+
+ public Socket createSocket(String host, int port)
+ throws IOException {
+ return createSocket(host, port, null, 0);
+ }
+
+ public Socket createSocket(InetAddress host, int port)
+ throws IOException {
+ return createSocket(host.getHostName(), port);
+ }
+
+ public Socket createSocket(InetAddress host, int port,
+ InetAddress localHost, int localPort)
+ throws IOException {
+ return createSocket(host.getHostName(), port, localHost, localPort);
+ }
+
+ public Socket createSocket(String host, int port,
+ InetAddress localHost, int localPort)
+ throws IOException {
+ return createSocket(host, port, localHost, localPort, 0);
+ }
+
+ /**
+ * Attempts to get a new socket connection to the given host within the
+ * given time limit.
+ *
+ * @param host the host name/IP
+ * @param port the port on the host
+ * @param localHost the local host name/IP to bind the socket to
+ * @param localPort the port on the local machine
+ * @param timeout the connection timeout (0==infinite)
+ * @return Socket a new socket
+ * @throws IOException if an I/O error occurs while creating thesocket
+ * @throws UnknownHostException if the IP address of the host cannot be
+ * determined
+ */
+ public Socket createSocket(String host, int port, InetAddress localHost,
+ int localPort, int timeout)
+ throws IOException {
+ return ssl.createSocket(host, port, localHost, localPort, timeout);
+ }
+
+ public Socket createSocket(Socket s, String remoteHost, int remotePort,
+ boolean autoClose)
+ throws IOException {
+ return ssl.createSocket(s, remoteHost, remotePort, autoClose);
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/SSLEchoServer.java b/src/java/org/apache/commons/ssl/SSLEchoServer.java
new file mode 100644
index 0000000..632606e
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/SSLEchoServer.java
@@ -0,0 +1,142 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/SSLEchoServer.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 2-May-2006
+ */
+public class SSLEchoServer {
+
+ public static void main(String[] args) throws Exception {
+ int port = 7443;
+ if (args.length >= 1) {
+ port = Integer.parseInt(args[0]);
+ }
+
+ SSLServer ssl = new SSLServer();
+ // ssl.setCheckExpiry( false );
+ // ssl.setNeedClientAuth( true );
+ ssl.addTrustMaterial(TrustMaterial.TRUST_ALL);
+ SSLServerSocket ss = (SSLServerSocket) ssl.createServerSocket(port, 3);
+ System.out.println("SSL Echo server listening on port: " + port);
+ while (true) {
+ SSLSocket s = (SSLSocket) ss.accept();
+ s.setSoTimeout(30000);
+ EchoRunnable r = new EchoRunnable(s);
+ new Thread(r).start();
+ }
+
+ }
+
+ public static class EchoRunnable implements Runnable {
+ private SSLSocket s;
+
+ public EchoRunnable(SSLSocket s) {
+ this.s = s;
+ }
+
+ public void run() {
+ InputStream in = null;
+ OutputStream out = null;
+ System.out.println("Socket accepted!");
+ try {
+ SSLSession session = s.getSession();
+
+ try {
+ Certificate[] certs = JavaImpl.getPeerCertificates(session);
+ if (certs != null) {
+ for (int i = 0; i < certs.length; i++) {
+ // log client cert info
+ X509Certificate cert = (X509Certificate) certs[i];
+ String s = "client cert " + i + ":";
+ s += JavaImpl.getSubjectX500(cert);
+ System.out.println(s);
+ System.out.println(Certificates.toString(cert));
+ }
+ }
+ }
+ catch (SSLPeerUnverifiedException sslpue) {
+ // oh well, no client cert for us
+ }
+
+ in = s.getInputStream();
+ out = s.getOutputStream();
+ String line = Util.readLine(in);
+ if (line != null && line.indexOf("HTTP") > 0) {
+ out.write("HTTP/1.1 200 OK\r\n\r\n".getBytes());
+ out.flush();
+ }
+ while (line != null) {
+ String echo = "ECHO:>" + line + "\n";
+ out.write(echo.getBytes());
+ out.flush();
+ line = Util.readLine(in);
+ }
+ }
+ catch (IOException ioe) {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ if (in != null) {
+ in.close();
+ }
+ s.close();
+ }
+ catch (Exception e) {
+ }
+
+ if (ioe instanceof InterruptedIOException) {
+ System.out.println("Socket closed after 30 second timeout.");
+ } else {
+ ioe.printStackTrace();
+ }
+
+ }
+ }
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/SSLProxyServer.java b/src/java/org/apache/commons/ssl/SSLProxyServer.java
new file mode 100644
index 0000000..ed3d62d
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/SSLProxyServer.java
@@ -0,0 +1,193 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/SSLProxyServer.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 5-May-2006
+ */
+public class SSLProxyServer {
+
+ public static void main(String[] args) throws Exception {
+ int port = 7444;
+ if (args.length >= 1) {
+ port = Integer.parseInt(args[0]);
+ }
+
+ ServerSocket ss = new ServerSocket(port);
+
+ System.out.println("SSL Proxy server listening on port: " + port);
+ while (true) {
+ Socket s = ss.accept();
+ s.setSoTimeout(10000);
+ ProxyRunnable r = new ProxyRunnable(s);
+ new Thread(r).start();
+ }
+
+ }
+
+ public static class ProxyRunnable implements Runnable {
+ private Socket s;
+
+ public ProxyRunnable(Socket s) {
+ this.s = s;
+ }
+
+ public void run() {
+ InputStream in = null;
+ OutputStream out = null;
+ InputStream newIn = null;
+ OutputStream newOut = null;
+ Socket newSocket = new Socket();
+ System.out.println("Socket accepted!");
+ try {
+ in = s.getInputStream();
+ out = s.getOutputStream();
+ String line = Util.readLine(in);
+ line = line.trim();
+ String connect = line.substring(0, "CONNECT".length());
+ InetSocketAddress addr = null;
+ if ("CONNECT".equalsIgnoreCase(connect)) {
+ line = line.substring("CONNECT".length()).trim();
+ line = line.substring(0, line.length() - "HTTP/1.1".length()).trim();
+ HostPort hostPort = Util.toAddress(line, 443);
+ addr = new InetSocketAddress(hostPort.host, hostPort.port);
+ System.out.println("Attempting to proxy to: " + line);
+ } else {
+ throw new IOException("not a proxy request: " + line);
+ }
+
+ int avail = in.available();
+ in.skip(avail);
+ Thread.yield();
+ avail = in.available();
+ while (avail != 0) {
+ in.skip(avail);
+ Thread.yield();
+ avail = in.available();
+ }
+
+ InetSocketAddress local = new InetSocketAddress(0);
+ newSocket.setSoTimeout(10000);
+ newSocket.bind(local);
+ newSocket.connect(addr, 5000);
+ newIn = newSocket.getInputStream();
+ newOut = newSocket.getOutputStream();
+
+ out.write("HTTP/1.1 200 OKAY\r\n\r\n".getBytes());
+ out.flush();
+
+ final IOException[] e = new IOException[1];
+ final InputStream rIn = in;
+ final OutputStream rNewOut = newOut;
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ byte[] buf = new byte[4096];
+ int read = rIn.read(buf);
+ while (read >= 0) {
+ if (read > 0) {
+ rNewOut.write(buf, 0, read);
+ rNewOut.flush();
+ }
+ read = rIn.read(buf);
+ }
+ }
+ catch (IOException ioe) {
+ e[0] = ioe;
+ }
+ }
+ };
+ new Thread(r).start();
+
+ byte[] buf = new byte[4096];
+ int read = newIn.read(buf);
+ while (read >= 0) {
+ if (read > 0) {
+ out.write(buf, 0, read);
+ out.flush();
+ }
+ if (e[0] != null) {
+ throw e[0];
+ }
+ read = newIn.read(buf);
+ }
+
+
+ }
+ catch (IOException ioe) {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ if (in != null) {
+ in.close();
+ }
+ s.close();
+ }
+ catch (Exception e) {
+ }
+
+ try {
+ if (newOut != null) {
+ newOut.close();
+ }
+ if (newIn != null) {
+ newIn.close();
+ }
+ newSocket.close();
+ }
+ catch (Exception e) {
+ }
+
+
+ if (ioe instanceof InterruptedIOException) {
+ System.out.println("Socket closed after 10 second timeout.");
+ } else {
+ ioe.printStackTrace();
+ }
+
+ }
+ }
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/SSLServer.java b/src/java/org/apache/commons/ssl/SSLServer.java
new file mode 100644
index 0000000..d110b8e
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/SSLServer.java
@@ -0,0 +1,295 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/SSLServer.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocketFactory;
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.security.GeneralSecurityException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since May 1, 2006
+ */
+public class SSLServer extends SSLServerSocketFactory {
+ protected final SSL ssl;
+
+ public SSLServer()
+ throws GeneralSecurityException, IOException {
+ this.ssl = new SSL();
+ // client certs aren't usually tied down to a single host (and who knows
+ // if the DNS reverse-lookup will work!).
+ setCheckHostname(false);
+
+ // If "javax.net.ssl.keyStore" is set, then we won't bother with this
+ // silly SSLServer default behaviour.
+ if (!ssl.usingSystemProperties) {
+ // commons-ssl default KeyMaterial will be
+ // ~/.keystore with a password of "changeit".
+ useDefaultKeyMaterial();
+ }
+ }
+
+ /**
+ * Tries to extract the TrustMaterial and KeyMaterial being used by a Tomcat
+ * SSL server (usually on 8443) by analyzing Tomcat's "server.xml" file. If
+ * the extraction is successful, the TrustMaterial and KeyMaterial are
+ * applied to this SSLServer.
+ *
+ * @return true if the operation was successful.
+ * @throws GeneralSecurityException setKeyMaterial() failed
+ * @throws IOException setKeyMaterial() failed
+ */
+ public boolean useTomcatSSLMaterial()
+ throws GeneralSecurityException, IOException {
+ // If running inside Tomcat, let's try to re-use Tomcat's SSL
+ // certificate for our own stuff (e.g. RMI-SSL).
+ Integer p8443 = new Integer(8443);
+ KeyMaterial km;
+ TrustMaterial tm;
+ km = (KeyMaterial) TomcatServerXML.KEY_MATERIAL_BY_PORT.get(p8443);
+ tm = (TrustMaterial) TomcatServerXML.TRUST_MATERIAL_BY_PORT.get(p8443);
+
+ // If 8443 isn't set, let's take lowest secure port.
+ km = km == null ? TomcatServerXML.KEY_MATERIAL : km;
+ tm = tm == null ? TomcatServerXML.TRUST_MATERIAL : tm;
+ boolean success = false;
+ if (km != null) {
+ setKeyMaterial(km);
+ success = true;
+ if (tm != null && !TrustMaterial.DEFAULT.equals(tm)) {
+ setTrustMaterial(tm);
+ }
+ }
+ return success;
+ }
+
+ private boolean useDefaultKeyMaterial()
+ throws GeneralSecurityException, IOException {
+ // If we're not able to re-use Tomcat's SSLServerSocket configuration,
+ // commons-ssl default KeyMaterial will be ~/.keystore with a password
+ // of "changeit".
+ Properties props = System.getProperties();
+ boolean pwdSet = props.containsKey("javax.net.ssl.keyStorePassword");
+ String pwd = props.getProperty("javax.net.ssl.keyStorePassword");
+ pwd = pwdSet ? pwd : "changeit";
+
+ String userHome = System.getProperty("user.home");
+ String path = userHome + "/.keystore";
+ File f = new File(path);
+ boolean success = false;
+ if (f.exists()) {
+ KeyMaterial km = null;
+ try {
+ km = new KeyMaterial(path, pwd.toCharArray());
+ }
+ catch (Exception e) {
+ // Don't want to blowup just because this silly default
+ // behaviour didn't work out.
+ if (pwdSet) {
+ // Buf if the user has specified a non-standard password for
+ // "javax.net.ssl.keyStorePassword", then we will warn them
+ // that things didn't work out.
+ System.err.println("commons-ssl automatic loading of [" + path + "] failed. ");
+ System.err.println(e);
+ }
+ }
+ if (km != null) {
+ setKeyMaterial(km);
+ success = true;
+ }
+ }
+ return success;
+ }
+
+ public void addTrustMaterial(TrustChain trustChain)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ ssl.addTrustMaterial(trustChain);
+ }
+
+ public void setTrustMaterial(TrustChain trustChain)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ ssl.setTrustMaterial(trustChain);
+ }
+
+ public void setKeyMaterial(KeyMaterial keyMaterial)
+ throws NoSuchAlgorithmException, KeyStoreException,
+ KeyManagementException, IOException, CertificateException {
+ ssl.setKeyMaterial(keyMaterial);
+ }
+
+ public void addAllowedName(String s) { ssl.addAllowedName(s); }
+
+ public void addAllowedNames(Collection c) { ssl.addAllowedNames(c); }
+
+ public void clearAllowedNames() { ssl.clearAllowedNames(); }
+
+ public void setCheckCRL(boolean b) { ssl.setCheckCRL(b); }
+
+ public void setCheckExpiry(boolean b) { ssl.setCheckExpiry(b); }
+
+ public void setCheckHostname(boolean b) { ssl.setCheckHostname(b); }
+
+ public void setConnectTimeout(int i) { ssl.setConnectTimeout(i); }
+
+ public void setDefaultProtocol(String s) { ssl.setDefaultProtocol(s); }
+
+ public void useDefaultJavaCiphers() { ssl.useDefaultJavaCiphers(); }
+
+ public void useStrongCiphers() { ssl.useStrongCiphers(); }
+
+ public void setEnabledCiphers(String[] ciphers) {
+ ssl.setEnabledCiphers(ciphers);
+ }
+
+ public void setEnabledProtocols(String[] protocols) {
+ ssl.setEnabledProtocols(protocols);
+ }
+
+ public void setHostnameVerifier(HostnameVerifier verifier) {
+ ssl.setHostnameVerifier(verifier);
+ }
+
+ public void setSoTimeout(int soTimeout) { ssl.setSoTimeout(soTimeout); }
+
+ public void setSSLWrapperFactory(SSLWrapperFactory wf) {
+ ssl.setSSLWrapperFactory(wf);
+ }
+
+ public void setNeedClientAuth(boolean b) { ssl.setNeedClientAuth(b); }
+
+ public void setWantClientAuth(boolean b) { ssl.setWantClientAuth(b); }
+
+ public void setUseClientMode(boolean b) { ssl.setUseClientMode(b); }
+
+ public List getAllowedNames() { return ssl.getAllowedNames(); }
+
+ public X509Certificate[] getAssociatedCertificateChain() {
+ return ssl.getAssociatedCertificateChain();
+ }
+
+ public boolean getCheckCRL() { return ssl.getCheckCRL(); }
+
+ public boolean getCheckExpiry() { return ssl.getCheckExpiry(); }
+
+ public boolean getCheckHostname() { return ssl.getCheckHostname(); }
+
+ public int getConnectTimeout() { return ssl.getConnectTimeout(); }
+
+ public String getDefaultProtocol() { return ssl.getDefaultProtocol(); }
+
+ public String[] getEnabledCiphers() { return ssl.getEnabledCiphers(); }
+
+ public String[] getEnabledProtocols() { return ssl.getEnabledProtocols(); }
+
+ public HostnameVerifier getHostnameVerifier() {
+ return ssl.getHostnameVerifier();
+ }
+
+ public int getSoTimeout() { return ssl.getSoTimeout(); }
+
+ public SSLWrapperFactory getSSLWrapperFactory() {
+ return ssl.getSSLWrapperFactory();
+ }
+
+ public boolean getNeedClientAuth() { return ssl.getNeedClientAuth(); }
+
+ public boolean getWantClientAuth() { return ssl.getWantClientAuth(); }
+
+ public boolean getUseClientMode() { /* SSLServer's default is false. */
+ return !ssl.getUseClientModeDefault() && ssl.getUseClientMode();
+ }
+
+ public SSLContext getSSLContext() throws GeneralSecurityException, IOException {
+ return ssl.getSSLContext();
+ }
+
+ public TrustChain getTrustChain() { return ssl.getTrustChain(); }
+
+ public X509Certificate[] getCurrentClientChain() {
+ return ssl.getCurrentClientChain();
+ }
+
+ public String[] getDefaultCipherSuites() {
+ return ssl.getDefaultCipherSuites();
+ }
+
+ public String[] getSupportedCipherSuites() {
+ return ssl.getSupportedCipherSuites();
+ }
+
+ public ServerSocket createServerSocket() throws IOException {
+ return ssl.createServerSocket();
+ }
+
+ public ServerSocket createServerSocket(int port)
+ throws IOException {
+ return createServerSocket(port, 50);
+ }
+
+ public ServerSocket createServerSocket(int port, int backlog)
+ throws IOException {
+ return createServerSocket(port, backlog, null);
+ }
+
+ /**
+ * Attempts to get a new socket connection to the given host within the
+ * given time limit.
+ *
+ * @param localHost the local host name/IP to bind against (null == ANY)
+ * @param port the port to listen on
+ * @param backlog number of connections allowed to queue up for accept().
+ * @return SSLServerSocket a new server socket
+ * @throws IOException if an I/O error occurs while creating thesocket
+ */
+ public ServerSocket createServerSocket(int port, int backlog,
+ InetAddress localHost)
+ throws IOException {
+ return ssl.createServerSocket(port, backlog, localHost);
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/SSLServerSocketWrapper.java b/src/java/org/apache/commons/ssl/SSLServerSocketWrapper.java
new file mode 100644
index 0000000..f83e158
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/SSLServerSocketWrapper.java
@@ -0,0 +1,182 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/SSLServerSocketWrapper.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.ServerSocketChannel;
+
+/**
+ * Wraps an SSLServerSocket - NOTE that the accept() method applies a number of
+ * important common-ssl settings before returning the SSLSocket!
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 20-Nov-2006
+ */
+public class SSLServerSocketWrapper extends SSLServerSocket {
+ protected SSLServerSocket s;
+ protected SSL ssl;
+ protected SSLWrapperFactory wf;
+
+ public SSLServerSocketWrapper(SSLServerSocket s, SSL ssl,
+ SSLWrapperFactory wf)
+ throws IOException {
+ super();
+ this.s = s;
+ this.ssl = ssl;
+ this.wf = wf;
+ }
+
+ /* javax.net.ssl.SSLServerSocket */
+
+ public Socket accept() throws IOException {
+ SSLSocket secureSocket = (SSLSocket) s.accept();
+
+ // Do the commons-ssl usual housekeeping for every socket:
+ ssl.doPreConnectSocketStuff(secureSocket);
+ InetAddress addr = secureSocket.getInetAddress();
+ String hostName = addr.getHostName();
+ ssl.doPostConnectSocketStuff(secureSocket, hostName);
+
+ return wf.wrap(secureSocket);
+ }
+
+ public String[] getEnabledCipherSuites() {
+ return s.getEnabledCipherSuites();
+ }
+
+ public String[] getEnabledProtocols() { return s.getEnabledProtocols(); }
+
+ public boolean getEnableSessionCreation() {
+ return s.getEnableSessionCreation();
+ }
+
+ public boolean getNeedClientAuth() { return s.getNeedClientAuth(); }
+
+ public String[] getSupportedCipherSuites() {
+ return s.getSupportedCipherSuites();
+ }
+
+ public String[] getSupportedProtocols() { return s.getSupportedProtocols(); }
+
+ public boolean getUseClientMode() { return s.getUseClientMode(); }
+
+ public boolean getWantClientAuth() { return s.getWantClientAuth(); }
+
+ public void setEnabledCipherSuites(String[] suites) {
+ s.setEnabledCipherSuites(suites);
+ }
+
+ public void setEnabledProtocols(String[] protocols) {
+ s.setEnabledProtocols(protocols);
+ }
+
+ public void setEnableSessionCreation(boolean flag) {
+ s.setEnableSessionCreation(flag);
+ }
+
+ public void setNeedClientAuth(boolean need) {
+ s.setNeedClientAuth(need);
+ }
+
+ public void setUseClientMode(boolean use) { s.setUseClientMode(use); }
+
+ public void setWantClientAuth(boolean want) {
+ s.setWantClientAuth(want);
+ }
+
+ /* java.net.Socket */
+
+ public void bind(SocketAddress endpoint) throws IOException {
+ s.bind(endpoint);
+ }
+
+ public void bind(SocketAddress ep, int bl) throws IOException {
+ s.bind(ep, bl);
+ }
+
+ public void close() throws IOException { s.close(); }
+
+ public ServerSocketChannel getChannel() { return s.getChannel(); }
+
+ public InetAddress getInetAddress() { return s.getInetAddress(); }
+
+ public int getLocalPort() { return s.getLocalPort(); }
+
+ public SocketAddress getLocalSocketAddress() {
+ return s.getLocalSocketAddress();
+ }
+
+ public int getReceiveBufferSize() throws SocketException {
+ return s.getReceiveBufferSize();
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ return s.getReuseAddress();
+ }
+
+ public int getSoTimeout() throws IOException { return s.getSoTimeout(); }
+
+ public boolean isBound() { return s.isBound(); }
+
+ public boolean isClosed() { return s.isClosed(); }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ s.setReceiveBufferSize(size);
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ s.setReuseAddress(on);
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ s.setSoTimeout(timeout);
+ }
+
+ public String toString() { return s.toString(); }
+
+ /* Java 1.5
+ public void setPerformancePreferences(int connectionTime, int latency, int bandwidth)
+ {
+ s.setPerformancePreferences( connectionTime, latency, bandwidth );
+ }
+ */
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/SSLSocketWrapper.java b/src/java/org/apache/commons/ssl/SSLSocketWrapper.java
new file mode 100644
index 0000000..20726d5
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/SSLSocketWrapper.java
@@ -0,0 +1,251 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/SSLSocketWrapper.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.SocketChannel;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 16-Aug-2006
+ */
+public class SSLSocketWrapper extends SSLSocket {
+ protected SSLSocket s;
+
+ public SSLSocketWrapper(SSLSocket s) {
+ this.s = s;
+ }
+
+ /* javax.net.ssl.SSLSocket */
+
+ public void addHandshakeCompletedListener(HandshakeCompletedListener hcl) {
+ s.addHandshakeCompletedListener(hcl);
+ }
+
+ public void removeHandshakeCompletedListener(HandshakeCompletedListener hcl) {
+ s.removeHandshakeCompletedListener(hcl);
+ }
+
+ public String[] getSupportedCipherSuites() {
+ return s.getSupportedCipherSuites();
+ }
+
+ public boolean getEnableSessionCreation() {
+ return s.getEnableSessionCreation();
+ }
+
+ public String[] getEnabledCipherSuites() {
+ return s.getEnabledCipherSuites();
+ }
+
+ public String[] getSupportedProtocols() { return s.getSupportedProtocols(); }
+
+ public String[] getEnabledProtocols() { return s.getEnabledProtocols(); }
+
+ public SSLSession getSession() { return s.getSession(); }
+
+ public boolean getUseClientMode() { return s.getUseClientMode(); }
+
+ public boolean getNeedClientAuth() { return s.getNeedClientAuth(); }
+
+ public boolean getWantClientAuth() { return s.getWantClientAuth(); }
+
+ public void setEnabledCipherSuites(String[] cs) {
+ s.setEnabledCipherSuites(cs);
+ }
+
+ public void setEnabledProtocols(String[] ep) {
+ s.setEnabledProtocols(ep);
+ }
+
+ public void startHandshake() throws IOException { s.startHandshake(); }
+
+ public void setUseClientMode(boolean b) { s.setUseClientMode(b); }
+
+ public void setNeedClientAuth(boolean b) { s.setNeedClientAuth(b); }
+
+ public void setWantClientAuth(boolean b) { s.setWantClientAuth(b); }
+
+ public void setEnableSessionCreation(boolean b) {
+ s.setEnableSessionCreation(b);
+ }
+
+ /* java.net.Socket */
+
+ public SocketChannel getChannel() { return s.getChannel(); }
+
+ public InetAddress getInetAddress() { return s.getInetAddress(); }
+
+ public boolean getKeepAlive() throws SocketException {
+ return s.getKeepAlive();
+ }
+
+ public InetAddress getLocalAddress() { return s.getLocalAddress(); }
+
+ public int getLocalPort() { return s.getLocalPort(); }
+
+ public SocketAddress getLocalSocketAddress() {
+ return s.getLocalSocketAddress();
+ }
+
+ public boolean getOOBInline() throws SocketException {
+ return s.getOOBInline();
+ }
+
+ public int getPort() { return s.getPort(); }
+
+ public int getReceiveBufferSize() throws SocketException {
+ return s.getReceiveBufferSize();
+ }
+
+ public SocketAddress getRemoteSocketAddress() {
+ return s.getRemoteSocketAddress();
+ }
+
+ public boolean getReuseAddress() throws SocketException {
+ return s.getReuseAddress();
+ }
+
+ public int getSendBufferSize() throws SocketException {
+ return s.getSendBufferSize();
+ }
+
+ public int getSoLinger() throws SocketException { return s.getSoLinger(); }
+
+ public int getSoTimeout() throws SocketException { return s.getSoTimeout(); }
+
+ public boolean getTcpNoDelay() throws SocketException {
+ return s.getTcpNoDelay();
+ }
+
+ public int getTrafficClass() throws SocketException {
+ return s.getTrafficClass();
+ }
+
+ public boolean isBound() { return s.isBound(); }
+
+ public boolean isClosed() { return s.isClosed(); }
+
+ public boolean isConnected() { return s.isConnected(); }
+
+ public boolean isInputShutdown() { return s.isInputShutdown(); }
+
+ public boolean isOutputShutdown() { return s.isOutputShutdown(); }
+
+ public void sendUrgentData(int data) throws IOException {
+ s.sendUrgentData(data);
+ }
+
+ public void setKeepAlive(boolean on) throws SocketException {
+ s.setKeepAlive(on);
+ }
+
+ public void setOOBInline(boolean on) throws SocketException {
+ s.setOOBInline(on);
+ }
+
+ public void setReceiveBufferSize(int size) throws SocketException {
+ s.setReceiveBufferSize(size);
+ }
+
+ public void setReuseAddress(boolean on) throws SocketException {
+ s.setReuseAddress(on);
+ }
+
+ public void setSendBufferSize(int size) throws SocketException {
+ s.setSendBufferSize(size);
+ }
+
+ public void setSoLinger(boolean on, int l) throws SocketException {
+ s.setSoLinger(on, l);
+ }
+
+ public void setSoTimeout(int timeout) throws SocketException {
+ s.setSoTimeout(timeout);
+ }
+
+ public void setTcpNoDelay(boolean on) throws SocketException {
+ s.setTcpNoDelay(on);
+ }
+
+ public void setTrafficClass(int tc) throws SocketException {
+ s.setTrafficClass(tc);
+ }
+
+ public void shutdownInput() throws IOException { s.shutdownInput(); }
+
+ public void shutdownOutput() throws IOException { s.shutdownOutput(); }
+
+ public String toString() { return s.toString(); }
+
+ /* Java 1.5
+ public void setPerformancePreferences(int connectionTime, int latency, int bandwidth)
+ {
+ s.setPerformancePreferences( connectionTime, latency, bandwidth );
+ }
+ */
+
+ public void bind(SocketAddress bindpoint) throws IOException {
+ s.bind(bindpoint);
+ }
+
+ public void close() throws IOException {
+ s.close();
+ }
+
+ public void connect(SocketAddress endpoint) throws IOException {
+ s.connect(endpoint);
+ }
+
+ public void connect(SocketAddress endpoint, int timeout) throws IOException {
+ s.connect(endpoint, timeout);
+ }
+
+ public InputStream getInputStream() throws IOException {
+ return s.getInputStream();
+ }
+
+ public OutputStream getOutputStream() throws IOException {
+ return s.getOutputStream();
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/SSLWrapperFactory.java b/src/java/org/apache/commons/ssl/SSLWrapperFactory.java
new file mode 100644
index 0000000..3848259
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/SSLWrapperFactory.java
@@ -0,0 +1,109 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/SSLWrapperFactory.java $
+ * $Revision: 129 $
+ * $Date: 2007-11-14 19:21:33 -0800 (Wed, 14 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSocket;
+import java.io.IOException;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 19-Sep-2006
+ */
+public interface SSLWrapperFactory {
+
+ /**
+ * Wraps an SSLSSocket.
+ *
+ * @param s SSLSocket to wrap.
+ * @return The new wrapped SSLSocket.
+ * @throws IOException if wrapping failed
+ */
+ public SSLSocket wrap(SSLSocket s) throws IOException;
+
+ /**
+ * Wraps an SSLServerSocket.
+ *
+ * @param s The SSLServerSocket to wrap.
+ * @param ssl The SSL object that created the SSLServerSocket.
+ * This way some important commons-ssl config can be applied
+ * to the returned socket.
+ * @return The new wrapped SSLServerSocket.
+ * @throws IOException if wrapping failed
+ */
+ public SSLServerSocket wrap(SSLServerSocket s, SSL ssl)
+ throws IOException;
+
+
+ /**
+ * NO_WRAP doesn't wrap the SSLSocket. It does wrap the SSLServerSocket
+ * so that we can do the usual housekeeping after accept() that we like to
+ * do on every socket. E.g. setSoTimeout, setEnabledProtocols,
+ * setEnabledCiphers, setUseClientMode, and the hostname verifier (which
+ * should be very rare on SSLServerSockets!).
+ */
+ public final static SSLWrapperFactory NO_WRAP = new SSLWrapperFactory() {
+ // Notice! No wrapping!
+ public SSLSocket wrap(SSLSocket s) { return s; }
+
+ // We still wrap the ServerSocket, but we don't wrap the result of the
+ // the accept() call.
+ public SSLServerSocket wrap(SSLServerSocket s, SSL ssl)
+ throws IOException {
+ // Can't wrap with Java 1.3 because SSLServerSocket's constructor has
+ // default access instead of protected access in Java 1.3.
+ boolean java13 = JavaImpl.isJava13();
+ return java13 ? s : new SSLServerSocketWrapper(s, ssl, this);
+ }
+ };
+
+ /**
+ * DUMB_WRAP is useful to make sure that wrapping the sockets doesn't break
+ * anything. It doesn't actually do anything interesting in its wrapped
+ * implementations.
+ */
+ public final static SSLWrapperFactory DUMB_WRAP = new SSLWrapperFactory() {
+ public SSLSocket wrap(SSLSocket s) { return new SSLSocketWrapper(s); }
+
+ public SSLServerSocket wrap(SSLServerSocket s, SSL ssl)
+ throws IOException {
+ // Can't wrap with Java 1.3 because SSLServerSocket's constructor has
+ // default access instead of protected access in Java 1.3.
+ boolean java13 = JavaImpl.isJava13();
+ return java13 ? s : new SSLServerSocketWrapper(s, ssl, this);
+ }
+ };
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/TomcatServerXML.java b/src/java/org/apache/commons/ssl/TomcatServerXML.java
new file mode 100644
index 0000000..e9ccc5c
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/TomcatServerXML.java
@@ -0,0 +1,231 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/TomcatServerXML.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 22-Feb-2007
+ */
+public class TomcatServerXML {
+ private final static LogWrapper log = LogWrapper.getLogger(TomcatServerXML.class);
+
+ /**
+ * KeyMaterial extracted from Tomcat's conf/server.xml. There might be
+ * several KeyMaterials to extract if Tomcat has different SSL Certificates
+ * listening on different ports. This particular KeyMaterial will come from
+ * the lowest secure port that Tomcat is properly configured to open.
+ */
+ public final static KeyMaterial KEY_MATERIAL;
+
+ /**
+ * TrustMaterial extracted from Tomcat's conf/server.xml. There might be
+ * several TrustMaterials to extract if Tomcat has different SSL Certificates
+ * listening on different ports. This particular TrustMaterial will come
+ * from the lowest secure port that Tomcat is properly configured to open.
+ * </p><p>
+ * There's a good chance this will be set to TrustMaterial.DEFAULT (which
+ * use's the JVM's '$JAVA_HOME/jre/lib/security/cacerts' file).
+ * </p><p>
+ * Note: With SSLServerSockets, TrustMaterial only matters when the
+ * incoming client socket (SSLSocket) presents a client certificate.
+ * </p>
+ */
+ public final static TrustMaterial TRUST_MATERIAL;
+
+ /**
+ * new Integer( port ) --> KeyMaterial mapping of SSL Certificates found
+ * inside Tomcat's conf/server.xml file.
+ */
+ public final static SortedMap KEY_MATERIAL_BY_PORT;
+
+ /**
+ * new Integer( port ) --> TrustMaterial mapping of SSL configuration
+ * found inside Tomcat's conf/server.xml file.
+ * </p><p>
+ * Many of these will probably be TrustMaterial.DEFAULT (which uses the
+ * JVM's '$JAVA_HOME/jre/lib/security/cacerts' file).
+ * </p><p>
+ * Note: With SSLServerSockets, TrustMaterial only matters when the
+ * incoming client socket (SSLSocket) presents a client certificate.
+ * </p>
+ */
+ public final static SortedMap TRUST_MATERIAL_BY_PORT;
+
+ static {
+ String tomcatHome = System.getProperty("catalina.home");
+ String serverXML = tomcatHome + "/conf/server.xml";
+ TreeMap keyMap = new TreeMap();
+ TreeMap trustMap = new TreeMap();
+ InputStream in = null;
+ Document doc = null;
+ try {
+ if (tomcatHome != null) {
+ File f = new File(serverXML);
+ if (f.exists()) {
+ try {
+ in = new FileInputStream(serverXML);
+ }
+ catch (IOException ioe) {
+ // oh well, no soup for us.
+ log.warn("Commons-SSL failed to load Tomcat's [" + serverXML + "] " + ioe);
+ }
+ }
+ }
+ if (in != null) {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ try {
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ doc = db.parse(in);
+ }
+ catch (Exception e) {
+ log.warn("Commons-SSL failed to parse Tomcat's [" + serverXML + "] " + e);
+ }
+ }
+ if (doc != null) {
+ loadTomcatConfig(doc, keyMap, trustMap);
+ }
+ }
+ finally {
+ if (in != null) {
+ try { in.close(); } catch (Exception e) { /* . */ }
+ }
+ }
+ KEY_MATERIAL_BY_PORT = Collections.unmodifiableSortedMap(keyMap);
+ TRUST_MATERIAL_BY_PORT = Collections.unmodifiableSortedMap(trustMap);
+
+ KeyMaterial km = null;
+ TrustMaterial tm = null;
+ if (!keyMap.isEmpty()) {
+ km = (KeyMaterial) keyMap.get(keyMap.firstKey());
+ }
+ if (!trustMap.isEmpty()) {
+ tm = (TrustMaterial) trustMap.get(trustMap.firstKey());
+ }
+ KEY_MATERIAL = km;
+ TRUST_MATERIAL = tm;
+
+ }
+
+ private static void loadTomcatConfig(Document d, Map keyMap, Map trustMap) {
+ final String userHome = System.getProperty("user.home");
+ NodeList nl = d.getElementsByTagName("Connector");
+ for (int i = 0; i < nl.getLength(); i++) {
+ KeyMaterial km = null;
+ TrustMaterial tm = null;
+
+ Element element = (Element) nl.item(i);
+ String secure = element.getAttribute("secure");
+ String portString = element.getAttribute("port");
+ Integer port = null;
+ String pass;
+ try {
+ portString = portString != null ? portString.trim() : "";
+ port = new Integer(portString);
+ }
+ catch (NumberFormatException nfe) {
+ // oh well
+ }
+ if (port != null && Util.isYes(secure)) {
+ // Key Material
+ String keystoreFile = element.getAttribute("keystoreFile");
+ pass = element.getAttribute("keystorePass");
+ if (!element.hasAttribute("keystoreFile")) {
+ keystoreFile = userHome + "/.keystore";
+ }
+ if (!element.hasAttribute("keystorePass")) {
+ pass = "changeit";
+ }
+ char[] keystorePass = pass != null ? pass.toCharArray() : null;
+
+ // Trust Material
+ String truststoreFile = element.getAttribute("truststoreFile");
+ pass = element.getAttribute("truststorePass");
+ if (!element.hasAttribute("truststoreFile")) {
+ truststoreFile = null;
+ }
+ if (!element.hasAttribute("truststorePass")) {
+ pass = null;
+ }
+ char[] truststorePass = pass != null ? pass.toCharArray() : null;
+
+
+ if (keystoreFile == null) {
+ km = null;
+ } else {
+ try {
+ km = new KeyMaterial(keystoreFile, keystorePass);
+ }
+ catch (Exception e) {
+ log.warn("Commons-SSL failed to load [" + keystoreFile + "] " + e);
+ }
+ }
+ if (truststoreFile == null) {
+ tm = TrustMaterial.DEFAULT;
+ } else {
+ try {
+ tm = new TrustMaterial(truststoreFile, truststorePass);
+ }
+ catch (Exception e) {
+ log.warn("Commons-SSL failed to load [" + truststoreFile + "] " + e);
+ }
+ }
+
+ Object o = keyMap.put(port, km);
+ if (o != null) {
+ log.debug("Commons-SSL TomcatServerXML keyMap clobbered port: " + port);
+ }
+ o = trustMap.put(port, tm);
+ if (o != null) {
+ log.debug("Commons-SSL TomcatServerXML trustMap clobbered port: " + port);
+ }
+ }
+ }
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/TrustChain.java b/src/java/org/apache/commons/ssl/TrustChain.java
new file mode 100644
index 0000000..4ef8683
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/TrustChain.java
@@ -0,0 +1,206 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/TrustChain.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 27-Feb-2006
+ */
+public class TrustChain {
+ private final Set trustMaterial =
+ Collections.synchronizedSet(new HashSet());
+ private SortedSet x509Certificates = null;
+ private KeyStore unifiedKeyStore = null;
+
+ public TrustChain() {
+ }
+
+ public synchronized KeyStore getUnifiedKeyStore()
+ throws KeyStoreException, IOException, NoSuchAlgorithmException,
+ CertificateException {
+
+ // x509Certificates serves as our "cache available" indicator.
+ if (x509Certificates != null) {
+ return unifiedKeyStore;
+ }
+
+ // First, extract all the X509Certificates from this TrustChain.
+ this.x509Certificates = new TreeSet(Certificates.COMPARE_BY_EXPIRY);
+ Iterator it = trustMaterial.iterator();
+ while (it.hasNext()) {
+ TrustMaterial tm = (TrustMaterial) it.next();
+ KeyStore ks = tm.getKeyStore();
+ if (ks != null) {
+ Enumeration en = ks.aliases();
+ while (en.hasMoreElements()) {
+ String alias = (String) en.nextElement();
+ if (ks.isCertificateEntry(alias)) {
+ X509Certificate cert;
+ cert = (X509Certificate) ks.getCertificate(alias);
+ if (!x509Certificates.contains(cert)) {
+ x509Certificates.add(cert);
+ }
+ }
+ }
+ }
+ }
+
+ // Now that the X509Certificates are extracted, create the unified
+ // keystore.
+ it = x509Certificates.iterator();
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ ks.load(null, null);
+ int count = 0;
+ while (it.hasNext()) {
+ X509Certificate cert = (X509Certificate) it.next();
+ // The "count" should keep the aliases unique (is that important?)
+ String alias = "commons-ssl-" + count;
+ ks.setCertificateEntry(alias, cert);
+ count++;
+ }
+ this.unifiedKeyStore = ks;
+ return unifiedKeyStore;
+ }
+
+ public synchronized void addTrustMaterial(TrustChain tc) {
+ this.x509Certificates = null; // invalidate cache
+ if (tc instanceof TrustMaterial) {
+ trustMaterial.add(tc);
+ }
+ // If duplicates are added, the Set will remove them.
+ trustMaterial.addAll(tc.trustMaterial);
+ }
+
+ public boolean contains(TrustChain tc) {
+ if (tc instanceof TrustMaterial) {
+ return trustMaterial.contains(tc);
+ } else {
+ return trustMaterial.containsAll(tc.trustMaterial);
+ }
+ }
+
+ public boolean contains(X509Certificate cert)
+ throws KeyStoreException, IOException, NoSuchAlgorithmException,
+ CertificateException {
+ return getCertificates().contains(cert);
+ }
+
+ public Object getTrustManagerFactory()
+ throws NoSuchAlgorithmException, KeyStoreException, IOException,
+ CertificateException {
+ KeyStore uks = getUnifiedKeyStore();
+ if (uks != null) {
+ return JavaImpl.newTrustManagerFactory(uks);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * @return Array of TrustManager[] - presumably these will be dropped into
+ * a call to SSLContext.init(). Note: returns null if this
+ * TrustChain doesn't contain anything to trust.
+ * @throws NoSuchAlgorithmException serious problems
+ * @throws KeyStoreException serious problems
+ * @throws IOException serious problems
+ * @throws CertificateException serious problems
+ */
+ public Object[] getTrustManagers()
+ throws NoSuchAlgorithmException, KeyStoreException, IOException,
+ CertificateException {
+ Object tmf = getTrustManagerFactory();
+ return tmf != null ? JavaImpl.getTrustManagers(tmf) : null;
+ }
+
+ /**
+ * @return All X509Certificates contained in this TrustChain as a SortedSet.
+ * The X509Certificates are sorted based on expiry date.
+ * <p/>
+ * See org.apache.commons.ssl.Certificates.COMPARE_BY_EXPIRY.
+ * @throws KeyStoreException serious problems
+ * @throws IOException serious problems
+ * @throws NoSuchAlgorithmException serious problems
+ * @throws CertificateException serious problems
+ */
+ public synchronized SortedSet getCertificates()
+ throws KeyStoreException, IOException, NoSuchAlgorithmException,
+ CertificateException {
+ if (x509Certificates == null) {
+ getUnifiedKeyStore();
+ }
+ return Collections.unmodifiableSortedSet(x509Certificates);
+ }
+
+ /**
+ * @return Count of all X509Certificates contained in this TrustChain.
+ * @throws KeyStoreException
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ */
+ public synchronized int getSize()
+ throws KeyStoreException, IOException, NoSuchAlgorithmException,
+ CertificateException {
+ return getCertificates().size();
+ }
+
+ /**
+ * @return Count of all X509Certificates contained in this TrustChain.
+ * @throws KeyStoreException
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ */
+ public synchronized boolean isEmpty()
+ throws KeyStoreException, IOException, NoSuchAlgorithmException,
+ CertificateException {
+ return getCertificates().isEmpty();
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/TrustMaterial.java b/src/java/org/apache/commons/ssl/TrustMaterial.java
new file mode 100644
index 0000000..79caceb
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/TrustMaterial.java
@@ -0,0 +1,272 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/TrustMaterial.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Iterator;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 27-Feb-2006
+ */
+public class TrustMaterial extends TrustChain {
+ final static int SIMPLE_TRUST_TYPE_TRUST_ALL = 1;
+ final static int SIMPLE_TRUST_TYPE_TRUST_THIS_JVM = 2;
+
+ /** Might be null if "$JAVA_HOME/jre/lib/security/cacerts" doesn't exist. */
+ public final static TrustMaterial CACERTS;
+
+ /** Might be null if "$JAVA_HOME/jre/lib/security/jssecacerts" doesn't exist. */
+ public final static TrustMaterial JSSE_CACERTS;
+
+ /**
+ * Should never be null (unless both CACERTS and JSSE_CACERTS are not
+ * present???). Is either CACERTS or JSSE_CACERTS. Priority given to
+ * JSSE_CACERTS, but 99.9% of the time it's CACERTS, since JSSE_CACERTS
+ * is almost never present.
+ */
+ public final static TrustMaterial DEFAULT;
+
+ static {
+ JavaImpl.load();
+ String javaHome = System.getProperty("java.home");
+ String pathToCacerts = javaHome + "/lib/security/cacerts";
+ String pathToJSSECacerts = javaHome + "/lib/security/jssecacerts";
+ TrustMaterial cacerts = null;
+ TrustMaterial jssecacerts = null;
+ try {
+ File f = new File(pathToCacerts);
+ if (f.exists()) {
+ cacerts = new TrustMaterial(pathToCacerts);
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ try {
+ File f = new File(pathToJSSECacerts);
+ if (f.exists()) {
+ jssecacerts = new TrustMaterial(pathToJSSECacerts);
+ }
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ CACERTS = cacerts;
+ JSSE_CACERTS = jssecacerts;
+ if (JSSE_CACERTS != null) {
+ DEFAULT = JSSE_CACERTS;
+ } else {
+ DEFAULT = CACERTS;
+ }
+ }
+
+ public final static TrustMaterial TRUST_ALL =
+ new TrustMaterial(SIMPLE_TRUST_TYPE_TRUST_ALL);
+
+ public final static TrustMaterial TRUST_THIS_JVM =
+ new TrustMaterial(SIMPLE_TRUST_TYPE_TRUST_THIS_JVM);
+
+ public final int simpleTrustType;
+ private final KeyStore jks;
+
+ private TrustMaterial(int simpleTrustType) {
+ this(null, simpleTrustType);
+ }
+
+ TrustMaterial(KeyStore jks, int simpleTrustType) {
+ if (jks == null && simpleTrustType != 0) {
+ // Just use CACERTS as a place holder, since Java 5 and 6 seem to get
+ // upset when we hand SSLContext null TrustManagers. See
+ // Java14.initSSL(), which despite its name, is also used
+ // with Java5 and Java6.
+ this.jks = CACERTS != null ? CACERTS.jks : JSSE_CACERTS.jks;
+ } else {
+ this.jks = jks;
+ }
+ addTrustMaterial(this);
+ this.simpleTrustType = simpleTrustType;
+ }
+
+ public TrustMaterial(Collection x509Certs)
+ throws GeneralSecurityException, IOException {
+ KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
+ ks.load(null, null);
+ loadCerts(ks, x509Certs);
+ this.jks = ks;
+ addTrustMaterial(this);
+
+ // We're not a simple trust type, so set value to 0.
+ // Only TRUST_ALL and TRUST_THIS_JVM are simple trust types.
+ this.simpleTrustType = 0;
+ }
+
+ public TrustMaterial(X509Certificate x509Cert)
+ throws GeneralSecurityException, IOException {
+ this(Collections.singleton(x509Cert));
+ }
+
+ public TrustMaterial(X509Certificate[] x509Certs)
+ throws GeneralSecurityException, IOException {
+ this(Arrays.asList(x509Certs));
+ }
+
+ public TrustMaterial(byte[] pemBase64)
+ throws GeneralSecurityException, IOException {
+ this(pemBase64, null);
+ }
+
+ public TrustMaterial(InputStream pemBase64)
+ throws GeneralSecurityException, IOException {
+ this(Util.streamToBytes(pemBase64));
+ }
+
+ public TrustMaterial(String pathToPemFile)
+ throws GeneralSecurityException, IOException {
+ this(new FileInputStream(pathToPemFile));
+ }
+
+ public TrustMaterial(File pemFile)
+ throws GeneralSecurityException, IOException {
+ this(new FileInputStream(pemFile));
+ }
+
+ public TrustMaterial(URL urlToPemFile)
+ throws GeneralSecurityException, IOException {
+ this(urlToPemFile.openStream());
+ }
+
+ public TrustMaterial(String pathToJksFile, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(new File(pathToJksFile), password);
+ }
+
+ public TrustMaterial(File jksFile, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(new FileInputStream(jksFile), password);
+ }
+
+ public TrustMaterial(URL urlToJKS, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(urlToJKS.openStream(), password);
+ }
+
+ public TrustMaterial(InputStream jks, char[] password)
+ throws GeneralSecurityException, IOException {
+ this(Util.streamToBytes(jks), password);
+ }
+
+
+ public TrustMaterial(byte[] jks, char[] password)
+ throws GeneralSecurityException, IOException {
+
+ KeyStoreBuilder.BuildResult br = KeyStoreBuilder.parse(jks, password);
+ if (br.jks != null) {
+ // If we've been given a keystore, just use that.
+ this.jks = br.jks;
+ } else {
+ // Otherwise we need to build a keystore from what we were given.
+ KeyStore ks = KeyStore.getInstance("jks");
+ if (br.chain != null && br.chain.length > 0) {
+ ks.load(null, password);
+ loadCerts(ks, Arrays.asList(br.chain));
+ }
+ this.jks = ks;
+ }
+
+ // Should validate our keystore to make sure it has at least ONE
+ // certificate entry:
+ KeyStore ks = this.jks;
+ boolean hasCertificates = false;
+ Enumeration en = ks.aliases();
+ while (en.hasMoreElements()) {
+ String alias = (String) en.nextElement();
+ if (ks.isCertificateEntry(alias)) {
+ hasCertificates = true;
+ break;
+ }
+ }
+ if (!hasCertificates) {
+ throw new KeyStoreException("TrustMaterial couldn't load any certificates to trust!");
+ }
+
+ // overwrite password
+ if (password != null && !(this instanceof KeyMaterial)) {
+ for (int i = 0; i < password.length; i++) {
+ password[i] = '*';
+ }
+ }
+ addTrustMaterial(this);
+
+ // We're not a simple trust type, so set value to 0.
+ // Only TRUST_ALL and TRUST_THIS_JVM are simple trust types.
+ this.simpleTrustType = 0;
+ }
+
+ public KeyStore getKeyStore() {
+ return jks;
+ }
+
+ private static void loadCerts(KeyStore ks, Collection certs)
+ throws KeyStoreException {
+ Iterator it = certs.iterator();
+ int count = 0;
+ while (it.hasNext()) {
+ X509Certificate cert = (X509Certificate) it.next();
+
+ // I could be fancy and parse out the CN field from the
+ // certificate's subject, but these names don't actually matter
+ // at all - I think they just have to be unique.
+ String cn = Certificates.getCN(cert);
+ String alias = cn + "_" + count;
+ ks.setCertificateEntry(alias, cert);
+ count++;
+ }
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/Util.java b/src/java/org/apache/commons/ssl/Util.java
new file mode 100644
index 0000000..d16cde8
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Util.java
@@ -0,0 +1,403 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Util.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 28-Feb-2006
+ */
+public class Util {
+ public final static int SIZE_KEY = 0;
+ public final static int LAST_READ_KEY = 1;
+
+ public static boolean isYes(String yesString) {
+ if (yesString == null) {
+ return false;
+ }
+ String s = yesString.trim().toUpperCase();
+ return "1".equals(s) || "YES".equals(s) || "TRUE".equals(s) ||
+ "ENABLE".equals(s) || "ENABLED".equals(s) || "Y".equals(s) ||
+ "ON".equals(s);
+ }
+
+ public static String trim(final String s) {
+ if (s == null || "".equals(s)) {
+ return s;
+ }
+ int i = 0;
+ int j = s.length() - 1;
+ while (isWhiteSpace(s.charAt(i))) {
+ i++;
+ }
+ while (isWhiteSpace(s.charAt(j))) {
+ j--;
+ }
+ return j >= i ? s.substring(i, j + 1) : "";
+ }
+
+ public static boolean isWhiteSpace(final char c) {
+ switch (c) {
+ case 0:
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\f':
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public static void pipeStream(InputStream in, OutputStream out)
+ throws IOException {
+ pipeStream(in, out, true);
+ }
+
+ public static void pipeStream(InputStream in, OutputStream out,
+ boolean autoClose)
+ throws IOException {
+ byte[] buf = new byte[4096];
+ IOException ioe = null;
+ try {
+ int bytesRead = in.read(buf);
+ while (bytesRead >= 0) {
+ if (bytesRead > 0) {
+ out.write(buf, 0, bytesRead);
+ }
+ bytesRead = in.read(buf);
+ }
+ }
+ finally {
+ // Probably it's best to let consumer call "close", but I'm usually
+ // the consumer, and I want to be lazy. [Julius, November 20th, 2006]
+ try { in.close(); } catch (IOException e) { ioe = e; }
+ if (autoClose) {
+ try { out.close(); } catch (IOException e) { ioe = e; }
+ }
+ }
+ if (ioe != null) {
+ throw ioe;
+ }
+ }
+
+ public static byte[] streamToBytes(final ByteArrayInputStream in,
+ int maxLength) {
+ byte[] buf = new byte[maxLength];
+ int[] status = fill(buf, 0, in);
+ int size = status[SIZE_KEY];
+ if (buf.length != size) {
+ byte[] smallerBuf = new byte[size];
+ System.arraycopy(buf, 0, smallerBuf, 0, size);
+ buf = smallerBuf;
+ }
+ return buf;
+ }
+
+ public static byte[] streamToBytes(final InputStream in, int maxLength)
+ throws IOException {
+ byte[] buf = new byte[maxLength];
+ int[] status = fill(buf, 0, in);
+ int size = status[SIZE_KEY];
+ if (buf.length != size) {
+ byte[] smallerBuf = new byte[size];
+ System.arraycopy(buf, 0, smallerBuf, 0, size);
+ buf = smallerBuf;
+ }
+ return buf;
+ }
+
+ public static byte[] streamToBytes(final InputStream in) throws IOException {
+ byte[] buf = new byte[4096];
+ try {
+ int[] status = fill(buf, 0, in);
+ int size = status[SIZE_KEY];
+ int lastRead = status[LAST_READ_KEY];
+ while (lastRead != -1) {
+ buf = resizeArray(buf);
+ status = fill(buf, size, in);
+ size = status[SIZE_KEY];
+ lastRead = status[LAST_READ_KEY];
+ }
+ if (buf.length != size) {
+ byte[] smallerBuf = new byte[size];
+ System.arraycopy(buf, 0, smallerBuf, 0, size);
+ buf = smallerBuf;
+ }
+ }
+ finally {
+ in.close();
+ }
+ return buf;
+ }
+
+ public static byte[] streamToBytes(final ByteArrayInputStream in) {
+ byte[] buf = new byte[4096];
+ int[] status = fill(buf, 0, in);
+ int size = status[SIZE_KEY];
+ int lastRead = status[LAST_READ_KEY];
+ while (lastRead != -1) {
+ buf = resizeArray(buf);
+ status = fill(buf, size, in);
+ size = status[SIZE_KEY];
+ lastRead = status[LAST_READ_KEY];
+ }
+ if (buf.length != size) {
+ byte[] smallerBuf = new byte[size];
+ System.arraycopy(buf, 0, smallerBuf, 0, size);
+ buf = smallerBuf;
+ }
+ // in.close(); <-- this is a no-op on ByteArrayInputStream.
+ return buf;
+ }
+
+ public static int[] fill(final byte[] buf, final int offset,
+ final InputStream in)
+ throws IOException {
+ int read = in.read(buf, offset, buf.length - offset);
+ int lastRead = read;
+ if (read == -1) {
+ read = 0;
+ }
+ while (lastRead != -1 && read + offset < buf.length) {
+ lastRead = in.read(buf, offset + read, buf.length - read - offset);
+ if (lastRead != -1) {
+ read += lastRead;
+ }
+ }
+ return new int[]{offset + read, lastRead};
+ }
+
+ public static int[] fill(final byte[] buf, final int offset,
+ final ByteArrayInputStream in) {
+ int read = in.read(buf, offset, buf.length - offset);
+ int lastRead = read;
+ if (read == -1) {
+ read = 0;
+ }
+ while (lastRead != -1 && read + offset < buf.length) {
+ lastRead = in.read(buf, offset + read, buf.length - read - offset);
+ if (lastRead != -1) {
+ read += lastRead;
+ }
+ }
+ return new int[]{offset + read, lastRead};
+ }
+
+ public static byte[] resizeArray(final byte[] bytes) {
+ byte[] biggerBytes = new byte[bytes.length * 2];
+ System.arraycopy(bytes, 0, biggerBytes, 0, bytes.length);
+ return biggerBytes;
+ }
+
+ public static String pad(String s, final int length, final boolean left) {
+ if (s == null) {
+ s = "";
+ }
+ int diff = length - s.length();
+ if (diff == 0) {
+ return s;
+ } else if (diff > 0) {
+ StringBuffer sb = new StringBuffer();
+ if (left) {
+ for (int i = 0; i < diff; i++) {
+ sb.append(' ');
+ }
+ }
+ sb.append(s);
+ if (!left) {
+ for (int i = 0; i < diff; i++) {
+ sb.append(' ');
+ }
+ }
+ return sb.toString();
+ } else {
+ return s;
+ }
+ }
+
+ public static Map parseArgs(final String[] cargs) {
+ Map args = new TreeMap();
+ Map ARGS_MATCH = Ping.ARGS_MATCH;
+
+ int l = cargs.length;
+ final String[] EMPTY_VALUES = {""};
+ for (int i = 0; i < l; i++) {
+ String k = cargs[i];
+ Ping.Arg a = (Ping.Arg) ARGS_MATCH.get(k);
+ if (l > i + 1) {
+ String v = cargs[++i];
+ while (ARGS_MATCH.containsKey(v)) {
+ args.put(a, EMPTY_VALUES);
+ a = (Ping.Arg) ARGS_MATCH.get(v);
+ v = "";
+ if (l > i + 1) {
+ v = cargs[++i];
+ }
+ }
+ String[] values = new String[1];
+ values[0] = v;
+ args.put(a, values);
+ if (l > i + 1 && !ARGS_MATCH.containsKey(cargs[i + 1])) {
+ LinkedList list = new LinkedList();
+ list.add(v);
+ while (l > i + 1 && !ARGS_MATCH.containsKey(cargs[i + 1])) {
+ v = cargs[++i];
+ list.add(v);
+ }
+ args.put(a, list.toArray(new String[list.size()]));
+ }
+ } else {
+ args.put(a, EMPTY_VALUES);
+ }
+ }
+ return args;
+ }
+
+ public static String readLine(final InputStream in) throws IOException {
+ StringBuffer buf = new StringBuffer(64);
+ int b = in.read();
+ while (b != -1) {
+ char c = (char) b;
+ if (c == '\n' || c == '\r') {
+ if (buf.length() >= 1) {
+ return buf.toString();
+ }
+ } else {
+ buf.append(c);
+ }
+ b = in.read();
+ }
+ return buf.length() >= 1 ? buf.toString() : null;
+ }
+
+ public static String readLine(final ByteArrayInputStream in) {
+ StringBuffer buf = new StringBuffer(64);
+ int b = in.read();
+ while (b != -1) {
+ char c = (char) b;
+ if (c == '\n' || c == '\r') {
+ if (buf.length() >= 1) {
+ return buf.toString();
+ }
+ } else {
+ buf.append(c);
+ }
+ b = in.read();
+ }
+ return buf.length() >= 1 ? buf.toString() : null;
+ }
+
+ public static HostPort toAddress(final String target,
+ final int defaultPort)
+ throws UnknownHostException {
+ String host = target;
+ int port = defaultPort;
+ StringTokenizer st = new StringTokenizer(target, ":");
+ if (st.hasMoreTokens()) {
+ host = st.nextToken().trim();
+ }
+ if (st.hasMoreTokens()) {
+ port = Integer.parseInt(st.nextToken().trim());
+ }
+ if (st.hasMoreTokens()) {
+ throw new IllegalArgumentException("Invalid host: " + target);
+ }
+ return new HostPort(host, port);
+ }
+
+ public static String cipherToAuthType(String cipher) {
+ if (cipher == null) {
+ return null;
+ }
+
+ // SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA ==> "DHE_DSS_EXPORT"
+ // SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA ==> "DHE_DSS"
+ // SSL_RSA_WITH_3DES_EDE_CBC_SHA ==> "RSA"
+
+ StringTokenizer st = new StringTokenizer(cipher.trim(), "_");
+ if (st.hasMoreTokens()) {
+ st.nextToken(); // always skip first token
+ }
+ if (st.hasMoreTokens()) {
+ String tok = st.nextToken();
+ StringBuffer buf = new StringBuffer();
+ buf.append(tok);
+ if (st.hasMoreTokens()) {
+ tok = st.nextToken();
+ while (!"WITH".equalsIgnoreCase(tok)) {
+ buf.append('_');
+ buf.append(tok);
+ tok = st.nextToken();
+ }
+ }
+ return buf.toString();
+ }
+ throw new IllegalArgumentException("not a valid cipher: " + cipher);
+ }
+
+
+ public static void main(String[] args) throws Exception {
+ String s = "line1\n\rline2\n\rline3";
+ InputStream in = new ByteArrayInputStream(s.getBytes());
+ String line = readLine(in);
+ while (line != null) {
+ System.out.println(line);
+ line = readLine(in);
+ }
+
+ System.out.println("--------- test 2 ----------");
+
+ s = "line1\n\rline2\n\rline3\n\r\n\r";
+ in = new ByteArrayInputStream(s.getBytes());
+ line = readLine(in);
+ while (line != null) {
+ System.out.println(line);
+ line = readLine(in);
+ }
+
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/Version.java b/src/java/org/apache/commons/ssl/Version.java
new file mode 100644
index 0000000..0cb3d2e
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/Version.java
@@ -0,0 +1,197 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Version.java $
+ * $Revision: 130 $
+ * $Date: 2007-11-14 19:24:15 -0800 (Wed, 14 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+
+/**
+ * Extracts tagged version from a subversion $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Version.java $ property, and prints it
+ * out nicely on standard out.
+ * <p/>
+ * e.g. If this version came from /tags/commons-ssl-0_3_9/, then Version.java
+ * will print: "Version: 0.3.9" on standard out.
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 14-Nov-2007
+ */
+public class Version {
+ public static final String HEAD_URL = "$HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/Version.java $";
+ public static final String VERSION;
+ public static final String COMPILE_TIME;
+
+ static {
+ // Try to extract a clean version number from svn's HeadURL property:
+ String v = "UNKNOWN";
+ boolean fromBranch = false;
+ int x = HEAD_URL.lastIndexOf("/tags/");
+ if (x >= 0) {
+ int y = HEAD_URL.indexOf("/", x + "/tags/".length());
+ if (y >= 0) {
+ v = HEAD_URL.substring(x + "/tags/".length(), y);
+ }
+ v = v.replace('_', '.');
+ v = v.replace('-', '.');
+ } else if (HEAD_URL.indexOf("/trunk/") >= 0) {
+ v = "trunk";
+ } else if (HEAD_URL.indexOf("/branches/") >= 0) {
+ fromBranch = true;
+ x = HEAD_URL.indexOf("/branches/");
+ int y = HEAD_URL.indexOf("/", x + "/branches/".length());
+ if (y >= 0) {
+ v = HEAD_URL.substring(x + "/branches/".length(), y);
+ }
+ v = v.replace('_', '.');
+ v = v.replace('-', '.');
+ }
+
+ String V = v.toUpperCase();
+ x = V.indexOf("COMMONS.SSL.");
+ if (x >= 0) {
+ v = v.substring(x + "commons.ssl.".length());
+ }
+ VERSION = fromBranch ? "***Branch*** " + v : v;
+
+ // Try to calculate when jar file was compiled:
+ String s;
+ try {
+ s = CompileTime.getCompileTimeString(Version.class);
+ }
+ catch (NoClassDefFoundError e) {
+ s = null;
+ }
+ COMPILE_TIME = s;
+ }
+
+ public static String versionString() {
+ String v;
+ if (COMPILE_TIME != null) {
+ v = CompileTime.formatVersion(VERSION, COMPILE_TIME);
+ } else {
+ v = VERSION;
+ }
+ return "Version: " + v;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(versionString());
+ }
+
+ public String toString() {
+ return versionString();
+ }
+
+
+ /**
+ * Searches through a jar file to the find the most recent timestamp of
+ * all the class files.
+ */
+ private static class CompileTime {
+ private final static String PATTERN = ".jar!";
+ private final static String PREFIX = "file:";
+ private final static String DF_FORMAT = "zzz:yyyy-MM-dd/HH:mm:ss.SSS";
+ private final static DateFormat DF = new SimpleDateFormat(DF_FORMAT);
+
+ public static String getCompileTimeString(Class clazz) {
+ String s = clazz.getName();
+ s = "/" + s.replace('.', '/') + ".class";
+ return getCompileTimeString(s);
+ }
+
+ private static String getCompileTimeString(String resource) {
+ try {
+ Date d = getCompileTime(resource);
+ return d != null ? DF.format(d) : "[unknown]";
+ }
+ catch (IOException ioe) {
+ return ioe.toString();
+ }
+ }
+
+ public static Date getCompileTime(String resource) throws IOException {
+ URL url = CompileTime.class.getResource(resource);
+ if (url != null) {
+ String urlString = url.getFile();
+ String fileLocation;
+ int i = urlString.indexOf(PATTERN);
+ if (i > 0) {
+ int x = i + PATTERN.length() - 1;
+ fileLocation = urlString.substring(0, x);
+ if (fileLocation.startsWith(PREFIX)) {
+ fileLocation = fileLocation.substring(PREFIX.length());
+ }
+ JarFile jf = new JarFile(fileLocation);
+ long newestTime = 0;
+ Enumeration entries = jf.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = (JarEntry) entries.nextElement();
+ if (entry.getName().endsWith(".class")) {
+ newestTime = Math.max(newestTime, entry.getTime());
+ }
+ }
+ if (newestTime > 0) {
+ return new Date(newestTime);
+ }
+ } else {
+ File f = new File(urlString);
+ try {
+ return new Date(f.lastModified());
+ }
+ catch (Exception e) {
+ return null;
+ }
+ }
+ }
+ return null;
+ }
+
+ public static String formatVersion(String version, String compileTime) {
+ StringBuffer buf = new StringBuffer();
+ buf.append(version);
+ buf.append(" Compiled: [");
+ buf.append(compileTime);
+ buf.append("]");
+ return buf.toString();
+ }
+
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/X509CertificateChainBuilder.java b/src/java/org/apache/commons/ssl/X509CertificateChainBuilder.java
new file mode 100644
index 0000000..204bf3a
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/X509CertificateChainBuilder.java
@@ -0,0 +1,181 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/X509CertificateChainBuilder.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl;
+
+import java.io.FileInputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SignatureException;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+
+/**
+ * Utility for building X509 certificate chains.
+ *
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 16-Nov-2005
+ */
+public class X509CertificateChainBuilder {
+ /**
+ * Builds the ordered certificate chain upwards from the startingPoint.
+ * Uses the supplied X509Certificate[] array to search for the parent,
+ * grandparent, and higher ancestor certificates. Stops at self-signed
+ * certificates, or when no ancestor can be found.
+ * <p/>
+ * Thanks to Joe Whitney for helping me put together a Big-O( m * n )
+ * implementation where m = the length of the final certificate chain.
+ * For a while I was using a Big-O( n ^ 2 ) implementation!
+ *
+ * @param startingPoint the X509Certificate for which we want to find
+ * ancestors
+ * @param certificates A pool of certificates in which we expect to find
+ * the startingPoint's ancestors.
+ * @return Array of X509Certificates, starting with the "startingPoint" and
+ * ending with highest level ancestor we could find in the supplied
+ * collection.
+ * @throws java.security.NoSuchAlgorithmException
+ * on unsupported signature
+ * algorithms.
+ * @throws java.security.InvalidKeyException
+ * on incorrect key.
+ * @throws java.security.NoSuchProviderException
+ * if there's no default provider.
+ * @throws java.security.cert.CertificateException
+ * on encoding errors.
+ */
+ public static X509Certificate[] buildPath(X509Certificate startingPoint,
+ Certificate[] certificates)
+ throws NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, CertificateException {
+ // Use a LinkedList, because we do lots of random it.remove() operations.
+ return buildPath(startingPoint,
+ new LinkedList(Arrays.asList(certificates)));
+ }
+
+ /**
+ * Builds the ordered certificate chain upwards from the startingPoint.
+ * Uses the supplied collection to search for the parent, grandparent,
+ * and higher ancestor certificates. Stops at self-signed certificates,
+ * or when no ancestor can be found.
+ * <p/>
+ * Thanks to Joe Whitney for helping me put together a Big-O( m * n )
+ * implementation where m = the length of the final certificate chain.
+ * For a while I was using a Big-O( n ^ 2 ) implementation!
+ *
+ * @param startingPoint the X509Certificate for which we want to find
+ * ancestors
+ * @param certificates A pool of certificates in which we expect to find
+ * the startingPoint's ancestors.
+ * @return Array of X509Certificates, starting with the "startingPoint" and
+ * ending with highest level ancestor we could find in the supplied
+ * collection.
+ * @throws java.security.NoSuchAlgorithmException
+ * on unsupported signature
+ * algorithms.
+ * @throws java.security.InvalidKeyException
+ * on incorrect key.
+ * @throws java.security.NoSuchProviderException
+ * if there's no default provider.
+ * @throws java.security.cert.CertificateException
+ * on encoding errors.
+ */
+ public static X509Certificate[] buildPath(X509Certificate startingPoint,
+ Collection certificates)
+ throws NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, CertificateException {
+ LinkedList path = new LinkedList();
+ path.add(startingPoint);
+ boolean nodeAdded = true;
+ // Keep looping until an iteration happens where we don't add any nodes
+ // to our path.
+ while (nodeAdded) {
+ // We'll start out by assuming nothing gets added. If something
+ // gets added, then nodeAdded will be changed to "true".
+ nodeAdded = false;
+ X509Certificate top = (X509Certificate) path.getLast();
+ try {
+ top.verify(top.getPublicKey());
+ // We're self-signed, so we're done!
+ break;
+ }
+ catch (SignatureException se) {
+ // Not self-signed. Let's see if we're signed by anyone in the
+ // collection.
+ Iterator it = certificates.iterator();
+ while (it.hasNext()) {
+ X509Certificate x509 = (X509Certificate) it.next();
+ try {
+ top.verify(x509.getPublicKey());
+ // No exception thrown, so we're signed by this guy!
+ path.add(x509);
+ nodeAdded = true;
+ it.remove(); // Not interested in this guy anymore!
+ break;
+ }
+ catch (SignatureException se2) {
+ // Not signed by this guy, let's try the next guy.
+ }
+ }
+ }
+ }
+
+ X509Certificate[] results = new X509Certificate[path.size()];
+ path.toArray(results);
+ return results;
+ }
+
+ public static void main(String[] args) throws Exception {
+ if (args.length < 2) {
+ System.out.println("Usage: [special-one] [file-with-certs]");
+ System.exit(1);
+ }
+ FileInputStream f1 = new FileInputStream(args[0]);
+ FileInputStream f2 = new FileInputStream(args[1]);
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ X509Certificate theOne = (X509Certificate) cf.generateCertificate(f1);
+ Collection c = cf.generateCertificates(f2);
+
+ X509Certificate[] path = buildPath(theOne, c);
+ for (int i = 0; i < path.length; i++) {
+ System.out.println(Certificates.getCN(path[i]));
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1Choice.java b/src/java/org/apache/commons/ssl/asn1/ASN1Choice.java
new file mode 100644
index 0000000..c08485e
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1Choice.java
@@ -0,0 +1,13 @@
+package org.apache.commons.ssl.asn1;
+
+/**
+ * Marker interface for CHOICE objects - if you implement this in a role your
+ * own object any attempt to tag the object implicitly will convert the tag to
+ * an explicit one as the encoding rules require.
+ * <p/>
+ * If you use this interface your class should also implement the getInstance
+ * pattern which takes a tag object and the tagging mode used.
+ */
+public interface ASN1Choice {
+ // marker interface
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1Encodable.java b/src/java/org/apache/commons/ssl/asn1/ASN1Encodable.java
new file mode 100644
index 0000000..99900cb
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1Encodable.java
@@ -0,0 +1,74 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public abstract class ASN1Encodable
+ implements DEREncodable {
+ public static final String DER = "DER";
+ public static final String BER = "BER";
+
+ public byte[] getEncoded()
+ throws IOException {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ aOut.writeObject(this);
+
+ return bOut.toByteArray();
+ }
+
+ public byte[] getEncoded(
+ String encoding)
+ throws IOException {
+ if (encoding.equals(DER)) {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(this);
+
+ return bOut.toByteArray();
+ }
+
+ return this.getEncoded();
+ }
+
+ /**
+ * Return the DER encoding of the object, null if the DER encoding can not be made.
+ *
+ * @return a DER byte array, null otherwise.
+ */
+ public byte[] getDEREncoded() {
+ try {
+ return this.getEncoded(DER);
+ }
+ catch (IOException e) {
+ return null;
+ }
+ }
+
+ public int hashCode() {
+ return this.toASN1Object().hashCode();
+ }
+
+ public boolean equals(
+ Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof DEREncodable)) {
+ return false;
+ }
+
+ DEREncodable other = (DEREncodable) o;
+
+ return this.toASN1Object().equals(other.getDERObject());
+ }
+
+ public DERObject getDERObject() {
+ return this.toASN1Object();
+ }
+
+ public abstract DERObject toASN1Object();
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1EncodableVector.java b/src/java/org/apache/commons/ssl/asn1/ASN1EncodableVector.java
new file mode 100644
index 0000000..b769758
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1EncodableVector.java
@@ -0,0 +1,10 @@
+package org.apache.commons.ssl.asn1;
+
+/** the parent class for this will eventually disappear. Use this one! */
+public class ASN1EncodableVector
+ extends DEREncodableVector {
+ // migrating from DEREncodeableVector
+ public ASN1EncodableVector() {
+
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1Generator.java b/src/java/org/apache/commons/ssl/asn1/ASN1Generator.java
new file mode 100644
index 0000000..b39d994
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1Generator.java
@@ -0,0 +1,13 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.OutputStream;
+
+public abstract class ASN1Generator {
+ protected OutputStream _out;
+
+ public ASN1Generator(OutputStream out) {
+ _out = out;
+ }
+
+ public abstract OutputStream getRawOutputStream();
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1InputStream.java b/src/java/org/apache/commons/ssl/asn1/ASN1InputStream.java
new file mode 100644
index 0000000..e68c231
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1InputStream.java
@@ -0,0 +1,420 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+
+/**
+ * a general purpose ASN.1 decoder - note: this class differs from the
+ * others in that it returns null after it has read the last object in
+ * the stream. If an ASN.1 NULL is encountered a DER/BER Null object is
+ * returned.
+ */
+public class ASN1InputStream
+ extends FilterInputStream
+ implements DERTags {
+ private static final DERObject END_OF_STREAM = new DERObject() {
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ throw new IOException("Eeek!");
+ }
+ public int hashCode() {
+ return 0;
+ }
+ public boolean equals(
+ Object o) {
+ return o == this;
+ }
+ };
+
+ boolean eofFound = false;
+ int limit = Integer.MAX_VALUE;
+
+ public ASN1InputStream(
+ InputStream is) {
+ super(is);
+ }
+
+ /**
+ * Create an ASN1InputStream based on the input byte array. The length of DER objects in
+ * the stream is automatically limited to the length of the input array.
+ *
+ * @param input array containing ASN.1 encoded data.
+ */
+ public ASN1InputStream(
+ byte[] input) {
+ this(new ByteArrayInputStream(input), input.length);
+ }
+
+ /**
+ * Create an ASN1InputStream where no DER object will be longer than limit.
+ *
+ * @param input stream containing ASN.1 encoded data.
+ * @param limit maximum size of a DER encoded object.
+ */
+ public ASN1InputStream(
+ InputStream input,
+ int limit) {
+ super(input);
+ this.limit = limit;
+ }
+
+ protected int readLength()
+ throws IOException {
+ int length = read();
+ if (length < 0) {
+ throw new IOException("EOF found when length expected");
+ }
+
+ if (length == 0x80) {
+ return -1; // indefinite-length encoding
+ }
+
+ if (length > 127) {
+ int size = length & 0x7f;
+
+ if (size > 4) {
+ throw new IOException("DER length more than 4 bytes");
+ }
+
+ length = 0;
+ for (int i = 0; i < size; i++) {
+ int next = read();
+
+ if (next < 0) {
+ throw new IOException("EOF found reading length");
+ }
+
+ length = (length << 8) + next;
+ }
+
+ if (length < 0) {
+ throw new IOException("corrupted stream - negative length found");
+ }
+
+ if (length >= limit) // after all we must have read at least 1 byte
+ {
+ throw new IOException("corrupted stream - out of bounds length found");
+ }
+ }
+
+ return length;
+ }
+
+ protected void readFully(
+ byte[] bytes)
+ throws IOException {
+ int left = bytes.length;
+ int len;
+
+ if (left == 0) {
+ return;
+ }
+
+ while ((len = read(bytes, bytes.length - left, left)) > 0) {
+ if ((left -= len) == 0) {
+ return;
+ }
+ }
+
+ if (left != 0) {
+ throw new EOFException("EOF encountered in middle of object");
+ }
+ }
+
+ /** build an object given its tag and the number of bytes to construct it from. */
+ protected DERObject buildObject(
+ int tag,
+ int tagNo,
+ int length)
+ throws IOException {
+ if ((tag & APPLICATION) != 0) {
+ return new DERApplicationSpecific(tagNo, readDefiniteLengthFully(length));
+ }
+
+ boolean isConstructed = (tag & CONSTRUCTED) != 0;
+
+ if (isConstructed) {
+ switch (tag) {
+ case SEQUENCE | CONSTRUCTED:
+ return new DERSequence(buildDerEncodableVector(length));
+ case SET | CONSTRUCTED:
+ return new DERSet(buildDerEncodableVector(length), false);
+ case OCTET_STRING | CONSTRUCTED:
+ return buildDerConstructedOctetString(length);
+ default: {
+ //
+ // with tagged object tag number is bottom 5 bits
+ //
+ if ((tag & TAGGED) != 0) {
+ if (length == 0) // empty tag!
+ {
+ return new DERTaggedObject(false, tagNo, new DERSequence());
+ }
+
+ ASN1EncodableVector v = buildDerEncodableVector(length);
+
+ if (v.size() == 1) {
+ //
+ // explicitly tagged (probably!) - if it isn't we'd have to
+ // tell from the context
+ //
+ return new DERTaggedObject(tagNo, v.get(0));
+ }
+
+ return new DERTaggedObject(false, tagNo, new DERSequence(v));
+ }
+
+ return new DERUnknownTag(tag, readDefiniteLengthFully(length));
+ }
+ }
+ }
+
+ byte[] bytes = readDefiniteLengthFully(length);
+
+ switch (tag) {
+ case NULL:
+ return DERNull.INSTANCE;
+ case BOOLEAN:
+ return new DERBoolean(bytes);
+ case INTEGER:
+ return new DERInteger(bytes);
+ case ENUMERATED:
+ return new DEREnumerated(bytes);
+ case OBJECT_IDENTIFIER:
+ return new DERObjectIdentifier(bytes);
+ case BIT_STRING: {
+ int padBits = bytes[0];
+ byte[] data = new byte[bytes.length - 1];
+
+ System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
+
+ return new DERBitString(data, padBits);
+ }
+ case NUMERIC_STRING:
+ return new DERNumericString(bytes);
+ case UTF8_STRING:
+ return new DERUTF8String(bytes);
+ case PRINTABLE_STRING:
+ return new DERPrintableString(bytes);
+ case IA5_STRING:
+ return new DERIA5String(bytes);
+ case T61_STRING:
+ return new DERT61String(bytes);
+ case VISIBLE_STRING:
+ return new DERVisibleString(bytes);
+ case GENERAL_STRING:
+ return new DERGeneralString(bytes);
+ case UNIVERSAL_STRING:
+ return new DERUniversalString(bytes);
+ case BMP_STRING:
+ return new DERBMPString(bytes);
+ case OCTET_STRING:
+ return new DEROctetString(bytes);
+ case UTC_TIME:
+ return new DERUTCTime(bytes);
+ case GENERALIZED_TIME:
+ return new DERGeneralizedTime(bytes);
+ default: {
+ //
+ // with tagged object tag number is bottom 5 bits
+ //
+ if ((tag & TAGGED) != 0) {
+ if (bytes.length == 0) // empty tag!
+ {
+ return new DERTaggedObject(false, tagNo, DERNull.INSTANCE);
+ }
+
+ //
+ // simple type - implicit... return an octet string
+ //
+ return new DERTaggedObject(false, tagNo, new DEROctetString(bytes));
+ }
+
+ return new DERUnknownTag(tag, bytes);
+ }
+ }
+ }
+
+ private byte[] readDefiniteLengthFully(int length)
+ throws IOException {
+ byte[] bytes = new byte[length];
+ readFully(bytes);
+ return bytes;
+ }
+
+ /** read a string of bytes representing an indefinite length object. */
+ private byte[] readIndefiniteLengthFully()
+ throws IOException {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ int b, b1;
+
+ b1 = read();
+
+ while ((b = read()) >= 0) {
+ if (b1 == 0 && b == 0) {
+ break;
+ }
+
+ bOut.write(b1);
+ b1 = b;
+ }
+
+ return bOut.toByteArray();
+ }
+
+ private BERConstructedOctetString buildConstructedOctetString(DERObject sentinel)
+ throws IOException {
+ Vector octs = new Vector();
+ DERObject o;
+
+ while ((o = readObject()) != sentinel) {
+ octs.addElement(o);
+ }
+
+ return new BERConstructedOctetString(octs);
+ }
+
+ //
+ // yes, people actually do this...
+ //
+ private BERConstructedOctetString buildDerConstructedOctetString(int length)
+ throws IOException {
+ DefiniteLengthInputStream dIn = new DefiniteLengthInputStream(this, length);
+ ASN1InputStream aIn = new ASN1InputStream(dIn, length);
+
+ return aIn.buildConstructedOctetString(null);
+ }
+
+ private ASN1EncodableVector buildEncodableVector(DERObject sentinel)
+ throws IOException {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ DERObject o;
+
+ while ((o = readObject()) != sentinel) {
+ v.add(o);
+ }
+
+ return v;
+ }
+
+ private ASN1EncodableVector buildDerEncodableVector(int length)
+ throws IOException {
+ DefiniteLengthInputStream dIn = new DefiniteLengthInputStream(this, length);
+ ASN1InputStream aIn = new ASN1InputStream(dIn, length);
+
+ return aIn.buildEncodableVector(null);
+ }
+
+ public DERObject readObject()
+ throws IOException {
+ int tag = read();
+ if (tag == -1) {
+ if (eofFound) {
+ throw new EOFException("attempt to read past end of file.");
+ }
+
+ eofFound = true;
+
+ return null;
+ }
+
+ int tagNo = 0;
+
+ if ((tag & TAGGED) != 0 || (tag & APPLICATION) != 0) {
+ tagNo = readTagNumber(tag);
+ }
+
+ int length = readLength();
+
+ if (length < 0) // indefinite length method
+ {
+ switch (tag) {
+ case NULL:
+ return BERNull.INSTANCE;
+ case SEQUENCE | CONSTRUCTED:
+ return new BERSequence(buildEncodableVector(END_OF_STREAM));
+ case SET | CONSTRUCTED:
+ return new BERSet(buildEncodableVector(END_OF_STREAM), false);
+ case OCTET_STRING | CONSTRUCTED:
+ return buildConstructedOctetString(END_OF_STREAM);
+ default: {
+ //
+ // with tagged object tag number is bottom 5 bits
+ //
+ if ((tag & TAGGED) != 0) {
+ //
+ // simple type - implicit... return an octet string
+ //
+ if ((tag & CONSTRUCTED) == 0) {
+ byte[] bytes = readIndefiniteLengthFully();
+
+ return new BERTaggedObject(false, tagNo, new DEROctetString(bytes));
+ }
+
+ //
+ // either constructed or explicitly tagged
+ //
+ ASN1EncodableVector v = buildEncodableVector(END_OF_STREAM);
+
+ if (v.size() == 0) // empty tag!
+ {
+ return new DERTaggedObject(tagNo);
+ }
+
+ if (v.size() == 1) {
+ //
+ // explicitly tagged (probably!) - if it isn't we'd have to
+ // tell from the context
+ //
+ return new BERTaggedObject(tagNo, v.get(0));
+ }
+
+ return new BERTaggedObject(false, tagNo, new BERSequence(v));
+ }
+
+ throw new IOException("unknown BER object encountered");
+ }
+ }
+ } else {
+ if (tag == 0 && length == 0) // end of contents marker.
+ {
+ return END_OF_STREAM;
+ }
+
+ return buildObject(tag, tagNo, length);
+ }
+ }
+
+ private int readTagNumber(int tag)
+ throws IOException {
+ int tagNo = tag & 0x1f;
+
+ if (tagNo == 0x1f) {
+ int b = read();
+
+ tagNo = 0;
+
+ while ((b >= 0) && ((b & 0x80) != 0)) {
+ tagNo |= (b & 0x7f);
+ tagNo <<= 7;
+ b = read();
+ }
+
+ if (b < 0) {
+ eofFound = true;
+ throw new EOFException("EOF found inside tag value.");
+ }
+
+ tagNo |= (b & 0x7f);
+ }
+
+ return tagNo;
+ }
+}
+
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1Null.java b/src/java/org/apache/commons/ssl/asn1/ASN1Null.java
new file mode 100644
index 0000000..7f56bbd
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1Null.java
@@ -0,0 +1,30 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** A NULL object. */
+public abstract class ASN1Null
+ extends ASN1Object {
+ public ASN1Null() {
+ }
+
+ public int hashCode() {
+ return 0;
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof ASN1Null)) {
+ return false;
+ }
+
+ return true;
+ }
+
+ abstract void encode(DEROutputStream out)
+ throws IOException;
+
+ public String toString() {
+ return "NULL";
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1Object.java b/src/java/org/apache/commons/ssl/asn1/ASN1Object.java
new file mode 100644
index 0000000..02a3930
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1Object.java
@@ -0,0 +1,34 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+public abstract class ASN1Object
+ extends DERObject {
+ /**
+ * Create a base ASN.1 object from a byte stream.
+ *
+ * @param data the byte stream to parse.
+ * @return the base ASN.1 object represented by the byte stream.
+ * @throws IOException if there is a problem parsing the data.
+ */
+ public static ASN1Object fromByteArray(byte[] data)
+ throws IOException {
+ ASN1InputStream aIn = new ASN1InputStream(data);
+
+ return (ASN1Object) aIn.readObject();
+ }
+
+ public final boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ return (o instanceof DEREncodable) && asn1Equals(((DEREncodable) o).getDERObject());
+ }
+
+ public abstract int hashCode();
+
+ abstract void encode(DEROutputStream out) throws IOException;
+
+ abstract boolean asn1Equals(DERObject o);
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1ObjectParser.java b/src/java/org/apache/commons/ssl/asn1/ASN1ObjectParser.java
new file mode 100644
index 0000000..ca2a576
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1ObjectParser.java
@@ -0,0 +1,55 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ASN1ObjectParser {
+ private int _baseTag;
+ private int _tagNumber;
+
+ private ASN1StreamParser _aIn;
+
+ protected ASN1ObjectParser(
+ int baseTag,
+ int tagNumber,
+ InputStream contentStream) {
+ _baseTag = baseTag;
+ _tagNumber = tagNumber;
+ _aIn = new ASN1StreamParser(contentStream);
+ }
+
+ /**
+ * Return the tag number for this object.
+ *
+ * @return the tag number.
+ */
+ int getTagNumber() {
+ return _tagNumber;
+ }
+
+ int getBaseTag() {
+ return _baseTag;
+ }
+
+ DEREncodable readObject()
+ throws IOException {
+ return _aIn.readObject();
+ }
+
+ ASN1EncodableVector readVector()
+ throws IllegalStateException {
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ DEREncodable obj;
+
+ try {
+ while ((obj = readObject()) != null) {
+ v.add(obj.getDERObject());
+ }
+ }
+ catch (IOException e) {
+ throw new IllegalStateException(e.getMessage());
+ }
+
+ return v;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1OctetString.java b/src/java/org/apache/commons/ssl/asn1/ASN1OctetString.java
new file mode 100644
index 0000000..10ab72e
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1OctetString.java
@@ -0,0 +1,137 @@
+package org.apache.commons.ssl.asn1;
+
+import org.apache.commons.ssl.util.Hex;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public abstract class ASN1OctetString
+ extends ASN1Object
+ implements ASN1OctetStringParser {
+ byte[] string;
+
+ /**
+ * return an Octet String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want.
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static ASN1OctetString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ /**
+ * return an Octet String from the given object.
+ *
+ * @param obj the object we want converted.
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1OctetString getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof ASN1OctetString) {
+ return (ASN1OctetString) obj;
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ if (obj instanceof ASN1Sequence) {
+ Vector v = new Vector();
+ Enumeration e = ((ASN1Sequence) obj).getObjects();
+
+ while (e.hasMoreElements()) {
+ v.addElement(e.nextElement());
+ }
+
+ return new BERConstructedOctetString(v);
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /** @param string the octets making up the octet string. */
+ public ASN1OctetString(
+ byte[] string) {
+ this.string = string;
+ }
+
+ public ASN1OctetString(
+ DEREncodable obj) {
+ try {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(obj);
+ dOut.close();
+
+ this.string = bOut.toByteArray();
+ }
+ catch (IOException e) {
+ throw new IllegalArgumentException("Error processing object : " + e.toString());
+ }
+ }
+
+ public InputStream getOctetStream() {
+ return new ByteArrayInputStream(string);
+ }
+
+ public ASN1OctetStringParser parser() {
+ return this;
+ }
+
+ public byte[] getOctets() {
+ return string;
+ }
+
+ public int hashCode() {
+ byte[] b = this.getOctets();
+ int value = 0;
+
+ for (int i = 0; i != b.length; i++) {
+ value ^= (b[i] & 0xff) << (i % 4);
+ }
+
+ return value;
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof ASN1OctetString)) {
+ return false;
+ }
+
+ ASN1OctetString other = (ASN1OctetString) o;
+
+ byte[] b1 = other.string;
+ byte[] b2 = this.string;
+
+ if (b1.length != b2.length) {
+ return false;
+ }
+
+ for (int i = 0; i != b1.length; i++) {
+ if (b1[i] != b2[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ abstract void encode(DEROutputStream out)
+ throws IOException;
+
+ public String toString() {
+ return "#" + Hex.encode(string);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1OctetStringParser.java b/src/java/org/apache/commons/ssl/asn1/ASN1OctetStringParser.java
new file mode 100644
index 0000000..b958534
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1OctetStringParser.java
@@ -0,0 +1,8 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.InputStream;
+
+public interface ASN1OctetStringParser
+ extends DEREncodable {
+ public InputStream getOctetStream();
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1OutputStream.java b/src/java/org/apache/commons/ssl/asn1/ASN1OutputStream.java
new file mode 100644
index 0000000..2cac08d
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1OutputStream.java
@@ -0,0 +1,26 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class ASN1OutputStream
+ extends DEROutputStream {
+ public ASN1OutputStream(
+ OutputStream os) {
+ super(os);
+ }
+
+ public void writeObject(
+ Object obj)
+ throws IOException {
+ if (obj == null) {
+ writeNull();
+ } else if (obj instanceof DERObject) {
+ ((DERObject) obj).encode(this);
+ } else if (obj instanceof DEREncodable) {
+ ((DEREncodable) obj).getDERObject().encode(this);
+ } else {
+ throw new IOException("object not ASN1Encodable");
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1Sequence.java b/src/java/org/apache/commons/ssl/asn1/ASN1Sequence.java
new file mode 100644
index 0000000..699edd1
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1Sequence.java
@@ -0,0 +1,183 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public abstract class ASN1Sequence
+ extends ASN1Object {
+ private Vector seq = new Vector();
+
+ /**
+ * return an ASN1Sequence from the given object.
+ *
+ * @param obj the object we want converted.
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1Sequence getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof ASN1Sequence) {
+ return (ASN1Sequence) obj;
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance");
+ }
+
+ /**
+ * Return an ASN1 sequence from a tagged object. There is a special
+ * case here, if an object appears to have been explicitly tagged on
+ * reading but we were expecting it to be implictly tagged in the
+ * normal course of events it indicates that we lost the surrounding
+ * sequence - so we need to add it back (this will happen if the tagged
+ * object is a sequence that contains other sequences). If you are
+ * dealing with implicitly tagged sequences you really <b>should</b>
+ * be using this method.
+ *
+ * @param obj the tagged object.
+ * @param explicit true if the object is meant to be explicitly tagged,
+ * false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static ASN1Sequence getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ if (explicit) {
+ if (!obj.isExplicit()) {
+ throw new IllegalArgumentException("object implicit - explicit expected.");
+ }
+
+ return (ASN1Sequence) obj.getObject();
+ } else {
+ //
+ // constructed object which appears to be explicitly tagged
+ // when it should be implicit means we have to add the
+ // surrounding sequence.
+ //
+ if (obj.isExplicit()) {
+ if (obj instanceof BERTaggedObject) {
+ return new BERSequence(obj.getObject());
+ } else {
+ return new DERSequence(obj.getObject());
+ }
+ } else {
+ if (obj.getObject() instanceof ASN1Sequence) {
+ return (ASN1Sequence) obj.getObject();
+ }
+ }
+ }
+
+ throw new IllegalArgumentException(
+ "unknown object in getInstanceFromTagged");
+ }
+
+ public Enumeration getObjects() {
+ return seq.elements();
+ }
+
+ public ASN1SequenceParser parser() {
+ final ASN1Sequence outer = this;
+
+ return new ASN1SequenceParser() {
+ private final int max = size();
+
+ private int index;
+
+ public DEREncodable readObject() throws IOException {
+ if (index == max) {
+ return null;
+ }
+
+ DEREncodable obj = getObjectAt(index++);
+ if (obj instanceof ASN1Sequence) {
+ return ((ASN1Sequence) obj).parser();
+ }
+ if (obj instanceof ASN1Set) {
+ return ((ASN1Set) obj).parser();
+ }
+
+ return obj;
+ }
+
+ public DERObject getDERObject() {
+ return outer;
+ }
+ };
+ }
+
+ /**
+ * return the object at the sequence postion indicated by index.
+ *
+ * @param index the sequence number (starting at zero) of the object
+ * @return the object at the sequence postion indicated by index.
+ */
+ public DEREncodable getObjectAt(
+ int index) {
+ return (DEREncodable) seq.elementAt(index);
+ }
+
+ /**
+ * return the number of objects in this sequence.
+ *
+ * @return the number of objects in this sequence.
+ */
+ public int size() {
+ return seq.size();
+ }
+
+ public int hashCode() {
+ Enumeration e = this.getObjects();
+ int hashCode = 0;
+
+ while (e.hasMoreElements()) {
+ Object o = e.nextElement();
+
+ if (o != null) {
+ hashCode ^= o.hashCode();
+ }
+ }
+
+ return hashCode;
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof ASN1Sequence)) {
+ return false;
+ }
+
+ ASN1Sequence other = (ASN1Sequence) o;
+
+ if (this.size() != other.size()) {
+ return false;
+ }
+
+ Enumeration s1 = this.getObjects();
+ Enumeration s2 = other.getObjects();
+
+ while (s1.hasMoreElements()) {
+ DERObject o1 = ((DEREncodable) s1.nextElement()).getDERObject();
+ DERObject o2 = ((DEREncodable) s2.nextElement()).getDERObject();
+
+ if (o1 == o2 || (o1 != null && o1.equals(o2))) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ protected void addObject(
+ DEREncodable obj) {
+ seq.addElement(obj);
+ }
+
+ abstract void encode(DEROutputStream out)
+ throws IOException;
+
+ public String toString() {
+ return seq.toString();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1SequenceParser.java b/src/java/org/apache/commons/ssl/asn1/ASN1SequenceParser.java
new file mode 100644
index 0000000..c64c93e
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1SequenceParser.java
@@ -0,0 +1,9 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+public interface ASN1SequenceParser
+ extends DEREncodable {
+ DEREncodable readObject()
+ throws IOException;
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1Set.java b/src/java/org/apache/commons/ssl/asn1/ASN1Set.java
new file mode 100644
index 0000000..549fc57
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1Set.java
@@ -0,0 +1,281 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+abstract public class ASN1Set
+ extends ASN1Object {
+ protected Vector set = new Vector();
+
+ /**
+ * return an ASN1Set from the given object.
+ *
+ * @param obj the object we want converted.
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static ASN1Set getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof ASN1Set) {
+ return (ASN1Set) obj;
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance");
+ }
+
+ /**
+ * Return an ASN1 set from a tagged object. There is a special
+ * case here, if an object appears to have been explicitly tagged on
+ * reading but we were expecting it to be implictly tagged in the
+ * normal course of events it indicates that we lost the surrounding
+ * set - so we need to add it back (this will happen if the tagged
+ * object is a sequence that contains other sequences). If you are
+ * dealing with implicitly tagged sets you really <b>should</b>
+ * be using this method.
+ *
+ * @param obj the tagged object.
+ * @param explicit true if the object is meant to be explicitly tagged
+ * false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static ASN1Set getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ if (explicit) {
+ if (!obj.isExplicit()) {
+ throw new IllegalArgumentException("object implicit - explicit expected.");
+ }
+
+ return (ASN1Set) obj.getObject();
+ } else {
+ //
+ // constructed object which appears to be explicitly tagged
+ // and it's really implicit means we have to add the
+ // surrounding sequence.
+ //
+ if (obj.isExplicit()) {
+ ASN1Set set = new DERSet(obj.getObject());
+
+ return set;
+ } else {
+ if (obj.getObject() instanceof ASN1Set) {
+ return (ASN1Set) obj.getObject();
+ }
+
+ //
+ // in this case the parser returns a sequence, convert it
+ // into a set.
+ //
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ if (obj.getObject() instanceof ASN1Sequence) {
+ ASN1Sequence s = (ASN1Sequence) obj.getObject();
+ Enumeration e = s.getObjects();
+
+ while (e.hasMoreElements()) {
+ v.add((DEREncodable) e.nextElement());
+ }
+
+ return new DERSet(v, false);
+ }
+ }
+ }
+
+ throw new IllegalArgumentException(
+ "unknown object in getInstanceFromTagged");
+ }
+
+ public ASN1Set() {
+ }
+
+ public Enumeration getObjects() {
+ return set.elements();
+ }
+
+ /**
+ * return the object at the set postion indicated by index.
+ *
+ * @param index the set number (starting at zero) of the object
+ * @return the object at the set postion indicated by index.
+ */
+ public DEREncodable getObjectAt(
+ int index) {
+ return (DEREncodable) set.elementAt(index);
+ }
+
+ /**
+ * return the number of objects in this set.
+ *
+ * @return the number of objects in this set.
+ */
+ public int size() {
+ return set.size();
+ }
+
+ public ASN1SetParser parser() {
+ final ASN1Set outer = this;
+
+ return new ASN1SetParser() {
+ private final int max = size();
+
+ private int index;
+
+ public DEREncodable readObject() throws IOException {
+ if (index == max) {
+ return null;
+ }
+
+ DEREncodable obj = getObjectAt(index++);
+ if (obj instanceof ASN1Sequence) {
+ return ((ASN1Sequence) obj).parser();
+ }
+ if (obj instanceof ASN1Set) {
+ return ((ASN1Set) obj).parser();
+ }
+
+ return obj;
+ }
+
+ public DERObject getDERObject() {
+ return outer;
+ }
+ };
+ }
+
+ public int hashCode() {
+ Enumeration e = this.getObjects();
+ int hashCode = 0;
+
+ while (e.hasMoreElements()) {
+ hashCode ^= e.nextElement().hashCode();
+ }
+
+ return hashCode;
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof ASN1Set)) {
+ return false;
+ }
+
+ ASN1Set other = (ASN1Set) o;
+
+ if (this.size() != other.size()) {
+ return false;
+ }
+
+ Enumeration s1 = this.getObjects();
+ Enumeration s2 = other.getObjects();
+
+ while (s1.hasMoreElements()) {
+ DERObject o1 = ((DEREncodable) s1.nextElement()).getDERObject();
+ DERObject o2 = ((DEREncodable) s2.nextElement()).getDERObject();
+
+ if (o1 == o2 || (o1 != null && o1.equals(o2))) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+
+ /** return true if a <= b (arrays are assumed padded with zeros). */
+ private boolean lessThanOrEqual(
+ byte[] a,
+ byte[] b) {
+ if (a.length <= b.length) {
+ for (int i = 0; i != a.length; i++) {
+ int l = a[i] & 0xff;
+ int r = b[i] & 0xff;
+
+ if (r > l) {
+ return true;
+ } else if (l > r) {
+ return false;
+ }
+ }
+
+ return true;
+ } else {
+ for (int i = 0; i != b.length; i++) {
+ int l = a[i] & 0xff;
+ int r = b[i] & 0xff;
+
+ if (r > l) {
+ return true;
+ } else if (l > r) {
+ return false;
+ }
+ }
+
+ return false;
+ }
+ }
+
+ private byte[] getEncoded(
+ DEREncodable obj) {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ try {
+ aOut.writeObject(obj);
+ }
+ catch (IOException e) {
+ throw new IllegalArgumentException("cannot encode object added to SET");
+ }
+
+ return bOut.toByteArray();
+ }
+
+ protected void sort() {
+ if (set.size() > 1) {
+ boolean swapped = true;
+ int lastSwap = set.size() - 1;
+
+ while (swapped) {
+ int index = 0;
+ int swapIndex = 0;
+ byte[] a = getEncoded((DEREncodable) set.elementAt(0));
+
+ swapped = false;
+
+ while (index != lastSwap) {
+ byte[] b = getEncoded((DEREncodable) set.elementAt(index + 1));
+
+ if (lessThanOrEqual(a, b)) {
+ a = b;
+ } else {
+ Object o = set.elementAt(index);
+
+ set.setElementAt(set.elementAt(index + 1), index);
+ set.setElementAt(o, index + 1);
+
+ swapped = true;
+ swapIndex = index;
+ }
+
+ index++;
+ }
+
+ lastSwap = swapIndex;
+ }
+ }
+ }
+
+ protected void addObject(
+ DEREncodable obj) {
+ set.addElement(obj);
+ }
+
+ abstract void encode(DEROutputStream out)
+ throws IOException;
+
+ public String toString() {
+ return set.toString();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1SetParser.java b/src/java/org/apache/commons/ssl/asn1/ASN1SetParser.java
new file mode 100644
index 0000000..00ffbd0
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1SetParser.java
@@ -0,0 +1,9 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+public interface ASN1SetParser
+ extends DEREncodable {
+ public DEREncodable readObject()
+ throws IOException;
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1StreamParser.java b/src/java/org/apache/commons/ssl/asn1/ASN1StreamParser.java
new file mode 100644
index 0000000..b1cd940
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1StreamParser.java
@@ -0,0 +1,193 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class ASN1StreamParser {
+ InputStream _in;
+
+ private int _limit;
+ private boolean _eofFound;
+
+ public ASN1StreamParser(
+ InputStream in) {
+ this(in, Integer.MAX_VALUE);
+ }
+
+ public ASN1StreamParser(
+ InputStream in,
+ int limit) {
+ this._in = in;
+ this._limit = limit;
+ }
+
+ public ASN1StreamParser(
+ byte[] encoding) {
+ this(new ByteArrayInputStream(encoding), encoding.length);
+ }
+
+ InputStream getParentStream() {
+ return _in;
+ }
+
+ private int readLength()
+ throws IOException {
+ int length = _in.read();
+ if (length < 0) {
+ throw new EOFException("EOF found when length expected");
+ }
+
+ if (length == 0x80) {
+ return -1; // indefinite-length encoding
+ }
+
+ if (length > 127) {
+ int size = length & 0x7f;
+
+ if (size > 4) {
+ throw new IOException("DER length more than 4 bytes");
+ }
+
+ length = 0;
+ for (int i = 0; i < size; i++) {
+ int next = _in.read();
+
+ if (next < 0) {
+ throw new EOFException("EOF found reading length");
+ }
+
+ length = (length << 8) + next;
+ }
+
+ if (length < 0) {
+ throw new IOException("corrupted stream - negative length found");
+ }
+
+ if (length >= _limit) // after all we must have read at least 1 byte
+ {
+ throw new IOException("corrupted stream - out of bounds length found");
+ }
+ }
+
+ return length;
+ }
+
+ public DEREncodable readObject()
+ throws IOException {
+ int tag = _in.read();
+ if (tag == -1) {
+ if (_eofFound) {
+ throw new EOFException("attempt to read past end of file.");
+ }
+
+ _eofFound = true;
+
+ return null;
+ }
+
+ //
+ // turn of looking for "00" while we resolve the tag
+ //
+ set00Check(false);
+
+ //
+ // calculate tag number
+ //
+ int baseTagNo = tag & ~DERTags.CONSTRUCTED;
+ int tagNo = baseTagNo;
+
+ if ((tag & DERTags.TAGGED) != 0) {
+ tagNo = tag & 0x1f;
+
+ //
+ // with tagged object tag number is bottom 5 bits, or stored at the start of the content
+ //
+ if (tagNo == 0x1f) {
+ tagNo = 0;
+
+ int b = _in.read();
+
+ while ((b >= 0) && ((b & 0x80) != 0)) {
+ tagNo |= (b & 0x7f);
+ tagNo <<= 7;
+ b = _in.read();
+ }
+
+ if (b < 0) {
+ _eofFound = true;
+
+ throw new EOFException("EOF encountered inside tag value.");
+ }
+
+ tagNo |= (b & 0x7f);
+ }
+ }
+
+ //
+ // calculate length
+ //
+ int length = readLength();
+
+ if (length < 0) // indefinite length
+ {
+ IndefiniteLengthInputStream indIn = new IndefiniteLengthInputStream(_in);
+
+ switch (baseTagNo) {
+ case DERTags.NULL:
+ while (indIn.read() >= 0) {
+ // make sure we skip to end of object
+ }
+ return BERNull.INSTANCE;
+ case DERTags.OCTET_STRING:
+ return new BEROctetStringParser(new ASN1ObjectParser(tag, tagNo, indIn));
+ case DERTags.SEQUENCE:
+ return new BERSequenceParser(new ASN1ObjectParser(tag, tagNo, indIn));
+ case DERTags.SET:
+ return new BERSetParser(new ASN1ObjectParser(tag, tagNo, indIn));
+ default:
+ return new BERTaggedObjectParser(tag, tagNo, indIn);
+ }
+ } else {
+ DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length);
+
+ switch (baseTagNo) {
+ case DERTags.INTEGER:
+ return new DERInteger(defIn.toByteArray());
+ case DERTags.NULL:
+ defIn.toByteArray(); // make sure we read to end of object bytes.
+ return DERNull.INSTANCE;
+ case DERTags.OBJECT_IDENTIFIER:
+ return new DERObjectIdentifier(defIn.toByteArray());
+ case DERTags.OCTET_STRING:
+ return new DEROctetString(defIn.toByteArray());
+ case DERTags.SEQUENCE:
+ return new DERSequence(loadVector(defIn, length)).parser();
+ case DERTags.SET:
+ return new DERSet(loadVector(defIn, length)).parser();
+ default:
+ return new BERTaggedObjectParser(tag, tagNo, defIn);
+ }
+ }
+ }
+
+ private void set00Check(boolean enabled) {
+ if (_in instanceof IndefiniteLengthInputStream) {
+ ((IndefiniteLengthInputStream) _in).setEofOn00(enabled);
+ }
+ }
+
+ private ASN1EncodableVector loadVector(InputStream in, int length)
+ throws IOException {
+ ASN1InputStream aIn = new ASN1InputStream(in, length);
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ DERObject obj;
+ while ((obj = aIn.readObject()) != null) {
+ v.add(obj);
+ }
+
+ return v;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1TaggedObject.java b/src/java/org/apache/commons/ssl/asn1/ASN1TaggedObject.java
new file mode 100644
index 0000000..063569b
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1TaggedObject.java
@@ -0,0 +1,177 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/**
+ * ASN.1 TaggedObject - in ASN.1 nottation this is any object proceeded by
+ * a [n] where n is some number - these are assume to follow the construction
+ * rules (as with sequences).
+ */
+public abstract class ASN1TaggedObject
+ extends ASN1Object
+ implements ASN1TaggedObjectParser {
+ int tagNo;
+ boolean empty = false;
+ boolean explicit = true;
+ DEREncodable obj = null;
+
+ static public ASN1TaggedObject getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ if (explicit) {
+ return (ASN1TaggedObject) obj.getObject();
+ }
+
+ throw new IllegalArgumentException("implicitly tagged tagged object");
+ }
+
+ static public ASN1TaggedObject getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof ASN1TaggedObject) {
+ return (ASN1TaggedObject) obj;
+ }
+
+ throw new IllegalArgumentException("unknown object in getInstance");
+ }
+
+ /**
+ * Create a tagged object in the explicit style.
+ *
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public ASN1TaggedObject(
+ int tagNo,
+ DEREncodable obj) {
+ this.explicit = true;
+ this.tagNo = tagNo;
+ this.obj = obj;
+ }
+
+ /**
+ * Create a tagged object with the style given by the value of explicit.
+ * <p>
+ * If the object implements ASN1Choice the tag style will always be changed
+ * to explicit in accordance with the ASN.1 encoding rules.
+ * </p>
+ *
+ * @param explicit true if the object is explicitly tagged.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public ASN1TaggedObject(
+ boolean explicit,
+ int tagNo,
+ DEREncodable obj) {
+ if (obj instanceof ASN1Choice) {
+ this.explicit = true;
+ } else {
+ this.explicit = explicit;
+ }
+
+ this.tagNo = tagNo;
+ this.obj = obj;
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof ASN1TaggedObject)) {
+ return false;
+ }
+
+ ASN1TaggedObject other = (ASN1TaggedObject) o;
+
+ if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit) {
+ return false;
+ }
+
+ if (obj == null) {
+ if (other.obj != null) {
+ return false;
+ }
+ } else {
+ if (!(obj.getDERObject().equals(other.obj.getDERObject()))) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int hashCode() {
+ int code = tagNo;
+
+ if (obj != null) {
+ code ^= obj.hashCode();
+ }
+
+ return code;
+ }
+
+ public int getTagNo() {
+ return tagNo;
+ }
+
+ /**
+ * return whether or not the object may be explicitly tagged.
+ * <p/>
+ * Note: if the object has been read from an input stream, the only
+ * time you can be sure if isExplicit is returning the true state of
+ * affairs is if it returns false. An implicitly tagged object may appear
+ * to be explicitly tagged, so you need to understand the context under
+ * which the reading was done as well, see getObject below.
+ */
+ public boolean isExplicit() {
+ return explicit;
+ }
+
+ public boolean isEmpty() {
+ return empty;
+ }
+
+ /**
+ * return whatever was following the tag.
+ * <p/>
+ * Note: tagged objects are generally context dependent if you're
+ * trying to extract a tagged object you should be going via the
+ * appropriate getInstance method.
+ */
+ public DERObject getObject() {
+ if (obj != null) {
+ return obj.getDERObject();
+ }
+
+ return null;
+ }
+
+ /**
+ * Return the object held in this tagged object as a parser assuming it has
+ * the type of the passed in tag. If the object doesn't have a parser
+ * associated with it, the base object is returned.
+ */
+ public DEREncodable getObjectParser(
+ int tag,
+ boolean isExplicit) {
+ switch (tag) {
+ case DERTags.SET:
+ return ASN1Set.getInstance(this, isExplicit).parser();
+ case DERTags.SEQUENCE:
+ return ASN1Sequence.getInstance(this, isExplicit).parser();
+ case DERTags.OCTET_STRING:
+ return ASN1OctetString.getInstance(this, isExplicit).parser();
+ }
+
+ if (isExplicit) {
+ return getObject();
+ }
+
+ throw new RuntimeException("implicit tagging not implemented for tag: " + tag);
+ }
+
+ abstract void encode(DEROutputStream out)
+ throws IOException;
+
+ public String toString() {
+ return "[" + tagNo + "]" + obj;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ASN1TaggedObjectParser.java b/src/java/org/apache/commons/ssl/asn1/ASN1TaggedObjectParser.java
new file mode 100644
index 0000000..7d24c6d
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ASN1TaggedObjectParser.java
@@ -0,0 +1,11 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+public interface ASN1TaggedObjectParser
+ extends DEREncodable {
+ public int getTagNo();
+
+ public DEREncodable getObjectParser(int tag, boolean isExplicit)
+ throws IOException;
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERConstructedOctetString.java b/src/java/org/apache/commons/ssl/asn1/BERConstructedOctetString.java
new file mode 100644
index 0000000..750de3b
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERConstructedOctetString.java
@@ -0,0 +1,137 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+
+public class BERConstructedOctetString
+ extends DEROctetString {
+ private static final int MAX_LENGTH = 1000;
+
+ /** convert a vector of octet strings into a single byte string */
+ static private byte[] toBytes(
+ Vector octs) {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ for (int i = 0; i != octs.size(); i++) {
+ try {
+ DEROctetString o = (DEROctetString) octs.elementAt(i);
+
+ bOut.write(o.getOctets());
+ }
+ catch (ClassCastException e) {
+ throw new IllegalArgumentException(octs.elementAt(i).getClass().getName() + " found in input should only contain DEROctetString");
+ }
+ catch (IOException e) {
+ throw new IllegalArgumentException("exception converting octets " + e.toString());
+ }
+ }
+
+ return bOut.toByteArray();
+ }
+
+ private Vector octs;
+
+ /** @param string the octets making up the octet string. */
+ public BERConstructedOctetString(
+ byte[] string) {
+ super(string);
+ }
+
+ public BERConstructedOctetString(
+ Vector octs) {
+ super(toBytes(octs));
+
+ this.octs = octs;
+ }
+
+ public BERConstructedOctetString(
+ DERObject obj) {
+ super(obj);
+ }
+
+ public BERConstructedOctetString(
+ DEREncodable obj) {
+ super(obj.getDERObject());
+ }
+
+ public byte[] getOctets() {
+ return string;
+ }
+
+ /** return the DER octets that make up this string. */
+ public Enumeration getObjects() {
+ if (octs == null) {
+ return generateOcts().elements();
+ }
+
+ return octs.elements();
+ }
+
+ private Vector generateOcts() {
+ int start = 0;
+ int end = 0;
+ Vector vec = new Vector();
+
+ while ((end + 1) < string.length) {
+ if (string[end] == 0 && string[end + 1] == 0) {
+ byte[] nStr = new byte[end - start + 1];
+
+ System.arraycopy(string, start, nStr, 0, nStr.length);
+
+ vec.addElement(new DEROctetString(nStr));
+ start = end + 1;
+ }
+ end++;
+ }
+
+ byte[] nStr = new byte[string.length - start];
+
+ System.arraycopy(string, start, nStr, 0, nStr.length);
+
+ vec.addElement(new DEROctetString(nStr));
+
+ return vec;
+ }
+
+ public void encode(
+ DEROutputStream out)
+ throws IOException {
+ if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) {
+ out.write(CONSTRUCTED | OCTET_STRING);
+
+ out.write(0x80);
+
+ //
+ // write out the octet array
+ //
+ if (octs != null) {
+ for (int i = 0; i != octs.size(); i++) {
+ out.writeObject(octs.elementAt(i));
+ }
+ } else {
+ for (int i = 0; i < string.length; i += MAX_LENGTH) {
+ int end;
+
+ if (i + MAX_LENGTH > string.length) {
+ end = string.length;
+ } else {
+ end = i + MAX_LENGTH;
+ }
+
+ byte[] nStr = new byte[end - i];
+
+ System.arraycopy(string, i, nStr, 0, nStr.length);
+
+ out.writeObject(new DEROctetString(nStr));
+ }
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ } else {
+ super.encode(out);
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERConstructedSequence.java b/src/java/org/apache/commons/ssl/asn1/BERConstructedSequence.java
new file mode 100644
index 0000000..5cccfb6
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERConstructedSequence.java
@@ -0,0 +1,29 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/** @deprecated use BERSequence */
+public class BERConstructedSequence
+ extends DERConstructedSequence {
+ /*
+ */
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) {
+ out.write(SEQUENCE | CONSTRUCTED);
+ out.write(0x80);
+
+ Enumeration e = getObjects();
+ while (e.hasMoreElements()) {
+ out.writeObject(e.nextElement());
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ } else {
+ super.encode(out);
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERGenerator.java b/src/java/org/apache/commons/ssl/asn1/BERGenerator.java
new file mode 100644
index 0000000..a81859b
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERGenerator.java
@@ -0,0 +1,82 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class BERGenerator
+ extends ASN1Generator {
+ private boolean _tagged = false;
+ private boolean _isExplicit;
+ private int _tagNo;
+
+ protected BERGenerator(
+ OutputStream out) {
+ super(out);
+ }
+
+ public BERGenerator(
+ OutputStream out,
+ int tagNo,
+ boolean isExplicit) {
+ super(out);
+
+ _tagged = true;
+ _isExplicit = isExplicit;
+ _tagNo = tagNo;
+ }
+
+ public OutputStream getRawOutputStream() {
+ return _out;
+ }
+
+ private void writeHdr(
+ int tag)
+ throws IOException {
+ _out.write(tag);
+ _out.write(0x80);
+ }
+
+ protected void writeBERHeader(
+ int tag)
+ throws IOException {
+ if (_tagged) {
+ int tagNum = _tagNo | DERTags.TAGGED;
+
+ if (_isExplicit) {
+ writeHdr(tagNum | DERTags.CONSTRUCTED);
+ writeHdr(tag);
+ } else {
+ if ((tag & DERTags.CONSTRUCTED) != 0) {
+ writeHdr(tagNum | DERTags.CONSTRUCTED);
+ } else {
+ writeHdr(tagNum);
+ }
+ }
+ } else {
+ writeHdr(tag);
+ }
+ }
+
+ protected void writeBERBody(
+ InputStream contentStream)
+ throws IOException {
+ int ch;
+
+ while ((ch = contentStream.read()) >= 0) {
+ _out.write(ch);
+ }
+ }
+
+ protected void writeBEREnd()
+ throws IOException {
+ _out.write(0x00);
+ _out.write(0x00);
+
+ if (_tagged && _isExplicit) // write extra end for tag header
+ {
+ _out.write(0x00);
+ _out.write(0x00);
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERInputStream.java b/src/java/org/apache/commons/ssl/asn1/BERInputStream.java
new file mode 100644
index 0000000..403b2ce
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERInputStream.java
@@ -0,0 +1,179 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Vector;
+
+/** @deprecated use ASN1InputStream */
+public class BERInputStream
+ extends DERInputStream {
+ private static final DERObject END_OF_STREAM = new DERObject() {
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ throw new IOException("Eeek!");
+ }
+ public int hashCode() {
+ return 0;
+ }
+ public boolean equals(
+ Object o) {
+ return o == this;
+ }
+ };
+ public BERInputStream(
+ InputStream is) {
+ super(is);
+ }
+
+ /** read a string of bytes representing an indefinite length object. */
+ private byte[] readIndefiniteLengthFully()
+ throws IOException {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ int b, b1;
+
+ b1 = read();
+
+ while ((b = read()) >= 0) {
+ if (b1 == 0 && b == 0) {
+ break;
+ }
+
+ bOut.write(b1);
+ b1 = b;
+ }
+
+ return bOut.toByteArray();
+ }
+
+ private BERConstructedOctetString buildConstructedOctetString()
+ throws IOException {
+ Vector octs = new Vector();
+
+ for (; ;) {
+ DERObject o = readObject();
+
+ if (o == END_OF_STREAM) {
+ break;
+ }
+
+ octs.addElement(o);
+ }
+
+ return new BERConstructedOctetString(octs);
+ }
+
+ public DERObject readObject()
+ throws IOException {
+ int tag = read();
+ if (tag == -1) {
+ throw new EOFException();
+ }
+
+ int length = readLength();
+
+ if (length < 0) // indefinite length method
+ {
+ switch (tag) {
+ case NULL:
+ return null;
+ case SEQUENCE | CONSTRUCTED:
+ BERConstructedSequence seq = new BERConstructedSequence();
+
+ for (; ;) {
+ DERObject obj = readObject();
+
+ if (obj == END_OF_STREAM) {
+ break;
+ }
+
+ seq.addObject(obj);
+ }
+ return seq;
+ case OCTET_STRING | CONSTRUCTED:
+ return buildConstructedOctetString();
+ case SET | CONSTRUCTED:
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ for (; ;) {
+ DERObject obj = readObject();
+
+ if (obj == END_OF_STREAM) {
+ break;
+ }
+
+ v.add(obj);
+ }
+ return new BERSet(v);
+ default:
+ //
+ // with tagged object tag number is bottom 5 bits
+ //
+ if ((tag & TAGGED) != 0) {
+ if ((tag & 0x1f) == 0x1f) {
+ throw new IOException("unsupported high tag encountered");
+ }
+
+ //
+ // simple type - implicit... return an octet string
+ //
+ if ((tag & CONSTRUCTED) == 0) {
+ byte[] bytes = readIndefiniteLengthFully();
+
+ return new BERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
+ }
+
+ //
+ // either constructed or explicitly tagged
+ //
+ DERObject dObj = readObject();
+
+ if (dObj == END_OF_STREAM) // empty tag!
+ {
+ return new DERTaggedObject(tag & 0x1f);
+ }
+
+ DERObject next = readObject();
+
+ //
+ // explicitly tagged (probably!) - if it isn't we'd have to
+ // tell from the context
+ //
+ if (next == END_OF_STREAM) {
+ return new BERTaggedObject(tag & 0x1f, dObj);
+ }
+
+ //
+ // another implicit object, we'll create a sequence...
+ //
+ seq = new BERConstructedSequence();
+
+ seq.addObject(dObj);
+
+ do {
+ seq.addObject(next);
+ next = readObject();
+ }
+ while (next != END_OF_STREAM);
+
+ return new BERTaggedObject(false, tag & 0x1f, seq);
+ }
+
+ throw new IOException("unknown BER object encountered");
+ }
+ } else {
+ if (tag == 0 && length == 0) // end of contents marker.
+ {
+ return END_OF_STREAM;
+ }
+
+ byte[] bytes = new byte[length];
+
+ readFully(bytes);
+
+ return buildObject(tag, bytes);
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERNull.java b/src/java/org/apache/commons/ssl/asn1/BERNull.java
new file mode 100644
index 0000000..e5c1626
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERNull.java
@@ -0,0 +1,22 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** A BER NULL object. */
+public class BERNull
+ extends DERNull {
+ public static final BERNull INSTANCE = new BERNull();
+
+ public BERNull() {
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) {
+ out.write(NULL);
+ } else {
+ super.encode(out);
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BEROctetStringGenerator.java b/src/java/org/apache/commons/ssl/asn1/BEROctetStringGenerator.java
new file mode 100644
index 0000000..b21fade
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BEROctetStringGenerator.java
@@ -0,0 +1,86 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class BEROctetStringGenerator
+ extends BERGenerator {
+ public BEROctetStringGenerator(OutputStream out)
+ throws IOException {
+ super(out);
+
+ writeBERHeader(DERTags.CONSTRUCTED | DERTags.OCTET_STRING);
+ }
+
+ public BEROctetStringGenerator(
+ OutputStream out,
+ int tagNo,
+ boolean isExplicit)
+ throws IOException {
+ super(out, tagNo, isExplicit);
+
+ writeBERHeader(DERTags.CONSTRUCTED | DERTags.OCTET_STRING);
+ }
+
+ public OutputStream getOctetOutputStream() {
+ return getOctetOutputStream(new byte[1000]); // limit for CER encoding.
+ }
+
+ public OutputStream getOctetOutputStream(
+ byte[] buf) {
+ return new BufferedBEROctetStream(buf);
+ }
+
+ private class BufferedBEROctetStream
+ extends OutputStream {
+ private byte[] _buf;
+ private int _off;
+
+ BufferedBEROctetStream(
+ byte[] buf) {
+ _buf = buf;
+ _off = 0;
+ }
+
+ public void write(
+ int b)
+ throws IOException {
+ _buf[_off++] = (byte) b;
+
+ if (_off == _buf.length) {
+ _out.write(new DEROctetString(_buf).getEncoded());
+ _off = 0;
+ }
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ while (len > 0) {
+ int numToCopy = Math.min(len, _buf.length - _off);
+ System.arraycopy(b, off, _buf, _off, numToCopy);
+
+ _off += numToCopy;
+ if (_off < _buf.length) {
+ break;
+ }
+
+ _out.write(new DEROctetString(_buf).getEncoded());
+ _off = 0;
+
+ off += numToCopy;
+ len -= numToCopy;
+ }
+ }
+
+ public void close()
+ throws IOException {
+ if (_off != 0) {
+ byte[] bytes = new byte[_off];
+ System.arraycopy(_buf, 0, bytes, 0, _off);
+
+ _out.write(new DEROctetString(bytes).getEncoded());
+ }
+
+ writeBEREnd();
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BEROctetStringParser.java b/src/java/org/apache/commons/ssl/asn1/BEROctetStringParser.java
new file mode 100644
index 0000000..2123c2b
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BEROctetStringParser.java
@@ -0,0 +1,36 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class BEROctetStringParser
+ implements ASN1OctetStringParser {
+ private ASN1ObjectParser _parser;
+
+ protected BEROctetStringParser(
+ ASN1ObjectParser parser) {
+ _parser = parser;
+ }
+
+ public InputStream getOctetStream() {
+ return new ConstructedOctetStream(_parser);
+ }
+
+ public DERObject getDERObject() {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ InputStream in = this.getOctetStream();
+ int ch;
+
+ try {
+ while ((ch = in.read()) >= 0) {
+ bOut.write(ch);
+ }
+ }
+ catch (IOException e) {
+ throw new IllegalStateException("IOException converting stream to byte array: " + e.getMessage());
+ }
+
+ return new BERConstructedOctetString(bOut.toByteArray());
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BEROutputStream.java b/src/java/org/apache/commons/ssl/asn1/BEROutputStream.java
new file mode 100644
index 0000000..36f99ee
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BEROutputStream.java
@@ -0,0 +1,26 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class BEROutputStream
+ extends DEROutputStream {
+ public BEROutputStream(
+ OutputStream os) {
+ super(os);
+ }
+
+ public void writeObject(
+ Object obj)
+ throws IOException {
+ if (obj == null) {
+ writeNull();
+ } else if (obj instanceof DERObject) {
+ ((DERObject) obj).encode(this);
+ } else if (obj instanceof DEREncodable) {
+ ((DEREncodable) obj).getDERObject().encode(this);
+ } else {
+ throw new IOException("object not BEREncodable");
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERSequence.java b/src/java/org/apache/commons/ssl/asn1/BERSequence.java
new file mode 100644
index 0000000..cc7667e
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERSequence.java
@@ -0,0 +1,44 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class BERSequence
+ extends DERSequence {
+ /** create an empty sequence */
+ public BERSequence() {
+ }
+
+ /** create a sequence containing one object */
+ public BERSequence(
+ DEREncodable obj) {
+ super(obj);
+ }
+
+ /** create a sequence containing a vector of objects. */
+ public BERSequence(
+ DEREncodableVector v) {
+ super(v);
+ }
+
+ /*
+ */
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) {
+ out.write(SEQUENCE | CONSTRUCTED);
+ out.write(0x80);
+
+ Enumeration e = getObjects();
+ while (e.hasMoreElements()) {
+ out.writeObject(e.nextElement());
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ } else {
+ super.encode(out);
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERSequenceGenerator.java b/src/java/org/apache/commons/ssl/asn1/BERSequenceGenerator.java
new file mode 100644
index 0000000..0e821ce
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERSequenceGenerator.java
@@ -0,0 +1,36 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class BERSequenceGenerator
+ extends BERGenerator {
+ public BERSequenceGenerator(
+ OutputStream out)
+ throws IOException {
+ super(out);
+
+ writeBERHeader(DERTags.CONSTRUCTED | DERTags.SEQUENCE);
+ }
+
+ public BERSequenceGenerator(
+ OutputStream out,
+ int tagNo,
+ boolean isExplicit)
+ throws IOException {
+ super(out, tagNo, isExplicit);
+
+ writeBERHeader(DERTags.CONSTRUCTED | DERTags.SEQUENCE);
+ }
+
+ public void addObject(
+ DEREncodable object)
+ throws IOException {
+ object.getDERObject().encode(new DEROutputStream(_out));
+ }
+
+ public void close()
+ throws IOException {
+ writeBEREnd();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERSequenceParser.java b/src/java/org/apache/commons/ssl/asn1/BERSequenceParser.java
new file mode 100644
index 0000000..fb7dad3
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERSequenceParser.java
@@ -0,0 +1,21 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+public class BERSequenceParser
+ implements ASN1SequenceParser {
+ private ASN1ObjectParser _parser;
+
+ BERSequenceParser(ASN1ObjectParser parser) {
+ this._parser = parser;
+ }
+
+ public DEREncodable readObject()
+ throws IOException {
+ return _parser.readObject();
+ }
+
+ public DERObject getDERObject() {
+ return new BERSequence(_parser.readVector());
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERSet.java b/src/java/org/apache/commons/ssl/asn1/BERSet.java
new file mode 100644
index 0000000..db80cf4
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERSet.java
@@ -0,0 +1,51 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class BERSet
+ extends DERSet {
+ /** create an empty sequence */
+ public BERSet() {
+ }
+
+ /** create a set containing one object */
+ public BERSet(
+ DEREncodable obj) {
+ super(obj);
+ }
+
+ /** @param v - a vector of objects making up the set. */
+ public BERSet(
+ DEREncodableVector v) {
+ super(v, false);
+ }
+
+ /** @param v - a vector of objects making up the set. */
+ BERSet(
+ DEREncodableVector v,
+ boolean needsSorting) {
+ super(v, needsSorting);
+ }
+
+ /*
+ */
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) {
+ out.write(SET | CONSTRUCTED);
+ out.write(0x80);
+
+ Enumeration e = getObjects();
+ while (e.hasMoreElements()) {
+ out.writeObject(e.nextElement());
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ } else {
+ super.encode(out);
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERSetParser.java b/src/java/org/apache/commons/ssl/asn1/BERSetParser.java
new file mode 100644
index 0000000..7f88189
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERSetParser.java
@@ -0,0 +1,21 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+public class BERSetParser
+ implements ASN1SetParser {
+ private ASN1ObjectParser _parser;
+
+ BERSetParser(ASN1ObjectParser parser) {
+ this._parser = parser;
+ }
+
+ public DEREncodable readObject()
+ throws IOException {
+ return _parser.readObject();
+ }
+
+ public DERObject getDERObject() {
+ return new BERSet(_parser.readVector());
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERTaggedObject.java b/src/java/org/apache/commons/ssl/asn1/BERTaggedObject.java
new file mode 100644
index 0000000..c0be868
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERTaggedObject.java
@@ -0,0 +1,94 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.util.Enumeration;
+
+/**
+ * BER TaggedObject - in ASN.1 nottation this is any object proceeded by
+ * a [n] where n is some number - these are assume to follow the construction
+ * rules (as with sequences).
+ */
+public class BERTaggedObject
+ extends DERTaggedObject {
+ /**
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public BERTaggedObject(
+ int tagNo,
+ DEREncodable obj) {
+ super(tagNo, obj);
+ }
+
+ /**
+ * @param explicit true if an explicitly tagged object.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public BERTaggedObject(
+ boolean explicit,
+ int tagNo,
+ DEREncodable obj) {
+ super(explicit, tagNo, obj);
+ }
+
+ /**
+ * create an implicitly tagged object that contains a zero
+ * length sequence.
+ */
+ public BERTaggedObject(
+ int tagNo) {
+ super(false, tagNo, new BERSequence());
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ if (out instanceof ASN1OutputStream || out instanceof BEROutputStream) {
+ out.write(CONSTRUCTED | TAGGED | tagNo);
+ out.write(0x80);
+
+ if (!empty) {
+ if (!explicit) {
+ if (obj instanceof ASN1OctetString) {
+ Enumeration e;
+
+ if (obj instanceof BERConstructedOctetString) {
+ e = ((BERConstructedOctetString) obj).getObjects();
+ } else {
+ ASN1OctetString octs = (ASN1OctetString) obj;
+ BERConstructedOctetString berO = new BERConstructedOctetString(octs.getOctets());
+
+ e = berO.getObjects();
+ }
+
+ while (e.hasMoreElements()) {
+ out.writeObject(e.nextElement());
+ }
+ } else if (obj instanceof ASN1Sequence) {
+ Enumeration e = ((ASN1Sequence) obj).getObjects();
+
+ while (e.hasMoreElements()) {
+ out.writeObject(e.nextElement());
+ }
+ } else if (obj instanceof ASN1Set) {
+ Enumeration e = ((ASN1Set) obj).getObjects();
+
+ while (e.hasMoreElements()) {
+ out.writeObject(e.nextElement());
+ }
+ } else {
+ throw new RuntimeException("not implemented: " + obj.getClass().getName());
+ }
+ } else {
+ out.writeObject(obj);
+ }
+ }
+
+ out.write(0x00);
+ out.write(0x00);
+ } else {
+ super.encode(out);
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/BERTaggedObjectParser.java b/src/java/org/apache/commons/ssl/asn1/BERTaggedObjectParser.java
new file mode 100644
index 0000000..0f45cdb
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/BERTaggedObjectParser.java
@@ -0,0 +1,118 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class BERTaggedObjectParser
+ implements ASN1TaggedObjectParser {
+ private int _baseTag;
+ private int _tagNumber;
+ private InputStream _contentStream;
+
+ private boolean _indefiniteLength;
+
+ protected BERTaggedObjectParser(
+ int baseTag,
+ int tagNumber,
+ InputStream contentStream) {
+ _baseTag = baseTag;
+ _tagNumber = tagNumber;
+ _contentStream = contentStream;
+ _indefiniteLength = contentStream instanceof IndefiniteLengthInputStream;
+ }
+
+ public boolean isConstructed() {
+ return (_baseTag & DERTags.CONSTRUCTED) != 0;
+ }
+
+ public int getTagNo() {
+ return _tagNumber;
+ }
+
+ public DEREncodable getObjectParser(
+ int tag,
+ boolean isExplicit)
+ throws IOException {
+ if (isExplicit) {
+ return new ASN1StreamParser(_contentStream).readObject();
+ } else {
+ switch (tag) {
+ case DERTags.SET:
+ if (_indefiniteLength) {
+ return new BERSetParser(new ASN1ObjectParser(_baseTag, _tagNumber, _contentStream));
+ } else {
+ return new DERSet(loadVector(_contentStream)).parser();
+ }
+ case DERTags.SEQUENCE:
+ if (_indefiniteLength) {
+ return new BERSequenceParser(new ASN1ObjectParser(_baseTag, _tagNumber, _contentStream));
+ } else {
+ return new DERSequence(loadVector(_contentStream)).parser();
+ }
+ case DERTags.OCTET_STRING:
+ if (_indefiniteLength || this.isConstructed()) {
+ return new BEROctetStringParser(new ASN1ObjectParser(_baseTag, _tagNumber, _contentStream));
+ } else {
+ return new DEROctetString(((DefiniteLengthInputStream) _contentStream).toByteArray()).parser();
+ }
+ }
+ }
+
+ throw new RuntimeException("implicit tagging not implemented");
+ }
+
+ private ASN1EncodableVector loadVector(InputStream in)
+ throws IOException {
+ ASN1StreamParser aIn = new ASN1StreamParser(in);
+ ASN1EncodableVector v = new ASN1EncodableVector();
+ DEREncodable obj = aIn.readObject();
+
+ while (obj != null) {
+ v.add(obj.getDERObject());
+ obj = aIn.readObject();
+ }
+
+ return v;
+ }
+
+ private ASN1EncodableVector rLoadVector(InputStream in) {
+ try {
+ return loadVector(in);
+ }
+ catch (IOException e) {
+ throw new IllegalStateException(e.getMessage());
+ }
+ }
+
+ public DERObject getDERObject() {
+ if (_indefiniteLength) {
+ ASN1EncodableVector v = rLoadVector(_contentStream);
+
+ if (v.size() > 1) {
+ return new BERTaggedObject(false, _tagNumber, new BERSequence(v));
+ } else if (v.size() == 1) {
+ return new BERTaggedObject(true, _tagNumber, v.get(0));
+ } else {
+ return new BERTaggedObject(false, _tagNumber, new BERSequence());
+ }
+ } else {
+ if (this.isConstructed()) {
+ ASN1EncodableVector v = rLoadVector(_contentStream);
+
+ if (v.size() == 1) {
+ return new DERTaggedObject(true, _tagNumber, v.get(0));
+ }
+
+ return new DERTaggedObject(false, _tagNumber, new DERSequence(v));
+ }
+
+ try {
+ return new DERTaggedObject(false, _tagNumber, new DEROctetString(((DefiniteLengthInputStream) _contentStream).toByteArray()));
+ }
+ catch (IOException e) {
+ throw new IllegalStateException(e.getMessage());
+ }
+ }
+
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/ConstructedOctetStream.java b/src/java/org/apache/commons/ssl/asn1/ConstructedOctetStream.java
new file mode 100644
index 0000000..18565bb
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/ConstructedOctetStream.java
@@ -0,0 +1,92 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class ConstructedOctetStream
+ extends InputStream {
+ private final ASN1ObjectParser _parser;
+
+ private boolean _first = true;
+ private InputStream _currentStream;
+
+ ConstructedOctetStream(
+ ASN1ObjectParser parser) {
+ _parser = parser;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ if (_currentStream == null) {
+ if (!_first) {
+ return -1;
+ }
+
+ ASN1OctetStringParser s = (ASN1OctetStringParser) _parser.readObject();
+
+ if (s == null) {
+ return -1;
+ }
+
+ _first = false;
+ _currentStream = s.getOctetStream();
+ }
+
+ int totalRead = 0;
+
+ for (; ;) {
+ int numRead = _currentStream.read(b, off + totalRead, len - totalRead);
+
+ if (numRead >= 0) {
+ totalRead += numRead;
+
+ if (totalRead == len) {
+ return totalRead;
+ }
+ } else {
+ ASN1OctetStringParser aos = (ASN1OctetStringParser) _parser.readObject();
+
+ if (aos == null) {
+ _currentStream = null;
+ return totalRead < 1 ? -1 : totalRead;
+ }
+
+ _currentStream = aos.getOctetStream();
+ }
+ }
+ }
+
+ public int read()
+ throws IOException {
+ if (_currentStream == null) {
+ if (!_first) {
+ return -1;
+ }
+
+ ASN1OctetStringParser s = (ASN1OctetStringParser) _parser.readObject();
+
+ if (s == null) {
+ return -1;
+ }
+
+ _first = false;
+ _currentStream = s.getOctetStream();
+ }
+
+ for (; ;) {
+ int b = _currentStream.read();
+
+ if (b >= 0) {
+ return b;
+ }
+
+ ASN1OctetStringParser s = (ASN1OctetStringParser) _parser.readObject();
+
+ if (s == null) {
+ _currentStream = null;
+ return -1;
+ }
+
+ _currentStream = s.getOctetStream();
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERApplicationSpecific.java b/src/java/org/apache/commons/ssl/asn1/DERApplicationSpecific.java
new file mode 100644
index 0000000..be1b192
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERApplicationSpecific.java
@@ -0,0 +1,143 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/** Base class for an application specific object */
+public class DERApplicationSpecific
+ extends ASN1Object {
+ private int tag;
+ private byte[] octets;
+
+ public DERApplicationSpecific(
+ int tag,
+ byte[] octets) {
+ this.tag = tag;
+ this.octets = octets;
+ }
+
+ public DERApplicationSpecific(
+ int tag,
+ DEREncodable object)
+ throws IOException {
+ this(true, tag, object);
+ }
+
+ public DERApplicationSpecific(
+ boolean explicit,
+ int tag,
+ DEREncodable object)
+ throws IOException {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dos = new DEROutputStream(bOut);
+
+ dos.writeObject(object);
+
+ byte[] data = bOut.toByteArray();
+
+ if (tag >= 0x1f) {
+ throw new IOException("unsupported tag number");
+ }
+
+ if (explicit) {
+ this.tag = tag | DERTags.CONSTRUCTED;
+ this.octets = data;
+ } else {
+ this.tag = tag;
+ int lenBytes = getLengthOfLength(data);
+ byte[] tmp = new byte[data.length - lenBytes];
+ System.arraycopy(data, lenBytes, tmp, 0, tmp.length);
+ this.octets = tmp;
+ }
+ }
+
+ private int getLengthOfLength(byte[] data) {
+ int count = 2; // TODO: assumes only a 1 byte tag number
+
+ while ((data[count - 1] & 0x80) != 0) {
+ count++;
+ }
+
+ return count;
+ }
+
+ public boolean isConstructed() {
+ return (tag & DERTags.CONSTRUCTED) != 0;
+ }
+
+ public byte[] getContents() {
+ return octets;
+ }
+
+ public int getApplicationTag() {
+ return tag;
+ }
+
+ public DERObject getObject()
+ throws IOException {
+ return new ASN1InputStream(getContents()).readObject();
+ }
+
+ /**
+ * Return the enclosed object assuming implicit tagging.
+ *
+ * @param derTagNo the type tag that should be applied to the object's contents.
+ * @return the resulting object
+ * @throws IOException if reconstruction fails.
+ */
+ public DERObject getObject(int derTagNo)
+ throws IOException {
+ if (tag >= 0x1f) {
+ throw new IOException("unsupported tag number");
+ }
+
+ byte[] tmp = this.getEncoded();
+
+ tmp[0] = (byte) derTagNo;
+
+ return new ASN1InputStream(tmp).readObject();
+ }
+
+ /* (non-Javadoc)
+ * @see org.apache.commons.ssl.asn1.DERObject#encode(org.apache.commons.ssl.asn1.DEROutputStream)
+ */
+ void encode(DEROutputStream out) throws IOException {
+ out.writeEncoded(DERTags.APPLICATION | tag, octets);
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERApplicationSpecific)) {
+ return false;
+ }
+
+ DERApplicationSpecific other = (DERApplicationSpecific) o;
+
+ if (tag != other.tag) {
+ return false;
+ }
+
+ if (octets.length != other.octets.length) {
+ return false;
+ }
+
+ for (int i = 0; i < octets.length; i++) {
+ if (octets[i] != other.octets[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int hashCode() {
+ byte[] b = this.getContents();
+ int value = 0;
+
+ for (int i = 0; i != b.length; i++) {
+ value ^= (b[i] & 0xff) << (i % 4);
+ }
+
+ return value ^ this.getApplicationTag();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERBMPString.java b/src/java/org/apache/commons/ssl/asn1/DERBMPString.java
new file mode 100644
index 0000000..e093582
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERBMPString.java
@@ -0,0 +1,104 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** DER BMPString object. */
+public class DERBMPString
+ extends ASN1Object
+ implements DERString {
+ String string;
+
+ /**
+ * return a BMP String from the given object.
+ *
+ * @param obj the object we want converted.
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERBMPString getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERBMPString) {
+ return (DERBMPString) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERBMPString(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a BMP String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERBMPString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+
+ /** basic constructor - byte encoded string. */
+ public DERBMPString(
+ byte[] string) {
+ char[] cs = new char[string.length / 2];
+
+ for (int i = 0; i != cs.length; i++) {
+ cs[i] = (char) ((string[2 * i] << 8) | (string[2 * i + 1] & 0xff));
+ }
+
+ this.string = new String(cs);
+ }
+
+ /** basic constructor */
+ public DERBMPString(
+ String string) {
+ this.string = string;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public String toString() {
+ return string;
+ }
+
+ public int hashCode() {
+ return this.getString().hashCode();
+ }
+
+ protected boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERBMPString)) {
+ return false;
+ }
+
+ DERBMPString s = (DERBMPString) o;
+
+ return this.getString().equals(s.getString());
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ char[] c = string.toCharArray();
+ byte[] b = new byte[c.length * 2];
+
+ for (int i = 0; i != c.length; i++) {
+ b[2 * i] = (byte) (c[i] >> 8);
+ b[2 * i + 1] = (byte) c[i];
+ }
+
+ out.writeEncoded(BMP_STRING, b);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERBitString.java b/src/java/org/apache/commons/ssl/asn1/DERBitString.java
new file mode 100644
index 0000000..2cb649c
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERBitString.java
@@ -0,0 +1,245 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+public class DERBitString
+ extends ASN1Object
+ implements DERString {
+ private static final char[] table = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+
+ protected byte[] data;
+ protected int padBits;
+
+ /**
+ * return the correct number of pad bits for a bit string defined in
+ * a 32 bit constant
+ */
+ static protected int getPadBits(
+ int bitString) {
+ int val = 0;
+ for (int i = 3; i >= 0; i--) {
+ //
+ // this may look a little odd, but if it isn't done like this pre jdk1.2
+ // JVM's break!
+ //
+ if (i != 0) {
+ if ((bitString >> (i * 8)) != 0) {
+ val = (bitString >> (i * 8)) & 0xFF;
+ break;
+ }
+ } else {
+ if (bitString != 0) {
+ val = bitString & 0xFF;
+ break;
+ }
+ }
+ }
+
+ if (val == 0) {
+ return 7;
+ }
+
+
+ int bits = 1;
+
+ while (((val <<= 1) & 0xFF) != 0) {
+ bits++;
+ }
+
+ return 8 - bits;
+ }
+
+ /**
+ * return the correct number of bytes for a bit string defined in
+ * a 32 bit constant
+ */
+ static protected byte[] getBytes(int bitString) {
+ int bytes = 4;
+ for (int i = 3; i >= 1; i--) {
+ if ((bitString & (0xFF << (i * 8))) != 0) {
+ break;
+ }
+ bytes--;
+ }
+
+ byte[] result = new byte[bytes];
+ for (int i = 0; i < bytes; i++) {
+ result[i] = (byte) ((bitString >> (i * 8)) & 0xFF);
+ }
+
+ return result;
+ }
+
+ /**
+ * return a Bit String from the passed in object
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERBitString getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERBitString) {
+ return (DERBitString) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ byte[] bytes = ((ASN1OctetString) obj).getOctets();
+ int padBits = bytes[0];
+ byte[] data = new byte[bytes.length - 1];
+
+ System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
+
+ return new DERBitString(data, padBits);
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a Bit String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERBitString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ protected DERBitString(
+ byte data,
+ int padBits) {
+ this.data = new byte[1];
+ this.data[0] = data;
+ this.padBits = padBits;
+ }
+
+ /**
+ * @param data the octets making up the bit string.
+ * @param padBits the number of extra bits at the end of the string.
+ */
+ public DERBitString(
+ byte[] data,
+ int padBits) {
+ this.data = data;
+ this.padBits = padBits;
+ }
+
+ public DERBitString(
+ byte[] data) {
+ this(data, 0);
+ }
+
+ public DERBitString(
+ DEREncodable obj) {
+ try {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(obj);
+ dOut.close();
+
+ this.data = bOut.toByteArray();
+ this.padBits = 0;
+ }
+ catch (IOException e) {
+ throw new IllegalArgumentException("Error processing object : " + e.toString());
+ }
+ }
+
+ public byte[] getBytes() {
+ return data;
+ }
+
+ public int getPadBits() {
+ return padBits;
+ }
+
+
+ /** @return the value of the bit string as an int (truncating if necessary) */
+ public int intValue() {
+ int value = 0;
+
+ for (int i = 0; i != data.length && i != 4; i++) {
+ value |= (data[i] & 0xff) << (8 * i);
+ }
+
+ return value;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ byte[] bytes = new byte[getBytes().length + 1];
+
+ bytes[0] = (byte) getPadBits();
+ System.arraycopy(getBytes(), 0, bytes, 1, bytes.length - 1);
+
+ out.writeEncoded(BIT_STRING, bytes);
+ }
+
+ public int hashCode() {
+ int value = 0;
+
+ for (int i = 0; i != data.length; i++) {
+ value ^= (data[i] & 0xff) << (i % 4);
+ }
+
+ return value;
+ }
+
+ protected boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERBitString)) {
+ return false;
+ }
+
+ DERBitString other = (DERBitString) o;
+
+ if (data.length != other.data.length) {
+ return false;
+ }
+
+ for (int i = 0; i != data.length; i++) {
+ if (data[i] != other.data[i]) {
+ return false;
+ }
+ }
+
+ return (padBits == other.padBits);
+ }
+
+ public String getString() {
+ StringBuffer buf = new StringBuffer("#");
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ try {
+ aOut.writeObject(this);
+ }
+ catch (IOException e) {
+ throw new RuntimeException("internal error encoding BitString");
+ }
+
+ byte[] string = bOut.toByteArray();
+
+ for (int i = 0; i != string.length; i++) {
+ buf.append(table[(string[i] >>> 4) & 0xf]);
+ buf.append(table[string[i] & 0xf]);
+ }
+
+ return buf.toString();
+ }
+
+ public String toString() {
+ return getString();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERBoolean.java b/src/java/org/apache/commons/ssl/asn1/DERBoolean.java
new file mode 100644
index 0000000..e49ec6c
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERBoolean.java
@@ -0,0 +1,96 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+public class DERBoolean
+ extends ASN1Object {
+ byte value;
+
+ public static final DERBoolean FALSE = new DERBoolean(false);
+ public static final DERBoolean TRUE = new DERBoolean(true);
+
+ /**
+ * return a boolean from the passed in object.
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERBoolean getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERBoolean) {
+ return (DERBoolean) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERBoolean(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /** return a DERBoolean from the passed in boolean. */
+ public static DERBoolean getInstance(
+ boolean value) {
+ return (value ? TRUE : FALSE);
+ }
+
+ /**
+ * return a Boolean from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERBoolean getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ public DERBoolean(
+ byte[] value) {
+ this.value = value[0];
+ }
+
+ public DERBoolean(
+ boolean value) {
+ this.value = (value) ? (byte) 0xff : (byte) 0;
+ }
+
+ public boolean isTrue() {
+ return (value != 0);
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ byte[] bytes = new byte[1];
+
+ bytes[0] = value;
+
+ out.writeEncoded(BOOLEAN, bytes);
+ }
+
+ protected boolean asn1Equals(
+ DERObject o) {
+ if ((o == null) || !(o instanceof DERBoolean)) {
+ return false;
+ }
+
+ return (value == ((DERBoolean) o).value);
+ }
+
+ public int hashCode() {
+ return value;
+ }
+
+
+ public String toString() {
+ return (value != 0) ? "TRUE" : "FALSE";
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERConstructedSequence.java b/src/java/org/apache/commons/ssl/asn1/DERConstructedSequence.java
new file mode 100644
index 0000000..f7cad53
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERConstructedSequence.java
@@ -0,0 +1,46 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+
+/** @deprecated use DERSequence. */
+public class DERConstructedSequence
+ extends ASN1Sequence {
+ public void addObject(
+ DEREncodable obj) {
+ super.addObject(obj);
+ }
+
+ public int getSize() {
+ return size();
+ }
+
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DER requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputing SEQUENCE,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ Enumeration e = this.getObjects();
+
+ while (e.hasMoreElements()) {
+ Object obj = e.nextElement();
+
+ dOut.writeObject(obj);
+ }
+
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ out.writeEncoded(SEQUENCE | CONSTRUCTED, bytes);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERConstructedSet.java b/src/java/org/apache/commons/ssl/asn1/DERConstructedSet.java
new file mode 100644
index 0000000..50adf8e
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERConstructedSet.java
@@ -0,0 +1,63 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+
+/** @deprecated use DERSet */
+public class DERConstructedSet
+ extends ASN1Set {
+ public DERConstructedSet() {
+ }
+
+ /** @param obj - a single object that makes up the set. */
+ public DERConstructedSet(
+ DEREncodable obj) {
+ this.addObject(obj);
+ }
+
+ /** @param v - a vector of objects making up the set. */
+ public DERConstructedSet(
+ DEREncodableVector v) {
+ for (int i = 0; i != v.size(); i++) {
+ this.addObject(v.get(i));
+ }
+ }
+
+ public void addObject(
+ DEREncodable obj) {
+ super.addObject(obj);
+ }
+
+ public int getSize() {
+ return size();
+ }
+
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DER requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputing SET,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ Enumeration e = this.getObjects();
+
+ while (e.hasMoreElements()) {
+ Object obj = e.nextElement();
+
+ dOut.writeObject(obj);
+ }
+
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ out.writeEncoded(SET | CONSTRUCTED, bytes);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DEREncodable.java b/src/java/org/apache/commons/ssl/asn1/DEREncodable.java
new file mode 100644
index 0000000..cbaebf9
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DEREncodable.java
@@ -0,0 +1,5 @@
+package org.apache.commons.ssl.asn1;
+
+public interface DEREncodable {
+ public DERObject getDERObject();
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DEREncodableVector.java b/src/java/org/apache/commons/ssl/asn1/DEREncodableVector.java
new file mode 100644
index 0000000..d441a44
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DEREncodableVector.java
@@ -0,0 +1,31 @@
+package org.apache.commons.ssl.asn1;
+
+import java.util.Vector;
+
+/**
+ * a general class for building up a vector of DER encodable objects -
+ * this will eventually be superceded by ASN1EncodableVector so you should
+ * use that class in preference.
+ */
+public class DEREncodableVector {
+ private Vector v = new Vector();
+
+ /** @deprecated use ASN1EncodableVector instead. */
+ public DEREncodableVector() {
+
+ }
+
+ public void add(
+ DEREncodable obj) {
+ v.addElement(obj);
+ }
+
+ public DEREncodable get(
+ int i) {
+ return (DEREncodable) v.elementAt(i);
+ }
+
+ public int size() {
+ return v.size();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DEREnumerated.java b/src/java/org/apache/commons/ssl/asn1/DEREnumerated.java
new file mode 100644
index 0000000..faacf13
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DEREnumerated.java
@@ -0,0 +1,96 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+public class DEREnumerated
+ extends ASN1Object {
+ byte[] bytes;
+
+ /**
+ * return an integer from the passed in object
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DEREnumerated getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DEREnumerated) {
+ return (DEREnumerated) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DEREnumerated(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an Enumerated from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DEREnumerated getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ public DEREnumerated(
+ int value) {
+ bytes = BigInteger.valueOf(value).toByteArray();
+ }
+
+ public DEREnumerated(
+ BigInteger value) {
+ bytes = value.toByteArray();
+ }
+
+ public DEREnumerated(
+ byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ public BigInteger getValue() {
+ return new BigInteger(bytes);
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(ENUMERATED, bytes);
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DEREnumerated)) {
+ return false;
+ }
+
+ DEREnumerated other = (DEREnumerated) o;
+
+ if (bytes.length != other.bytes.length) {
+ return false;
+ }
+
+ for (int i = 0; i != bytes.length; i++) {
+ if (bytes[i] != other.bytes[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int hashCode() {
+ return this.getValue().hashCode();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERGeneralString.java b/src/java/org/apache/commons/ssl/asn1/DERGeneralString.java
new file mode 100644
index 0000000..d571a1d
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERGeneralString.java
@@ -0,0 +1,75 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+public class DERGeneralString
+ extends ASN1Object implements DERString {
+ private String string;
+
+ public static DERGeneralString getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERGeneralString) {
+ return (DERGeneralString) obj;
+ }
+ if (obj instanceof ASN1OctetString) {
+ return new DERGeneralString(((ASN1OctetString) obj).getOctets());
+ }
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+ throw new IllegalArgumentException("illegal object in getInstance: "
+ + obj.getClass().getName());
+ }
+
+ public static DERGeneralString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ public DERGeneralString(byte[] string) {
+ char[] cs = new char[string.length];
+ for (int i = 0; i != cs.length; i++) {
+ cs[i] = (char) (string[i] & 0xff);
+ }
+ this.string = new String(cs);
+ }
+
+ public DERGeneralString(String string) {
+ this.string = string;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public String toString() {
+ return string;
+ }
+
+ public byte[] getOctets() {
+ char[] cs = string.toCharArray();
+ byte[] bs = new byte[cs.length];
+ for (int i = 0; i != cs.length; i++) {
+ bs[i] = (byte) cs[i];
+ }
+ return bs;
+ }
+
+ void encode(DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(GENERAL_STRING, this.getOctets());
+ }
+
+ public int hashCode() {
+ return this.getString().hashCode();
+ }
+
+ boolean asn1Equals(DERObject o) {
+ if (!(o instanceof DERGeneralString)) {
+ return false;
+ }
+ DERGeneralString s = (DERGeneralString) o;
+ return this.getString().equals(s.getString());
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERGeneralizedTime.java b/src/java/org/apache/commons/ssl/asn1/DERGeneralizedTime.java
new file mode 100644
index 0000000..0e2de28
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERGeneralizedTime.java
@@ -0,0 +1,242 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.SimpleTimeZone;
+import java.util.TimeZone;
+
+/** Generalized time object. */
+public class DERGeneralizedTime
+ extends ASN1Object {
+ String time;
+
+ /**
+ * return a generalized time from the passed in object
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERGeneralizedTime getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERGeneralizedTime) {
+ return (DERGeneralizedTime) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERGeneralizedTime(((ASN1OctetString) obj).getOctets());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a Generalized Time object from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERGeneralizedTime getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ /**
+ * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
+ * for local time, or Z+-HHMM on the end, for difference between local
+ * time and UTC time. The fractional second amount f must consist of at
+ * least one number with trailing zeroes removed.
+ *
+ * @param time the time string.
+ * @throws IllegalArgumentException if String is an illegal format.
+ */
+ public DERGeneralizedTime(
+ String time) {
+ this.time = time;
+ try {
+ this.getDate();
+ }
+ catch (ParseException e) {
+ throw new IllegalArgumentException("invalid date string: " + e.getMessage());
+ }
+ }
+
+ /** base constructer from a java.util.date object */
+ public DERGeneralizedTime(
+ Date time) {
+ SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
+
+ dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+
+ this.time = dateF.format(time);
+ }
+
+ DERGeneralizedTime(
+ byte[] bytes) {
+ //
+ // explicitly convert to characters
+ //
+ char[] dateC = new char[bytes.length];
+
+ for (int i = 0; i != dateC.length; i++) {
+ dateC[i] = (char) (bytes[i] & 0xff);
+ }
+
+ this.time = new String(dateC);
+ }
+
+ /**
+ * Return the time.
+ *
+ * @return The time string as it appeared in the encoded object.
+ */
+ public String getTimeString() {
+ return time;
+ }
+
+ /**
+ * return the time - always in the form of
+ * YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+ * <p/>
+ * Normally in a certificate we would expect "Z" rather than "GMT",
+ * however adding the "GMT" means we can just use:
+ * <pre>
+ * dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+ * </pre>
+ * To read in the time and get a date which is compatible with our local
+ * time zone.
+ */
+ public String getTime() {
+ //
+ // standardise the format.
+ //
+ if (time.charAt(time.length() - 1) == 'Z') {
+ return time.substring(0, time.length() - 1) + "GMT+00:00";
+ } else {
+ int signPos = time.length() - 5;
+ char sign = time.charAt(signPos);
+ if (sign == '-' || sign == '+') {
+ return time.substring(0, signPos)
+ + "GMT"
+ + time.substring(signPos, signPos + 3)
+ + ":"
+ + time.substring(signPos + 3);
+ } else {
+ signPos = time.length() - 3;
+ sign = time.charAt(signPos);
+ if (sign == '-' || sign == '+') {
+ return time.substring(0, signPos)
+ + "GMT"
+ + time.substring(signPos)
+ + ":00";
+ }
+ }
+ }
+ return time + calculateGMTOffset();
+ }
+
+ private String calculateGMTOffset() {
+ String sign = "+";
+ TimeZone timeZone = TimeZone.getDefault();
+ int offset = timeZone.getRawOffset();
+ if (offset < 0) {
+ sign = "-";
+ offset = -offset;
+ }
+ int hours = offset / (60 * 60 * 1000);
+ int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000);
+
+ try {
+ if (timeZone.useDaylightTime() && timeZone.inDaylightTime(this.getDate())) {
+ hours += sign.equals("+") ? 1 : -1;
+ }
+ }
+ catch (ParseException e) {
+ // we'll do our best and ignore daylight savings
+ }
+
+ return "GMT" + sign + convert(hours) + ":" + convert(minutes);
+ }
+
+ private String convert(int time) {
+ if (time < 10) {
+ return "0" + time;
+ }
+
+ return Integer.toString(time);
+ }
+
+ public Date getDate()
+ throws ParseException {
+ SimpleDateFormat dateF;
+ String d = time;
+
+ if (time.endsWith("Z")) {
+ if (hasFractionalSeconds()) {
+ dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSS'Z'");
+ } else {
+ dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'");
+ }
+
+ dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+ } else if (time.indexOf('-') > 0 || time.indexOf('+') > 0) {
+ d = this.getTime();
+ if (hasFractionalSeconds()) {
+ dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSSz");
+ } else {
+ dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+ }
+
+ dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+ } else {
+ if (hasFractionalSeconds()) {
+ dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSSS");
+ } else {
+ dateF = new SimpleDateFormat("yyyyMMddHHmmss");
+ }
+
+ dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
+ }
+
+ return dateF.parse(d);
+ }
+
+ private boolean hasFractionalSeconds() {
+ return time.indexOf('.') == 14;
+ }
+
+ private byte[] getOctets() {
+ char[] cs = time.toCharArray();
+ byte[] bs = new byte[cs.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ bs[i] = (byte) cs[i];
+ }
+
+ return bs;
+ }
+
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(GENERALIZED_TIME, this.getOctets());
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERGeneralizedTime)) {
+ return false;
+ }
+
+ return time.equals(((DERGeneralizedTime) o).time);
+ }
+
+ public int hashCode() {
+ return time.hashCode();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERGenerator.java b/src/java/org/apache/commons/ssl/asn1/DERGenerator.java
new file mode 100644
index 0000000..359d931
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERGenerator.java
@@ -0,0 +1,108 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public abstract class DERGenerator
+ extends ASN1Generator {
+ private boolean _tagged = false;
+ private boolean _isExplicit;
+ private int _tagNo;
+
+ protected DERGenerator(
+ OutputStream out) {
+ super(out);
+ }
+
+ public DERGenerator(
+ OutputStream out,
+ int tagNo,
+ boolean isExplicit) {
+ super(out);
+
+ _tagged = true;
+ _isExplicit = isExplicit;
+ _tagNo = tagNo;
+ }
+
+ private void writeLength(
+ OutputStream out,
+ int length)
+ throws IOException {
+ if (length > 127) {
+ int size = 1;
+ int val = length;
+
+ while ((val >>>= 8) != 0) {
+ size++;
+ }
+
+ out.write((byte) (size | 0x80));
+
+ for (int i = (size - 1) * 8; i >= 0; i -= 8) {
+ out.write((byte) (length >> i));
+ }
+ } else {
+ out.write((byte) length);
+ }
+ }
+
+ void writeDEREncoded(
+ OutputStream out,
+ int tag,
+ byte[] bytes)
+ throws IOException {
+ out.write(tag);
+ writeLength(out, bytes.length);
+ out.write(bytes);
+ }
+
+ void writeDEREncoded(
+ int tag,
+ byte[] bytes)
+ throws IOException {
+ if (_tagged) {
+ int tagNum = _tagNo | DERTags.TAGGED;
+
+ if (_isExplicit) {
+ int newTag = _tagNo | DERTags.CONSTRUCTED | DERTags.TAGGED;
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ writeDEREncoded(bOut, tag, bytes);
+
+ writeDEREncoded(_out, newTag, bOut.toByteArray());
+ } else {
+ if ((tag & DERTags.CONSTRUCTED) != 0) {
+ writeDEREncoded(_out, tagNum | DERTags.CONSTRUCTED, bytes);
+ } else {
+ writeDEREncoded(_out, tagNum, bytes);
+ }
+ }
+ } else {
+ writeDEREncoded(_out, tag, bytes);
+ }
+ }
+
+ void writeDEREncoded(
+ OutputStream out,
+ int tag,
+ InputStream in)
+ throws IOException {
+ out.write(tag);
+
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+
+ int b = 0;
+ while ((b = in.read()) >= 0) {
+ bOut.write(b);
+ }
+
+ byte[] bytes = bOut.toByteArray();
+
+ writeLength(out, bytes.length);
+ out.write(bytes);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERIA5String.java b/src/java/org/apache/commons/ssl/asn1/DERIA5String.java
new file mode 100644
index 0000000..53d1abf
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERIA5String.java
@@ -0,0 +1,142 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** DER IA5String object - this is an ascii string. */
+public class DERIA5String
+ extends ASN1Object
+ implements DERString {
+ String string;
+
+ /**
+ * return a IA5 string from the passed in object
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERIA5String getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERIA5String) {
+ return (DERIA5String) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERIA5String(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an IA5 String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERIA5String getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ /** basic constructor - with bytes. */
+ public DERIA5String(
+ byte[] string) {
+ char[] cs = new char[string.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ cs[i] = (char) (string[i] & 0xff);
+ }
+
+ this.string = new String(cs);
+ }
+
+ /** basic constructor - without validation. */
+ public DERIA5String(
+ String string) {
+ this(string, false);
+ }
+
+ /**
+ * Constructor with optional validation.
+ *
+ * @param string the base string to wrap.
+ * @param validate whether or not to check the string.
+ * @throws IllegalArgumentException if validate is true and the string
+ * contains characters that should not be in an IA5String.
+ */
+ public DERIA5String(
+ String string,
+ boolean validate) {
+ if (validate && !isIA5String(string)) {
+ throw new IllegalArgumentException("string contains illegal characters");
+ }
+
+ this.string = string;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public String toString() {
+ return string;
+ }
+
+ public byte[] getOctets() {
+ char[] cs = string.toCharArray();
+ byte[] bs = new byte[cs.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ bs[i] = (byte) cs[i];
+ }
+
+ return bs;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(IA5_STRING, this.getOctets());
+ }
+
+ public int hashCode() {
+ return this.getString().hashCode();
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERIA5String)) {
+ return false;
+ }
+
+ DERIA5String s = (DERIA5String) o;
+
+ return this.getString().equals(s.getString());
+ }
+
+ /**
+ * return true if the passed in String can be represented without
+ * loss as an IA5String, false otherwise.
+ *
+ * @return true if in printable set, false otherwise.
+ */
+ public static boolean isIA5String(
+ String str) {
+ for (int i = str.length() - 1; i >= 0; i--) {
+ char ch = str.charAt(i);
+
+ if (ch > 0x007f) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERInputStream.java b/src/java/org/apache/commons/ssl/asn1/DERInputStream.java
new file mode 100644
index 0000000..5d35bd3
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERInputStream.java
@@ -0,0 +1,237 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Don't use this class. It will eventually disappear, use ASN1InputStream.
+ * <br>
+ * This class is scheduled for removal.
+ *
+ * @deprecated use ASN1InputStream
+ */
+public class DERInputStream
+ extends FilterInputStream implements DERTags {
+ /** @deprecated use ASN1InputStream */
+ public DERInputStream(
+ InputStream is) {
+ super(is);
+ }
+
+ protected int readLength()
+ throws IOException {
+ int length = read();
+ if (length < 0) {
+ throw new IOException("EOF found when length expected");
+ }
+
+ if (length == 0x80) {
+ return -1; // indefinite-length encoding
+ }
+
+ if (length > 127) {
+ int size = length & 0x7f;
+
+ if (size > 4) {
+ throw new IOException("DER length more than 4 bytes");
+ }
+
+ length = 0;
+ for (int i = 0; i < size; i++) {
+ int next = read();
+
+ if (next < 0) {
+ throw new IOException("EOF found reading length");
+ }
+
+ length = (length << 8) + next;
+ }
+
+ if (length < 0) {
+ throw new IOException("corrupted stream - negative length found");
+ }
+ }
+
+ return length;
+ }
+
+ protected void readFully(
+ byte[] bytes)
+ throws IOException {
+ int left = bytes.length;
+
+ if (left == 0) {
+ return;
+ }
+
+ while (left > 0) {
+ int l = read(bytes, bytes.length - left, left);
+
+ if (l < 0) {
+ throw new EOFException("unexpected end of stream");
+ }
+
+ left -= l;
+ }
+ }
+
+ /**
+ * build an object given its tag and a byte stream to construct it
+ * from.
+ */
+ protected DERObject buildObject(
+ int tag,
+ byte[] bytes)
+ throws IOException {
+ switch (tag) {
+ case NULL:
+ return null;
+ case SEQUENCE | CONSTRUCTED:
+ ByteArrayInputStream bIn = new ByteArrayInputStream(bytes);
+ BERInputStream dIn = new BERInputStream(bIn);
+ DERConstructedSequence seq = new DERConstructedSequence();
+
+ try {
+ for (; ;) {
+ DERObject obj = dIn.readObject();
+
+ seq.addObject(obj);
+ }
+ }
+ catch (EOFException ex) {
+ return seq;
+ }
+ case SET | CONSTRUCTED:
+ bIn = new ByteArrayInputStream(bytes);
+ dIn = new BERInputStream(bIn);
+
+ ASN1EncodableVector v = new ASN1EncodableVector();
+
+ try {
+ for (; ;) {
+ DERObject obj = dIn.readObject();
+
+ v.add(obj);
+ }
+ }
+ catch (EOFException ex) {
+ return new DERConstructedSet(v);
+ }
+ case BOOLEAN:
+ return new DERBoolean(bytes);
+ case INTEGER:
+ return new DERInteger(bytes);
+ case ENUMERATED:
+ return new DEREnumerated(bytes);
+ case OBJECT_IDENTIFIER:
+ return new DERObjectIdentifier(bytes);
+ case BIT_STRING:
+ int padBits = bytes[0];
+ byte[] data = new byte[bytes.length - 1];
+
+ System.arraycopy(bytes, 1, data, 0, bytes.length - 1);
+
+ return new DERBitString(data, padBits);
+ case UTF8_STRING:
+ return new DERUTF8String(bytes);
+ case PRINTABLE_STRING:
+ return new DERPrintableString(bytes);
+ case IA5_STRING:
+ return new DERIA5String(bytes);
+ case T61_STRING:
+ return new DERT61String(bytes);
+ case VISIBLE_STRING:
+ return new DERVisibleString(bytes);
+ case UNIVERSAL_STRING:
+ return new DERUniversalString(bytes);
+ case GENERAL_STRING:
+ return new DERGeneralString(bytes);
+ case BMP_STRING:
+ return new DERBMPString(bytes);
+ case OCTET_STRING:
+ return new DEROctetString(bytes);
+ case UTC_TIME:
+ return new DERUTCTime(bytes);
+ case GENERALIZED_TIME:
+ return new DERGeneralizedTime(bytes);
+ default:
+ //
+ // with tagged object tag number is bottom 5 bits
+ //
+ if ((tag & TAGGED) != 0) {
+ if ((tag & 0x1f) == 0x1f) {
+ throw new IOException("unsupported high tag encountered");
+ }
+
+ if (bytes.length == 0) // empty tag!
+ {
+ if ((tag & CONSTRUCTED) == 0) {
+ return new DERTaggedObject(false, tag & 0x1f, new DERNull());
+ } else {
+ return new DERTaggedObject(false, tag & 0x1f, new DERConstructedSequence());
+ }
+ }
+
+ //
+ // simple type - implicit... return an octet string
+ //
+ if ((tag & CONSTRUCTED) == 0) {
+ return new DERTaggedObject(false, tag & 0x1f, new DEROctetString(bytes));
+ }
+
+ bIn = new ByteArrayInputStream(bytes);
+ dIn = new BERInputStream(bIn);
+
+ DEREncodable dObj = dIn.readObject();
+
+ //
+ // explicitly tagged (probably!) - if it isn't we'd have to
+ // tell from the context
+ //
+ if (dIn.available() == 0) {
+ return new DERTaggedObject(tag & 0x1f, dObj);
+ }
+
+ //
+ // another implicit object, we'll create a sequence...
+ //
+ seq = new DERConstructedSequence();
+
+ seq.addObject(dObj);
+
+ try {
+ for (; ;) {
+ dObj = dIn.readObject();
+
+ seq.addObject(dObj);
+ }
+ }
+ catch (EOFException ex) {
+ // ignore --
+ }
+
+ return new DERTaggedObject(false, tag & 0x1f, seq);
+ }
+
+ return new DERUnknownTag(tag, bytes);
+ }
+ }
+
+ public DERObject readObject()
+ throws IOException {
+ int tag = read();
+ if (tag == -1) {
+ throw new EOFException();
+ }
+
+ int length = readLength();
+ byte[] bytes = new byte[length];
+
+ readFully(bytes);
+
+ return buildObject(tag, bytes);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERInteger.java b/src/java/org/apache/commons/ssl/asn1/DERInteger.java
new file mode 100644
index 0000000..4265efe
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERInteger.java
@@ -0,0 +1,114 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+public class DERInteger
+ extends ASN1Object {
+ byte[] bytes;
+
+ /**
+ * return an integer from the passed in object
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERInteger getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERInteger) {
+ return (DERInteger) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERInteger(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an Integer from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERInteger getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ public DERInteger(
+ int value) {
+ bytes = BigInteger.valueOf(value).toByteArray();
+ }
+
+ public DERInteger(
+ BigInteger value) {
+ bytes = value.toByteArray();
+ }
+
+ public DERInteger(
+ byte[] bytes) {
+ this.bytes = bytes;
+ }
+
+ public BigInteger getValue() {
+ return new BigInteger(bytes);
+ }
+
+ /**
+ * in some cases positive values get crammed into a space,
+ * that's not quite big enough...
+ */
+ public BigInteger getPositiveValue() {
+ return new BigInteger(1, bytes);
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(INTEGER, bytes);
+ }
+
+ public int hashCode() {
+ int value = 0;
+
+ for (int i = 0; i != bytes.length; i++) {
+ value ^= (bytes[i] & 0xff) << (i % 4);
+ }
+
+ return value;
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERInteger)) {
+ return false;
+ }
+
+ DERInteger other = (DERInteger) o;
+
+ if (bytes.length != other.bytes.length) {
+ return false;
+ }
+
+ for (int i = 0; i != bytes.length; i++) {
+ if (bytes[i] != other.bytes[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public String toString() {
+ return getValue().toString();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERNull.java b/src/java/org/apache/commons/ssl/asn1/DERNull.java
new file mode 100644
index 0000000..774cb6e
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERNull.java
@@ -0,0 +1,20 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** A NULL object. */
+public class DERNull
+ extends ASN1Null {
+ public static final DERNull INSTANCE = new DERNull();
+
+ byte[] zeroBytes = new byte[0];
+
+ public DERNull() {
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(NULL, zeroBytes);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERNumericString.java b/src/java/org/apache/commons/ssl/asn1/DERNumericString.java
new file mode 100644
index 0000000..9b72196
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERNumericString.java
@@ -0,0 +1,148 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** DER NumericString object - this is an ascii string of characters {0,1,2,3,4,5,6,7,8,9, }. */
+public class DERNumericString
+ extends ASN1Object
+ implements DERString {
+ String string;
+
+ /**
+ * return a Numeric string from the passed in object
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERNumericString getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERNumericString) {
+ return (DERNumericString) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERNumericString(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an Numeric String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERNumericString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ /** basic constructor - with bytes. */
+ public DERNumericString(
+ byte[] string) {
+ char[] cs = new char[string.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ cs[i] = (char) (string[i] & 0xff);
+ }
+
+ this.string = new String(cs);
+ }
+
+ /** basic constructor - without validation.. */
+ public DERNumericString(
+ String string) {
+ this(string, false);
+ }
+
+ /**
+ * Constructor with optional validation.
+ *
+ * @param string the base string to wrap.
+ * @param validate whether or not to check the string.
+ * @throws IllegalArgumentException if validate is true and the string
+ * contains characters that should not be in a NumericString.
+ */
+ public DERNumericString(
+ String string,
+ boolean validate) {
+ if (validate && !isNumericString(string)) {
+ throw new IllegalArgumentException("string contains illegal characters");
+ }
+
+ this.string = string;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public String toString() {
+ return string;
+ }
+
+ public byte[] getOctets() {
+ char[] cs = string.toCharArray();
+ byte[] bs = new byte[cs.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ bs[i] = (byte) cs[i];
+ }
+
+ return bs;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(NUMERIC_STRING, this.getOctets());
+ }
+
+ public int hashCode() {
+ return this.getString().hashCode();
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERNumericString)) {
+ return false;
+ }
+
+ DERNumericString s = (DERNumericString) o;
+
+ return this.getString().equals(s.getString());
+ }
+
+ /**
+ * Return true if the string can be represented as a NumericString ('0'..'9', ' ')
+ *
+ * @param str string to validate.
+ * @return true if numeric, fale otherwise.
+ */
+ public static boolean isNumericString(
+ String str) {
+ for (int i = str.length() - 1; i >= 0; i--) {
+ char ch = str.charAt(i);
+
+ if (ch > 0x007f) {
+ return false;
+ }
+
+ if (('0' <= ch && ch <= '9') || ch == ' ') {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERObject.java b/src/java/org/apache/commons/ssl/asn1/DERObject.java
new file mode 100644
index 0000000..df6dd86
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERObject.java
@@ -0,0 +1,18 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+public abstract class DERObject
+ extends ASN1Encodable
+ implements DERTags {
+ public DERObject toASN1Object() {
+ return this;
+ }
+
+ public abstract int hashCode();
+
+ public abstract boolean equals(Object o);
+
+ abstract void encode(DEROutputStream out)
+ throws IOException;
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERObjectIdentifier.java b/src/java/org/apache/commons/ssl/asn1/DERObjectIdentifier.java
new file mode 100644
index 0000000..f53153f
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERObjectIdentifier.java
@@ -0,0 +1,245 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigInteger;
+
+public class DERObjectIdentifier
+ extends ASN1Object {
+ String identifier;
+
+ /**
+ * return an OID from the passed in object
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERObjectIdentifier getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERObjectIdentifier) {
+ return (DERObjectIdentifier) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERObjectIdentifier(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an Object Identifier from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERObjectIdentifier getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+
+ DERObjectIdentifier(
+ byte[] bytes) {
+ StringBuffer objId = new StringBuffer();
+ long value = 0;
+ BigInteger bigValue = null;
+ boolean first = true;
+
+ for (int i = 0; i != bytes.length; i++) {
+ int b = bytes[i] & 0xff;
+
+ if (value < 0x80000000000000L) {
+ value = value * 128 + (b & 0x7f);
+ if ((b & 0x80) == 0) // end of number reached
+ {
+ if (first) {
+ switch ((int) value / 40) {
+ case 0:
+ objId.append('0');
+ break;
+ case 1:
+ objId.append('1');
+ value -= 40;
+ break;
+ default:
+ objId.append('2');
+ value -= 80;
+ }
+ first = false;
+ }
+
+ objId.append('.');
+ objId.append(value);
+ value = 0;
+ }
+ } else {
+ if (bigValue == null) {
+ bigValue = BigInteger.valueOf(value);
+ }
+ bigValue = bigValue.shiftLeft(7);
+ bigValue = bigValue.or(BigInteger.valueOf(b & 0x7f));
+ if ((b & 0x80) == 0) {
+ objId.append('.');
+ objId.append(bigValue);
+ bigValue = null;
+ value = 0;
+ }
+ }
+ }
+
+ this.identifier = objId.toString();
+ }
+
+ public DERObjectIdentifier(
+ String identifier) {
+ if (!isValidIdentifier(identifier)) {
+ throw new IllegalArgumentException("string " + identifier + " not an OID");
+ }
+
+ this.identifier = identifier;
+ }
+
+ public String getId() {
+ return identifier;
+ }
+
+ private void writeField(
+ OutputStream out,
+ long fieldValue)
+ throws IOException {
+ if (fieldValue >= (1L << 7)) {
+ if (fieldValue >= (1L << 14)) {
+ if (fieldValue >= (1L << 21)) {
+ if (fieldValue >= (1L << 28)) {
+ if (fieldValue >= (1L << 35)) {
+ if (fieldValue >= (1L << 42)) {
+ if (fieldValue >= (1L << 49)) {
+ if (fieldValue >= (1L << 56)) {
+ out.write((int) (fieldValue >> 56) | 0x80);
+ }
+ out.write((int) (fieldValue >> 49) | 0x80);
+ }
+ out.write((int) (fieldValue >> 42) | 0x80);
+ }
+ out.write((int) (fieldValue >> 35) | 0x80);
+ }
+ out.write((int) (fieldValue >> 28) | 0x80);
+ }
+ out.write((int) (fieldValue >> 21) | 0x80);
+ }
+ out.write((int) (fieldValue >> 14) | 0x80);
+ }
+ out.write((int) (fieldValue >> 7) | 0x80);
+ }
+ out.write((int) fieldValue & 0x7f);
+ }
+
+ private void writeField(
+ OutputStream out,
+ BigInteger fieldValue)
+ throws IOException {
+ int byteCount = (fieldValue.bitLength() + 6) / 7;
+ if (byteCount == 0) {
+ out.write(0);
+ } else {
+ BigInteger tmpValue = fieldValue;
+ byte[] tmp = new byte[byteCount];
+ for (int i = byteCount - 1; i >= 0; i--) {
+ tmp[i] = (byte) ((tmpValue.intValue() & 0x7f) | 0x80);
+ tmpValue = tmpValue.shiftRight(7);
+ }
+ tmp[byteCount - 1] &= 0x7f;
+ out.write(tmp);
+ }
+
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ OIDTokenizer tok = new OIDTokenizer(identifier);
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ writeField(bOut,
+ Integer.parseInt(tok.nextToken()) * 40
+ + Integer.parseInt(tok.nextToken()));
+
+ while (tok.hasMoreTokens()) {
+ String token = tok.nextToken();
+ if (token.length() < 18) {
+ writeField(bOut, Long.parseLong(token));
+ } else {
+ writeField(bOut, new BigInteger(token));
+ }
+ }
+
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ out.writeEncoded(OBJECT_IDENTIFIER, bytes);
+ }
+
+ public int hashCode() {
+ return identifier.hashCode();
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERObjectIdentifier)) {
+ return false;
+ }
+
+ return identifier.equals(((DERObjectIdentifier) o).identifier);
+ }
+
+ public String toString() {
+ return getId();
+ }
+
+ private static boolean isValidIdentifier(
+ String identifier) {
+ if (identifier.length() < 3
+ || identifier.charAt(1) != '.') {
+ return false;
+ }
+
+ char first = identifier.charAt(0);
+ if (first < '0' || first > '2') {
+ return false;
+ }
+
+ boolean periodAllowed = false;
+ for (int i = identifier.length() - 1; i >= 2; i--) {
+ char ch = identifier.charAt(i);
+
+ if ('0' <= ch && ch <= '9') {
+ periodAllowed = true;
+ continue;
+ }
+
+ if (ch == '.') {
+ if (!periodAllowed) {
+ return false;
+ }
+
+ periodAllowed = false;
+ continue;
+ }
+
+ return false;
+ }
+
+ return periodAllowed;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DEROctetString.java b/src/java/org/apache/commons/ssl/asn1/DEROctetString.java
new file mode 100644
index 0000000..113a99c
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DEROctetString.java
@@ -0,0 +1,23 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+public class DEROctetString
+ extends ASN1OctetString {
+ /** @param string the octets making up the octet string. */
+ public DEROctetString(
+ byte[] string) {
+ super(string);
+ }
+
+ public DEROctetString(
+ DEREncodable obj) {
+ super(obj);
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(OCTET_STRING, string);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DEROutputStream.java b/src/java/org/apache/commons/ssl/asn1/DEROutputStream.java
new file mode 100644
index 0000000..4a85500
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DEROutputStream.java
@@ -0,0 +1,73 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class DEROutputStream
+ extends FilterOutputStream implements DERTags {
+ public DEROutputStream(
+ OutputStream os) {
+ super(os);
+ }
+
+ private void writeLength(
+ int length)
+ throws IOException {
+ if (length > 127) {
+ int size = 1;
+ int val = length;
+
+ while ((val >>>= 8) != 0) {
+ size++;
+ }
+
+ write((byte) (size | 0x80));
+
+ for (int i = (size - 1) * 8; i >= 0; i -= 8) {
+ write((byte) (length >> i));
+ }
+ } else {
+ write((byte) length);
+ }
+ }
+
+ void writeEncoded(
+ int tag,
+ byte[] bytes)
+ throws IOException {
+ write(tag);
+ writeLength(bytes.length);
+ write(bytes);
+ }
+
+ protected void writeNull()
+ throws IOException {
+ write(NULL);
+ write(0x00);
+ }
+
+ public void write(byte[] buf)
+ throws IOException {
+ out.write(buf, 0, buf.length);
+ }
+
+ public void write(byte[] buf, int offSet, int len)
+ throws IOException {
+ out.write(buf, offSet, len);
+ }
+
+ public void writeObject(
+ Object obj)
+ throws IOException {
+ if (obj == null) {
+ writeNull();
+ } else if (obj instanceof DERObject) {
+ ((DERObject) obj).encode(this);
+ } else if (obj instanceof DEREncodable) {
+ ((DEREncodable) obj).getDERObject().encode(this);
+ } else {
+ throw new IOException("object not DEREncodable");
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERPrintableString.java b/src/java/org/apache/commons/ssl/asn1/DERPrintableString.java
new file mode 100644
index 0000000..48bd5c7
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERPrintableString.java
@@ -0,0 +1,172 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** DER PrintableString object. */
+public class DERPrintableString
+ extends ASN1Object
+ implements DERString {
+ String string;
+
+ /**
+ * return a printable string from the passed in object.
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERPrintableString getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERPrintableString) {
+ return (DERPrintableString) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERPrintableString(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a Printable String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERPrintableString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ /** basic constructor - byte encoded string. */
+ public DERPrintableString(
+ byte[] string) {
+ char[] cs = new char[string.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ cs[i] = (char) (string[i] & 0xff);
+ }
+
+ this.string = new String(cs);
+ }
+
+ /** basic constructor - this does not validate the string */
+ public DERPrintableString(
+ String string) {
+ this(string, false);
+ }
+
+ /**
+ * Constructor with optional validation.
+ *
+ * @param string the base string to wrap.
+ * @param validate whether or not to check the string.
+ * @throws IllegalArgumentException if validate is true and the string
+ * contains characters that should not be in a PrintableString.
+ */
+ public DERPrintableString(
+ String string,
+ boolean validate) {
+ if (validate && !isPrintableString(string)) {
+ throw new IllegalArgumentException("string contains illegal characters");
+ }
+
+ this.string = string;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public byte[] getOctets() {
+ char[] cs = string.toCharArray();
+ byte[] bs = new byte[cs.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ bs[i] = (byte) cs[i];
+ }
+
+ return bs;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(PRINTABLE_STRING, this.getOctets());
+ }
+
+ public int hashCode() {
+ return this.getString().hashCode();
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERPrintableString)) {
+ return false;
+ }
+
+ DERPrintableString s = (DERPrintableString) o;
+
+ return this.getString().equals(s.getString());
+ }
+
+ public String toString() {
+ return string;
+ }
+
+ /**
+ * return true if the passed in String can be represented without
+ * loss as a PrintableString, false otherwise.
+ *
+ * @return true if in printable set, false otherwise.
+ */
+ public static boolean isPrintableString(
+ String str) {
+ for (int i = str.length() - 1; i >= 0; i--) {
+ char ch = str.charAt(i);
+
+ if (ch > 0x007f) {
+ return false;
+ }
+
+ if ('a' <= ch && ch <= 'z') {
+ continue;
+ }
+
+ if ('A' <= ch && ch <= 'Z') {
+ continue;
+ }
+
+ if ('0' <= ch && ch <= '9') {
+ continue;
+ }
+
+ switch (ch) {
+ case ' ':
+ case '\'':
+ case '(':
+ case ')':
+ case '+':
+ case '-':
+ case '.':
+ case ':':
+ case '=':
+ case '?':
+ case '/':
+ case ',':
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERSequence.java b/src/java/org/apache/commons/ssl/asn1/DERSequence.java
new file mode 100644
index 0000000..9416a2d
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERSequence.java
@@ -0,0 +1,62 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+
+public class DERSequence
+ extends ASN1Sequence {
+ /** create an empty sequence */
+ public DERSequence() {
+ }
+
+ /** create a sequence containing one object */
+ public DERSequence(
+ DEREncodable obj) {
+ this.addObject(obj);
+ }
+
+ /** create a sequence containing a vector of objects. */
+ public DERSequence(
+ DEREncodableVector v) {
+ for (int i = 0; i != v.size(); i++) {
+ this.addObject(v.get(i));
+ }
+ }
+
+ /** create a sequence containing an array of objects. */
+ public DERSequence(
+ ASN1Encodable[] a) {
+ for (int i = 0; i != a.length; i++) {
+ this.addObject(a[i]);
+ }
+ }
+
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DER requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputing SEQUENCE,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ Enumeration e = this.getObjects();
+
+ while (e.hasMoreElements()) {
+ Object obj = e.nextElement();
+
+ dOut.writeObject(obj);
+ }
+
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ out.writeEncoded(SEQUENCE | CONSTRUCTED, bytes);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERSequenceGenerator.java b/src/java/org/apache/commons/ssl/asn1/DERSequenceGenerator.java
new file mode 100644
index 0000000..4fd7003
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERSequenceGenerator.java
@@ -0,0 +1,39 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+public class DERSequenceGenerator
+ extends DERGenerator {
+ private final ByteArrayOutputStream _bOut = new ByteArrayOutputStream();
+
+ public DERSequenceGenerator(
+ OutputStream out)
+ throws IOException {
+ super(out);
+ }
+
+ public DERSequenceGenerator(
+ OutputStream out,
+ int tagNo,
+ boolean isExplicit)
+ throws IOException {
+ super(out, tagNo, isExplicit);
+ }
+
+ public void addObject(
+ DEREncodable object)
+ throws IOException {
+ object.getDERObject().encode(new DEROutputStream(_bOut));
+ }
+
+ public OutputStream getRawOutputStream() {
+ return _bOut;
+ }
+
+ public void close()
+ throws IOException {
+ writeDEREncoded(DERTags.CONSTRUCTED | DERTags.SEQUENCE, _bOut.toByteArray());
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERSet.java b/src/java/org/apache/commons/ssl/asn1/DERSet.java
new file mode 100644
index 0000000..4fbb0f8
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERSet.java
@@ -0,0 +1,76 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Enumeration;
+
+/** A DER encoded set object */
+public class DERSet
+ extends ASN1Set {
+ /** create an empty set */
+ public DERSet() {
+ }
+
+ /** @param obj - a single object that makes up the set. */
+ public DERSet(
+ DEREncodable obj) {
+ this.addObject(obj);
+ }
+
+ /** @param v - a vector of objects making up the set. */
+ public DERSet(
+ DEREncodableVector v) {
+ this(v, true);
+ }
+
+ /** create a set from an array of objects. */
+ public DERSet(
+ ASN1Encodable[] a) {
+ for (int i = 0; i != a.length; i++) {
+ this.addObject(a[i]);
+ }
+
+ this.sort();
+ }
+
+ /** @param v - a vector of objects making up the set. */
+ DERSet(
+ DEREncodableVector v,
+ boolean needsSorting) {
+ for (int i = 0; i != v.size(); i++) {
+ this.addObject(v.get(i));
+ }
+
+ if (needsSorting) {
+ this.sort();
+ }
+ }
+
+ /*
+ * A note on the implementation:
+ * <p>
+ * As DER requires the constructed, definite-length model to
+ * be used for structured types, this varies slightly from the
+ * ASN.1 descriptions given. Rather than just outputing SET,
+ * we also have to specify CONSTRUCTED, and the objects length.
+ */
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+ Enumeration e = this.getObjects();
+
+ while (e.hasMoreElements()) {
+ Object obj = e.nextElement();
+
+ dOut.writeObject(obj);
+ }
+
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ out.writeEncoded(SET | CONSTRUCTED, bytes);
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERString.java b/src/java/org/apache/commons/ssl/asn1/DERString.java
new file mode 100644
index 0000000..71565b0
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERString.java
@@ -0,0 +1,6 @@
+package org.apache.commons.ssl.asn1;
+
+/** basic interface for DER string objects. */
+public interface DERString {
+ public String getString();
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERT61String.java b/src/java/org/apache/commons/ssl/asn1/DERT61String.java
new file mode 100644
index 0000000..bd92539
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERT61String.java
@@ -0,0 +1,103 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** DER T61String (also the teletex string) */
+public class DERT61String
+ extends ASN1Object
+ implements DERString {
+ String string;
+
+ /**
+ * return a T61 string from the passed in object.
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERT61String getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERT61String) {
+ return (DERT61String) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERT61String(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an T61 String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERT61String getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ /** basic constructor - with bytes. */
+ public DERT61String(
+ byte[] string) {
+ char[] cs = new char[string.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ cs[i] = (char) (string[i] & 0xff);
+ }
+
+ this.string = new String(cs);
+ }
+
+ /** basic constructor - with string. */
+ public DERT61String(
+ String string) {
+ this.string = string;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public String toString() {
+ return string;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(T61_STRING, this.getOctets());
+ }
+
+ public byte[] getOctets() {
+ char[] cs = string.toCharArray();
+ byte[] bs = new byte[cs.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ bs[i] = (byte) cs[i];
+ }
+
+ return bs;
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERT61String)) {
+ return false;
+ }
+
+ return this.getString().equals(((DERT61String) o).getString());
+ }
+
+ public int hashCode() {
+ return this.getString().hashCode();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERTaggedObject.java b/src/java/org/apache/commons/ssl/asn1/DERTaggedObject.java
new file mode 100644
index 0000000..6dd457c
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERTaggedObject.java
@@ -0,0 +1,74 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * DER TaggedObject - in ASN.1 nottation this is any object proceeded by
+ * a [n] where n is some number - these are assume to follow the construction
+ * rules (as with sequences).
+ */
+public class DERTaggedObject
+ extends ASN1TaggedObject {
+ /**
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public DERTaggedObject(
+ int tagNo,
+ DEREncodable obj) {
+ super(tagNo, obj);
+ }
+
+ /**
+ * @param explicit true if an explicitly tagged object.
+ * @param tagNo the tag number for this object.
+ * @param obj the tagged object.
+ */
+ public DERTaggedObject(
+ boolean explicit,
+ int tagNo,
+ DEREncodable obj) {
+ super(explicit, tagNo, obj);
+ }
+
+ /**
+ * create an implicitly tagged object that contains a zero
+ * length sequence.
+ */
+ public DERTaggedObject(
+ int tagNo) {
+ super(false, tagNo, new DERSequence());
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ if (!empty) {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ DEROutputStream dOut = new DEROutputStream(bOut);
+
+ dOut.writeObject(obj);
+ dOut.close();
+
+ byte[] bytes = bOut.toByteArray();
+
+ if (explicit) {
+ out.writeEncoded(CONSTRUCTED | TAGGED | tagNo, bytes);
+ } else {
+ //
+ // need to mark constructed types...
+ //
+ if ((bytes[0] & CONSTRUCTED) != 0) {
+ bytes[0] = (byte) (CONSTRUCTED | TAGGED | tagNo);
+ } else {
+ bytes[0] = (byte) (TAGGED | tagNo);
+ }
+
+ out.write(bytes);
+ }
+ } else {
+ out.writeEncoded(CONSTRUCTED | TAGGED | tagNo, new byte[0]);
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERTags.java b/src/java/org/apache/commons/ssl/asn1/DERTags.java
new file mode 100644
index 0000000..9fb9b41
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERTags.java
@@ -0,0 +1,35 @@
+package org.apache.commons.ssl.asn1;
+
+public interface DERTags {
+ public static final int BOOLEAN = 0x01;
+ public static final int INTEGER = 0x02;
+ public static final int BIT_STRING = 0x03;
+ public static final int OCTET_STRING = 0x04;
+ public static final int NULL = 0x05;
+ public static final int OBJECT_IDENTIFIER = 0x06;
+ public static final int EXTERNAL = 0x08;
+ public static final int ENUMERATED = 0x0a;
+ public static final int SEQUENCE = 0x10;
+ public static final int SEQUENCE_OF = 0x10; // for completeness
+ public static final int SET = 0x11;
+ public static final int SET_OF = 0x11; // for completeness
+
+
+ public static final int NUMERIC_STRING = 0x12;
+ public static final int PRINTABLE_STRING = 0x13;
+ public static final int T61_STRING = 0x14;
+ public static final int VIDEOTEX_STRING = 0x15;
+ public static final int IA5_STRING = 0x16;
+ public static final int UTC_TIME = 0x17;
+ public static final int GENERALIZED_TIME = 0x18;
+ public static final int GRAPHIC_STRING = 0x19;
+ public static final int VISIBLE_STRING = 0x1a;
+ public static final int GENERAL_STRING = 0x1b;
+ public static final int UNIVERSAL_STRING = 0x1c;
+ public static final int BMP_STRING = 0x1e;
+ public static final int UTF8_STRING = 0x0c;
+
+ public static final int CONSTRUCTED = 0x20;
+ public static final int APPLICATION = 0x40;
+ public static final int TAGGED = 0x80;
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERUTCTime.java b/src/java/org/apache/commons/ssl/asn1/DERUTCTime.java
new file mode 100644
index 0000000..c858e0c
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERUTCTime.java
@@ -0,0 +1,214 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.SimpleTimeZone;
+
+/** UTC time object. */
+public class DERUTCTime
+ extends ASN1Object {
+ String time;
+
+ /**
+ * return an UTC Time from the passed in object.
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERUTCTime getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERUTCTime) {
+ return (DERUTCTime) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERUTCTime(((ASN1OctetString) obj).getOctets());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return an UTC Time from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERUTCTime getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ /**
+ * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
+ * never encoded. When you're creating one of these objects from scratch, that's
+ * what you want to use, otherwise we'll try to deal with whatever gets read from
+ * the input stream... (this is why the input format is different from the getTime()
+ * method output).
+ * <p/>
+ *
+ * @param time the time string.
+ */
+ public DERUTCTime(
+ String time) {
+ this.time = time;
+ try {
+ this.getDate();
+ }
+ catch (ParseException e) {
+ throw new IllegalArgumentException("invalid date string: " + e.getMessage());
+ }
+ }
+
+ /** base constructer from a java.util.date object */
+ public DERUTCTime(
+ Date time) {
+ SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'");
+
+ dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+
+ this.time = dateF.format(time);
+ }
+
+ DERUTCTime(
+ byte[] bytes) {
+ //
+ // explicitly convert to characters
+ //
+ char[] dateC = new char[bytes.length];
+
+ for (int i = 0; i != dateC.length; i++) {
+ dateC[i] = (char) (bytes[i] & 0xff);
+ }
+
+ this.time = new String(dateC);
+ }
+
+ /**
+ * return the time as a date based on whatever a 2 digit year will return. For
+ * standardised processing use getAdjustedDate().
+ *
+ * @return the resulting date
+ * @throws ParseException if the date string cannot be parsed.
+ */
+ public Date getDate()
+ throws ParseException {
+ SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz");
+
+ return dateF.parse(getTime());
+ }
+
+ /**
+ * return the time as an adjusted date
+ * in the range of 1950 - 2049.
+ *
+ * @return a date in the range of 1950 to 2049.
+ * @throws ParseException if the date string cannot be parsed.
+ */
+ public Date getAdjustedDate()
+ throws ParseException {
+ SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
+
+ dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+
+ return dateF.parse(getAdjustedTime());
+ }
+
+ /**
+ * return the time - always in the form of
+ * YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+ * <p/>
+ * Normally in a certificate we would expect "Z" rather than "GMT",
+ * however adding the "GMT" means we can just use:
+ * <pre>
+ * dateF = new SimpleDateFormat("yyMMddHHmmssz");
+ * </pre>
+ * To read in the time and get a date which is compatible with our local
+ * time zone.
+ * <p/>
+ * <b>Note:</b> In some cases, due to the local date processing, this
+ * may lead to unexpected results. If you want to stick the normal
+ * convention of 1950 to 2049 use the getAdjustedTime() method.
+ */
+ public String getTime() {
+ //
+ // standardise the format.
+ //
+ if (time.indexOf('-') < 0 && time.indexOf('+') < 0) {
+ if (time.length() == 11) {
+ return time.substring(0, 10) + "00GMT+00:00";
+ } else {
+ return time.substring(0, 12) + "GMT+00:00";
+ }
+ } else {
+ int index = time.indexOf('-');
+ if (index < 0) {
+ index = time.indexOf('+');
+ }
+ String d = time;
+
+ if (index == time.length() - 3) {
+ d += "00";
+ }
+
+ if (index == 10) {
+ return d.substring(0, 10) + "00GMT" + d.substring(10, 13) + ":" + d.substring(13, 15);
+ } else {
+ return d.substring(0, 12) + "GMT" + d.substring(12, 15) + ":" + d.substring(15, 17);
+ }
+ }
+ }
+
+ /**
+ * return a time string as an adjusted date with a 4 digit year. This goes
+ * in the range of 1950 - 2049.
+ */
+ public String getAdjustedTime() {
+ String d = this.getTime();
+
+ if (d.charAt(0) < '5') {
+ return "20" + d;
+ } else {
+ return "19" + d;
+ }
+ }
+
+ private byte[] getOctets() {
+ char[] cs = time.toCharArray();
+ byte[] bs = new byte[cs.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ bs[i] = (byte) cs[i];
+ }
+
+ return bs;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(UTC_TIME, this.getOctets());
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERUTCTime)) {
+ return false;
+ }
+
+ return time.equals(((DERUTCTime) o).time);
+ }
+
+ public int hashCode() {
+ return time.hashCode();
+ }
+
+ public String toString() {
+ return time;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERUTF8String.java b/src/java/org/apache/commons/ssl/asn1/DERUTF8String.java
new file mode 100644
index 0000000..768c525
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERUTF8String.java
@@ -0,0 +1,83 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** DER UTF8String object. */
+public class DERUTF8String
+ extends ASN1Object
+ implements DERString {
+ String string;
+
+ /**
+ * return an UTF8 string from the passed in object.
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERUTF8String getInstance(Object obj) {
+ if (obj == null || obj instanceof DERUTF8String) {
+ return (DERUTF8String) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERUTF8String(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: "
+ + obj.getClass().getName());
+ }
+
+ /**
+ * return an UTF8 String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly tagged false
+ * otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot be converted.
+ */
+ public static DERUTF8String getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ /** basic constructor - byte encoded string. */
+ DERUTF8String(byte[] string) {
+ this.string = Strings.fromUTF8ByteArray(string);
+ }
+
+ /** basic constructor */
+ public DERUTF8String(String string) {
+ this.string = string;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public String toString() {
+ return string;
+ }
+
+ public int hashCode() {
+ return this.getString().hashCode();
+ }
+
+ boolean asn1Equals(DERObject o) {
+ if (!(o instanceof DERUTF8String)) {
+ return false;
+ }
+
+ DERUTF8String s = (DERUTF8String) o;
+
+ return this.getString().equals(s.getString());
+ }
+
+ void encode(DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(UTF8_STRING, Strings.toUTF8ByteArray(string));
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERUniversalString.java b/src/java/org/apache/commons/ssl/asn1/DERUniversalString.java
new file mode 100644
index 0000000..29be4bf
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERUniversalString.java
@@ -0,0 +1,100 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/** DER UniversalString object. */
+public class DERUniversalString
+ extends ASN1Object
+ implements DERString {
+ private static final char[] table = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+ private byte[] string;
+
+ /**
+ * return a Universal String from the passed in object.
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERUniversalString getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERUniversalString) {
+ return (DERUniversalString) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERUniversalString(((ASN1OctetString) obj).getOctets());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a Universal String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERUniversalString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ /** basic constructor - byte encoded string. */
+ public DERUniversalString(
+ byte[] string) {
+ this.string = string;
+ }
+
+ public String getString() {
+ StringBuffer buf = new StringBuffer("#");
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ ASN1OutputStream aOut = new ASN1OutputStream(bOut);
+
+ try {
+ aOut.writeObject(this);
+ }
+ catch (IOException e) {
+ throw new RuntimeException("internal error encoding BitString");
+ }
+
+ byte[] string = bOut.toByteArray();
+
+ for (int i = 0; i != string.length; i++) {
+ buf.append(table[(string[i] >>> 4) & 0xf]);
+ buf.append(table[string[i] & 0xf]);
+ }
+
+ return buf.toString();
+ }
+
+ public String toString() {
+ return getString();
+ }
+
+ public byte[] getOctets() {
+ return string;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(UNIVERSAL_STRING, this.getOctets());
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERUniversalString)) {
+ return false;
+ }
+
+ return this.getString().equals(((DERUniversalString) o).getString());
+ }
+
+ public int hashCode() {
+ return this.getString().hashCode();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERUnknownTag.java b/src/java/org/apache/commons/ssl/asn1/DERUnknownTag.java
new file mode 100644
index 0000000..5a02fde
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERUnknownTag.java
@@ -0,0 +1,71 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** We insert one of these when we find a tag we don't recognise. */
+public class DERUnknownTag
+ extends DERObject {
+ int tag;
+ byte[] data;
+
+ /**
+ * @param tag the tag value.
+ * @param data the octets making up the time.
+ */
+ public DERUnknownTag(
+ int tag,
+ byte[] data) {
+ this.tag = tag;
+ this.data = data;
+ }
+
+ public int getTag() {
+ return tag;
+ }
+
+ public byte[] getData() {
+ return data;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(tag, data);
+ }
+
+ public boolean equals(
+ Object o) {
+ if (!(o instanceof DERUnknownTag)) {
+ return false;
+ }
+
+ DERUnknownTag other = (DERUnknownTag) o;
+
+ if (tag != other.tag) {
+ return false;
+ }
+
+ if (data.length != other.data.length) {
+ return false;
+ }
+
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] != other.data[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public int hashCode() {
+ byte[] b = this.getData();
+ int value = 0;
+
+ for (int i = 0; i != b.length; i++) {
+ value ^= (b[i] & 0xff) << (i % 4);
+ }
+
+ return value ^ this.getTag();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DERVisibleString.java b/src/java/org/apache/commons/ssl/asn1/DERVisibleString.java
new file mode 100644
index 0000000..0b8ec89
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DERVisibleString.java
@@ -0,0 +1,103 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+
+/** DER VisibleString object. */
+public class DERVisibleString
+ extends ASN1Object
+ implements DERString {
+ String string;
+
+ /**
+ * return a Visible String from the passed in object.
+ *
+ * @throws IllegalArgumentException if the object cannot be converted.
+ */
+ public static DERVisibleString getInstance(
+ Object obj) {
+ if (obj == null || obj instanceof DERVisibleString) {
+ return (DERVisibleString) obj;
+ }
+
+ if (obj instanceof ASN1OctetString) {
+ return new DERVisibleString(((ASN1OctetString) obj).getOctets());
+ }
+
+ if (obj instanceof ASN1TaggedObject) {
+ return getInstance(((ASN1TaggedObject) obj).getObject());
+ }
+
+ throw new IllegalArgumentException("illegal object in getInstance: " + obj.getClass().getName());
+ }
+
+ /**
+ * return a Visible String from a tagged object.
+ *
+ * @param obj the tagged object holding the object we want
+ * @param explicit true if the object is meant to be explicitly
+ * tagged false otherwise.
+ * @throws IllegalArgumentException if the tagged object cannot
+ * be converted.
+ */
+ public static DERVisibleString getInstance(
+ ASN1TaggedObject obj,
+ boolean explicit) {
+ return getInstance(obj.getObject());
+ }
+
+ /** basic constructor - byte encoded string. */
+ public DERVisibleString(
+ byte[] string) {
+ char[] cs = new char[string.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ cs[i] = (char) (string[i] & 0xff);
+ }
+
+ this.string = new String(cs);
+ }
+
+ /** basic constructor */
+ public DERVisibleString(
+ String string) {
+ this.string = string;
+ }
+
+ public String getString() {
+ return string;
+ }
+
+ public String toString() {
+ return string;
+ }
+
+ public byte[] getOctets() {
+ char[] cs = string.toCharArray();
+ byte[] bs = new byte[cs.length];
+
+ for (int i = 0; i != cs.length; i++) {
+ bs[i] = (byte) cs[i];
+ }
+
+ return bs;
+ }
+
+ void encode(
+ DEROutputStream out)
+ throws IOException {
+ out.writeEncoded(VISIBLE_STRING, this.getOctets());
+ }
+
+ boolean asn1Equals(
+ DERObject o) {
+ if (!(o instanceof DERVisibleString)) {
+ return false;
+ }
+
+ return this.getString().equals(((DERVisibleString) o).getString());
+ }
+
+ public int hashCode() {
+ return this.getString().hashCode();
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/DefiniteLengthInputStream.java b/src/java/org/apache/commons/ssl/asn1/DefiniteLengthInputStream.java
new file mode 100644
index 0000000..f88a078
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/DefiniteLengthInputStream.java
@@ -0,0 +1,83 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+class DefiniteLengthInputStream
+ extends LimitedInputStream {
+ private int _length;
+
+ DefiniteLengthInputStream(
+ InputStream in,
+ int length) {
+ super(in);
+
+ if (length < 0) {
+ throw new IllegalArgumentException("negative lengths not allowed");
+ }
+
+ this._length = length;
+ }
+
+ public int read()
+ throws IOException {
+ if (_length > 0) {
+ int b = _in.read();
+
+ if (b < 0) {
+ throw new EOFException();
+ }
+
+ --_length;
+ return b;
+ }
+
+ setParentEofDetect(true);
+
+ return -1;
+ }
+
+ public int read(byte[] buf, int off, int len)
+ throws IOException {
+ if (_length > 0) {
+ int toRead = Math.min(len, _length);
+ int numRead = _in.read(buf, off, toRead);
+
+ if (numRead < 0)
+ throw new EOFException();
+
+ _length -= numRead;
+ return numRead;
+ }
+
+ setParentEofDetect(true);
+
+ return -1;
+ }
+
+ byte[] toByteArray()
+ throws IOException {
+ byte[] bytes = new byte[_length];
+
+ if (_length > 0) {
+ int pos = 0;
+ do {
+ int read = _in.read(bytes, pos, _length - pos);
+
+ if (read < 0) {
+ throw new EOFException();
+ }
+
+ pos += read;
+ }
+ while (pos < _length);
+
+ _length = 0;
+ }
+
+ setParentEofDetect(true);
+
+ return bytes;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/IndefiniteLengthInputStream.java b/src/java/org/apache/commons/ssl/asn1/IndefiniteLengthInputStream.java
new file mode 100644
index 0000000..1f48af8
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/IndefiniteLengthInputStream.java
@@ -0,0 +1,98 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+class IndefiniteLengthInputStream
+ extends LimitedInputStream {
+ private int _b1;
+ private int _b2;
+ private boolean _eofReached = false;
+ private boolean _eofOn00 = true;
+
+ IndefiniteLengthInputStream(
+ InputStream in)
+ throws IOException {
+ super(in);
+
+ _b1 = in.read();
+ _b2 = in.read();
+ _eofReached = (_b2 < 0);
+ }
+
+ void setEofOn00(
+ boolean eofOn00) {
+ _eofOn00 = eofOn00;
+ }
+
+ boolean checkForEof() {
+ if (_eofOn00 && (_b1 == 0x00 && _b2 == 0x00)) {
+ _eofReached = true;
+ setParentEofDetect(true);
+ }
+ return _eofReached;
+ }
+
+ public int read(byte[] b, int off, int len)
+ throws IOException {
+ // Only use this optimisation if we aren't checking for 00
+ if (_eofOn00 || len < 3) {
+ return super.read(b, off, len);
+ }
+
+ if (_eofReached) {
+ return -1;
+ }
+
+ int numRead = _in.read(b, off + 2, len - 2);
+
+ if (numRead < 0) {
+// throw new EOFException();
+ _eofReached = true;
+ return -1;
+ }
+
+ b[off] = (byte) _b1;
+ b[off + 1] = (byte) _b2;
+
+ _b1 = _in.read();
+ _b2 = _in.read();
+
+ if (_b2 < 0) {
+ // Corrupted stream
+// throw new EOFException();
+ _eofReached = true;
+ // Just fall thru...
+ }
+
+ return numRead + 2;
+ }
+
+ public int read()
+ throws IOException {
+ if (checkForEof()) {
+ return -1;
+ }
+
+ int b = _in.read();
+
+ //
+ // strictly speaking we should return b1 and b2, but if this happens the stream
+ // is corrupted so we are already in trouble.
+ //
+ if (b < 0) {
+ // Corrupted stream
+// throw new EOFException();
+ _eofReached = true;
+
+ return -1;
+ }
+
+ int v = _b1;
+
+ _b1 = _b2;
+ _b2 = b;
+
+ return v;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/LimitedInputStream.java b/src/java/org/apache/commons/ssl/asn1/LimitedInputStream.java
new file mode 100644
index 0000000..e1af7d2
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/LimitedInputStream.java
@@ -0,0 +1,23 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.InputStream;
+
+abstract class LimitedInputStream
+ extends InputStream {
+ protected final InputStream _in;
+
+ LimitedInputStream(
+ InputStream in) {
+ this._in = in;
+ }
+
+ InputStream getUnderlyingStream() {
+ return _in;
+ }
+
+ protected void setParentEofDetect(boolean on) {
+ if (_in instanceof IndefiniteLengthInputStream) {
+ ((IndefiniteLengthInputStream) _in).setEofOn00(on);
+ }
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/OIDTokenizer.java b/src/java/org/apache/commons/ssl/asn1/OIDTokenizer.java
new file mode 100644
index 0000000..b59c009
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/OIDTokenizer.java
@@ -0,0 +1,42 @@
+package org.apache.commons.ssl.asn1;
+
+/**
+ * class for breaking up an OID into it's component tokens, ala
+ * java.util.StringTokenizer. We need this class as some of the
+ * lightweight Java environment don't support classes like
+ * StringTokenizer.
+ */
+public class OIDTokenizer {
+ private String oid;
+ private int index;
+
+ public OIDTokenizer(
+ String oid) {
+ this.oid = oid;
+ this.index = 0;
+ }
+
+ public boolean hasMoreTokens() {
+ return (index != -1);
+ }
+
+ public String nextToken() {
+ if (index == -1) {
+ return null;
+ }
+
+ String token;
+ int end = oid.indexOf('.', index);
+
+ if (end == -1) {
+ token = oid.substring(index);
+ index = -1;
+ return token;
+ }
+
+ token = oid.substring(index, end);
+
+ index = end + 1;
+ return token;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/asn1/Strings.java b/src/java/org/apache/commons/ssl/asn1/Strings.java
new file mode 100644
index 0000000..74104be
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/asn1/Strings.java
@@ -0,0 +1,195 @@
+package org.apache.commons.ssl.asn1;
+
+import java.io.ByteArrayOutputStream;
+import java.util.Vector;
+
+public final class Strings {
+ public static String fromUTF8ByteArray(byte[] bytes) {
+ int i = 0;
+ int length = 0;
+
+ while (i < bytes.length) {
+ length++;
+ if ((bytes[i] & 0xf0) == 0xf0) {
+ // surrogate pair
+ length++;
+ i += 4;
+ } else if ((bytes[i] & 0xe0) == 0xe0) {
+ i += 3;
+ } else if ((bytes[i] & 0xc0) == 0xc0) {
+ i += 2;
+ } else {
+ i += 1;
+ }
+ }
+
+ char[] cs = new char[length];
+
+ i = 0;
+ length = 0;
+
+ while (i < bytes.length) {
+ char ch;
+
+ if ((bytes[i] & 0xf0) == 0xf0) {
+ int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i + 1] & 0x3F) << 12) | ((bytes[i + 2] & 0x3F) << 6) | (bytes[i + 3] & 0x3F);
+ int U = codePoint - 0x10000;
+ char W1 = (char) (0xD800 | (U >> 10));
+ char W2 = (char) (0xDC00 | (U & 0x3FF));
+ cs[length++] = W1;
+ ch = W2;
+ i += 4;
+ } else if ((bytes[i] & 0xe0) == 0xe0) {
+ ch = (char) (((bytes[i] & 0x0f) << 12)
+ | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f));
+ i += 3;
+ } else if ((bytes[i] & 0xd0) == 0xd0) {
+ ch = (char) (((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
+ i += 2;
+ } else if ((bytes[i] & 0xc0) == 0xc0) {
+ ch = (char) (((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f));
+ i += 2;
+ } else {
+ ch = (char) (bytes[i] & 0xff);
+ i += 1;
+ }
+
+ cs[length++] = ch;
+ }
+
+ return new String(cs);
+ }
+
+ public static byte[] toUTF8ByteArray(String string) {
+ ByteArrayOutputStream bOut = new ByteArrayOutputStream();
+ char[] c = string.toCharArray();
+ int i = 0;
+
+ while (i < c.length) {
+ char ch = c[i];
+
+ if (ch < 0x0080) {
+ bOut.write(ch);
+ } else if (ch < 0x0800) {
+ bOut.write(0xc0 | (ch >> 6));
+ bOut.write(0x80 | (ch & 0x3f));
+ }
+ // surrogate pair
+ else if (ch >= 0xD800 && ch <= 0xDFFF) {
+ // in error - can only happen, if the Java String class has a
+ // bug.
+ if (i + 1 >= c.length) {
+ throw new IllegalStateException("invalid UTF-16 codepoint");
+ }
+ char W1 = ch;
+ ch = c[++i];
+ char W2 = ch;
+ // in error - can only happen, if the Java String class has a
+ // bug.
+ if (W1 > 0xDBFF) {
+ throw new IllegalStateException("invalid UTF-16 codepoint");
+ }
+ int codePoint = (((W1 & 0x03FF) << 10) | (W2 & 0x03FF)) + 0x10000;
+ bOut.write(0xf0 | (codePoint >> 18));
+ bOut.write(0x80 | ((codePoint >> 12) & 0x3F));
+ bOut.write(0x80 | ((codePoint >> 6) & 0x3F));
+ bOut.write(0x80 | (codePoint & 0x3F));
+ } else {
+ bOut.write(0xe0 | (ch >> 12));
+ bOut.write(0x80 | ((ch >> 6) & 0x3F));
+ bOut.write(0x80 | (ch & 0x3F));
+ }
+
+ i++;
+ }
+
+ return bOut.toByteArray();
+ }
+
+ /**
+ * A locale independent version of toUpperCase.
+ *
+ * @param string input to be converted
+ * @return a US Ascii uppercase version
+ */
+ public static String toUpperCase(String string) {
+ boolean changed = false;
+ char[] chars = string.toCharArray();
+
+ for (int i = 0; i != chars.length; i++) {
+ char ch = chars[i];
+ if ('a' <= ch && 'z' >= ch) {
+ changed = true;
+ chars[i] = (char) (ch - 'a' + 'A');
+ }
+ }
+
+ if (changed) {
+ return new String(chars);
+ }
+
+ return string;
+ }
+
+ /**
+ * A locale independent version of toLowerCase.
+ *
+ * @param string input to be converted
+ * @return a US ASCII lowercase version
+ */
+ public static String toLowerCase(String string) {
+ boolean changed = false;
+ char[] chars = string.toCharArray();
+
+ for (int i = 0; i != chars.length; i++) {
+ char ch = chars[i];
+ if ('A' <= ch && 'Z' >= ch) {
+ changed = true;
+ chars[i] = (char) (ch - 'A' + 'a');
+ }
+ }
+
+ if (changed) {
+ return new String(chars);
+ }
+
+ return string;
+ }
+
+ public static byte[] toByteArray(String string) {
+ byte[] bytes = new byte[string.length()];
+
+ for (int i = 0; i != bytes.length; i++) {
+ char ch = string.charAt(i);
+
+ bytes[i] = (byte) ch;
+ }
+
+ return bytes;
+ }
+
+ public static String[] split(String input, char delimiter) {
+ Vector v = new Vector();
+ boolean moreTokens = true;
+ String subString;
+
+ while (moreTokens) {
+ int tokenLocation = input.indexOf(delimiter);
+ if (tokenLocation > 0) {
+ subString = input.substring(0, tokenLocation);
+ v.addElement(subString);
+ input = input.substring(tokenLocation + 1);
+ } else {
+ moreTokens = false;
+ v.addElement(input);
+ }
+ }
+
+ String[] res = new String[v.size()];
+
+ for (int i = 0; i != res.length; i++) {
+ res[i] = (String) v.elementAt(i);
+ }
+ return res;
+ }
+}
diff --git a/src/java/org/apache/commons/ssl/rmi/DateRMI.java b/src/java/org/apache/commons/ssl/rmi/DateRMI.java
new file mode 100644
index 0000000..c76bc74
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/rmi/DateRMI.java
@@ -0,0 +1,69 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/rmi/DateRMI.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl.rmi;
+
+import java.io.Serializable;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+import java.util.Date;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 22-Feb-2007
+ */
+public class DateRMI extends UnicastRemoteObject
+ implements Remote, Serializable, RemoteDate {
+ private Date d;
+
+ public DateRMI() throws RemoteException {
+ super();
+ this.d = new Date();
+ }
+
+ public Date getDate() throws RemoteException {
+ return d;
+ }
+
+ public boolean equals(Object o) {
+ RemoteDate rd = (RemoteDate) o;
+ try {
+ return d.equals(rd.getDate());
+ }
+ catch (RemoteException re) {
+ return false;
+ }
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/rmi/IntegerRMI.java b/src/java/org/apache/commons/ssl/rmi/IntegerRMI.java
new file mode 100644
index 0000000..de05f0d
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/rmi/IntegerRMI.java
@@ -0,0 +1,69 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/rmi/IntegerRMI.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl.rmi;
+
+import java.io.Serializable;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.server.UnicastRemoteObject;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 22-Feb-2007
+ */
+public class IntegerRMI extends UnicastRemoteObject
+ implements Remote, Serializable, RemoteInteger {
+ private int i;
+
+ public IntegerRMI() throws RemoteException {
+ super();
+ this.i = (int) Math.round(Math.random() * 1000000.0);
+ }
+
+ public int getInt() throws RemoteException {
+ return i;
+ }
+
+ public boolean equals(Object o) {
+ RemoteInteger ri = (RemoteInteger) o;
+ try {
+ return i == ri.getInt();
+ }
+ catch (RemoteException re) {
+ return false;
+ }
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/rmi/RemoteDate.java b/src/java/org/apache/commons/ssl/rmi/RemoteDate.java
new file mode 100644
index 0000000..555c13e
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/rmi/RemoteDate.java
@@ -0,0 +1,46 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/rmi/RemoteDate.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl.rmi;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.util.Date;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 22-Feb-2007
+ */
+public interface RemoteDate extends Remote {
+ public Date getDate() throws RemoteException;
+}
diff --git a/src/java/org/apache/commons/ssl/rmi/RemoteInteger.java b/src/java/org/apache/commons/ssl/rmi/RemoteInteger.java
new file mode 100644
index 0000000..6e70e1a
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/rmi/RemoteInteger.java
@@ -0,0 +1,45 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/rmi/RemoteInteger.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl.rmi;
+
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 22-Feb-2007
+ */
+public interface RemoteInteger extends Remote {
+ public int getInt() throws RemoteException;
+}
diff --git a/src/java/org/apache/commons/ssl/rmi/Test.java b/src/java/org/apache/commons/ssl/rmi/Test.java
new file mode 100644
index 0000000..c2531d6
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/rmi/Test.java
@@ -0,0 +1,200 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/rmi/Test.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl.rmi;
+
+import org.apache.commons.ssl.LogWrapper;
+import org.apache.commons.ssl.RMISocketFactoryImpl;
+
+import java.net.MalformedURLException;
+import java.rmi.Naming;
+import java.rmi.NotBoundException;
+import java.rmi.Remote;
+import java.rmi.RemoteException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.server.RMISocketFactory;
+
+/**
+ * @author Credit Union Central of British Columbia
+ * @author <a href="http://www.cucbc.com/">www.cucbc.com</a>
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at cucbc.com</a>
+ * @since 22-Feb-2007
+ */
+public class Test {
+ private final static LogWrapper log = LogWrapper.getLogger(Test.class);
+ private final static String TEST_DATE_NAME = "/org.apache.commons.ssl.rmi.testdate";
+ private final static String TEST_INT_NAME = "/org.apache.commons.ssl.rmi.testint";
+ protected final static int PORT;
+ protected final static String URL;
+
+ private static boolean rmiRunning = false;
+
+ static {
+ int port = 1099;
+ String host = "127.0.0.1";
+ PORT = port;
+ // e.g. "rmi://localhost:1099/"
+ URL = "rmi://" + host + ":" + port;
+ }
+
+ /**
+ * <p/>
+ * JNDI/RMI lookup wrapper. Appends "java:" if we expect
+ * binding/lookup to occur in the same JVM. Otherwise, appends "rmi:".
+ * </p>
+ *
+ * @param ref String reference.
+ * @return Object Object previously bound with String reference.
+ * @throws java.rmi.RemoteException rmi problem
+ * @throws java.rmi.NotBoundException rmi problem
+ * @throws java.net.MalformedURLException rmi problem
+ */
+ public static Object lookup(String ref)
+ throws RemoteException, NotBoundException, MalformedURLException {
+ return Naming.lookup(URL + ref);
+ }
+
+ /**
+ * <p/>
+ * JNDI/RMI rebind wrapper for the UCS. Appends "java:" if we expect
+ * binding/lookup to occur in the same JVM. Otherwise, append "rmi:".
+ * </p><p>
+ * Also attempts to start a naming server on the localhost if one is
+ * not already running. Currently we use RMI.
+ * </p>
+ *
+ * @param ref String reference to bind with.
+ * @param obj Object to bind.
+ * @throws java.rmi.RemoteException rmi problem
+ * @throws java.net.MalformedURLException rmi problem
+ */
+ public static void rebind(String ref, Remote obj)
+ throws RemoteException, MalformedURLException {
+ requireNameServer();
+ String realRef = URL + ref;
+ Naming.rebind(realRef, obj);
+ try {
+ Object o = lookup(ref);
+ log.debug("Bound " + o.getClass().getName() + " to [" + realRef + "]");
+ }
+ catch (NotBoundException nbe) {
+ log.debug("Error binding " + obj.getClass().getName() + " to [" + realRef + "]");
+ }
+ }
+
+ private static void rebindTest() throws Exception {
+ Remote remoteTest = new DateRMI();
+ Naming.rebind(URL + TEST_DATE_NAME, remoteTest);
+ Object o = Naming.lookup(URL + TEST_DATE_NAME);
+ if (!remoteTest.equals(o)) {
+ throw new RuntimeException("rmi: Test failed. Lookup != Rebind");
+ }
+ }
+
+ /**
+ * <p/>
+ * Attempts to start a naming server on the localhost if one is not
+ * already running.
+ * </p>
+ */
+ private synchronized static void requireNameServer() {
+ if (rmiRunning) {
+ // We've already established that the name server is running.
+ return;
+ }
+ try {
+ // If this rebind works, then the naming server is running.
+ rebindTest();
+ rmiRunning = true;
+ }
+ catch (Exception e) {
+ Test.tryToStartNameServer();
+ try {
+ // Okay, we've started our naming server. Now we must perform a
+ // quick test to see that it's actually doing something.
+ rebindTest();
+ log.debug(Test.class.getName() + " successfully started.");
+ rmiRunning = true;
+ return;
+ }
+ catch (Exception e2) {
+ e2.printStackTrace();
+ log.error(e2.getMessage(), e2);
+ }
+
+ String msg = Test.class.getName() + " cannot start.";
+ log.error(msg);
+ throw new RuntimeException(msg);
+ }
+ }
+
+ public static void tryToStartNameServer() {
+ String className = Test.class.getName();
+ log.debug(className + " probably not running. Trying to start one.");
+ try {
+ LocateRegistry.createRegistry(PORT);
+ log.debug("registry on " + PORT + " started!");
+ }
+ catch (Exception problem) {
+ // bah - no luck
+ problem.printStackTrace();
+ log.warn(problem, problem);
+ }
+ }
+
+
+ public static void main(String[] args) throws Exception {
+ System.setProperty(RMISocketFactoryImpl.RMI_HOSTNAME_KEY, "localhost");
+ RMISocketFactoryImpl impl = new RMISocketFactoryImpl();
+ RMISocketFactory.setSocketFactory(impl);
+
+ if (args.length > 0) {
+
+ } else {
+ Test.requireNameServer();
+ Test.rebindTest();
+
+ IntegerRMI remoteInt = new IntegerRMI();
+ Test.rebind(TEST_INT_NAME, remoteInt);
+ }
+
+ Object o = Test.lookup(TEST_DATE_NAME);
+ RemoteDate rd = (RemoteDate) o;
+ System.out.println("The remote-date is: " + rd.getDate());
+
+ o = Test.lookup(TEST_INT_NAME);
+ RemoteInteger ri = (RemoteInteger) o;
+ System.out.println("The remote-int is: " + ri.getInt());
+
+ }
+
+
+}
diff --git a/src/java/org/apache/commons/ssl/util/Hex.java b/src/java/org/apache/commons/ssl/util/Hex.java
new file mode 100644
index 0000000..52a83fa
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/util/Hex.java
@@ -0,0 +1,83 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/src/java/org/apache/commons/ssl/util/Hex.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.ssl.util;
+
+/**
+ * Utility class for dealing with hex-encoding of binary data.
+ *
+ * @author <a href="mailto:juliusdavies at cucbc.com">juliusdavies at gmail.com</a>
+ * @since 13-Nov-2007
+ */
+public class Hex {
+
+ public static byte[] decode(String s) {
+ byte[] b = new byte[s.length() / 2];
+ for (int i = 0; i < b.length; i++) {
+ String hex = s.substring(2 * i, 2 * (i + 1));
+ b[i] = (byte) Integer.parseInt(hex, 16);
+ }
+ return b;
+ }
+
+ public static byte[] decode(byte[] hexString) {
+ byte[] b = new byte[hexString.length / 2];
+ char[] chars = new char[2];
+ for (int i = 0; i < b.length; i++) {
+ chars[0] = (char) hexString[2 * i];
+ chars[1] = (char) hexString[2 * i + 1];
+ String hex = new String(chars);
+ b[i] = (byte) Integer.parseInt(hex, 16);
+ }
+ return b;
+ }
+
+ public static String encode(byte[] b) {
+ return encode(b, 0, b.length);
+ }
+
+ public static String encode(byte[] b, int offset, int length) {
+ StringBuffer buf = new StringBuffer();
+ int len = Math.min(offset + length, b.length);
+ for (int i = offset; i < len; i++) {
+ int c = (int) b[i];
+ if (c < 0) {
+ c = c + 256;
+ }
+ if (c >= 0 && c <= 15) {
+ buf.append('0');
+ }
+ buf.append(Integer.toHexString(c));
+ }
+ return buf.toString();
+ }
+
+}
diff --git a/src/java/org/apache/commons/ssl/util/PublicKeyDeriver.java b/src/java/org/apache/commons/ssl/util/PublicKeyDeriver.java
new file mode 100644
index 0000000..aa3e26d
--- /dev/null
+++ b/src/java/org/apache/commons/ssl/util/PublicKeyDeriver.java
@@ -0,0 +1,82 @@
+/*
+ * $HeadURL: http://juliusdavies.ca/svn/not-yet-commons-ssl/trunk/src/java/org/apache/commons/ssl/Certificates.java $
+ * $Revision: 121 $
+ * $Date: 2007-11-13 21:26:57 -0800 (Tue, 13 Nov 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.commons.ssl.util;
+
+import java.math.BigInteger;
+import java.security.GeneralSecurityException;
+import java.security.KeyException;
+import java.security.KeyFactory;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPrivateKey;
+import java.security.interfaces.RSAPrivateCrtKey;
+import java.security.spec.DSAPublicKeySpec;
+import java.security.spec.RSAPublicKeySpec;
+
+/**
+ * Utility class for deriving a public key from a given private key.
+ *
+ * @author Chad La Joie <lajoie OF georgetown.edu>
+ * @since November 14th, 2007
+ */
+public class PublicKeyDeriver {
+
+ /**
+ * Utility method for deriving a public key from a given private key.
+ *
+ * @param key private key for which we need a public key (DSA or RSA).
+ * @return the corresponding public key
+ * @throws GeneralSecurityException if it didn't work
+ */
+ public static PublicKey derivePublicKey(PrivateKey key) throws GeneralSecurityException {
+ if (key instanceof DSAPrivateKey) {
+ DSAPrivateKey dsaKey = (DSAPrivateKey) key;
+ DSAParams keyParams = dsaKey.getParams();
+ BigInteger g = keyParams.getG();
+ BigInteger p = keyParams.getP();
+ BigInteger q = keyParams.getQ();
+ BigInteger x = dsaKey.getX();
+ BigInteger y = q.modPow(x, p);
+ DSAPublicKeySpec keySpec = new DSAPublicKeySpec(y, p, q, g);
+ return KeyFactory.getInstance("DSA").generatePublic(keySpec);
+ } else if (key instanceof RSAPrivateCrtKey) {
+ RSAPrivateCrtKey rsaKey = (RSAPrivateCrtKey) key;
+ BigInteger modulus = rsaKey.getModulus();
+ BigInteger exponent = rsaKey.getPublicExponent();
+ RSAPublicKeySpec keySpec = new RSAPublicKeySpec(modulus, exponent);
+ return KeyFactory.getInstance("RSA").generatePublic(keySpec);
+ } else {
+ throw new KeyException("Private key was not a DSA or RSA key");
+ }
+ }
+}
+
diff --git a/version.txt b/version.txt
new file mode 100644
index 0000000..8db9de5
--- /dev/null
+++ b/version.txt
@@ -0,0 +1,3 @@
+$URL: http://juliusdavies.ca/svn/not-yet-commons-ssl/tags/commons-ssl-0.3.9/version.txt $
+$Date: 2007-11-13 21:36:51 -0800 (Tue, 13 Nov 2007) $
+$Revision: 123 $
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/not-yet-commons-ssl.git
More information about the pkg-java-commits
mailing list